diff --git a/.checkpatch.conf b/.checkpatch.conf deleted file mode 100644 index 72c3529c3e9174606f8cd4ca5d773700e0bab690..0000000000000000000000000000000000000000 --- a/.checkpatch.conf +++ /dev/null @@ -1,15 +0,0 @@ ---no-tree ---no-signoff ---summary-file ---show-types ---max-line-length=80 - ---ignore COMPLEX_MACRO ---ignore SPLIT_STRING ---ignore CONST_STRUCT ---ignore FILE_PATH_CHANGES ---ignore MISSING_SIGN_OFF ---ignore PREFER_PACKED ---ignore COMMIT_MESSAGE ---ignore SSCANF_TO_KSTRTO ---ignore SPDX_LICENSE_TAG diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 9f57aa19327ee71fcdb0420aa5375eb803093550..0000000000000000000000000000000000000000 --- a/.gitignore +++ /dev/null @@ -1,189 +0,0 @@ -*.o -*.a -*.lo -*.la -*.so -*.gcno -*.gcda -.deps -.libs -.dirstamp -Makefile -Makefile.in -aclocal.m4 -config.guess -config.h -config.h.in -config.h.in~ -config.log -config.status -config.sub -configure -depcomp -compile -install-sh -libtool -ltmain.sh -missing -stamp-h1 -autom4te.cache -test-driver -test-suite.log -coverage.info -coverage -ell - -lib/bluez.pc -lib/bluetooth -src/builtin.h -src/bluetoothd -tools/97-hid2hci.rules - -profiles/cups/bluetooth -profiles/iap/iapd - -attrib/gatttool -tools/avinfo -tools/bccmd -tools/hwdb -tools/ciptool -tools/ciptool.1 -tools/hciattach -tools/hciattach.1 -tools/hciconfig -tools/hciconfig.1 -tools/hcieventmask -tools/hcisecfilter -tools/hcitool -tools/hcitool.1 -tools/hcidump -tools/hcidump.1 -tools/hid2hci -tools/hid2hci.1 -tools/rfcomm -tools/rfcomm.1 -tools/l2ping -tools/l2ping.1 -tools/l2test -tools/cltest -tools/rctest -tools/rctest.1 -tools/scotest -tools/amptest -tools/oobtest -tools/advtest -tools/sdptool -tools/sdptool.1 -tools/avtest -tools/bdaddr -tools/bluemoon -tools/seq2bseq -tools/hex2hcd -tools/bcmfw -tools/nokfw -tools/rtlfw -tools/btiotest -tools/mpris-proxy -tools/bluetooth-player -tools/l2cap-tester -tools/sco-tester -tools/hci-tester -tools/eddystone -tools/ibeacon -tools/btproxy -tools/btinfo -tools/3dsp -tools/obexctl -tools/gatt-service -tools/btgatt-client -tools/btgatt-server -tools/create-image -tools/test-runner -tools/check-selftest -tools/mcaptest -tools/bneptest -test/sap_client.pyc -test/bluezutils.pyc -unit/test-ringbuf -unit/test-queue -unit/test-eir -unit/test-uuid -unit/test-crc -unit/test-textfile -unit/test-gdbus-client -unit/test-sdp -unit/test-lib -unit/test-mgmt -unit/test-uhid -unit/test-hfp -unit/test-crypto -unit/test-ecc -unit/test-hog -tools/mgmt-tester -tools/smp-tester -tools/gap-tester -tools/rfcomm-tester -tools/bnep-tester -tools/userchan-tester -tools/btattach -tools/btattach.1 -tools/btconfig -tools/btmgmt -tools/btsnoop -tools/btpclient -tools/btpclientctl -tools/btmon-logger -tools/bluetooth-logger.service -peripheral/btsensor -monitor/btmon -monitor/btmon.1 -emulator/btvirt -emulator/b1ee -emulator/hfp -client/bluetoothctl -tools/meshctl -tools/mesh-cfgclient -tools/mesh-cfgtest -mesh/bluetooth-meshd -mesh/bluetooth-meshd.8 -mesh/bluetooth-meshd.rst - -src/bluetoothd.8 -src/bluetoothd.rst -src/bluetooth.service -mesh/bluetooth-mesh.service - -obexd/src/builtin.h -obexd/src/obexd -obexd/src/obex.service -tools/obex-client-tool -tools/obex-server-tool -unit/test-gobex -unit/test-gobex-apparam -unit/test-gobex-header -unit/test-gobex-packet -unit/test-gobex-transfer -unit/test-avdtp -unit/test-avctp -unit/test-avrcp -unit/test-gatt -unit/test-midi -unit/test-gattrib -unit/test-mesh-crypto -unit/test-*.log -unit/test-*.trs - -android/system-emulator -android/bluetoothd -android/avdtptest -android/haltest -android/android-tester -android/ipc-tester -android/bluetoothd-snoop -android/test-ipc -android/test-*.log -android/test-*.trs - -cscope.in.out -cscope.out -cscope.po.out diff --git a/.gitlint b/.gitlint deleted file mode 100644 index 59ed7d605edc87f31eff1c54d1d3207941499934..0000000000000000000000000000000000000000 --- a/.gitlint +++ /dev/null @@ -1,48 +0,0 @@ -# All these sections are optional, edit this file as you like. -# [general] -# ignore=title-trailing-punctuation, T3 -# verbosity should be a value between 1 and 3, the commandline -v flags take precedence over this -# verbosity = 2 -# By default gitlint will ignore merge commits. Set to 'false' to disable. -# ignore-merge-commits=true -# Enable debug mode (prints more output). Disabled by default. -# debug=true - -# Set the extra-path where gitlint will search for user defined rules -# See http://jorisroovers.github.io/gitlint/user_defined_rules for details -# extra-path=examples/ - -[title-max-length] -line-length=72 - -# [title-must-not-contain-word] -# Comma-separated list of words that should not occur in the title. Matching is case -# insensitive. It's fine if the keyword occurs as part of a larger word (so "WIPING" -# will not cause a violation, but "WIP: my title" will. -# words=wip - -# [title-match-regex] -# python like regex (https://docs.python.org/2/library/re.html) that the -# commit-msg title must be matched to. -# Note that the regex can contradict with other rules if not used correctly -# (e.g. title-must-not-contain-word). -# regex=^US[0-9]* - -# [B1] -# B1 = body-max-line-length -# line-length=120 - -[body-min-length] -min-length=1 - -# [body-is-missing] -# Whether to ignore this rule on merge commits (which typically only have a title) -# default = True -# ignore-merge-commits=false - -# [body-changed-file-mention] -# List of files that need to be explicitly mentioned in the body when they are changed -# This is useful for when developers often erroneously edit certain files or git submodules. -# By specifying this rule, developers can only change the file when they explicitly reference -# it in the commit message. -# files=gitlint/rules.py,README.md diff --git a/.mailmap b/.mailmap deleted file mode 100644 index a7e36e3037a5f807522a264c4380be794468e0ae..0000000000000000000000000000000000000000 --- a/.mailmap +++ /dev/null @@ -1,11 +0,0 @@ -Luiz Augusto von Dentz <luiz.dentz-von@nokia.com> <luiz.dentz-von@nokia.com> -Vinicius Costa Gomes <vinicius.gomes@openbossa.org> <vinicius.gomes@openbossa.org> -Elvis Pfützenreuter <epx@signove.com> <epx@signove.com> -Santiago Carot-Nemesio <scarot@libresoft.es> <scarot@libresoft.es> -José Antonio Santos Cadenas <santoscadenas@gmail.com> <santoscadenas@gmail.com> -Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com> <Waldemar.Rymarkiewicz@tieto.com> -Alok Barsode <alokbarsode@gmail.com> <alok@greatbear.(none)> -André Dieb Martins <andre.dieb@signove.com> <andre.dieb@signove.com> -Tedd Ho-Jeong An <tedd.an@intel.com> <tedd.an@intel.com> -Martin Xu <martin.xu@linux.intel.com> <martin.xu@linux.intel.com> -Marie Janssen <jamuraa@chromium.org> <jamuraa@chromium.org> diff --git a/AUTHORS b/AUTHORS index 291d9b049128e4a91a5a0f274506d43a5d2fafe4..879f97f99c652dd47a683ab9e930b6d84c9d5e97 100644 --- a/AUTHORS +++ b/AUTHORS @@ -53,7 +53,7 @@ Daniel Orstadius <daniel.orstadius@gmail.com> Anderson Briglia <anderson.briglia@openbossa.org> Anderson Lizardo <anderson.lizardo@openbossa.org> Bruna Moreira <bruna.moreira@openbossa.org> -Brian Gix <brian.gix@intel.com> +Brian Gix <brian.gix@gmail.com> Andre Guedes <andre.guedes@openbossa.org> Sheldon Demario <sheldon.demario@openbossa.org> Lucas De Marchi <lucas.demarchi@profusion.mobi> @@ -84,7 +84,7 @@ Petri Gynther <pgynther@google.com> Scott James Remnant <scott@netsplit.com> Jakub Tyszkowski <jakub.tyszkowski@tieto.com> Grzegorz KoÅ‚odziejczyk <grzegorz.kolodziejczyk@codecoup.pl> -Marcin KrÄ…glak <marcin.kraglak@tieto.com> +Marcin KrÄ…glak <marcin.kraglak@telink-semi.com> Åukasz Rymanowski <lukasz.rymanowski@codecoup.pl> Jerzy Kasenberg <jerzy.kasenberg@tieto.com> Arman Uguray <armansito@chromium.org> diff --git a/ChangeLog b/ChangeLog index ad0e6799c7c1a741abbfdc062b7b7cf23d512b6e..766f0a89957be9c1d995282ba019608cbb8c9eac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,95 @@ +ver 5.79: + Fix issue with handling address type while pairing. + Add support for allowing to set A2DP transport delay. + Add support for persistent userspace HID operation. + Add support for handling syncing to multiple BISes. + +ver 5.78: + Fix issue with handling notification of scanned BISes to BASS + Fix issue with handling checking BIS caps against peer caps. + Fix issue with handling MGMT Set Device Flags overwrites. + Fix issue with handling ASE notification order. + Fix issue with handling BIG Info report events. + Fix issue with handling PACS Server role. + Fix issue with registering UHID_START multiple times. + Fix issue with pairing method not setting auto-connect. + +ver 5.77: + Fix issue with storing and handling connection parameters. + Fix issue with handling device that are marked as temporary. + Fix issue with HID and special handling for non-keyboards. + Fix issue with BR/EDR not support when discoverable is off. + Add support for initial implementation of ASHA profile. + +ver 5.76: + Fix issue with broadcast channel location and stream capabilities. + Fix issue with handling BIS management and synchronization. + Fix issue with handling Extended Advertising. + Fix issue with UserspaceHID and replay structures. + Add support for providing PPCP characteristic. + +ver 5.75: + Fix issue with build system and header inclusion. + +ver 5.74: + Fix issue with not enabling Wideband Speech when available. + Fix issue with UserspaceHID and Bluetooth Classic devices. + Fix issue with checking for services being connected. + Fix issue with GATT client connection creation. + Fix issue with OBEX and small file transfers. + Fix issue with handling pairing with Apple AirPods. + +ver 5.73: + Fix issue with BAP and setting up broadcast source. + Fix issue with BAP and register all endpoints. + Fix issue with BAP and missing metadata property. + Fix issue with BAP and not handling out of order responses. + Fix issue with BAP and attempting to set device as connectable. + Add support for CCP plugin for call control profile. + +ver 5.72: + Fix issue with BAP and handling stream IO linking. + Fix issue with BAP and setup of multiple streams per endpoint. + Fix issue with AVDTP and potential incorrect transaction label. + Fix issue with A2DP and handling crash on suspend. + Fix issue with GATT database and an invalid pointer. + Add support for AICS service. + +ver 5.71: + Fix issue with not registering CSIS service. + Fix issue with registering pairing callbacks. + Fix issue with corruption during discovery filter parsing. + +ver 5.70: + Fix issue with not sending GATT confirmations. + Fix issue with not handling initiator properly. + Fix issue with not checking PBAP counter length. + Add support for MICP profile and MICS service. + +ver 5.69: + Fix issue with BAP enabling state correctly when resuming. + Fix issue with detaching source ASEs only after Stop Ready. + Fix issue with handling VCP audio location and descriptor. + Fix issue with generating IRK for adapter with privacy enabled. + Add support for BAP broadcast sink. + +ver 5.68: + Fix issue with A2DP and handling of Transport.Acquire. + +ver 5.67: + Fix issue with BAP and initiating QoS and Enable procedures. + Fix issue with BAP and detaching streams when PAC is removed. + Fix issue with BAP and reading all instances of PAC. + Fix issue with BAP and not being able to reconfigure. + Fix issue with BAP and transport configuration changes. + Fix issue with BAP and handling unexpected disconnect. + Fix issue with GATT and not removing pending services. + Fix issue with GATT and client ready handling. + Fix issue with handling fallback to transient hostname. + Add support for SecureConnections configuration option. + Add support for Mesh Remove Provisioning. + Add support for Mesh Private Beacons. + ver 5.66: Fix issue with A2DP and transport connection collisions. Fix issue with allowing application specific error codes. diff --git a/HACKING b/HACKING deleted file mode 100644 index 29b136b34054c30f7f5462558347a7e687c4c8e3..0000000000000000000000000000000000000000 --- a/HACKING +++ /dev/null @@ -1,151 +0,0 @@ -Hacking on BlueZ -**************** - -Build tools requirements -======================== - -When building and testing directly from the repository it is important to -have at least automake version 1.10 or later installed. - - -Working with the source code repository -======================================= - -The repository contains two extra scripts that accomplish the bootstrap -process. One is called "bootstrap" which is the basic scripts that uses the -autotools scripts to create the needed files for building and installing. -It makes sure to call the right programs depending on the usage of shared or -static libraries or translations etc. - -The second program is called "bootstrap-configure". This program will make -sure to properly clean the repository, call the "bootstrap" script and then -call configure with proper settings for development. It will use the best -options and pass them over to configure. These options normally include -the enabling the maintainer mode and the debugging features. - -So while in a normal source project the call "./configure ..." is used to -configure the project with its settings like prefix and extra options. In -case of bare repositories call "./bootstrap-configure" and it will bootstrap -the repository and calls configure with all the correct options to make -development easier. - -In case of preparing for a release with "make distcheck", don't use -bootstrap-configure since it could export development specific settings. - -So the normal steps to checkout, build and install such a repository is -like this: - - Checkout repository - # git clone git://git.kernel.org/pub/scm/bluetooth/bluez.git - # cd bluez - - Configure and build - # ./bootstrap-configure - # make - - Configure and build with cgcc (Sparse) - # ./bootstrap-configure CC=cgcc - # make - - Run unit tests - # make check - - Check installation - # make install DESTDIR=$PWD/x - # find x - # rm -rf x - - Check distribution - # make distcheck - - Final installation - # sudo make install - - Remove autogenerated files - # make maintainer-clean - - -Running from within the source code repository -============================================== - -When using "./configure --enable-maintainer-mode" the automake scripts will -use the plugins directly from within the repository. This removes the need -to use "make install" when testing "bluetoothd". The "bootstrap-configure" -automatically includes this option. - - Copy configuration file which specifies the required security policies - # sudo cp ./src/bluetooth.conf /etc/dbus-1/system.d/ - - Disable SELinux - # sudo setenforce 0 - - Run daemon in foreground with debugging - # sudo ./src/bluetoothd -n -d -f ./src/main.conf - - Run daemon with valgrind - # sudo valgrind --trace-children=yes --track-origins=yes --track-fds=yes \ - --show-possibly-lost=no --leak-check=full --suppressions=./tools/valgrind.supp \ - ./src/bluetoothd -n -d -f ./src/main.conf - -For production installations or distribution packaging it is important that -the "--enable-maintainer-mode" option is NOT used. - -Note multiple arguments to -d can be specified, colon, comma or space -separated. The arguments are relative source code filenames for which -debugging output should be enabled; output shell-style globs are -accepted (e.g.: 'plugins/*:src/main.c'). - -Submitting patches -================== - -If you fixed a bug or you want to add support for something, patches are -welcome! In order to ease the inclusion of your patch, it's important to follow -some rules, otherwise it will likely be rejected by maintainers. - -Make sure the author name and email are set properly: - - # git config --global user.name <name> - # git config --global user.email <email> - -The preferred way to send patches is by email, using git send-email: - - # git config --global sendemail.smtpencryption <tls> - # git config --global sendemail.smtpserver <smtp.gmail.com> - # git config --global sendemail.smtpuser <yourname@gmail.com> - # git config --global sendemail.smtpserverport <587> - # git config sendemail.to linux-bluetooth@vger.kernel.org - -BlueZ rules for submitting patches follow most of the rules used by Linux kernel -(https://www.kernel.org/doc/Documentation/SubmittingPatches) with some remarks: - -1) Do *not* add "Signed-off-by" lines in your commit messages. BlueZ does not -use them, so including them is actually an error. - -2) Be sure to follow the coding style rules of BlueZ. They are listed in -doc/coding-style.txt. - -3) Split your patch according to the top-level directories. E.g.: if you added -a feature that touches files under 'include/', 'src/' and 'drivers/' -directories, split in three separated patches, taking care not to -break compilation. - -4) Bug fixes should be sent first as they take priority over new features. - -5) The commit message should follow 50/72 formatting which means the header -should be limited to 50 characters and the description should be wrapped at 72 -characters except if it contains quoted information from debug tools like -backtraces, compiler errors, etc. - -6) Prefix the email subject with [PATCH BlueZ]: - - # git config format.subjectprefix "PATCH BlueZ" - -7) Add a cover letter when introducing a new feature explaning what problem -you're trying to solve: - - # git format-patch --cover-letter -M origin/master -o outgoing/ - # edit outgoing/0000-* - -8) Submit: - - # git send-email outgoing/* diff --git a/LICENSES/dual/Apache-2.0 b/LICENSES/dual/Apache-2.0 deleted file mode 100644 index 6e89ddeab187e08398d1b7804fc740ca0e1c427c..0000000000000000000000000000000000000000 --- a/LICENSES/dual/Apache-2.0 +++ /dev/null @@ -1,187 +0,0 @@ -Valid-License-Identifier: Apache-2.0 -SPDX-URL: https://spdx.org/licenses/Apache-2.0.html -Usage-Guide: - Do NOT use. The Apache-2.0 is not GPL2 compatible. It may only be used - for dual-licensed files where the other license is GPL2 compatible. - If you end up using this it MUST be used together with a GPL2 compatible - license using "OR". - To use the Apache License version 2.0 put the following SPDX tag/value - pair into a comment according to the placement guidelines in the - licensing rules documentation: - SPDX-License-Identifier: Apache-2.0 -License-Text: - -Apache License - -Version 2.0, January 2004 - -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the -copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other -entities that control, are controlled by, or are under common control with -that entity. For the purposes of this definition, "control" means (i) the -power, direct or indirect, to cause the direction or management of such -entity, whether by contract or otherwise, or (ii) ownership of fifty -percent (50%) or more of the outstanding shares, or (iii) beneficial -ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, -including but not limited to software source code, documentation source, -and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation -or translation of a Source form, including but not limited to compiled -object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, -made available under the License, as indicated by a copyright notice that -is included in or attached to the work (an example is provided in the -Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, -that is based on (or derived from) the Work and for which the editorial -revisions, annotations, elaborations, or other modifications represent, as -a whole, an original work of authorship. For the purposes of this License, -Derivative Works shall not include works that remain separable from, or -merely link (or bind by name) to the interfaces of, the Work and Derivative -Works thereof. - -"Contribution" shall mean any work of authorship, including the original -version of the Work and any modifications or additions to that Work or -Derivative Works thereof, that is intentionally submitted to Licensor for -inclusion in the Work by the copyright owner or by an individual or Legal -Entity authorized to submit on behalf of the copyright owner. For the -purposes of this definition, "submitted" means any form of electronic, -verbal, or written communication sent to the Licensor or its -representatives, including but not limited to communication on electronic -mailing lists, source code control systems, and issue tracking systems that -are managed by, or on behalf of, the Licensor for the purpose of discussing -and improving the Work, but excluding communication that is conspicuously -marked or otherwise designated in writing by the copyright owner as "Not a -Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on -behalf of whom a Contribution has been received by Licensor and -subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this - License, each Contributor hereby grants to You a perpetual, worldwide, - non-exclusive, no-charge, royalty-free, irrevocable copyright license to - reproduce, prepare Derivative Works of, publicly display, publicly - perform, sublicense, and distribute the Work and such Derivative Works - in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this - License, each Contributor hereby grants to You a perpetual, worldwide, - non-exclusive, no-charge, royalty-free, irrevocable (except as stated in - this section) patent license to make, have made, use, offer to sell, - sell, import, and otherwise transfer the Work, where such license - applies only to those patent claims licensable by such Contributor that - are necessarily infringed by their Contribution(s) alone or by - combination of their Contribution(s) with the Work to which such - Contribution(s) was submitted. If You institute patent litigation - against any entity (including a cross-claim or counterclaim in a - lawsuit) alleging that the Work or a Contribution incorporated within - the Work constitutes direct or contributory patent infringement, then - any patent licenses granted to You under this License for that Work - shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or - Derivative Works thereof in any medium, with or without modifications, - and in Source or Object form, provided that You meet the following - conditions: - - a. You must give any other recipients of the Work or Derivative Works a - copy of this License; and - - b. You must cause any modified files to carry prominent notices stating - that You changed the files; and - - c. You must retain, in the Source form of any Derivative Works that You - distribute, all copyright, patent, trademark, and attribution notices - from the Source form of the Work, excluding those notices that do not - pertain to any part of the Derivative Works; and - - d. If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained within - such NOTICE file, excluding those notices that do not pertain to any - part of the Derivative Works, in at least one of the following - places: within a NOTICE text file distributed as part of the - Derivative Works; within the Source form or documentation, if - provided along with the Derivative Works; or, within a display - generated by the Derivative Works, if and wherever such third-party - notices normally appear. The contents of the NOTICE file are for - informational purposes only and do not modify the License. You may - add Your own attribution notices within Derivative Works that You - distribute, alongside or as an addendum to the NOTICE text from the - Work, provided that such additional attribution notices cannot be - construed as modifying the License. - - You may add Your own copyright statement to Your modifications and may - provide additional or different license terms and conditions for use, - reproduction, or distribution of Your modifications, or for any such - Derivative Works as a whole, provided Your use, reproduction, and - distribution of the Work otherwise complies with the conditions stated - in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any - Contribution intentionally submitted for inclusion in the Work by You to - the Licensor shall be under the terms and conditions of this License, - without any additional terms or conditions. Notwithstanding the above, - nothing herein shall supersede or modify the terms of any separate - license agreement you may have executed with Licensor regarding such - Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to - in writing, Licensor provides the Work (and each Contributor provides - its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS - OF ANY KIND, either express or implied, including, without limitation, - any warranties or conditions of TITLE, NON-INFRINGEMENT, - MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely - responsible for determining the appropriateness of using or - redistributing the Work and assume any risks associated with Your - exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether - in tort (including negligence), contract, or otherwise, unless required - by applicable law (such as deliberate and grossly negligent acts) or - agreed to in writing, shall any Contributor be liable to You for - damages, including any direct, indirect, special, incidental, or - consequential damages of any character arising as a result of this - License or out of the use or inability to use the Work (including but - not limited to damages for loss of goodwill, work stoppage, computer - failure or malfunction, or any and all other commercial damages or - losses), even if such Contributor has been advised of the possibility of - such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the - Work or Derivative Works thereof, You may choose to offer, and charge a - fee for, acceptance of support, warranty, indemnity, or other liability - obligations and/or rights consistent with this License. However, in - accepting such obligations, You may act only on Your own behalf and on - Your sole responsibility, not on behalf of any other Contributor, and - only if You agree to indemnify, defend, and hold each Contributor - harmless for any liability incurred by, or claims asserted against, such - Contributor by reason of your accepting any such warranty or additional - liability. - -END OF TERMS AND CONDITIONS diff --git a/LICENSES/preferred/BSD-2-Clause b/LICENSES/preferred/BSD-2-Clause deleted file mode 100644 index da366e2ce50be9b4ec250cad773677bee7fc1d9d..0000000000000000000000000000000000000000 --- a/LICENSES/preferred/BSD-2-Clause +++ /dev/null @@ -1,32 +0,0 @@ -Valid-License-Identifier: BSD-2-Clause -SPDX-URL: https://spdx.org/licenses/BSD-2-Clause.html -Usage-Guide: - To use the BSD 2-clause "Simplified" License put the following SPDX - tag/value pair into a comment according to the placement guidelines in - the licensing rules documentation: - SPDX-License-Identifier: BSD-2-Clause -License-Text: - -Copyright (c) <year> <owner> . All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSES/preferred/GPL-2.0 b/LICENSES/preferred/GPL-2.0 deleted file mode 100644 index 9d6c26e6ff97656fffad65172ddf757576133017..0000000000000000000000000000000000000000 --- a/LICENSES/preferred/GPL-2.0 +++ /dev/null @@ -1,355 +0,0 @@ -Valid-License-Identifier: GPL-2.0 -Valid-License-Identifier: GPL-2.0-only -Valid-License-Identifier: GPL-2.0-or-later -SPDX-URL: https://spdx.org/licenses/GPL-2.0.html -Usage-Guide: - To use this license in source code, put one of the following SPDX - tag/value pairs into a comment according to the placement - guidelines in the licensing rules documentation. - For 'GNU General Public License (GPL) version 2 only' use: - SPDX-License-Identifier: GPL-2.0-only - For 'GNU General Public License (GPL) version 2 or any later version' use: - SPDX-License-Identifier: GPL-2.0-or-later -License-Text: - - 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 -1:w -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/LICENSES/preferred/LGPL-2.1 b/LICENSES/preferred/LGPL-2.1 deleted file mode 100644 index 8e08d6ea5f8d4752f71c215f30ee631356b2eab0..0000000000000000000000000000000000000000 --- a/LICENSES/preferred/LGPL-2.1 +++ /dev/null @@ -1,503 +0,0 @@ -Valid-License-Identifier: LGPL-2.1 -Valid-License-Identifier: LGPL-2.1-or-later -SPDX-URL: https://spdx.org/licenses/LGPL-2.1.html -Usage-Guide: - To use this license in source code, put one of the following SPDX - tag/value pairs into a comment according to the placement - guidelines in the licensing rules documentation. - For 'GNU Lesser General Public License (LGPL) version 2.1 only' use: - SPDX-License-Identifier: LGPL-2.1 - For 'GNU Lesser General Public License (LGPL) version 2.1 or any later - version' use: - SPDX-License-Identifier: LGPL-2.1-or-later -License-Text: - -GNU LESSER GENERAL PUBLIC LICENSE -Version 2.1, February 1999 - -Copyright (C) 1991, 1999 Free Software Foundation, Inc. -51 Franklin Street, 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. - -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 an 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 Street, 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/LICENSES/preferred/MIT b/LICENSES/preferred/MIT deleted file mode 100644 index f33a68ceb3ea00a533d2331a091ec7f2580bb4df..0000000000000000000000000000000000000000 --- a/LICENSES/preferred/MIT +++ /dev/null @@ -1,30 +0,0 @@ -Valid-License-Identifier: MIT -SPDX-URL: https://spdx.org/licenses/MIT.html -Usage-Guide: - To use the MIT License put the following SPDX tag/value pair into a - comment according to the placement guidelines in the licensing rules - documentation: - SPDX-License-Identifier: MIT -License-Text: - -MIT License - -Copyright (c) <year> <copyright holders> - -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. diff --git a/Makefile.am b/Makefile.am index 7041f8eeb52bd4d3fc411054444cc328bc448ce9..f639f7f8b0a32d8d7de3a9c9cb1310d51e09d99d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,7 +16,7 @@ CLEANFILES = EXTRA_DIST = -pkglibexecdir = $(libexecdir)/bluetooth +pkglibexecdir = @PKGLIBEXECDIR@ pkglibexec_PROGRAMS = @@ -31,11 +31,17 @@ AM_LDFLAGS = $(MISC_LDFLAGS) confdir = $(sysconfdir)/bluetooth statedir = $(localstatedir)/lib/bluetooth +bluetoothd-fix-permissions: + install -dm555 $(DESTDIR)$(confdir) + install -dm700 $(DESTDIR)$(statedir) + if DATAFILES dbusdir = $(DBUS_CONFDIR)/dbus-1/system.d dbus_DATA = src/bluetooth.conf -conf_DATA = +conf_DATA = src/main.conf +conf_DATA += profiles/input/input.conf +conf_DATA += profiles/network/network.conf state_DATA = endif @@ -43,19 +49,18 @@ if SYSTEMD systemdsystemunitdir = $(SYSTEMD_SYSTEMUNITDIR) systemdsystemunit_DATA = src/bluetooth.service +systemduserunitdir = $(SYSTEMD_USERUNITDIR) +systemduserunit_DATA = + dbussystembusdir = $(DBUS_SYSTEMBUSDIR) dbussystembus_DATA = src/org.bluez.service endif -EXTRA_DIST += src/bluetooth.service.in src/org.bluez.service +EXTRA_DIST += src/org.bluez.service plugindir = $(libdir)/bluetooth/plugins -if MAINTAINER_MODE -build_plugindir = $(abs_top_srcdir)/plugins/.libs -else build_plugindir = $(plugindir) -endif if MANPAGES man_MANS = @@ -82,8 +87,7 @@ pkginclude_HEADERS += $(lib_headers) lib_LTLIBRARIES += lib/libbluetooth.la lib_libbluetooth_la_SOURCES = $(lib_headers) $(lib_sources) -lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 22:8:19 -lib_libbluetooth_la_DEPENDENCIES = $(local_headers) +lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 22:15:19 endif noinst_LTLIBRARIES += lib/libbluetooth-internal.la @@ -100,12 +104,10 @@ gdbus_libgdbus_internal_la_SOURCES = gdbus/gdbus.h \ if EXTERNAL_ELL ell_cflags = @ELL_CFLAGS@ ell_ldadd = @ELL_LIBS@ -ell_dependencies = ell_built_sources = ell/shared else ell_cflags = ell_ldadd = ell/libell-internal.la -ell_dependencies = $(ell_ldadd) ell_built_sources = ell/shared ell/internal ell/ell.h noinst_LTLIBRARIES += ell/libell-internal.la @@ -231,9 +233,16 @@ shared_sources = src/shared/io.h src/shared/timeout.h \ src/shared/gap.h src/shared/gap.c \ src/shared/log.h src/shared/log.c \ src/shared/bap.h src/shared/bap.c src/shared/ascs.h \ + src/shared/bap-debug.h src/shared/bap-debug.c \ src/shared/mcs.h src/shared/mcp.h src/shared/mcp.c \ src/shared/vcp.c src/shared/vcp.h \ - src/shared/lc3.h src/shared/tty.h + src/shared/micp.c src/shared/micp.h \ + src/shared/csip.c src/shared/csip.h \ + src/shared/bass.h src/shared/bass.c \ + src/shared/ccp.h src/shared/ccp.c \ + src/shared/lc3.h src/shared/tty.h \ + src/shared/bap-defs.h \ + src/shared/asha.h src/shared/asha.c if READLINE shared_sources += src/shared/shell.c src/shared/shell.h @@ -284,24 +293,14 @@ gobex_sources = gobex/gobex.h gobex/gobex.c \ builtin_modules = builtin_sources = builtin_cppflags = -builtin_nodist = builtin_ldadd = include Makefile.plugins -if MAINTAINER_MODE -plugin_LTLIBRARIES += plugins/external-dummy.la -plugins_external_dummy_la_SOURCES = plugins/external-dummy.c -plugins_external_dummy_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \ - -no-undefined -plugins_external_dummy_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden -endif - pkglibexec_PROGRAMS += src/bluetoothd src_bluetoothd_SOURCES = $(builtin_sources) \ $(attrib_sources) $(btio_sources) \ - src/bluetooth.ver \ src/main.c src/log.h src/log.c \ src/backtrace.h src/backtrace.c \ src/rfkill.c src/btd.h src/sdpd.h \ @@ -326,35 +325,99 @@ src_bluetoothd_SOURCES = $(builtin_sources) \ src/eir.h src/eir.c \ src/adv_monitor.h src/adv_monitor.c \ src/battery.h src/battery.c \ - src/settings.h src/settings.c + src/settings.h src/settings.c \ + src/set.h src/set.c src_bluetoothd_LDADD = lib/libbluetooth-internal.la \ gdbus/libgdbus-internal.la \ src/libshared-glib.la \ $(BACKTRACE_LIBS) $(GLIB_LIBS) $(DBUS_LIBS) -ldl -lrt \ $(builtin_ldadd) + +if EXTERNAL_PLUGINS +src_bluetoothd_SOURCES += src/bluetooth.ver src_bluetoothd_LDFLAGS = $(AM_LDFLAGS) -Wl,--export-dynamic \ -Wl,--version-script=$(srcdir)/src/bluetooth.ver - -src_bluetoothd_DEPENDENCIES = lib/libbluetooth-internal.la \ - gdbus/libgdbus-internal.la \ - src/libshared-glib.la \ - src/bluetooth.service +endif src_bluetoothd_CPPFLAGS = $(AM_CPPFLAGS) -DBLUETOOTH_PLUGIN_BUILTIN \ -DPLUGINDIR=\""$(build_plugindir)"\" \ $(BACKTRACE_CFLAGS) $(builtin_cppflags) src_bluetoothd_SHORTNAME = bluetoothd -builtin_files = src/builtin.h $(builtin_nodist) +builtin_files = src/builtin.h nodist_src_bluetoothd_SOURCES = $(builtin_files) -CLEANFILES += $(builtin_files) src/bluetooth.service +CLEANFILES += $(builtin_files) if MANPAGES man_MANS += src/bluetoothd.8 +man_MANS += doc/hci.7 doc/l2cap.7 doc/rfcomm.7 +man_MANS += doc/org.bluez.Adapter.5 doc/org.bluez.Device.5 \ + doc/org.bluez.DeviceSet.5 doc/org.bluez.AgentManager.5 \ + doc/org.bluez.Agent.5 doc/org.bluez.ProfileManager.5 \ + doc/org.bluez.Profile.5 doc/org.bluez.NetworkServer.5 \ + doc/org.bluez.Network.5 doc/org.bluez.Input.5 \ + doc/org.bluez.BatteryProviderManager.5 \ + doc/org.bluez.BatteryProvider.5 doc/org.bluez.Battery.5 \ + doc/org.bluez.AdminPolicySet.5 \ + doc/org.bluez.AdminPolicyStatus.5 +man_MANS += doc/org.bluez.Media.5 doc/org.bluez.MediaControl.5 \ + doc/org.bluez.MediaPlayer.5 doc/org.bluez.MediaFolder.5 \ + doc/org.bluez.MediaItem.5 doc/org.bluez.MediaEndpoint.5 \ + doc/org.bluez.MediaTransport.5 doc/org.bluez.MediaAssistant.5 +man_MANS += doc/org.bluez.GattManager.5 doc/org.bluez.GattProfile.5 \ + doc/org.bluez.GattService.5 \ + doc/org.bluez.GattCharacteristic.5 \ + doc/org.bluez.GattDescriptor.5 \ + doc/org.bluez.LEAdvertisingManager.5 \ + doc/org.bluez.LEAdvertisement.5 \ + doc/org.bluez.AdvertisementMonitorManager.5 \ + doc/org.bluez.AdvertisementMonitor.5 +man_MANS += doc/org.bluez.obex.Client.5 doc/org.bluez.obex.Session.5 \ + doc/org.bluez.obex.Transfer.5 \ + doc/org.bluez.obex.ObjectPush.5 \ + doc/org.bluez.obex.FileTransfer.5 \ + doc/org.bluez.obex.Synchronization.5 \ + doc/org.bluez.obex.PhonebookAccess.5 \ + doc/org.bluez.obex.MessageAccess.5 \ + doc/org.bluez.obex.Message.5 \ + doc/org.bluez.obex.AgentManager.5 doc/org.bluez.obex.Agent.5 \ + doc/org.bluez.obex.Image.5 endif manual_pages += src/bluetoothd.8 +manual_pages += doc/hci.7 doc/l2cap.7 doc/rfcomm.7 +manual_pages += doc/org.bluez.Adapter.5 doc/org.bluez.Device.5 \ + doc/org.bluez.DeviceSet.5 doc/org.bluez.AgentManager.5 \ + doc/org.bluez.Agent.5 doc/org.bluez.ProfileManager.5 \ + doc/org.bluez.Profile.5 doc/org.bluez.NetworkServer.5 \ + doc/org.bluez.Network.5 doc/org.bluez.Input.5\ + doc/org.bluez.BatteryProviderManager.5 \ + doc/org.bluez.BatteryProvider.5 doc/org.bluez.Battery.5 \ + doc/org.bluez.AdminPolicySet.5 \ + doc/org.bluez.AdminPolicyStatus.5 +manual_pages += doc/org.bluez.Media.5 doc/org.bluez.MediaControl.5 \ + doc/org.bluez.MediaPlayer.5 doc/org.bluez.MediaFolder.5 \ + doc/org.bluez.MediaItem.5 doc/org.bluez.MediaEndpoint.5 \ + doc/org.bluez.MediaTransport.5 doc/org.bluez.MediaAssistant.5 +manual_pages += doc/org.bluez.GattManager.5 doc/org.bluez.GattProfile.5 \ + doc/org.bluez.GattService.5 \ + doc/org.bluez.GattCharacteristic.5 \ + doc/org.bluez.GattDescriptor.5 \ + doc/org.bluez.LEAdvertisingManager.5 \ + doc/org.bluez.LEAdvertisement.5 \ + doc/org.bluez.AdvertisementMonitorManager.5 \ + doc/org.bluez.AdvertisementMonitor.5 +manual_pages += doc/org.bluez.obex.Client.5 doc/org.bluez.obex.Session.5 \ + doc/org.bluez.obex.Transfer.5 \ + doc/org.bluez.obex.ObjectPush.5 \ + doc/org.bluez.obex.FileTransfer.5 \ + doc/org.bluez.obex.Synchronization.5 \ + doc/org.bluez.obex.PhonebookAccess.5 \ + doc/org.bluez.obex.MessageAccess.5 \ + doc/org.bluez.obex.Message.5 \ + doc/org.bluez.obex.AgentManager.5 doc/org.bluez.obex.Agent.5 \ + doc/org.bluez.obex.Image.5 EXTRA_DIST += src/genbuiltin src/bluetooth.conf \ src/main.conf profiles/network/network.conf \ @@ -368,6 +431,14 @@ include Makefile.obexd include android/Makefile.am include Makefile.mesh +if SYSTEMD +install-data-hook: obexd-add-service-symlink +else +install-data-hook: bluetoothd-fix-permissions obexd-add-service-symlink +endif + +uninstall-hook: obexd-remove-service-symlink + if HID2HCI rulesdir = $(UDEV_DIR)/rules.d @@ -387,19 +458,49 @@ EXTRA_DIST += $(test_scripts) EXTRA_DIST += doc/assigned-numbers.txt doc/supported-features.txt \ doc/test-coverage.txt \ - doc/test-runner.txt \ + doc/test-runner.rst \ doc/settings-storage.txt EXTRA_DIST += doc/mgmt-api.txt \ - doc/adapter-api.txt doc/device-api.txt \ - doc/agent-api.txt doc/profile-api.txt \ - doc/network-api.txt doc/media-api.txt \ - doc/health-api.txt doc/sap-api.txt \ - doc/input-api.txt - -EXTRA_DIST += doc/gatt-api.txt doc/advertising-api.txt - -EXTRA_DIST += doc/obex-api.txt doc/obex-agent-api.txt + doc/health-api.txt \ + doc/sap-api.txt + +EXTRA_DIST += doc/hci.rst doc/l2cap.rst doc/rfcomm.rst + +EXTRA_DIST += doc/org.bluez.Adapter.rst doc/org.bluez.Device.rst \ + doc/org.bluez.DeviceSet.rst doc/org.bluez.AgentManager.rst \ + doc/org.bluez.Agent.rst doc/org.bluez.ProfileManager.rst \ + doc/org.bluez.Profile.rst doc/org.bluez.NetworkServer.rst \ + doc/org.bluez.Network.rst doc/org.bluez.Input.rst \ + doc/org.bluez.BatteryProviderManager.rst \ + doc/org.bluez.BatteryProvider.rst doc/org.bluez.Battery.rst \ + doc/org.bluez.AdminPolicySet.rst \ + doc/org.bluez.AdminPolicyStatus.rst + +EXTRA_DIST += doc/org.bluez.Media.rst doc/org.bluez.MediaControl.rst \ + doc/org.bluez.MediaPlayer.rst doc/org.bluez.MediaFolder.rst \ + doc/org.bluez.MediaItem.rst doc/org.bluez.MediaEndpoint.rst \ + doc/org.bluez.MediaTransport.rst doc/org.bluez.MediaAssistant.rst + +EXTRA_DIST += doc/org.bluez.GattManager.rst doc/org.bluez.GattProfile.rst\ + doc/org.bluez.GattService.rst \ + doc/org.bluez.GattCharacteristic.rst \ + doc/org.bluez.GattDescriptor.rst \ + doc/org.bluez.LEAdvertisingManager.rst \ + doc/org.bluez.LEAdvertisement.rst \ + doc/org.bluez.AdvertisementMonitorManager.rst \ + doc/org.bluez.AdvertisementMonitor.rst + +EXTRA_DIST += doc/org.bluez.obex.Client.rst doc/org.bluez.obex.Session.rst \ + doc/org.bluez.obex.Transfer.rst \ + doc/org.bluez.obex.ObjectPush.rst \ + doc/org.bluez.obex.FileTransfer.rst \ + doc/org.bluez.obex.Synchronization.rst \ + doc/org.bluez.obex.PhonebookAccess.rst \ + doc/org.bluez.obex.MessageAccess.rst \ + doc/org.bluez.obex.Message.rst \ + doc/org.bluez.obex.AgentManager.rst doc/org.bluez.obex.Agent.rst \ + doc/org.bluez.obex.Image.rst EXTRA_DIST += doc/pics-opp.txt doc/pixit-opp.txt \ doc/pts-opp.txt @@ -565,9 +666,33 @@ unit_tests += unit/test-gattrib unit_test_gattrib_SOURCES = unit/test-gattrib.c attrib/gattrib.c \ $(btio_sources) src/log.h src/log.c -unit_test_gattrib_LDADD = lib/libbluetooth-internal.la \ - src/libshared-glib.la \ - $(GLIB_LIBS) $(DBUS_LIBS) -ldl -lrt +unit_test_gattrib_LDADD = src/libshared-glib.la \ + lib/libbluetooth-internal.la \ + $(GLIB_LIBS) $(DBUS_LIBS) -ldl -lrt + +unit_tests += unit/test-bap + +unit_test_bap_SOURCES = unit/test-bap.c +unit_test_bap_LDADD = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(GLIB_LIBS) + +unit_tests += unit/test-micp + +unit_test_micp_SOURCES = unit/test-micp.c +unit_test_micp_LDADD = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(GLIB_LIBS) + +unit_tests += unit/test-bass + +unit_test_bass_SOURCES = unit/test-bass.c $(btio_sources) +unit_test_bass_LDADD = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(GLIB_LIBS) + +unit_tests += unit/test-vcp + +unit_test_vcp_SOURCES = unit/test-vcp.c $(btio_sources) +unit_test_vcp_LDADD = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(GLIB_LIBS) if MIDI unit_tests += unit/test-midi @@ -629,13 +754,6 @@ MAINTAINERCLEANFILES = Makefile.in \ aclocal.m4 configure config.h.in config.sub config.guess \ ltmain.sh depcomp compile missing install-sh mkinstalldirs test-driver -SED_PROCESS = $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ - $(SED) -e 's,@pkglibexecdir\@,$(pkglibexecdir),g' \ - -e 's,@libexecdir\@,$(libexecdir),g' \ - -e 's,@statedir\@,$(statedir),g' \ - -e 's,@confdir\@,$(confdir),g' \ - < $< > $@ - if RUN_RST2MAN RST2MAN_PROCESS = $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ $(RST2MAN) --strict --no-raw \ @@ -645,12 +763,15 @@ RST2MAN_PROCESS = $(AM_V_GEN)test -f $@ || \ { echo "Generated manual page $@ does not exist"; false; } endif -%.service: %.service.in Makefile - $(SED_PROCESS) - %.1: %.rst Makefile $(RST2MAN_PROCESS) +%.5: %.rst Makefile + $(RST2MAN_PROCESS) + +%.7: %.rst Makefile + $(RST2MAN_PROCESS) + %.8: %.rst Makefile $(RST2MAN_PROCESS) @@ -692,8 +813,8 @@ ell/ell.h: Makefile maintainer-clean-local: -rm -rf ell -if COVERAGE clean-coverage: +if COVERAGE @lcov --directory $(top_builddir) --zerocounters $(RM) -r coverage $(top_builddir)/coverage.info @@ -702,15 +823,9 @@ coverage: check --output-file $(top_builddir)/coverage.info $(AM_V_at)$(MKDIR_P) coverage @genhtml -o coverage/ $(top_builddir)/coverage.info +endif clean-local: clean-coverage -find $(top_builddir) -name "*.gcno" -delete -find $(top_builddir) -name "*.gcda" -delete $(RM) -r lib/bluetooth - -else -clean-local: - -find $(top_builddir) -name "*.gcno" -delete - -find $(top_builddir) -name "*.gcda" -delete - $(RM) -r lib/bluetooth -endif diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000000000000000000000000000000000000..fc54e01974f3a2063a6c1cd2190ba9ca7ed76d51 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,14022 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@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@ +bin_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ + $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) +noinst_PROGRAMS = $(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_9) \ + $(am__EXEEXT_10) $(am__EXEEXT_11) $(am__EXEEXT_12) \ + $(am__EXEEXT_18) +pkglibexec_PROGRAMS = src/bluetoothd$(EXEEXT) $(am__EXEEXT_19) \ + $(am__EXEEXT_20) $(am__EXEEXT_21) +@LIBRARY_TRUE@am__append_1 = $(lib_headers) +@LIBRARY_TRUE@am__append_2 = lib/libbluetooth.la +@EXTERNAL_ELL_FALSE@am__append_3 = ell/libell-internal.la +@LIBSHARED_ELL_TRUE@am__append_4 = src/libshared-ell.la +@READLINE_TRUE@am__append_5 = src/shared/shell.c src/shared/shell.h +@ADMIN_TRUE@am__append_6 = admin +@ADMIN_TRUE@am__append_7 = plugins/admin.c +@NFC_TRUE@am__append_8 = neard +@NFC_TRUE@am__append_9 = plugins/neard.c +@SAP_TRUE@am__append_10 = sap +@SAP_TRUE@am__append_11 = profiles/sap/main.c profiles/sap/manager.h \ +@SAP_TRUE@ profiles/sap/manager.c profiles/sap/server.h \ +@SAP_TRUE@ profiles/sap/server.c profiles/sap/sap.h \ +@SAP_TRUE@ profiles/sap/sap-dummy.c + +@A2DP_TRUE@am__append_12 = a2dp +@A2DP_TRUE@am__append_13 = profiles/audio/source.h profiles/audio/source.c \ +@A2DP_TRUE@ profiles/audio/sink.h profiles/audio/sink.c \ +@A2DP_TRUE@ profiles/audio/a2dp.h profiles/audio/a2dp.c \ +@A2DP_TRUE@ profiles/audio/avdtp.h profiles/audio/avdtp.c \ +@A2DP_TRUE@ profiles/audio/media.h profiles/audio/media.c \ +@A2DP_TRUE@ profiles/audio/transport.h profiles/audio/transport.c \ +@A2DP_TRUE@ profiles/audio/a2dp-codecs.h + +@AVRCP_TRUE@am__append_14 = avrcp +@AVRCP_TRUE@am__append_15 = profiles/audio/control.h profiles/audio/control.c \ +@AVRCP_TRUE@ profiles/audio/avctp.h profiles/audio/avctp.c \ +@AVRCP_TRUE@ profiles/audio/avrcp.h profiles/audio/avrcp.c \ +@AVRCP_TRUE@ profiles/audio/player.h profiles/audio/player.c + +@NETWORK_TRUE@am__append_16 = network +@NETWORK_TRUE@am__append_17 = profiles/network/manager.c \ +@NETWORK_TRUE@ profiles/network/bnep.h profiles/network/bnep.c \ +@NETWORK_TRUE@ profiles/network/server.h profiles/network/server.c \ +@NETWORK_TRUE@ profiles/network/connection.h \ +@NETWORK_TRUE@ profiles/network/connection.c + +@HID_TRUE@am__append_18 = input +@HID_TRUE@am__append_19 = profiles/input/manager.c \ +@HID_TRUE@ profiles/input/server.h profiles/input/server.c \ +@HID_TRUE@ profiles/input/device.h profiles/input/device.c \ +@HID_TRUE@ profiles/input/hidp_defs.h profiles/input/sixaxis.h + +@HOG_TRUE@am__append_20 = hog +@HOG_TRUE@am__append_21 = profiles/input/hog.c \ +@HOG_TRUE@ profiles/input/hog-lib.c profiles/input/hog-lib.h \ +@HOG_TRUE@ profiles/deviceinfo/dis.c profiles/deviceinfo/dis.h \ +@HOG_TRUE@ profiles/battery/bas.c profiles/battery/bas.h \ +@HOG_TRUE@ profiles/scanparam/scpp.c profiles/scanparam/scpp.h \ +@HOG_TRUE@ profiles/input/suspend.h profiles/input/suspend-none.c + +@HEALTH_TRUE@am__append_22 = health +@HEALTH_TRUE@am__append_23 = profiles/health/mcap.h profiles/health/mcap.c \ +@HEALTH_TRUE@ profiles/health/hdp_main.c profiles/health/hdp_types.h \ +@HEALTH_TRUE@ profiles/health/hdp_manager.h \ +@HEALTH_TRUE@ profiles/health/hdp_manager.c \ +@HEALTH_TRUE@ profiles/health/hdp.h profiles/health/hdp.c \ +@HEALTH_TRUE@ profiles/health/hdp_util.h profiles/health/hdp_util.c + +@MIDI_TRUE@am__append_24 = midi +@MIDI_TRUE@am__append_25 = profiles/midi/midi.c \ +@MIDI_TRUE@ profiles/midi/libmidi.h \ +@MIDI_TRUE@ profiles/midi/libmidi.c + +@MIDI_TRUE@am__append_26 = $(ALSA_CFLAGS) +@MIDI_TRUE@am__append_27 = $(ALSA_LIBS) +@SIXAXIS_TRUE@am__append_28 = sixaxis +@SIXAXIS_TRUE@am__append_29 = plugins/sixaxis.c +@SIXAXIS_TRUE@am__append_30 = $(UDEV_LIBS) +@BAP_TRUE@am__append_31 = bap +@BAP_TRUE@am__append_32 = profiles/audio/bap.h profiles/audio/bap.c +@BASS_TRUE@am__append_33 = bass +@BASS_TRUE@am__append_34 = profiles/audio/bass.h profiles/audio/bass.c +@MCP_TRUE@am__append_35 = mcp +@MCP_TRUE@am__append_36 = profiles/audio/mcp.c +@VCP_TRUE@am__append_37 = vcp +@VCP_TRUE@am__append_38 = profiles/audio/vcp.c +@MICP_TRUE@am__append_39 = micp +@MICP_TRUE@am__append_40 = profiles/audio/micp.c +@CCP_TRUE@am__append_41 = ccp +@CCP_TRUE@am__append_42 = profiles/audio/ccp.c +@CSIP_TRUE@am__append_43 = csip +@CSIP_TRUE@am__append_44 = profiles/audio/csip.c +@ASHA_TRUE@am__append_45 = asha +@ASHA_TRUE@am__append_46 = profiles/audio/asha.h profiles/audio/asha.c +@EXTERNAL_PLUGINS_TRUE@am__append_47 = src/bluetooth.ver + +# SPDX-License-Identifier: GPL-2.0 +@CLIENT_TRUE@am__append_48 = client/bluetoothctl +@MONITOR_TRUE@am__append_49 = monitor/btmon +@MANPAGES_TRUE@@MONITOR_TRUE@am__append_50 = monitor/btmon.1 +@LOGGER_TRUE@am__append_51 = tools/btmon-logger +@LOGGER_TRUE@@SYSTEMD_TRUE@am__append_52 = tools/bluetooth-logger.service +@TESTING_TRUE@am__append_53 = emulator/btvirt emulator/b1ee emulator/hfp \ +@TESTING_TRUE@ peripheral/btsensor tools/3dsp \ +@TESTING_TRUE@ tools/mgmt-tester tools/gap-tester \ +@TESTING_TRUE@ tools/l2cap-tester tools/sco-tester \ +@TESTING_TRUE@ tools/smp-tester tools/hci-tester \ +@TESTING_TRUE@ tools/rfcomm-tester tools/bnep-tester \ +@TESTING_TRUE@ tools/userchan-tester tools/iso-tester \ +@TESTING_TRUE@ tools/mesh-tester tools/ioctl-tester + +@TOOLS_TRUE@am__append_54 = tools/rctest tools/l2test tools/l2ping tools/bluemoon \ +@TOOLS_TRUE@ tools/hex2hcd tools/mpris-proxy tools/btattach tools/isotest + +@TOOLS_TRUE@am__append_55 = tools/bdaddr tools/avinfo tools/avtest \ +@TOOLS_TRUE@ tools/scotest tools/amptest tools/hwdb \ +@TOOLS_TRUE@ tools/hcieventmask tools/hcisecfilter \ +@TOOLS_TRUE@ tools/btinfo tools/btconfig \ +@TOOLS_TRUE@ tools/btsnoop tools/btproxy \ +@TOOLS_TRUE@ tools/btiotest tools/bneptest tools/mcaptest \ +@TOOLS_TRUE@ tools/cltest tools/oobtest tools/advtest \ +@TOOLS_TRUE@ tools/seq2bseq tools/nokfw tools/rtlfw \ +@TOOLS_TRUE@ tools/bcmfw tools/create-image \ +@TOOLS_TRUE@ tools/eddystone tools/ibeacon \ +@TOOLS_TRUE@ tools/btgatt-client tools/btgatt-server \ +@TOOLS_TRUE@ tools/test-runner tools/check-selftest \ +@TOOLS_TRUE@ tools/gatt-service profiles/iap/iapd + +@SYSTEMD_TRUE@@TOOLS_TRUE@am__append_56 = tools/mpris-proxy.service +@MANPAGES_TRUE@@TOOLS_TRUE@am__append_57 = tools/rctest.1 tools/l2ping.1 tools/btattach.1 tools/isotest.1 \ +@MANPAGES_TRUE@@TOOLS_TRUE@ tools/btmgmt.1 client/bluetoothctl.1 \ +@MANPAGES_TRUE@@TOOLS_TRUE@ client/bluetoothctl-mgmt.1 \ +@MANPAGES_TRUE@@TOOLS_TRUE@ client/bluetoothctl-monitor.1 client/bluetoothctl-admin.1 \ +@MANPAGES_TRUE@@TOOLS_TRUE@ client/bluetoothctl-advertise.1 client/bluetoothctl-endpoint.1 \ +@MANPAGES_TRUE@@TOOLS_TRUE@ client/bluetoothctl-gatt.1 client/bluetoothctl-player.1 \ +@MANPAGES_TRUE@@TOOLS_TRUE@ client/bluetoothctl-scan.1 client/bluetoothctl-transport.1 \ +@MANPAGES_TRUE@@TOOLS_TRUE@ client/bluetoothctl-assistant.1 + +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@am__append_58 = tools/meshctl +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@am__append_59 = tools/mesh-gatt/local_node.json tools/mesh-gatt/prov_db.json +@MESH_TRUE@@TOOLS_TRUE@am__append_60 = tools/mesh-cfgclient \ +@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-cfgtest +@DEPRECATED_TRUE@@TOOLS_TRUE@am__append_61 = tools/hciattach tools/hciconfig tools/hcitool tools/hcidump \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/rfcomm tools/sdptool tools/ciptool + +@DEPRECATED_TRUE@@MANPAGES_TRUE@@TOOLS_TRUE@am__append_62 = tools/hciattach.1 tools/hciconfig.1 \ +@DEPRECATED_TRUE@@MANPAGES_TRUE@@TOOLS_TRUE@ tools/hcitool.1 tools/hcidump.1 \ +@DEPRECATED_TRUE@@MANPAGES_TRUE@@TOOLS_TRUE@ tools/rfcomm.1 tools/sdptool.1 tools/ciptool.1 + +@HID2HCI_TRUE@udev_PROGRAMS = tools/hid2hci$(EXEEXT) +@HID2HCI_TRUE@@MANPAGES_TRUE@am__append_63 = tools/hid2hci.1 +@READLINE_TRUE@am__append_64 = tools/btmgmt tools/obex-client-tool tools/obex-server-tool \ +@READLINE_TRUE@ tools/bluetooth-player tools/obexctl + +@DEPRECATED_TRUE@@READLINE_TRUE@am__append_65 = attrib/gatttool +@CUPS_TRUE@cups_PROGRAMS = profiles/cups/bluetooth$(EXEEXT) +@BTPCLIENT_TRUE@am__append_66 = tools/btpclient tools/btpclientctl + +# SPDX-License-Identifier: GPL-2.0 +@OBEX_TRUE@@SYSTEMD_TRUE@am__append_67 = obexd/src/obex.service +@EXPERIMENTAL_TRUE@@OBEX_TRUE@am__append_68 = pcsuite +@EXPERIMENTAL_TRUE@@OBEX_TRUE@am__append_69 = obexd/plugins/pcsuite.c +@OBEX_TRUE@am__append_70 = obexd/plugins/phonebook-dummy.c obexd/plugins/phonebook-ebook.c \ +@OBEX_TRUE@ obexd/plugins/phonebook-tracker.c + +@OBEX_TRUE@am__append_71 = obexd/src/obexd +@ANDROID_TRUE@am__append_72 = -DANDROID_VERSION=0x050100 +@ANDROID_TRUE@am__append_73 = android/system-emulator \ +@ANDROID_TRUE@ android/bluetoothd-snoop android/bluetoothd \ +@ANDROID_TRUE@ android/avdtptest android/haltest \ +@ANDROID_TRUE@ android/android-tester android/ipc-tester +@ANDROID_TRUE@am__append_74 = android/bluetooth.default.la \ +@ANDROID_TRUE@ android/audio.a2dp.default.la \ +@ANDROID_TRUE@ android/audio.sco.default.la +@ANDROID_TRUE@am__append_75 = android/test-ipc + +# SPDX-License-Identifier: GPL-2.0 +@DATAFILES_TRUE@@MESH_TRUE@am__append_76 = mesh/bluetooth-mesh.conf +@DATAFILES_TRUE@@MESH_TRUE@am__append_77 = mesh/mesh-main.conf +@MESH_TRUE@@SYSTEMD_TRUE@am__append_78 = mesh/bluetooth-mesh.service +@MESH_TRUE@@SYSTEMD_TRUE@am__append_79 = mesh/org.bluez.mesh.service +@MESH_TRUE@am__append_80 = mesh/bluetooth-meshd +@MANPAGES_TRUE@@MESH_TRUE@am__append_81 = mesh/bluetooth-meshd.8 +@MESH_TRUE@am__append_82 = mesh/bluetooth-meshd.8 +@HID2HCI_TRUE@am__append_83 = $(rules_DATA) +@OBEX_TRUE@am__append_84 = unit/test-gobex-header unit/test-gobex-packet unit/test-gobex \ +@OBEX_TRUE@ unit/test-gobex-transfer unit/test-gobex-apparam + +@MIDI_TRUE@am__append_85 = unit/test-midi +@MESH_TRUE@am__append_86 = unit/test-mesh-crypto +@MAINTAINER_MODE_TRUE@am__append_87 = $(unit_tests) +TESTS = $(am__EXEEXT_17) +@DBUS_RUN_SESSION_TRUE@am__append_88 = dbus-run-session -- +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ + $(am__configure_deps) $(am__dist_zshcompletion_DATA_DIST) \ + $(am__pkginclude_HEADERS_DIST) $(am__DIST_COMMON) +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 = lib/bluez.pc mesh/bluetooth-meshd.rst \ + mesh/bluetooth-mesh.service obexd/src/obex.service \ + obexd/src/org.bluez.obex.service src/bluetoothd.rst \ + src/bluetooth.service tools/bluetooth-logger.service \ + tools/mpris-proxy.service +CONFIG_CLEAN_VPATH_FILES = +@CLIENT_TRUE@am__EXEEXT_1 = client/bluetoothctl$(EXEEXT) +@MONITOR_TRUE@am__EXEEXT_2 = monitor/btmon$(EXEEXT) +@TOOLS_TRUE@am__EXEEXT_3 = tools/rctest$(EXEEXT) tools/l2test$(EXEEXT) \ +@TOOLS_TRUE@ tools/l2ping$(EXEEXT) tools/bluemoon$(EXEEXT) \ +@TOOLS_TRUE@ tools/hex2hcd$(EXEEXT) tools/mpris-proxy$(EXEEXT) \ +@TOOLS_TRUE@ tools/btattach$(EXEEXT) tools/isotest$(EXEEXT) +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@am__EXEEXT_4 = tools/meshctl$(EXEEXT) +@MESH_TRUE@@TOOLS_TRUE@am__EXEEXT_5 = tools/mesh-cfgclient$(EXEEXT) \ +@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-cfgtest$(EXEEXT) +@DEPRECATED_TRUE@@TOOLS_TRUE@am__EXEEXT_6 = tools/hciattach$(EXEEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hciconfig$(EXEEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hcitool$(EXEEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hcidump$(EXEEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/rfcomm$(EXEEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/sdptool$(EXEEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/ciptool$(EXEEXT) +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(cupsdir)" \ + "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(udevdir)" \ + "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ + "$(DESTDIR)$(testdir)" "$(DESTDIR)$(man1dir)" \ + "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man7dir)" \ + "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(confdir)" \ + "$(DESTDIR)$(dbusdir)" "$(DESTDIR)$(dbussessionbusdir)" \ + "$(DESTDIR)$(dbussystembusdir)" \ + "$(DESTDIR)$(zshcompletiondir)" "$(DESTDIR)$(pkgconfigdir)" \ + "$(DESTDIR)$(rulesdir)" "$(DESTDIR)$(statedir)" \ + "$(DESTDIR)$(systemdsystemunitdir)" \ + "$(DESTDIR)$(systemduserunitdir)" "$(DESTDIR)$(pkgincludedir)" +@TESTING_TRUE@am__EXEEXT_7 = emulator/btvirt$(EXEEXT) \ +@TESTING_TRUE@ emulator/b1ee$(EXEEXT) emulator/hfp$(EXEEXT) \ +@TESTING_TRUE@ peripheral/btsensor$(EXEEXT) tools/3dsp$(EXEEXT) \ +@TESTING_TRUE@ tools/mgmt-tester$(EXEEXT) \ +@TESTING_TRUE@ tools/gap-tester$(EXEEXT) \ +@TESTING_TRUE@ tools/l2cap-tester$(EXEEXT) \ +@TESTING_TRUE@ tools/sco-tester$(EXEEXT) \ +@TESTING_TRUE@ tools/smp-tester$(EXEEXT) \ +@TESTING_TRUE@ tools/hci-tester$(EXEEXT) \ +@TESTING_TRUE@ tools/rfcomm-tester$(EXEEXT) \ +@TESTING_TRUE@ tools/bnep-tester$(EXEEXT) \ +@TESTING_TRUE@ tools/userchan-tester$(EXEEXT) \ +@TESTING_TRUE@ tools/iso-tester$(EXEEXT) \ +@TESTING_TRUE@ tools/mesh-tester$(EXEEXT) \ +@TESTING_TRUE@ tools/ioctl-tester$(EXEEXT) +@TOOLS_TRUE@am__EXEEXT_8 = tools/bdaddr$(EXEEXT) tools/avinfo$(EXEEXT) \ +@TOOLS_TRUE@ tools/avtest$(EXEEXT) tools/scotest$(EXEEXT) \ +@TOOLS_TRUE@ tools/amptest$(EXEEXT) tools/hwdb$(EXEEXT) \ +@TOOLS_TRUE@ tools/hcieventmask$(EXEEXT) \ +@TOOLS_TRUE@ tools/hcisecfilter$(EXEEXT) tools/btinfo$(EXEEXT) \ +@TOOLS_TRUE@ tools/btconfig$(EXEEXT) tools/btsnoop$(EXEEXT) \ +@TOOLS_TRUE@ tools/btproxy$(EXEEXT) tools/btiotest$(EXEEXT) \ +@TOOLS_TRUE@ tools/bneptest$(EXEEXT) tools/mcaptest$(EXEEXT) \ +@TOOLS_TRUE@ tools/cltest$(EXEEXT) tools/oobtest$(EXEEXT) \ +@TOOLS_TRUE@ tools/advtest$(EXEEXT) tools/seq2bseq$(EXEEXT) \ +@TOOLS_TRUE@ tools/nokfw$(EXEEXT) tools/rtlfw$(EXEEXT) \ +@TOOLS_TRUE@ tools/bcmfw$(EXEEXT) tools/create-image$(EXEEXT) \ +@TOOLS_TRUE@ tools/eddystone$(EXEEXT) tools/ibeacon$(EXEEXT) \ +@TOOLS_TRUE@ tools/btgatt-client$(EXEEXT) \ +@TOOLS_TRUE@ tools/btgatt-server$(EXEEXT) \ +@TOOLS_TRUE@ tools/test-runner$(EXEEXT) \ +@TOOLS_TRUE@ tools/check-selftest$(EXEEXT) \ +@TOOLS_TRUE@ tools/gatt-service$(EXEEXT) \ +@TOOLS_TRUE@ profiles/iap/iapd$(EXEEXT) +@READLINE_TRUE@am__EXEEXT_9 = tools/btmgmt$(EXEEXT) \ +@READLINE_TRUE@ tools/obex-client-tool$(EXEEXT) \ +@READLINE_TRUE@ tools/obex-server-tool$(EXEEXT) \ +@READLINE_TRUE@ tools/bluetooth-player$(EXEEXT) \ +@READLINE_TRUE@ tools/obexctl$(EXEEXT) +@DEPRECATED_TRUE@@READLINE_TRUE@am__EXEEXT_10 = \ +@DEPRECATED_TRUE@@READLINE_TRUE@ attrib/gatttool$(EXEEXT) +@BTPCLIENT_TRUE@am__EXEEXT_11 = tools/btpclient$(EXEEXT) \ +@BTPCLIENT_TRUE@ tools/btpclientctl$(EXEEXT) +@ANDROID_TRUE@am__EXEEXT_12 = android/system-emulator$(EXEEXT) \ +@ANDROID_TRUE@ android/bluetoothd-snoop$(EXEEXT) \ +@ANDROID_TRUE@ android/bluetoothd$(EXEEXT) \ +@ANDROID_TRUE@ android/avdtptest$(EXEEXT) \ +@ANDROID_TRUE@ android/haltest$(EXEEXT) \ +@ANDROID_TRUE@ android/android-tester$(EXEEXT) \ +@ANDROID_TRUE@ android/ipc-tester$(EXEEXT) +@ANDROID_TRUE@am__EXEEXT_13 = android/test-ipc$(EXEEXT) +@OBEX_TRUE@am__EXEEXT_14 = unit/test-gobex-header$(EXEEXT) \ +@OBEX_TRUE@ unit/test-gobex-packet$(EXEEXT) \ +@OBEX_TRUE@ unit/test-gobex$(EXEEXT) \ +@OBEX_TRUE@ unit/test-gobex-transfer$(EXEEXT) \ +@OBEX_TRUE@ unit/test-gobex-apparam$(EXEEXT) +@MIDI_TRUE@am__EXEEXT_15 = unit/test-midi$(EXEEXT) +@MESH_TRUE@am__EXEEXT_16 = unit/test-mesh-crypto$(EXEEXT) +am__EXEEXT_17 = $(am__EXEEXT_13) unit/test-tester$(EXEEXT) \ + unit/test-eir$(EXEEXT) unit/test-uuid$(EXEEXT) \ + unit/test-textfile$(EXEEXT) unit/test-crc$(EXEEXT) \ + unit/test-crypto$(EXEEXT) unit/test-ecc$(EXEEXT) \ + unit/test-ringbuf$(EXEEXT) unit/test-queue$(EXEEXT) \ + unit/test-mgmt$(EXEEXT) unit/test-uhid$(EXEEXT) \ + unit/test-sdp$(EXEEXT) unit/test-avdtp$(EXEEXT) \ + unit/test-avctp$(EXEEXT) unit/test-avrcp$(EXEEXT) \ + unit/test-hfp$(EXEEXT) unit/test-gdbus-client$(EXEEXT) \ + $(am__EXEEXT_14) unit/test-lib$(EXEEXT) \ + unit/test-gatt$(EXEEXT) unit/test-hog$(EXEEXT) \ + unit/test-gattrib$(EXEEXT) unit/test-bap$(EXEEXT) \ + unit/test-micp$(EXEEXT) unit/test-bass$(EXEEXT) \ + unit/test-vcp$(EXEEXT) $(am__EXEEXT_15) $(am__EXEEXT_16) +@MAINTAINER_MODE_TRUE@am__EXEEXT_18 = $(am__EXEEXT_17) +@LOGGER_TRUE@am__EXEEXT_19 = tools/btmon-logger$(EXEEXT) +@OBEX_TRUE@am__EXEEXT_20 = obexd/src/obexd$(EXEEXT) +@MESH_TRUE@am__EXEEXT_21 = mesh/bluetooth-meshd$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) $(cups_PROGRAMS) $(noinst_PROGRAMS) \ + $(pkglibexec_PROGRAMS) $(udev_PROGRAMS) +LIBRARIES = $(noinst_LIBRARIES) +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 = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) \ + $(plugin_LTLIBRARIES) +am__DEPENDENCIES_1 = +@ANDROID_TRUE@android_audio_a2dp_default_la_DEPENDENCIES = \ +@ANDROID_TRUE@ $(am__DEPENDENCIES_1) +am__android_audio_a2dp_default_la_SOURCES_DIST = android/audio-msg.h \ + android/hal-msg.h android/hal-audio.h android/hal-audio.c \ + android/hal-audio-sbc.c android/hal-audio-aptx.c \ + android/hardware/audio.h android/hardware/audio_effect.h \ + android/hardware/hardware.h android/system/audio.h +am__dirstamp = $(am__leading_dot)dirstamp +@ANDROID_TRUE@am_android_audio_a2dp_default_la_OBJECTS = \ +@ANDROID_TRUE@ android/audio_a2dp_default_la-hal-audio.lo \ +@ANDROID_TRUE@ android/audio_a2dp_default_la-hal-audio-sbc.lo \ +@ANDROID_TRUE@ android/audio_a2dp_default_la-hal-audio-aptx.lo +android_audio_a2dp_default_la_OBJECTS = \ + $(am_android_audio_a2dp_default_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +android_audio_a2dp_default_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(android_audio_a2dp_default_la_CFLAGS) $(CFLAGS) \ + $(android_audio_a2dp_default_la_LDFLAGS) $(LDFLAGS) -o $@ +@ANDROID_TRUE@am_android_audio_a2dp_default_la_rpath = -rpath \ +@ANDROID_TRUE@ $(plugindir) +@ANDROID_TRUE@android_audio_sco_default_la_DEPENDENCIES = \ +@ANDROID_TRUE@ $(am__DEPENDENCIES_1) +am__android_audio_sco_default_la_SOURCES_DIST = android/hal-log.h \ + android/sco-msg.h android/hal-sco.c android/hardware/audio.h \ + android/hardware/audio_effect.h android/hardware/hardware.h \ + android/audio_utils/resampler.c \ + android/audio_utils/resampler.h android/system/audio.h +@ANDROID_TRUE@am_android_audio_sco_default_la_OBJECTS = \ +@ANDROID_TRUE@ android/audio_sco_default_la-hal-sco.lo \ +@ANDROID_TRUE@ android/audio_utils/audio_sco_default_la-resampler.lo +android_audio_sco_default_la_OBJECTS = \ + $(am_android_audio_sco_default_la_OBJECTS) +android_audio_sco_default_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(android_audio_sco_default_la_CFLAGS) $(CFLAGS) \ + $(android_audio_sco_default_la_LDFLAGS) $(LDFLAGS) -o $@ +@ANDROID_TRUE@am_android_audio_sco_default_la_rpath = -rpath \ +@ANDROID_TRUE@ $(plugindir) +android_bluetooth_default_la_LIBADD = +am__android_bluetooth_default_la_SOURCES_DIST = android/hal.h \ + android/hal-bluetooth.c android/hal-socket.c \ + android/hal-hidhost.c android/hal-health.c android/hal-pan.c \ + android/hal-a2dp.c android/hal-a2dp-sink.c android/hal-avrcp.c \ + android/hal-avrcp-ctrl.c android/hal-handsfree.c \ + android/hal-handsfree-client.c android/hal-gatt.c \ + android/hal-map-client.c android/hardware/bluetooth.h \ + android/hardware/bt_av.h android/hardware/bt_gatt.h \ + android/hardware/bt_gatt_client.h \ + android/hardware/bt_gatt_server.h \ + android/hardware/bt_gatt_types.h android/hardware/bt_hf.h \ + android/hardware/bt_hh.h android/hardware/bt_hl.h \ + android/hardware/bt_pan.h android/hardware/bt_rc.h \ + android/hardware/bt_sock.h android/hardware/bt_hf_client.h \ + android/hardware/bt_mce.h android/hardware/hardware.h \ + android/cutils/properties.h android/ipc-common.h \ + android/hal-log.h android/hal-ipc.h android/hal-ipc.c \ + android/hal-utils.h android/hal-utils.c +@ANDROID_TRUE@am_android_bluetooth_default_la_OBJECTS = \ +@ANDROID_TRUE@ android/bluetooth_default_la-hal-bluetooth.lo \ +@ANDROID_TRUE@ android/bluetooth_default_la-hal-socket.lo \ +@ANDROID_TRUE@ android/bluetooth_default_la-hal-hidhost.lo \ +@ANDROID_TRUE@ android/bluetooth_default_la-hal-health.lo \ +@ANDROID_TRUE@ android/bluetooth_default_la-hal-pan.lo \ +@ANDROID_TRUE@ android/bluetooth_default_la-hal-a2dp.lo \ +@ANDROID_TRUE@ android/bluetooth_default_la-hal-a2dp-sink.lo \ +@ANDROID_TRUE@ android/bluetooth_default_la-hal-avrcp.lo \ +@ANDROID_TRUE@ android/bluetooth_default_la-hal-avrcp-ctrl.lo \ +@ANDROID_TRUE@ android/bluetooth_default_la-hal-handsfree.lo \ +@ANDROID_TRUE@ android/bluetooth_default_la-hal-handsfree-client.lo \ +@ANDROID_TRUE@ android/bluetooth_default_la-hal-gatt.lo \ +@ANDROID_TRUE@ android/bluetooth_default_la-hal-map-client.lo \ +@ANDROID_TRUE@ android/bluetooth_default_la-hal-ipc.lo \ +@ANDROID_TRUE@ android/bluetooth_default_la-hal-utils.lo +android_bluetooth_default_la_OBJECTS = \ + $(am_android_bluetooth_default_la_OBJECTS) +android_bluetooth_default_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) \ + $(android_bluetooth_default_la_LDFLAGS) $(LDFLAGS) -o $@ +@ANDROID_TRUE@am_android_bluetooth_default_la_rpath = -rpath \ +@ANDROID_TRUE@ $(plugindir) +ell_libell_internal_la_LIBADD = +am__ell_libell_internal_la_SOURCES_DIST = ell/util.h ell/log.h \ + ell/queue.h ell/hashmap.h ell/random.h ell/signal.h ell/time.h \ + ell/time-private.h ell/timeout.h ell/cipher.h ell/checksum.h \ + ell/io.h ell/idle.h ell/main.h ell/settings.h ell/strv.h \ + ell/string.h ell/utf8.h ell/dbus.h ell/dbus-service.h \ + ell/dbus-client.h ell/key.h ell/cert.h ell/pem.h ell/base64.h \ + ell/asn1-private.h ell/cert-private.h ell/pem-private.h \ + ell/uuid.h ell/useful.h ell/main-private.h ell/tester.h \ + ell/tls.h ell/tls-private.h ell/ecc.h ell/ecc-private.h \ + ell/cleanup.h ell/ecdh.h ell/private.h ell/missing.h \ + ell/util.c ell/log.c ell/queue.c ell/hashmap.c ell/random.c \ + ell/signal.c ell/time.c ell/timeout.c ell/io.c ell/idle.c \ + ell/main.c ell/settings.c ell/strv.c ell/string.c ell/cipher.c \ + ell/checksum.c ell/pem.c ell/cert.c ell/cert-crypto.c \ + ell/key.c ell/base64.c ell/utf8.c ell/dbus-private.h \ + ell/dbus.c ell/dbus-message.c ell/dbus-util.c \ + ell/dbus-service.c ell/dbus-client.c ell/dbus-name-cache.c \ + ell/dbus-filter.c ell/gvariant-private.h ell/gvariant-util.c \ + ell/siphash-private.h ell/siphash.c ell/uuid.c ell/tester.c \ + ell/tls.c ell/tls-extensions.c ell/tls-suites.c \ + ell/tls-record.c ell/ecc.c ell/ecc-external.c ell/ecdh.c +am__objects_1 = +@EXTERNAL_ELL_FALSE@am__objects_2 = ell/util.lo ell/log.lo \ +@EXTERNAL_ELL_FALSE@ ell/queue.lo ell/hashmap.lo ell/random.lo \ +@EXTERNAL_ELL_FALSE@ ell/signal.lo ell/time.lo ell/timeout.lo \ +@EXTERNAL_ELL_FALSE@ ell/io.lo ell/idle.lo ell/main.lo \ +@EXTERNAL_ELL_FALSE@ ell/settings.lo ell/strv.lo ell/string.lo \ +@EXTERNAL_ELL_FALSE@ ell/cipher.lo ell/checksum.lo ell/pem.lo \ +@EXTERNAL_ELL_FALSE@ ell/cert.lo ell/cert-crypto.lo ell/key.lo \ +@EXTERNAL_ELL_FALSE@ ell/base64.lo ell/utf8.lo ell/dbus.lo \ +@EXTERNAL_ELL_FALSE@ ell/dbus-message.lo ell/dbus-util.lo \ +@EXTERNAL_ELL_FALSE@ ell/dbus-service.lo ell/dbus-client.lo \ +@EXTERNAL_ELL_FALSE@ ell/dbus-name-cache.lo ell/dbus-filter.lo \ +@EXTERNAL_ELL_FALSE@ ell/gvariant-util.lo ell/siphash.lo \ +@EXTERNAL_ELL_FALSE@ ell/uuid.lo ell/tester.lo ell/tls.lo \ +@EXTERNAL_ELL_FALSE@ ell/tls-extensions.lo ell/tls-suites.lo \ +@EXTERNAL_ELL_FALSE@ ell/tls-record.lo ell/ecc.lo \ +@EXTERNAL_ELL_FALSE@ ell/ecc-external.lo ell/ecdh.lo +@EXTERNAL_ELL_FALSE@am_ell_libell_internal_la_OBJECTS = \ +@EXTERNAL_ELL_FALSE@ $(am__objects_1) $(am__objects_2) \ +@EXTERNAL_ELL_FALSE@ $(am__objects_1) +ell_libell_internal_la_OBJECTS = $(am_ell_libell_internal_la_OBJECTS) +@EXTERNAL_ELL_FALSE@am_ell_libell_internal_la_rpath = +gdbus_libgdbus_internal_la_LIBADD = +am_gdbus_libgdbus_internal_la_OBJECTS = gdbus/mainloop.lo \ + gdbus/watch.lo gdbus/object.lo gdbus/client.lo gdbus/polkit.lo +gdbus_libgdbus_internal_la_OBJECTS = \ + $(am_gdbus_libgdbus_internal_la_OBJECTS) +lib_libbluetooth_internal_la_LIBADD = +am__objects_3 = lib/bluetooth.lo lib/hci.lo lib/sdp.lo +am__objects_4 = lib/uuid.lo +am_lib_libbluetooth_internal_la_OBJECTS = $(am__objects_1) \ + $(am__objects_3) $(am__objects_1) $(am__objects_4) +lib_libbluetooth_internal_la_OBJECTS = \ + $(am_lib_libbluetooth_internal_la_OBJECTS) +lib_libbluetooth_la_LIBADD = +am__lib_libbluetooth_la_SOURCES_DIST = lib/bluetooth.h lib/hci.h \ + lib/hci_lib.h lib/sco.h lib/l2cap.h lib/sdp.h lib/sdp_lib.h \ + lib/rfcomm.h lib/bnep.h lib/cmtp.h lib/hidp.h lib/bluetooth.c \ + lib/hci.c lib/sdp.c +@LIBRARY_TRUE@am_lib_libbluetooth_la_OBJECTS = $(am__objects_1) \ +@LIBRARY_TRUE@ $(am__objects_3) +lib_libbluetooth_la_OBJECTS = $(am_lib_libbluetooth_la_OBJECTS) +lib_libbluetooth_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(lib_libbluetooth_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@LIBRARY_TRUE@am_lib_libbluetooth_la_rpath = -rpath $(libdir) +src_libshared_ell_la_LIBADD = +am__src_libshared_ell_la_SOURCES_DIST = src/shared/io.h \ + src/shared/timeout.h src/shared/queue.h src/shared/queue.c \ + src/shared/util.h src/shared/util.c src/shared/mgmt.h \ + src/shared/mgmt.c src/shared/crypto.h src/shared/crypto.c \ + src/shared/ecc.h src/shared/ecc.c src/shared/ringbuf.h \ + src/shared/ringbuf.c src/shared/tester.h src/shared/hci.h \ + src/shared/hci.c src/shared/hci-crypto.h \ + src/shared/hci-crypto.c src/shared/hfp.h src/shared/hfp.c \ + src/shared/uhid.h src/shared/uhid.c src/shared/pcap.h \ + src/shared/pcap.c src/shared/btsnoop.h src/shared/btsnoop.c \ + src/shared/ad.h src/shared/ad.c src/shared/att-types.h \ + src/shared/att.h src/shared/att.c src/shared/gatt-helpers.h \ + src/shared/gatt-helpers.c src/shared/gatt-client.h \ + src/shared/gatt-client.c src/shared/gatt-server.h \ + src/shared/gatt-server.c src/shared/gatt-db.h \ + src/shared/gatt-db.c src/shared/gap.h src/shared/gap.c \ + src/shared/log.h src/shared/log.c src/shared/bap.h \ + src/shared/bap.c src/shared/ascs.h src/shared/bap-debug.h \ + src/shared/bap-debug.c src/shared/mcs.h src/shared/mcp.h \ + src/shared/mcp.c src/shared/vcp.c src/shared/vcp.h \ + src/shared/micp.c src/shared/micp.h src/shared/csip.c \ + src/shared/csip.h src/shared/bass.h src/shared/bass.c \ + src/shared/ccp.h src/shared/ccp.c src/shared/lc3.h \ + src/shared/tty.h src/shared/bap-defs.h src/shared/asha.h \ + src/shared/asha.c src/shared/shell.c src/shared/shell.h \ + src/shared/io-ell.c src/shared/timeout-ell.c \ + src/shared/mainloop.h src/shared/mainloop-ell.c +@READLINE_TRUE@am__objects_5 = src/shared/libshared_ell_la-shell.lo +am__objects_6 = src/shared/libshared_ell_la-queue.lo \ + src/shared/libshared_ell_la-util.lo \ + src/shared/libshared_ell_la-mgmt.lo \ + src/shared/libshared_ell_la-crypto.lo \ + src/shared/libshared_ell_la-ecc.lo \ + src/shared/libshared_ell_la-ringbuf.lo \ + src/shared/libshared_ell_la-hci.lo \ + src/shared/libshared_ell_la-hci-crypto.lo \ + src/shared/libshared_ell_la-hfp.lo \ + src/shared/libshared_ell_la-uhid.lo \ + src/shared/libshared_ell_la-pcap.lo \ + src/shared/libshared_ell_la-btsnoop.lo \ + src/shared/libshared_ell_la-ad.lo \ + src/shared/libshared_ell_la-att.lo \ + src/shared/libshared_ell_la-gatt-helpers.lo \ + src/shared/libshared_ell_la-gatt-client.lo \ + src/shared/libshared_ell_la-gatt-server.lo \ + src/shared/libshared_ell_la-gatt-db.lo \ + src/shared/libshared_ell_la-gap.lo \ + src/shared/libshared_ell_la-log.lo \ + src/shared/libshared_ell_la-bap.lo \ + src/shared/libshared_ell_la-bap-debug.lo \ + src/shared/libshared_ell_la-mcp.lo \ + src/shared/libshared_ell_la-vcp.lo \ + src/shared/libshared_ell_la-micp.lo \ + src/shared/libshared_ell_la-csip.lo \ + src/shared/libshared_ell_la-bass.lo \ + src/shared/libshared_ell_la-ccp.lo \ + src/shared/libshared_ell_la-asha.lo $(am__objects_5) +@LIBSHARED_ELL_TRUE@am_src_libshared_ell_la_OBJECTS = \ +@LIBSHARED_ELL_TRUE@ $(am__objects_6) \ +@LIBSHARED_ELL_TRUE@ src/shared/libshared_ell_la-io-ell.lo \ +@LIBSHARED_ELL_TRUE@ src/shared/libshared_ell_la-timeout-ell.lo \ +@LIBSHARED_ELL_TRUE@ src/shared/libshared_ell_la-mainloop-ell.lo +src_libshared_ell_la_OBJECTS = $(am_src_libshared_ell_la_OBJECTS) +src_libshared_ell_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(src_libshared_ell_la_CFLAGS) $(CFLAGS) \ + $(src_libshared_ell_la_LDFLAGS) $(LDFLAGS) -o $@ +@LIBSHARED_ELL_TRUE@am_src_libshared_ell_la_rpath = +src_libshared_glib_la_LIBADD = +am__src_libshared_glib_la_SOURCES_DIST = src/shared/io.h \ + src/shared/timeout.h src/shared/queue.h src/shared/queue.c \ + src/shared/util.h src/shared/util.c src/shared/mgmt.h \ + src/shared/mgmt.c src/shared/crypto.h src/shared/crypto.c \ + src/shared/ecc.h src/shared/ecc.c src/shared/ringbuf.h \ + src/shared/ringbuf.c src/shared/tester.h src/shared/hci.h \ + src/shared/hci.c src/shared/hci-crypto.h \ + src/shared/hci-crypto.c src/shared/hfp.h src/shared/hfp.c \ + src/shared/uhid.h src/shared/uhid.c src/shared/pcap.h \ + src/shared/pcap.c src/shared/btsnoop.h src/shared/btsnoop.c \ + src/shared/ad.h src/shared/ad.c src/shared/att-types.h \ + src/shared/att.h src/shared/att.c src/shared/gatt-helpers.h \ + src/shared/gatt-helpers.c src/shared/gatt-client.h \ + src/shared/gatt-client.c src/shared/gatt-server.h \ + src/shared/gatt-server.c src/shared/gatt-db.h \ + src/shared/gatt-db.c src/shared/gap.h src/shared/gap.c \ + src/shared/log.h src/shared/log.c src/shared/bap.h \ + src/shared/bap.c src/shared/ascs.h src/shared/bap-debug.h \ + src/shared/bap-debug.c src/shared/mcs.h src/shared/mcp.h \ + src/shared/mcp.c src/shared/vcp.c src/shared/vcp.h \ + src/shared/micp.c src/shared/micp.h src/shared/csip.c \ + src/shared/csip.h src/shared/bass.h src/shared/bass.c \ + src/shared/ccp.h src/shared/ccp.c src/shared/lc3.h \ + src/shared/tty.h src/shared/bap-defs.h src/shared/asha.h \ + src/shared/asha.c src/shared/shell.c src/shared/shell.h \ + src/shared/io-glib.c src/shared/timeout-glib.c \ + src/shared/mainloop-glib.c src/shared/mainloop-notify.h \ + src/shared/mainloop-notify.c src/shared/tester.c +@READLINE_TRUE@am__objects_7 = src/shared/libshared_glib_la-shell.lo +am__objects_8 = src/shared/libshared_glib_la-queue.lo \ + src/shared/libshared_glib_la-util.lo \ + src/shared/libshared_glib_la-mgmt.lo \ + src/shared/libshared_glib_la-crypto.lo \ + src/shared/libshared_glib_la-ecc.lo \ + src/shared/libshared_glib_la-ringbuf.lo \ + src/shared/libshared_glib_la-hci.lo \ + src/shared/libshared_glib_la-hci-crypto.lo \ + src/shared/libshared_glib_la-hfp.lo \ + src/shared/libshared_glib_la-uhid.lo \ + src/shared/libshared_glib_la-pcap.lo \ + src/shared/libshared_glib_la-btsnoop.lo \ + src/shared/libshared_glib_la-ad.lo \ + src/shared/libshared_glib_la-att.lo \ + src/shared/libshared_glib_la-gatt-helpers.lo \ + src/shared/libshared_glib_la-gatt-client.lo \ + src/shared/libshared_glib_la-gatt-server.lo \ + src/shared/libshared_glib_la-gatt-db.lo \ + src/shared/libshared_glib_la-gap.lo \ + src/shared/libshared_glib_la-log.lo \ + src/shared/libshared_glib_la-bap.lo \ + src/shared/libshared_glib_la-bap-debug.lo \ + src/shared/libshared_glib_la-mcp.lo \ + src/shared/libshared_glib_la-vcp.lo \ + src/shared/libshared_glib_la-micp.lo \ + src/shared/libshared_glib_la-csip.lo \ + src/shared/libshared_glib_la-bass.lo \ + src/shared/libshared_glib_la-ccp.lo \ + src/shared/libshared_glib_la-asha.lo $(am__objects_7) +am_src_libshared_glib_la_OBJECTS = $(am__objects_8) \ + src/shared/libshared_glib_la-io-glib.lo \ + src/shared/libshared_glib_la-timeout-glib.lo \ + src/shared/libshared_glib_la-mainloop-glib.lo \ + src/shared/libshared_glib_la-mainloop-notify.lo \ + src/shared/libshared_glib_la-tester.lo +src_libshared_glib_la_OBJECTS = $(am_src_libshared_glib_la_OBJECTS) +src_libshared_glib_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(src_libshared_glib_la_CFLAGS) $(CFLAGS) \ + $(src_libshared_glib_la_LDFLAGS) $(LDFLAGS) -o $@ +src_libshared_mainloop_la_LIBADD = +am__src_libshared_mainloop_la_SOURCES_DIST = src/shared/io.h \ + src/shared/timeout.h src/shared/queue.h src/shared/queue.c \ + src/shared/util.h src/shared/util.c src/shared/mgmt.h \ + src/shared/mgmt.c src/shared/crypto.h src/shared/crypto.c \ + src/shared/ecc.h src/shared/ecc.c src/shared/ringbuf.h \ + src/shared/ringbuf.c src/shared/tester.h src/shared/hci.h \ + src/shared/hci.c src/shared/hci-crypto.h \ + src/shared/hci-crypto.c src/shared/hfp.h src/shared/hfp.c \ + src/shared/uhid.h src/shared/uhid.c src/shared/pcap.h \ + src/shared/pcap.c src/shared/btsnoop.h src/shared/btsnoop.c \ + src/shared/ad.h src/shared/ad.c src/shared/att-types.h \ + src/shared/att.h src/shared/att.c src/shared/gatt-helpers.h \ + src/shared/gatt-helpers.c src/shared/gatt-client.h \ + src/shared/gatt-client.c src/shared/gatt-server.h \ + src/shared/gatt-server.c src/shared/gatt-db.h \ + src/shared/gatt-db.c src/shared/gap.h src/shared/gap.c \ + src/shared/log.h src/shared/log.c src/shared/bap.h \ + src/shared/bap.c src/shared/ascs.h src/shared/bap-debug.h \ + src/shared/bap-debug.c src/shared/mcs.h src/shared/mcp.h \ + src/shared/mcp.c src/shared/vcp.c src/shared/vcp.h \ + src/shared/micp.c src/shared/micp.h src/shared/csip.c \ + src/shared/csip.h src/shared/bass.h src/shared/bass.c \ + src/shared/ccp.h src/shared/ccp.c src/shared/lc3.h \ + src/shared/tty.h src/shared/bap-defs.h src/shared/asha.h \ + src/shared/asha.c src/shared/shell.c src/shared/shell.h \ + src/shared/io-mainloop.c src/shared/timeout-mainloop.c \ + src/shared/mainloop.h src/shared/mainloop.c \ + src/shared/mainloop-notify.h src/shared/mainloop-notify.c +@READLINE_TRUE@am__objects_9 = \ +@READLINE_TRUE@ src/shared/libshared_mainloop_la-shell.lo +am__objects_10 = src/shared/libshared_mainloop_la-queue.lo \ + src/shared/libshared_mainloop_la-util.lo \ + src/shared/libshared_mainloop_la-mgmt.lo \ + src/shared/libshared_mainloop_la-crypto.lo \ + src/shared/libshared_mainloop_la-ecc.lo \ + src/shared/libshared_mainloop_la-ringbuf.lo \ + src/shared/libshared_mainloop_la-hci.lo \ + src/shared/libshared_mainloop_la-hci-crypto.lo \ + src/shared/libshared_mainloop_la-hfp.lo \ + src/shared/libshared_mainloop_la-uhid.lo \ + src/shared/libshared_mainloop_la-pcap.lo \ + src/shared/libshared_mainloop_la-btsnoop.lo \ + src/shared/libshared_mainloop_la-ad.lo \ + src/shared/libshared_mainloop_la-att.lo \ + src/shared/libshared_mainloop_la-gatt-helpers.lo \ + src/shared/libshared_mainloop_la-gatt-client.lo \ + src/shared/libshared_mainloop_la-gatt-server.lo \ + src/shared/libshared_mainloop_la-gatt-db.lo \ + src/shared/libshared_mainloop_la-gap.lo \ + src/shared/libshared_mainloop_la-log.lo \ + src/shared/libshared_mainloop_la-bap.lo \ + src/shared/libshared_mainloop_la-bap-debug.lo \ + src/shared/libshared_mainloop_la-mcp.lo \ + src/shared/libshared_mainloop_la-vcp.lo \ + src/shared/libshared_mainloop_la-micp.lo \ + src/shared/libshared_mainloop_la-csip.lo \ + src/shared/libshared_mainloop_la-bass.lo \ + src/shared/libshared_mainloop_la-ccp.lo \ + src/shared/libshared_mainloop_la-asha.lo $(am__objects_9) +am_src_libshared_mainloop_la_OBJECTS = $(am__objects_10) \ + src/shared/libshared_mainloop_la-io-mainloop.lo \ + src/shared/libshared_mainloop_la-timeout-mainloop.lo \ + src/shared/libshared_mainloop_la-mainloop.lo \ + src/shared/libshared_mainloop_la-mainloop-notify.lo +src_libshared_mainloop_la_OBJECTS = \ + $(am_src_libshared_mainloop_la_OBJECTS) +src_libshared_mainloop_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) \ + $(src_libshared_mainloop_la_LDFLAGS) $(LDFLAGS) -o $@ +am__android_android_tester_SOURCES_DIST = emulator/hciemu.h \ + emulator/hciemu.c emulator/vhci.h emulator/vhci.c \ + emulator/btdev.h emulator/btdev.c emulator/bthost.h \ + emulator/bthost.c emulator/smp.c monitor/rfcomm.h \ + android/hardware/hardware.c android/tester-bluetooth.c \ + android/tester-socket.c android/tester-hidhost.c \ + android/tester-pan.c android/tester-hdp.c \ + android/tester-a2dp.c android/tester-avrcp.c \ + android/tester-gatt.c android/tester-map-client.c \ + android/tester-main.h android/tester-main.c +@ANDROID_TRUE@am_android_android_tester_OBJECTS = emulator/android_android_tester-hciemu.$(OBJEXT) \ +@ANDROID_TRUE@ emulator/android_android_tester-vhci.$(OBJEXT) \ +@ANDROID_TRUE@ emulator/android_android_tester-btdev.$(OBJEXT) \ +@ANDROID_TRUE@ emulator/android_android_tester-bthost.$(OBJEXT) \ +@ANDROID_TRUE@ emulator/android_android_tester-smp.$(OBJEXT) \ +@ANDROID_TRUE@ android/hardware/android_tester-hardware.$(OBJEXT) \ +@ANDROID_TRUE@ android/android_tester-tester-bluetooth.$(OBJEXT) \ +@ANDROID_TRUE@ android/android_tester-tester-socket.$(OBJEXT) \ +@ANDROID_TRUE@ android/android_tester-tester-hidhost.$(OBJEXT) \ +@ANDROID_TRUE@ android/android_tester-tester-pan.$(OBJEXT) \ +@ANDROID_TRUE@ android/android_tester-tester-hdp.$(OBJEXT) \ +@ANDROID_TRUE@ android/android_tester-tester-a2dp.$(OBJEXT) \ +@ANDROID_TRUE@ android/android_tester-tester-avrcp.$(OBJEXT) \ +@ANDROID_TRUE@ android/android_tester-tester-gatt.$(OBJEXT) \ +@ANDROID_TRUE@ android/android_tester-tester-map-client.$(OBJEXT) \ +@ANDROID_TRUE@ android/android_tester-tester-main.$(OBJEXT) +android_android_tester_OBJECTS = $(am_android_android_tester_OBJECTS) +@ANDROID_TRUE@android_android_tester_DEPENDENCIES = \ +@ANDROID_TRUE@ lib/libbluetooth-internal.la \ +@ANDROID_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +android_android_tester_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(android_android_tester_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__android_avdtptest_SOURCES_DIST = android/avdtptest.c src/log.h \ + src/log.c btio/btio.h btio/btio.c src/shared/util.h \ + src/shared/util.c src/shared/queue.h src/shared/queue.c \ + src/shared/log.h src/shared/log.c android/avdtp.h \ + android/avdtp.c +@ANDROID_TRUE@am_android_avdtptest_OBJECTS = \ +@ANDROID_TRUE@ android/avdtptest-avdtptest.$(OBJEXT) \ +@ANDROID_TRUE@ src/android_avdtptest-log.$(OBJEXT) \ +@ANDROID_TRUE@ btio/android_avdtptest-btio.$(OBJEXT) \ +@ANDROID_TRUE@ src/shared/android_avdtptest-util.$(OBJEXT) \ +@ANDROID_TRUE@ src/shared/android_avdtptest-queue.$(OBJEXT) \ +@ANDROID_TRUE@ src/shared/android_avdtptest-log.$(OBJEXT) \ +@ANDROID_TRUE@ android/avdtptest-avdtp.$(OBJEXT) +android_avdtptest_OBJECTS = $(am_android_avdtptest_OBJECTS) +@ANDROID_TRUE@android_avdtptest_DEPENDENCIES = \ +@ANDROID_TRUE@ lib/libbluetooth-internal.la \ +@ANDROID_TRUE@ $(am__DEPENDENCIES_1) +android_avdtptest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(android_avdtptest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +am__android_bluetoothd_SOURCES_DIST = android/main.c src/log.c \ + android/hal-msg.h android/audio-msg.h android/sco-msg.h \ + android/utils.h src/sdpd-database.c src/sdpd-server.c \ + src/sdpd-service.c src/sdpd-request.c src/uuid-helper.h \ + src/uuid-helper.c src/eir.h src/eir.c android/bluetooth.h \ + android/bluetooth.c android/hidhost.h android/hidhost.c \ + profiles/scanparam/scpp.h profiles/scanparam/scpp.c \ + profiles/deviceinfo/dis.h profiles/deviceinfo/dis.c \ + profiles/battery/bas.h profiles/battery/bas.c \ + profiles/input/hog-lib.h profiles/input/hog-lib.c \ + android/ipc-common.h android/ipc.h android/ipc.c \ + android/avdtp.h android/avdtp.c android/a2dp.h android/a2dp.c \ + android/a2dp-sink.h android/a2dp-sink.c android/avctp.h \ + android/avctp.c android/avrcp.h android/avrcp.c \ + android/avrcp-lib.h android/avrcp-lib.c android/socket.h \ + android/socket.c android/sco.h android/sco.c android/pan.h \ + android/pan.c android/handsfree.h android/handsfree.c \ + android/handsfree-client.c android/handsfree-client.h \ + android/gatt.h android/gatt.c android/health.h \ + android/health.c profiles/health/mcap.h profiles/health/mcap.c \ + android/map-client.h android/map-client.c attrib/att.c \ + attrib/att.h attrib/gatt.c attrib/gatt.h attrib/gattrib.c \ + attrib/gattrib.h btio/btio.h btio/btio.c src/sdp-client.h \ + src/sdp-client.c profiles/network/bnep.h \ + profiles/network/bnep.c +@ANDROID_TRUE@am_android_bluetoothd_OBJECTS = android/main.$(OBJEXT) \ +@ANDROID_TRUE@ src/log.$(OBJEXT) src/sdpd-database.$(OBJEXT) \ +@ANDROID_TRUE@ src/sdpd-server.$(OBJEXT) \ +@ANDROID_TRUE@ src/sdpd-service.$(OBJEXT) \ +@ANDROID_TRUE@ src/sdpd-request.$(OBJEXT) \ +@ANDROID_TRUE@ src/uuid-helper.$(OBJEXT) src/eir.$(OBJEXT) \ +@ANDROID_TRUE@ android/bluetooth.$(OBJEXT) \ +@ANDROID_TRUE@ android/hidhost.$(OBJEXT) \ +@ANDROID_TRUE@ profiles/scanparam/scpp.$(OBJEXT) \ +@ANDROID_TRUE@ profiles/deviceinfo/dis.$(OBJEXT) \ +@ANDROID_TRUE@ profiles/battery/bas.$(OBJEXT) \ +@ANDROID_TRUE@ profiles/input/hog-lib.$(OBJEXT) \ +@ANDROID_TRUE@ android/ipc.$(OBJEXT) android/avdtp.$(OBJEXT) \ +@ANDROID_TRUE@ android/a2dp.$(OBJEXT) \ +@ANDROID_TRUE@ android/a2dp-sink.$(OBJEXT) \ +@ANDROID_TRUE@ android/avctp.$(OBJEXT) android/avrcp.$(OBJEXT) \ +@ANDROID_TRUE@ android/avrcp-lib.$(OBJEXT) \ +@ANDROID_TRUE@ android/socket.$(OBJEXT) android/sco.$(OBJEXT) \ +@ANDROID_TRUE@ android/pan.$(OBJEXT) \ +@ANDROID_TRUE@ android/handsfree.$(OBJEXT) \ +@ANDROID_TRUE@ android/handsfree-client.$(OBJEXT) \ +@ANDROID_TRUE@ android/gatt.$(OBJEXT) android/health.$(OBJEXT) \ +@ANDROID_TRUE@ profiles/health/mcap.$(OBJEXT) \ +@ANDROID_TRUE@ android/map-client.$(OBJEXT) \ +@ANDROID_TRUE@ attrib/att.$(OBJEXT) attrib/gatt.$(OBJEXT) \ +@ANDROID_TRUE@ attrib/gattrib.$(OBJEXT) btio/btio.$(OBJEXT) \ +@ANDROID_TRUE@ src/sdp-client.$(OBJEXT) \ +@ANDROID_TRUE@ profiles/network/bnep.$(OBJEXT) +android_bluetoothd_OBJECTS = $(am_android_bluetoothd_OBJECTS) +@ANDROID_TRUE@android_bluetoothd_DEPENDENCIES = \ +@ANDROID_TRUE@ lib/libbluetooth-internal.la \ +@ANDROID_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +am__android_bluetoothd_snoop_SOURCES_DIST = \ + android/bluetoothd-snoop.c src/log.c +@ANDROID_TRUE@am_android_bluetoothd_snoop_OBJECTS = \ +@ANDROID_TRUE@ android/bluetoothd-snoop.$(OBJEXT) \ +@ANDROID_TRUE@ src/log.$(OBJEXT) +android_bluetoothd_snoop_OBJECTS = \ + $(am_android_bluetoothd_snoop_OBJECTS) +@ANDROID_TRUE@android_bluetoothd_snoop_DEPENDENCIES = \ +@ANDROID_TRUE@ src/libshared-mainloop.la $(am__DEPENDENCIES_1) +am__android_haltest_SOURCES_DIST = android/client/haltest.c \ + android/client/pollhandler.h android/client/pollhandler.c \ + android/client/terminal.h android/client/terminal.c \ + android/client/history.h android/client/history.c \ + android/client/tabcompletion.c android/client/if-main.h \ + android/client/if-av.c android/client/if-av-sink.c \ + android/client/if-rc.c android/client/if-rc-ctrl.c \ + android/client/if-bt.c android/client/if-gatt.c \ + android/client/if-hf.c android/client/if-hf-client.c \ + android/client/if-hh.c android/client/if-pan.c \ + android/client/if-hl.c android/client/if-sock.c \ + android/client/if-audio.c android/client/if-sco.c \ + android/client/if-mce.c android/hardware/hardware.c \ + android/hal-utils.h android/hal-utils.c +@ANDROID_TRUE@am_android_haltest_OBJECTS = \ +@ANDROID_TRUE@ android/client/haltest-haltest.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-pollhandler.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-terminal.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-history.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-tabcompletion.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-if-av.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-if-av-sink.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-if-rc.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-if-rc-ctrl.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-if-bt.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-if-gatt.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-if-hf.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-if-hf-client.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-if-hh.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-if-pan.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-if-hl.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-if-sock.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-if-audio.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-if-sco.$(OBJEXT) \ +@ANDROID_TRUE@ android/client/haltest-if-mce.$(OBJEXT) \ +@ANDROID_TRUE@ android/hardware/haltest-hardware.$(OBJEXT) \ +@ANDROID_TRUE@ android/haltest-hal-utils.$(OBJEXT) +android_haltest_OBJECTS = $(am_android_haltest_OBJECTS) +android_haltest_DEPENDENCIES = +android_haltest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(android_haltest_LDFLAGS) $(LDFLAGS) \ + -o $@ +am__android_ipc_tester_SOURCES_DIST = emulator/hciemu.h \ + emulator/hciemu.c emulator/vhci.h emulator/vhci.c \ + emulator/btdev.h emulator/btdev.c emulator/bthost.h \ + emulator/bthost.c emulator/smp.c android/hal-utils.h \ + android/hal-utils.c android/ipc-common.h android/ipc-tester.c +@ANDROID_TRUE@am_android_ipc_tester_OBJECTS = \ +@ANDROID_TRUE@ emulator/android_ipc_tester-hciemu.$(OBJEXT) \ +@ANDROID_TRUE@ emulator/android_ipc_tester-vhci.$(OBJEXT) \ +@ANDROID_TRUE@ emulator/android_ipc_tester-btdev.$(OBJEXT) \ +@ANDROID_TRUE@ emulator/android_ipc_tester-bthost.$(OBJEXT) \ +@ANDROID_TRUE@ emulator/android_ipc_tester-smp.$(OBJEXT) \ +@ANDROID_TRUE@ android/ipc_tester-hal-utils.$(OBJEXT) \ +@ANDROID_TRUE@ android/ipc_tester-ipc-tester.$(OBJEXT) +android_ipc_tester_OBJECTS = $(am_android_ipc_tester_OBJECTS) +@ANDROID_TRUE@android_ipc_tester_DEPENDENCIES = \ +@ANDROID_TRUE@ lib/libbluetooth-internal.la \ +@ANDROID_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +am__android_system_emulator_SOURCES_DIST = android/system-emulator.c +@ANDROID_TRUE@am_android_system_emulator_OBJECTS = \ +@ANDROID_TRUE@ android/system-emulator.$(OBJEXT) +android_system_emulator_OBJECTS = \ + $(am_android_system_emulator_OBJECTS) +@ANDROID_TRUE@android_system_emulator_DEPENDENCIES = \ +@ANDROID_TRUE@ src/libshared-mainloop.la +am__android_test_ipc_SOURCES_DIST = android/test-ipc.c src/log.h \ + src/log.c android/ipc-common.h android/ipc.c android/ipc.h +@ANDROID_TRUE@am_android_test_ipc_OBJECTS = \ +@ANDROID_TRUE@ android/test-ipc.$(OBJEXT) src/log.$(OBJEXT) \ +@ANDROID_TRUE@ android/ipc.$(OBJEXT) +android_test_ipc_OBJECTS = $(am_android_test_ipc_OBJECTS) +@ANDROID_TRUE@android_test_ipc_DEPENDENCIES = src/libshared-glib.la \ +@ANDROID_TRUE@ $(am__DEPENDENCIES_1) +am__attrib_gatttool_SOURCES_DIST = attrib/gatttool.c attrib/att.c \ + attrib/gatt.c attrib/gattrib.c btio/btio.c attrib/gatttool.h \ + attrib/interactive.c attrib/utils.c src/log.c client/display.c \ + client/display.h +@DEPRECATED_TRUE@@READLINE_TRUE@am_attrib_gatttool_OBJECTS = \ +@DEPRECATED_TRUE@@READLINE_TRUE@ attrib/gatttool.$(OBJEXT) \ +@DEPRECATED_TRUE@@READLINE_TRUE@ attrib/att.$(OBJEXT) \ +@DEPRECATED_TRUE@@READLINE_TRUE@ attrib/gatt.$(OBJEXT) \ +@DEPRECATED_TRUE@@READLINE_TRUE@ attrib/gattrib.$(OBJEXT) \ +@DEPRECATED_TRUE@@READLINE_TRUE@ btio/btio.$(OBJEXT) \ +@DEPRECATED_TRUE@@READLINE_TRUE@ attrib/interactive.$(OBJEXT) \ +@DEPRECATED_TRUE@@READLINE_TRUE@ attrib/utils.$(OBJEXT) \ +@DEPRECATED_TRUE@@READLINE_TRUE@ src/log.$(OBJEXT) \ +@DEPRECATED_TRUE@@READLINE_TRUE@ client/display.$(OBJEXT) +attrib_gatttool_OBJECTS = $(am_attrib_gatttool_OBJECTS) +@DEPRECATED_TRUE@@READLINE_TRUE@attrib_gatttool_DEPENDENCIES = \ +@DEPRECATED_TRUE@@READLINE_TRUE@ lib/libbluetooth-internal.la \ +@DEPRECATED_TRUE@@READLINE_TRUE@ src/libshared-glib.la \ +@DEPRECATED_TRUE@@READLINE_TRUE@ $(am__DEPENDENCIES_1) +am__client_bluetoothctl_SOURCES_DIST = client/main.c client/print.h \ + client/print.c client/display.h client/display.c \ + client/agent.h client/agent.c client/advertising.h \ + client/advertising.c client/adv_monitor.h client/adv_monitor.c \ + client/gatt.h client/gatt.c client/admin.h client/admin.c \ + client/player.h client/player.c client/mgmt.h client/mgmt.c \ + client/assistant.h client/assistant.c +@CLIENT_TRUE@am_client_bluetoothctl_OBJECTS = client/main.$(OBJEXT) \ +@CLIENT_TRUE@ client/print.$(OBJEXT) client/display.$(OBJEXT) \ +@CLIENT_TRUE@ client/agent.$(OBJEXT) \ +@CLIENT_TRUE@ client/advertising.$(OBJEXT) \ +@CLIENT_TRUE@ client/adv_monitor.$(OBJEXT) \ +@CLIENT_TRUE@ client/gatt.$(OBJEXT) client/admin.$(OBJEXT) \ +@CLIENT_TRUE@ client/player.$(OBJEXT) client/mgmt.$(OBJEXT) \ +@CLIENT_TRUE@ client/assistant.$(OBJEXT) +client_bluetoothctl_OBJECTS = $(am_client_bluetoothctl_OBJECTS) +@CLIENT_TRUE@client_bluetoothctl_DEPENDENCIES = \ +@CLIENT_TRUE@ lib/libbluetooth-internal.la \ +@CLIENT_TRUE@ gdbus/libgdbus-internal.la src/libshared-glib.la \ +@CLIENT_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am__emulator_b1ee_SOURCES_DIST = emulator/b1ee.c +@TESTING_TRUE@am_emulator_b1ee_OBJECTS = emulator/b1ee.$(OBJEXT) +emulator_b1ee_OBJECTS = $(am_emulator_b1ee_OBJECTS) +@TESTING_TRUE@emulator_b1ee_DEPENDENCIES = src/libshared-mainloop.la +am__emulator_btvirt_SOURCES_DIST = emulator/main.c monitor/bt.h \ + emulator/serial.h emulator/serial.c emulator/server.h \ + emulator/server.c emulator/vhci.h emulator/vhci.c \ + emulator/btdev.h emulator/btdev.c emulator/bthost.h \ + emulator/bthost.c emulator/smp.c emulator/phy.h emulator/phy.c \ + emulator/amp.h emulator/amp.c emulator/le.h emulator/le.c +@TESTING_TRUE@am_emulator_btvirt_OBJECTS = emulator/main.$(OBJEXT) \ +@TESTING_TRUE@ emulator/serial.$(OBJEXT) \ +@TESTING_TRUE@ emulator/server.$(OBJEXT) \ +@TESTING_TRUE@ emulator/vhci.$(OBJEXT) emulator/btdev.$(OBJEXT) \ +@TESTING_TRUE@ emulator/bthost.$(OBJEXT) emulator/smp.$(OBJEXT) \ +@TESTING_TRUE@ emulator/phy.$(OBJEXT) emulator/amp.$(OBJEXT) \ +@TESTING_TRUE@ emulator/le.$(OBJEXT) +emulator_btvirt_OBJECTS = $(am_emulator_btvirt_OBJECTS) +@TESTING_TRUE@emulator_btvirt_DEPENDENCIES = \ +@TESTING_TRUE@ lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-mainloop.la +am__emulator_hfp_SOURCES_DIST = emulator/hfp.c +@TESTING_TRUE@am_emulator_hfp_OBJECTS = emulator/hfp.$(OBJEXT) +emulator_hfp_OBJECTS = $(am_emulator_hfp_OBJECTS) +@TESTING_TRUE@emulator_hfp_DEPENDENCIES = src/libshared-mainloop.la +am__mesh_bluetooth_meshd_SOURCES_DIST = mesh/mesh.h mesh/mesh.c \ + mesh/net-keys.h mesh/net-keys.c mesh/mesh-io.h mesh/mesh-io.c \ + mesh/mesh-mgmt.h mesh/mesh-mgmt.c mesh/error.h \ + mesh/mesh-io-api.h mesh/mesh-io-unit.h mesh/mesh-io-unit.c \ + mesh/mesh-io-mgmt.h mesh/mesh-io-mgmt.c mesh/mesh-io-generic.h \ + mesh/mesh-io-generic.c mesh/net.h mesh/net.c mesh/crypto.h \ + mesh/crypto.c mesh/friend.h mesh/friend.c mesh/appkey.h \ + mesh/appkey.c mesh/node.h mesh/node.c mesh/provision.h \ + mesh/prov.h mesh/model.h mesh/model.c mesh/cfgmod.h \ + mesh/cfgmod-server.c mesh/remprv.h mesh/remprv-server.c \ + mesh/mesh-config.h mesh/mesh-config-json.c mesh/util.h \ + mesh/util.c mesh/dbus.h mesh/dbus.c mesh/agent.h mesh/agent.c \ + mesh/prov-acceptor.c mesh/prov-initiator.c mesh/manager.h \ + mesh/manager.c mesh/pb-adv.h mesh/pb-adv.c mesh/keyring.h \ + mesh/keyring.c mesh/rpl.h mesh/rpl.c mesh/prv-beacon.h \ + mesh/prvbeac-server.c mesh/mesh-defs.h mesh/main.c +@MESH_TRUE@am__objects_11 = mesh/mesh.$(OBJEXT) \ +@MESH_TRUE@ mesh/net-keys.$(OBJEXT) mesh/mesh-io.$(OBJEXT) \ +@MESH_TRUE@ mesh/mesh-mgmt.$(OBJEXT) \ +@MESH_TRUE@ mesh/mesh-io-unit.$(OBJEXT) \ +@MESH_TRUE@ mesh/mesh-io-mgmt.$(OBJEXT) \ +@MESH_TRUE@ mesh/mesh-io-generic.$(OBJEXT) mesh/net.$(OBJEXT) \ +@MESH_TRUE@ mesh/crypto.$(OBJEXT) mesh/friend.$(OBJEXT) \ +@MESH_TRUE@ mesh/appkey.$(OBJEXT) mesh/node.$(OBJEXT) \ +@MESH_TRUE@ mesh/model.$(OBJEXT) mesh/cfgmod-server.$(OBJEXT) \ +@MESH_TRUE@ mesh/remprv-server.$(OBJEXT) \ +@MESH_TRUE@ mesh/mesh-config-json.$(OBJEXT) mesh/util.$(OBJEXT) \ +@MESH_TRUE@ mesh/dbus.$(OBJEXT) mesh/agent.$(OBJEXT) \ +@MESH_TRUE@ mesh/prov-acceptor.$(OBJEXT) \ +@MESH_TRUE@ mesh/prov-initiator.$(OBJEXT) \ +@MESH_TRUE@ mesh/manager.$(OBJEXT) mesh/pb-adv.$(OBJEXT) \ +@MESH_TRUE@ mesh/keyring.$(OBJEXT) mesh/rpl.$(OBJEXT) \ +@MESH_TRUE@ mesh/prvbeac-server.$(OBJEXT) +@MESH_TRUE@am_mesh_bluetooth_meshd_OBJECTS = $(am__objects_11) \ +@MESH_TRUE@ mesh/main.$(OBJEXT) +mesh_bluetooth_meshd_OBJECTS = $(am_mesh_bluetooth_meshd_OBJECTS) +@EXTERNAL_ELL_FALSE@am__DEPENDENCIES_2 = ell/libell-internal.la +@MESH_TRUE@mesh_bluetooth_meshd_DEPENDENCIES = src/libshared-ell.la \ +@MESH_TRUE@ $(am__DEPENDENCIES_2) +am__monitor_btmon_SOURCES_DIST = monitor/main.c monitor/bt.h \ + monitor/display.h monitor/display.c monitor/hcidump.h \ + monitor/hcidump.c monitor/ellisys.h monitor/ellisys.c \ + monitor/control.h monitor/control.c monitor/packet.h \ + monitor/packet.c monitor/vendor.h monitor/vendor.c \ + monitor/lmp.h monitor/lmp.c monitor/crc.h monitor/crc.c \ + monitor/ll.h monitor/ll.c monitor/l2cap.h monitor/l2cap.c \ + monitor/sdp.h monitor/sdp.c monitor/avctp.h monitor/avctp.c \ + monitor/avdtp.h monitor/avdtp.c monitor/a2dp.h monitor/a2dp.c \ + monitor/rfcomm.h monitor/rfcomm.c monitor/bnep.h \ + monitor/bnep.c monitor/hwdb.h monitor/hwdb.c monitor/keys.h \ + monitor/keys.c monitor/analyze.h monitor/analyze.c \ + monitor/intel.h monitor/intel.c monitor/broadcom.h \ + monitor/broadcom.c monitor/msft.h monitor/msft.c \ + monitor/jlink.h monitor/jlink.c monitor/tty.h \ + monitor/emulator.h monitor/att.h monitor/att.c src/log.h \ + src/log.c src/textfile.h src/textfile.c src/settings.h \ + src/settings.c +@MONITOR_TRUE@am_monitor_btmon_OBJECTS = monitor/main.$(OBJEXT) \ +@MONITOR_TRUE@ monitor/display.$(OBJEXT) \ +@MONITOR_TRUE@ monitor/hcidump.$(OBJEXT) \ +@MONITOR_TRUE@ monitor/ellisys.$(OBJEXT) \ +@MONITOR_TRUE@ monitor/control.$(OBJEXT) \ +@MONITOR_TRUE@ monitor/packet.$(OBJEXT) \ +@MONITOR_TRUE@ monitor/vendor.$(OBJEXT) monitor/lmp.$(OBJEXT) \ +@MONITOR_TRUE@ monitor/crc.$(OBJEXT) monitor/ll.$(OBJEXT) \ +@MONITOR_TRUE@ monitor/l2cap.$(OBJEXT) monitor/sdp.$(OBJEXT) \ +@MONITOR_TRUE@ monitor/avctp.$(OBJEXT) monitor/avdtp.$(OBJEXT) \ +@MONITOR_TRUE@ monitor/a2dp.$(OBJEXT) monitor/rfcomm.$(OBJEXT) \ +@MONITOR_TRUE@ monitor/bnep.$(OBJEXT) monitor/hwdb.$(OBJEXT) \ +@MONITOR_TRUE@ monitor/keys.$(OBJEXT) monitor/analyze.$(OBJEXT) \ +@MONITOR_TRUE@ monitor/intel.$(OBJEXT) \ +@MONITOR_TRUE@ monitor/broadcom.$(OBJEXT) \ +@MONITOR_TRUE@ monitor/msft.$(OBJEXT) monitor/jlink.$(OBJEXT) \ +@MONITOR_TRUE@ monitor/att.$(OBJEXT) src/log.$(OBJEXT) \ +@MONITOR_TRUE@ src/textfile.$(OBJEXT) src/settings.$(OBJEXT) +monitor_btmon_OBJECTS = $(am_monitor_btmon_OBJECTS) +@MONITOR_TRUE@monitor_btmon_DEPENDENCIES = \ +@MONITOR_TRUE@ lib/libbluetooth-internal.la \ +@MONITOR_TRUE@ src/libshared-mainloop.la $(am__DEPENDENCIES_1) \ +@MONITOR_TRUE@ $(am__DEPENDENCIES_1) +am__obexd_src_obexd_SOURCES_DIST = btio/btio.h btio/btio.c \ + gobex/gobex.h gobex/gobex.c gobex/gobex-defs.h \ + gobex/gobex-defs.c gobex/gobex-packet.c gobex/gobex-packet.h \ + gobex/gobex-header.c gobex/gobex-header.h \ + gobex/gobex-transfer.c gobex/gobex-debug.h \ + gobex/gobex-apparam.c gobex/gobex-apparam.h \ + obexd/plugins/filesystem.c obexd/plugins/filesystem.h \ + obexd/plugins/bluetooth.c obexd/plugins/pcsuite.c \ + obexd/plugins/opp.c obexd/plugins/ftp.c obexd/plugins/ftp.h \ + obexd/plugins/irmc.c obexd/plugins/pbap.c \ + obexd/plugins/vcard.h obexd/plugins/vcard.c \ + obexd/plugins/phonebook.h \ + obexd/plugins/phonebook-@PLUGIN_PHONEBOOK@.c \ + obexd/plugins/mas.c obexd/src/map_ap.h \ + obexd/plugins/messages.h obexd/plugins/messages-dummy.c \ + obexd/client/mns.c obexd/client/map-event.h obexd/src/main.c \ + obexd/src/obexd.h obexd/src/plugin.h obexd/src/plugin.c \ + obexd/src/log.h obexd/src/log.c obexd/src/manager.h \ + obexd/src/manager.c obexd/src/obex.h obexd/src/obex.c \ + obexd/src/obex-priv.h obexd/src/mimetype.h \ + obexd/src/mimetype.c obexd/src/service.h obexd/src/service.c \ + obexd/src/transport.h obexd/src/transport.c obexd/src/server.h \ + obexd/src/server.c obexd/client/manager.h \ + obexd/client/manager.c obexd/client/session.h \ + obexd/client/session.c obexd/client/bluetooth.h \ + obexd/client/bluetooth.c obexd/client/sync.h \ + obexd/client/sync.c obexd/client/pbap.h obexd/client/pbap.c \ + obexd/client/ftp.h obexd/client/ftp.c obexd/client/opp.h \ + obexd/client/opp.c obexd/client/map.h obexd/client/map.c \ + obexd/client/bip.h obexd/client/bip.c \ + obexd/client/bip-common.h obexd/client/bip-common.c \ + obexd/client/map-event.c obexd/client/transfer.h \ + obexd/client/transfer.c obexd/client/transport.h \ + obexd/client/transport.c obexd/client/driver.h \ + obexd/client/driver.c +am__objects_12 = btio/obexd-btio.$(OBJEXT) +am__objects_13 = gobex/obexd-gobex.$(OBJEXT) \ + gobex/obexd-gobex-defs.$(OBJEXT) \ + gobex/obexd-gobex-packet.$(OBJEXT) \ + gobex/obexd-gobex-header.$(OBJEXT) \ + gobex/obexd-gobex-transfer.$(OBJEXT) \ + gobex/obexd-gobex-apparam.$(OBJEXT) +@EXPERIMENTAL_TRUE@@OBEX_TRUE@am__objects_14 = obexd/plugins/obexd-pcsuite.$(OBJEXT) +@OBEX_TRUE@am__objects_15 = obexd/plugins/obexd-filesystem.$(OBJEXT) \ +@OBEX_TRUE@ obexd/plugins/obexd-bluetooth.$(OBJEXT) \ +@OBEX_TRUE@ $(am__objects_14) obexd/plugins/obexd-opp.$(OBJEXT) \ +@OBEX_TRUE@ obexd/plugins/obexd-ftp.$(OBJEXT) \ +@OBEX_TRUE@ obexd/plugins/obexd-irmc.$(OBJEXT) \ +@OBEX_TRUE@ obexd/plugins/obexd-pbap.$(OBJEXT) \ +@OBEX_TRUE@ obexd/plugins/obexd-vcard.$(OBJEXT) \ +@OBEX_TRUE@ obexd/plugins/obexd-phonebook-@PLUGIN_PHONEBOOK@.$(OBJEXT) \ +@OBEX_TRUE@ obexd/plugins/obexd-mas.$(OBJEXT) \ +@OBEX_TRUE@ obexd/plugins/obexd-messages-dummy.$(OBJEXT) \ +@OBEX_TRUE@ obexd/client/obexd-mns.$(OBJEXT) +@OBEX_TRUE@am_obexd_src_obexd_OBJECTS = $(am__objects_12) \ +@OBEX_TRUE@ $(am__objects_13) $(am__objects_15) \ +@OBEX_TRUE@ obexd/src/obexd-main.$(OBJEXT) \ +@OBEX_TRUE@ obexd/src/obexd-plugin.$(OBJEXT) \ +@OBEX_TRUE@ obexd/src/obexd-log.$(OBJEXT) \ +@OBEX_TRUE@ obexd/src/obexd-manager.$(OBJEXT) \ +@OBEX_TRUE@ obexd/src/obexd-obex.$(OBJEXT) \ +@OBEX_TRUE@ obexd/src/obexd-mimetype.$(OBJEXT) \ +@OBEX_TRUE@ obexd/src/obexd-service.$(OBJEXT) \ +@OBEX_TRUE@ obexd/src/obexd-transport.$(OBJEXT) \ +@OBEX_TRUE@ obexd/src/obexd-server.$(OBJEXT) \ +@OBEX_TRUE@ obexd/client/obexd-manager.$(OBJEXT) \ +@OBEX_TRUE@ obexd/client/obexd-session.$(OBJEXT) \ +@OBEX_TRUE@ obexd/client/obexd-bluetooth.$(OBJEXT) \ +@OBEX_TRUE@ obexd/client/obexd-sync.$(OBJEXT) \ +@OBEX_TRUE@ obexd/client/obexd-pbap.$(OBJEXT) \ +@OBEX_TRUE@ obexd/client/obexd-ftp.$(OBJEXT) \ +@OBEX_TRUE@ obexd/client/obexd-opp.$(OBJEXT) \ +@OBEX_TRUE@ obexd/client/obexd-map.$(OBJEXT) \ +@OBEX_TRUE@ obexd/client/obexd-bip.$(OBJEXT) \ +@OBEX_TRUE@ obexd/client/obexd-bip-common.$(OBJEXT) \ +@OBEX_TRUE@ obexd/client/obexd-map-event.$(OBJEXT) \ +@OBEX_TRUE@ obexd/client/obexd-transfer.$(OBJEXT) \ +@OBEX_TRUE@ obexd/client/obexd-transport.$(OBJEXT) \ +@OBEX_TRUE@ obexd/client/obexd-driver.$(OBJEXT) +am__objects_16 = $(am__objects_1) +nodist_obexd_src_obexd_OBJECTS = $(am__objects_16) +obexd_src_obexd_OBJECTS = $(am_obexd_src_obexd_OBJECTS) \ + $(nodist_obexd_src_obexd_OBJECTS) +@OBEX_TRUE@obexd_src_obexd_DEPENDENCIES = \ +@OBEX_TRUE@ lib/libbluetooth-internal.la \ +@OBEX_TRUE@ gdbus/libgdbus-internal.la src/libshared-glib.la \ +@OBEX_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ +@OBEX_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +obexd_src_obexd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(obexd_src_obexd_LDFLAGS) $(LDFLAGS) \ + -o $@ +am__peripheral_btsensor_SOURCES_DIST = peripheral/main.c \ + peripheral/efivars.h peripheral/efivars.c peripheral/attach.h \ + peripheral/attach.c peripheral/log.h peripheral/log.c \ + peripheral/gap.h peripheral/gap.c peripheral/gatt.h \ + peripheral/gatt.c +@TESTING_TRUE@am_peripheral_btsensor_OBJECTS = \ +@TESTING_TRUE@ peripheral/main.$(OBJEXT) \ +@TESTING_TRUE@ peripheral/efivars.$(OBJEXT) \ +@TESTING_TRUE@ peripheral/attach.$(OBJEXT) \ +@TESTING_TRUE@ peripheral/log.$(OBJEXT) \ +@TESTING_TRUE@ peripheral/gap.$(OBJEXT) \ +@TESTING_TRUE@ peripheral/gatt.$(OBJEXT) +peripheral_btsensor_OBJECTS = $(am_peripheral_btsensor_OBJECTS) +@TESTING_TRUE@peripheral_btsensor_DEPENDENCIES = \ +@TESTING_TRUE@ src/libshared-mainloop.la \ +@TESTING_TRUE@ lib/libbluetooth-internal.la +am__profiles_cups_bluetooth_SOURCES_DIST = profiles/cups/main.c \ + profiles/cups/cups.h profiles/cups/sdp.c profiles/cups/spp.c \ + profiles/cups/hcrp.c +@CUPS_TRUE@am_profiles_cups_bluetooth_OBJECTS = \ +@CUPS_TRUE@ profiles/cups/main.$(OBJEXT) \ +@CUPS_TRUE@ profiles/cups/sdp.$(OBJEXT) \ +@CUPS_TRUE@ profiles/cups/spp.$(OBJEXT) \ +@CUPS_TRUE@ profiles/cups/hcrp.$(OBJEXT) +profiles_cups_bluetooth_OBJECTS = \ + $(am_profiles_cups_bluetooth_OBJECTS) +@CUPS_TRUE@profiles_cups_bluetooth_DEPENDENCIES = \ +@CUPS_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ +@CUPS_TRUE@ lib/libbluetooth-internal.la \ +@CUPS_TRUE@ gdbus/libgdbus-internal.la +am__profiles_iap_iapd_SOURCES_DIST = profiles/iap/main.c +@TOOLS_TRUE@am_profiles_iap_iapd_OBJECTS = \ +@TOOLS_TRUE@ profiles/iap/main.$(OBJEXT) +profiles_iap_iapd_OBJECTS = $(am_profiles_iap_iapd_OBJECTS) +@TOOLS_TRUE@profiles_iap_iapd_DEPENDENCIES = \ +@TOOLS_TRUE@ gdbus/libgdbus-internal.la $(am__DEPENDENCIES_1) \ +@TOOLS_TRUE@ $(am__DEPENDENCIES_1) +am__src_bluetoothd_SOURCES_DIST = plugins/hostname.c plugins/wiimote.c \ + plugins/autopair.c plugins/policy.c plugins/admin.c \ + plugins/neard.c profiles/sap/main.c profiles/sap/manager.h \ + profiles/sap/manager.c profiles/sap/server.h \ + profiles/sap/server.c profiles/sap/sap.h \ + profiles/sap/sap-dummy.c profiles/audio/source.h \ + profiles/audio/source.c profiles/audio/sink.h \ + profiles/audio/sink.c profiles/audio/a2dp.h \ + profiles/audio/a2dp.c profiles/audio/avdtp.h \ + profiles/audio/avdtp.c profiles/audio/media.h \ + profiles/audio/media.c profiles/audio/transport.h \ + profiles/audio/transport.c profiles/audio/a2dp-codecs.h \ + profiles/audio/control.h profiles/audio/control.c \ + profiles/audio/avctp.h profiles/audio/avctp.c \ + profiles/audio/avrcp.h profiles/audio/avrcp.c \ + profiles/audio/player.h profiles/audio/player.c \ + profiles/network/manager.c profiles/network/bnep.h \ + profiles/network/bnep.c profiles/network/server.h \ + profiles/network/server.c profiles/network/connection.h \ + profiles/network/connection.c profiles/input/manager.c \ + profiles/input/server.h profiles/input/server.c \ + profiles/input/device.h profiles/input/device.c \ + profiles/input/hidp_defs.h profiles/input/sixaxis.h \ + profiles/input/hog.c profiles/input/hog-lib.c \ + profiles/input/hog-lib.h profiles/deviceinfo/dis.c \ + profiles/deviceinfo/dis.h profiles/battery/bas.c \ + profiles/battery/bas.h profiles/scanparam/scpp.c \ + profiles/scanparam/scpp.h profiles/input/suspend.h \ + profiles/input/suspend-none.c profiles/health/mcap.h \ + profiles/health/mcap.c profiles/health/hdp_main.c \ + profiles/health/hdp_types.h profiles/health/hdp_manager.h \ + profiles/health/hdp_manager.c profiles/health/hdp.h \ + profiles/health/hdp.c profiles/health/hdp_util.h \ + profiles/health/hdp_util.c profiles/gap/gas.c \ + profiles/scanparam/scan.c profiles/deviceinfo/deviceinfo.c \ + profiles/midi/midi.c profiles/midi/libmidi.h \ + profiles/midi/libmidi.c profiles/battery/battery.c \ + plugins/sixaxis.c profiles/audio/bap.h profiles/audio/bap.c \ + profiles/audio/bass.h profiles/audio/bass.c \ + profiles/audio/mcp.c profiles/audio/vcp.c \ + profiles/audio/micp.c profiles/audio/ccp.c \ + profiles/audio/csip.c profiles/audio/asha.h \ + profiles/audio/asha.c attrib/att.h attrib/att-database.h \ + attrib/att.c attrib/gatt.h attrib/gatt.c attrib/gattrib.h \ + attrib/gattrib.c btio/btio.h btio/btio.c src/main.c src/log.h \ + src/log.c src/backtrace.h src/backtrace.c src/rfkill.c \ + src/btd.h src/sdpd.h src/sdpd-server.c src/sdpd-request.c \ + src/sdpd-service.c src/sdpd-database.c src/gatt-database.h \ + src/gatt-database.c src/sdp-xml.h src/sdp-xml.c \ + src/sdp-client.h src/sdp-client.c src/textfile.h \ + src/textfile.c src/uuid-helper.h src/uuid-helper.c \ + src/plugin.h src/plugin.c src/storage.h src/storage.c \ + src/advertising.h src/advertising.c src/agent.h src/agent.c \ + src/error.h src/error.c src/adapter.h src/adapter.c \ + src/profile.h src/profile.c src/service.h src/service.c \ + src/gatt-client.h src/gatt-client.c src/device.h src/device.c \ + src/dbus-common.c src/dbus-common.h src/eir.h src/eir.c \ + src/adv_monitor.h src/adv_monitor.c src/battery.h \ + src/battery.c src/settings.h src/settings.c src/set.h \ + src/set.c src/bluetooth.ver +@ADMIN_TRUE@am__objects_17 = plugins/bluetoothd-admin.$(OBJEXT) +@NFC_TRUE@am__objects_18 = plugins/bluetoothd-neard.$(OBJEXT) +@SAP_TRUE@am__objects_19 = profiles/sap/bluetoothd-main.$(OBJEXT) \ +@SAP_TRUE@ profiles/sap/bluetoothd-manager.$(OBJEXT) \ +@SAP_TRUE@ profiles/sap/bluetoothd-server.$(OBJEXT) \ +@SAP_TRUE@ profiles/sap/bluetoothd-sap-dummy.$(OBJEXT) +@A2DP_TRUE@am__objects_20 = \ +@A2DP_TRUE@ profiles/audio/bluetoothd-source.$(OBJEXT) \ +@A2DP_TRUE@ profiles/audio/bluetoothd-sink.$(OBJEXT) \ +@A2DP_TRUE@ profiles/audio/bluetoothd-a2dp.$(OBJEXT) \ +@A2DP_TRUE@ profiles/audio/bluetoothd-avdtp.$(OBJEXT) \ +@A2DP_TRUE@ profiles/audio/bluetoothd-media.$(OBJEXT) \ +@A2DP_TRUE@ profiles/audio/bluetoothd-transport.$(OBJEXT) +@AVRCP_TRUE@am__objects_21 = \ +@AVRCP_TRUE@ profiles/audio/bluetoothd-control.$(OBJEXT) \ +@AVRCP_TRUE@ profiles/audio/bluetoothd-avctp.$(OBJEXT) \ +@AVRCP_TRUE@ profiles/audio/bluetoothd-avrcp.$(OBJEXT) \ +@AVRCP_TRUE@ profiles/audio/bluetoothd-player.$(OBJEXT) +@NETWORK_TRUE@am__objects_22 = \ +@NETWORK_TRUE@ profiles/network/bluetoothd-manager.$(OBJEXT) \ +@NETWORK_TRUE@ profiles/network/bluetoothd-bnep.$(OBJEXT) \ +@NETWORK_TRUE@ profiles/network/bluetoothd-server.$(OBJEXT) \ +@NETWORK_TRUE@ profiles/network/bluetoothd-connection.$(OBJEXT) +@HID_TRUE@am__objects_23 = \ +@HID_TRUE@ profiles/input/bluetoothd-manager.$(OBJEXT) \ +@HID_TRUE@ profiles/input/bluetoothd-server.$(OBJEXT) \ +@HID_TRUE@ profiles/input/bluetoothd-device.$(OBJEXT) +@HOG_TRUE@am__objects_24 = profiles/input/bluetoothd-hog.$(OBJEXT) \ +@HOG_TRUE@ profiles/input/bluetoothd-hog-lib.$(OBJEXT) \ +@HOG_TRUE@ profiles/deviceinfo/bluetoothd-dis.$(OBJEXT) \ +@HOG_TRUE@ profiles/battery/bluetoothd-bas.$(OBJEXT) \ +@HOG_TRUE@ profiles/scanparam/bluetoothd-scpp.$(OBJEXT) \ +@HOG_TRUE@ profiles/input/bluetoothd-suspend-none.$(OBJEXT) +@HEALTH_TRUE@am__objects_25 = \ +@HEALTH_TRUE@ profiles/health/bluetoothd-mcap.$(OBJEXT) \ +@HEALTH_TRUE@ profiles/health/bluetoothd-hdp_main.$(OBJEXT) \ +@HEALTH_TRUE@ profiles/health/bluetoothd-hdp_manager.$(OBJEXT) \ +@HEALTH_TRUE@ profiles/health/bluetoothd-hdp.$(OBJEXT) \ +@HEALTH_TRUE@ profiles/health/bluetoothd-hdp_util.$(OBJEXT) +@MIDI_TRUE@am__objects_26 = profiles/midi/bluetoothd-midi.$(OBJEXT) \ +@MIDI_TRUE@ profiles/midi/bluetoothd-libmidi.$(OBJEXT) +@SIXAXIS_TRUE@am__objects_27 = plugins/bluetoothd-sixaxis.$(OBJEXT) +@BAP_TRUE@am__objects_28 = profiles/audio/bluetoothd-bap.$(OBJEXT) +@BASS_TRUE@am__objects_29 = profiles/audio/bluetoothd-bass.$(OBJEXT) +@MCP_TRUE@am__objects_30 = profiles/audio/bluetoothd-mcp.$(OBJEXT) +@VCP_TRUE@am__objects_31 = profiles/audio/bluetoothd-vcp.$(OBJEXT) +@MICP_TRUE@am__objects_32 = profiles/audio/bluetoothd-micp.$(OBJEXT) +@CCP_TRUE@am__objects_33 = profiles/audio/bluetoothd-ccp.$(OBJEXT) +@CSIP_TRUE@am__objects_34 = profiles/audio/bluetoothd-csip.$(OBJEXT) +@ASHA_TRUE@am__objects_35 = profiles/audio/bluetoothd-asha.$(OBJEXT) +am__objects_36 = plugins/bluetoothd-hostname.$(OBJEXT) \ + plugins/bluetoothd-wiimote.$(OBJEXT) \ + plugins/bluetoothd-autopair.$(OBJEXT) \ + plugins/bluetoothd-policy.$(OBJEXT) $(am__objects_17) \ + $(am__objects_18) $(am__objects_19) $(am__objects_20) \ + $(am__objects_21) $(am__objects_22) $(am__objects_23) \ + $(am__objects_24) $(am__objects_25) \ + profiles/gap/bluetoothd-gas.$(OBJEXT) \ + profiles/scanparam/bluetoothd-scan.$(OBJEXT) \ + profiles/deviceinfo/bluetoothd-deviceinfo.$(OBJEXT) \ + $(am__objects_26) \ + profiles/battery/bluetoothd-battery.$(OBJEXT) \ + $(am__objects_27) $(am__objects_28) $(am__objects_29) \ + $(am__objects_30) $(am__objects_31) $(am__objects_32) \ + $(am__objects_33) $(am__objects_34) $(am__objects_35) +am__objects_37 = attrib/bluetoothd-att.$(OBJEXT) \ + attrib/bluetoothd-gatt.$(OBJEXT) \ + attrib/bluetoothd-gattrib.$(OBJEXT) +am__objects_38 = btio/bluetoothd-btio.$(OBJEXT) +am_src_bluetoothd_OBJECTS = $(am__objects_36) $(am__objects_37) \ + $(am__objects_38) src/bluetoothd-main.$(OBJEXT) \ + src/bluetoothd-log.$(OBJEXT) \ + src/bluetoothd-backtrace.$(OBJEXT) \ + src/bluetoothd-rfkill.$(OBJEXT) \ + src/bluetoothd-sdpd-server.$(OBJEXT) \ + src/bluetoothd-sdpd-request.$(OBJEXT) \ + src/bluetoothd-sdpd-service.$(OBJEXT) \ + src/bluetoothd-sdpd-database.$(OBJEXT) \ + src/bluetoothd-gatt-database.$(OBJEXT) \ + src/bluetoothd-sdp-xml.$(OBJEXT) \ + src/bluetoothd-sdp-client.$(OBJEXT) \ + src/bluetoothd-textfile.$(OBJEXT) \ + src/bluetoothd-uuid-helper.$(OBJEXT) \ + src/bluetoothd-plugin.$(OBJEXT) \ + src/bluetoothd-storage.$(OBJEXT) \ + src/bluetoothd-advertising.$(OBJEXT) \ + src/bluetoothd-agent.$(OBJEXT) src/bluetoothd-error.$(OBJEXT) \ + src/bluetoothd-adapter.$(OBJEXT) \ + src/bluetoothd-profile.$(OBJEXT) \ + src/bluetoothd-service.$(OBJEXT) \ + src/bluetoothd-gatt-client.$(OBJEXT) \ + src/bluetoothd-device.$(OBJEXT) \ + src/bluetoothd-dbus-common.$(OBJEXT) \ + src/bluetoothd-eir.$(OBJEXT) \ + src/bluetoothd-adv_monitor.$(OBJEXT) \ + src/bluetoothd-battery.$(OBJEXT) \ + src/bluetoothd-settings.$(OBJEXT) src/bluetoothd-set.$(OBJEXT) \ + $(am__objects_1) +nodist_src_bluetoothd_OBJECTS = $(am__objects_1) +src_bluetoothd_OBJECTS = $(am_src_bluetoothd_OBJECTS) \ + $(nodist_src_bluetoothd_OBJECTS) +@MIDI_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) +@SIXAXIS_TRUE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1) +am__DEPENDENCIES_5 = $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_4) +src_bluetoothd_DEPENDENCIES = lib/libbluetooth-internal.la \ + gdbus/libgdbus-internal.la src/libshared-glib.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_5) +src_bluetoothd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(src_bluetoothd_LDFLAGS) $(LDFLAGS) -o \ + $@ +am__tools_3dsp_SOURCES_DIST = tools/3dsp.c monitor/bt.h +@TESTING_TRUE@am_tools_3dsp_OBJECTS = tools/3dsp.$(OBJEXT) +tools_3dsp_OBJECTS = $(am_tools_3dsp_OBJECTS) +@TESTING_TRUE@tools_3dsp_DEPENDENCIES = src/libshared-mainloop.la +am__tools_advtest_SOURCES_DIST = tools/advtest.c +@TOOLS_TRUE@am_tools_advtest_OBJECTS = tools/advtest.$(OBJEXT) +tools_advtest_OBJECTS = $(am_tools_advtest_OBJECTS) +@TOOLS_TRUE@tools_advtest_DEPENDENCIES = lib/libbluetooth-internal.la \ +@TOOLS_TRUE@ src/libshared-mainloop.la +tools_amptest_SOURCES = tools/amptest.c +tools_amptest_OBJECTS = tools/amptest.$(OBJEXT) +@TOOLS_TRUE@tools_amptest_DEPENDENCIES = lib/libbluetooth-internal.la +tools_avinfo_SOURCES = tools/avinfo.c +tools_avinfo_OBJECTS = tools/avinfo.$(OBJEXT) +@TOOLS_TRUE@tools_avinfo_DEPENDENCIES = lib/libbluetooth-internal.la +tools_avtest_SOURCES = tools/avtest.c +tools_avtest_OBJECTS = tools/avtest.$(OBJEXT) +@TOOLS_TRUE@tools_avtest_DEPENDENCIES = lib/libbluetooth-internal.la +tools_bcmfw_SOURCES = tools/bcmfw.c +tools_bcmfw_OBJECTS = tools/bcmfw.$(OBJEXT) +tools_bcmfw_LDADD = $(LDADD) +am__tools_bdaddr_SOURCES_DIST = tools/bdaddr.c src/oui.h src/oui.c +@TOOLS_TRUE@am_tools_bdaddr_OBJECTS = tools/bdaddr.$(OBJEXT) \ +@TOOLS_TRUE@ src/oui.$(OBJEXT) +tools_bdaddr_OBJECTS = $(am_tools_bdaddr_OBJECTS) +@TOOLS_TRUE@tools_bdaddr_DEPENDENCIES = lib/libbluetooth-internal.la \ +@TOOLS_TRUE@ $(am__DEPENDENCIES_1) +am__tools_bluemoon_SOURCES_DIST = tools/bluemoon.c monitor/bt.h +@TOOLS_TRUE@am_tools_bluemoon_OBJECTS = tools/bluemoon.$(OBJEXT) +tools_bluemoon_OBJECTS = $(am_tools_bluemoon_OBJECTS) +@TOOLS_TRUE@tools_bluemoon_DEPENDENCIES = src/libshared-mainloop.la +am__tools_bluetooth_player_SOURCES_DIST = tools/bluetooth-player.c \ + client/print.c client/player.c +@READLINE_TRUE@am_tools_bluetooth_player_OBJECTS = \ +@READLINE_TRUE@ tools/bluetooth-player.$(OBJEXT) \ +@READLINE_TRUE@ client/print.$(OBJEXT) client/player.$(OBJEXT) +tools_bluetooth_player_OBJECTS = $(am_tools_bluetooth_player_OBJECTS) +@READLINE_TRUE@tools_bluetooth_player_DEPENDENCIES = \ +@READLINE_TRUE@ gdbus/libgdbus-internal.la \ +@READLINE_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) \ +@READLINE_TRUE@ $(am__DEPENDENCIES_1) +am__tools_bnep_tester_SOURCES_DIST = tools/bnep-tester.c monitor/bt.h \ + emulator/hciemu.h emulator/hciemu.c emulator/vhci.h \ + emulator/vhci.c emulator/btdev.h emulator/btdev.c \ + emulator/bthost.h emulator/bthost.c emulator/smp.c +@TESTING_TRUE@am_tools_bnep_tester_OBJECTS = \ +@TESTING_TRUE@ tools/bnep-tester.$(OBJEXT) \ +@TESTING_TRUE@ emulator/hciemu.$(OBJEXT) \ +@TESTING_TRUE@ emulator/vhci.$(OBJEXT) emulator/btdev.$(OBJEXT) \ +@TESTING_TRUE@ emulator/bthost.$(OBJEXT) emulator/smp.$(OBJEXT) +tools_bnep_tester_OBJECTS = $(am_tools_bnep_tester_OBJECTS) +@TESTING_TRUE@tools_bnep_tester_DEPENDENCIES = \ +@TESTING_TRUE@ lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +am__tools_bneptest_SOURCES_DIST = tools/bneptest.c btio/btio.h \ + btio/btio.c src/log.h src/log.c profiles/network/bnep.h \ + profiles/network/bnep.c +@TOOLS_TRUE@am_tools_bneptest_OBJECTS = tools/bneptest.$(OBJEXT) \ +@TOOLS_TRUE@ btio/btio.$(OBJEXT) src/log.$(OBJEXT) \ +@TOOLS_TRUE@ profiles/network/bnep.$(OBJEXT) +tools_bneptest_OBJECTS = $(am_tools_bneptest_OBJECTS) +@TOOLS_TRUE@tools_bneptest_DEPENDENCIES = \ +@TOOLS_TRUE@ lib/libbluetooth-internal.la $(am__DEPENDENCIES_1) \ +@TOOLS_TRUE@ src/libshared-mainloop.la +am__tools_btattach_SOURCES_DIST = tools/btattach.c monitor/bt.h +@TOOLS_TRUE@am_tools_btattach_OBJECTS = tools/btattach.$(OBJEXT) +tools_btattach_OBJECTS = $(am_tools_btattach_OBJECTS) +@TOOLS_TRUE@tools_btattach_DEPENDENCIES = src/libshared-mainloop.la +am__tools_btconfig_SOURCES_DIST = tools/btconfig.c +@TOOLS_TRUE@am_tools_btconfig_OBJECTS = tools/btconfig.$(OBJEXT) +tools_btconfig_OBJECTS = $(am_tools_btconfig_OBJECTS) +@TOOLS_TRUE@tools_btconfig_DEPENDENCIES = src/libshared-mainloop.la +am__tools_btgatt_client_SOURCES_DIST = tools/btgatt-client.c \ + src/uuid-helper.c +@TOOLS_TRUE@am_tools_btgatt_client_OBJECTS = \ +@TOOLS_TRUE@ tools/btgatt-client.$(OBJEXT) \ +@TOOLS_TRUE@ src/uuid-helper.$(OBJEXT) +tools_btgatt_client_OBJECTS = $(am_tools_btgatt_client_OBJECTS) +@TOOLS_TRUE@tools_btgatt_client_DEPENDENCIES = \ +@TOOLS_TRUE@ src/libshared-mainloop.la \ +@TOOLS_TRUE@ lib/libbluetooth-internal.la +am__tools_btgatt_server_SOURCES_DIST = tools/btgatt-server.c \ + src/uuid-helper.c +@TOOLS_TRUE@am_tools_btgatt_server_OBJECTS = \ +@TOOLS_TRUE@ tools/btgatt-server.$(OBJEXT) \ +@TOOLS_TRUE@ src/uuid-helper.$(OBJEXT) +tools_btgatt_server_OBJECTS = $(am_tools_btgatt_server_OBJECTS) +@TOOLS_TRUE@tools_btgatt_server_DEPENDENCIES = \ +@TOOLS_TRUE@ src/libshared-mainloop.la \ +@TOOLS_TRUE@ lib/libbluetooth-internal.la +am__tools_btinfo_SOURCES_DIST = tools/btinfo.c monitor/bt.h +@TOOLS_TRUE@am_tools_btinfo_OBJECTS = tools/btinfo.$(OBJEXT) +tools_btinfo_OBJECTS = $(am_tools_btinfo_OBJECTS) +@TOOLS_TRUE@tools_btinfo_DEPENDENCIES = src/libshared-mainloop.la +am__tools_btiotest_SOURCES_DIST = tools/btiotest.c btio/btio.h \ + btio/btio.c +@TOOLS_TRUE@am_tools_btiotest_OBJECTS = tools/btiotest.$(OBJEXT) \ +@TOOLS_TRUE@ btio/btio.$(OBJEXT) +tools_btiotest_OBJECTS = $(am_tools_btiotest_OBJECTS) +@TOOLS_TRUE@tools_btiotest_DEPENDENCIES = \ +@TOOLS_TRUE@ lib/libbluetooth-internal.la $(am__DEPENDENCIES_1) +am__tools_btmgmt_SOURCES_DIST = tools/btmgmt.c src/uuid-helper.c \ + client/display.c client/mgmt.c +@READLINE_TRUE@am_tools_btmgmt_OBJECTS = tools/btmgmt.$(OBJEXT) \ +@READLINE_TRUE@ src/uuid-helper.$(OBJEXT) \ +@READLINE_TRUE@ client/display.$(OBJEXT) client/mgmt.$(OBJEXT) +tools_btmgmt_OBJECTS = $(am_tools_btmgmt_OBJECTS) +@READLINE_TRUE@tools_btmgmt_DEPENDENCIES = \ +@READLINE_TRUE@ lib/libbluetooth-internal.la \ +@READLINE_TRUE@ src/libshared-mainloop.la +am__tools_btmon_logger_SOURCES_DIST = tools/btmon-logger.c +@LOGGER_TRUE@am_tools_btmon_logger_OBJECTS = \ +@LOGGER_TRUE@ tools/btmon-logger.$(OBJEXT) +tools_btmon_logger_OBJECTS = $(am_tools_btmon_logger_OBJECTS) +@LOGGER_TRUE@tools_btmon_logger_DEPENDENCIES = \ +@LOGGER_TRUE@ src/libshared-mainloop.la +am__tools_btpclient_SOURCES_DIST = tools/btpclient.c src/shared/btp.c \ + src/shared/btp.h +@BTPCLIENT_TRUE@am_tools_btpclient_OBJECTS = \ +@BTPCLIENT_TRUE@ tools/btpclient.$(OBJEXT) \ +@BTPCLIENT_TRUE@ src/shared/btp.$(OBJEXT) +tools_btpclient_OBJECTS = $(am_tools_btpclient_OBJECTS) +@BTPCLIENT_TRUE@tools_btpclient_DEPENDENCIES = \ +@BTPCLIENT_TRUE@ lib/libbluetooth-internal.la \ +@BTPCLIENT_TRUE@ src/libshared-ell.la $(am__DEPENDENCIES_2) +am__tools_btpclientctl_SOURCES_DIST = tools/btpclientctl.c \ + client/display.c +@BTPCLIENT_TRUE@am_tools_btpclientctl_OBJECTS = \ +@BTPCLIENT_TRUE@ tools/btpclientctl.$(OBJEXT) \ +@BTPCLIENT_TRUE@ client/display.$(OBJEXT) +tools_btpclientctl_OBJECTS = $(am_tools_btpclientctl_OBJECTS) +@BTPCLIENT_TRUE@tools_btpclientctl_DEPENDENCIES = \ +@BTPCLIENT_TRUE@ src/libshared-mainloop.la \ +@BTPCLIENT_TRUE@ src/libshared-glib.la \ +@BTPCLIENT_TRUE@ lib/libbluetooth-internal.la +am__tools_btproxy_SOURCES_DIST = tools/btproxy.c monitor/bt.h +@TOOLS_TRUE@am_tools_btproxy_OBJECTS = tools/btproxy.$(OBJEXT) +tools_btproxy_OBJECTS = $(am_tools_btproxy_OBJECTS) +@TOOLS_TRUE@tools_btproxy_DEPENDENCIES = src/libshared-mainloop.la +am__tools_btsnoop_SOURCES_DIST = tools/btsnoop.c +@TOOLS_TRUE@am_tools_btsnoop_OBJECTS = tools/btsnoop.$(OBJEXT) +tools_btsnoop_OBJECTS = $(am_tools_btsnoop_OBJECTS) +@TOOLS_TRUE@tools_btsnoop_DEPENDENCIES = src/libshared-mainloop.la +tools_check_selftest_SOURCES = tools/check-selftest.c +tools_check_selftest_OBJECTS = tools/check-selftest.$(OBJEXT) +tools_check_selftest_LDADD = $(LDADD) +tools_ciptool_SOURCES = tools/ciptool.c +tools_ciptool_OBJECTS = tools/ciptool.$(OBJEXT) +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_ciptool_DEPENDENCIES = \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ lib/libbluetooth-internal.la +am__tools_cltest_SOURCES_DIST = tools/cltest.c +@TOOLS_TRUE@am_tools_cltest_OBJECTS = tools/cltest.$(OBJEXT) +tools_cltest_OBJECTS = $(am_tools_cltest_OBJECTS) +@TOOLS_TRUE@tools_cltest_DEPENDENCIES = lib/libbluetooth-internal.la \ +@TOOLS_TRUE@ src/libshared-mainloop.la +am__tools_create_image_SOURCES_DIST = tools/create-image.c +@TOOLS_TRUE@am_tools_create_image_OBJECTS = \ +@TOOLS_TRUE@ tools/create-image.$(OBJEXT) +tools_create_image_OBJECTS = $(am_tools_create_image_OBJECTS) +tools_create_image_LDADD = $(LDADD) +am__tools_eddystone_SOURCES_DIST = tools/eddystone.c monitor/bt.h +@TOOLS_TRUE@am_tools_eddystone_OBJECTS = tools/eddystone.$(OBJEXT) +tools_eddystone_OBJECTS = $(am_tools_eddystone_OBJECTS) +@TOOLS_TRUE@tools_eddystone_DEPENDENCIES = src/libshared-mainloop.la +am__tools_gap_tester_SOURCES_DIST = tools/gap-tester.c monitor/bt.h \ + emulator/hciemu.h emulator/hciemu.c emulator/vhci.h \ + emulator/vhci.c emulator/btdev.h emulator/btdev.c \ + emulator/bthost.h emulator/bthost.c emulator/smp.c +@TESTING_TRUE@am_tools_gap_tester_OBJECTS = \ +@TESTING_TRUE@ tools/gap-tester.$(OBJEXT) \ +@TESTING_TRUE@ emulator/hciemu.$(OBJEXT) \ +@TESTING_TRUE@ emulator/vhci.$(OBJEXT) emulator/btdev.$(OBJEXT) \ +@TESTING_TRUE@ emulator/bthost.$(OBJEXT) emulator/smp.$(OBJEXT) +tools_gap_tester_OBJECTS = $(am_tools_gap_tester_OBJECTS) +@TESTING_TRUE@tools_gap_tester_DEPENDENCIES = \ +@TESTING_TRUE@ lib/libbluetooth-internal.la \ +@TESTING_TRUE@ gdbus/libgdbus-internal.la src/libshared-glib.la \ +@TESTING_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am__tools_gatt_service_SOURCES_DIST = tools/gatt-service.c +@TOOLS_TRUE@am_tools_gatt_service_OBJECTS = \ +@TOOLS_TRUE@ tools/gatt-service.$(OBJEXT) +tools_gatt_service_OBJECTS = $(am_tools_gatt_service_OBJECTS) +@TOOLS_TRUE@tools_gatt_service_DEPENDENCIES = \ +@TOOLS_TRUE@ gdbus/libgdbus-internal.la \ +@TOOLS_TRUE@ src/libshared-mainloop.la $(am__DEPENDENCIES_1) \ +@TOOLS_TRUE@ $(am__DEPENDENCIES_1) +am__tools_hci_tester_SOURCES_DIST = tools/hci-tester.c monitor/bt.h +@TESTING_TRUE@am_tools_hci_tester_OBJECTS = \ +@TESTING_TRUE@ tools/hci-tester.$(OBJEXT) +tools_hci_tester_OBJECTS = $(am_tools_hci_tester_OBJECTS) +@TESTING_TRUE@tools_hci_tester_DEPENDENCIES = src/libshared-glib.la \ +@TESTING_TRUE@ $(am__DEPENDENCIES_1) +am__tools_hciattach_SOURCES_DIST = tools/hciattach.c tools/hciattach.h \ + tools/hciattach_st.c tools/hciattach_ti.c \ + tools/hciattach_tialt.c tools/hciattach_ath3k.c \ + tools/hciattach_qualcomm.c tools/hciattach_intel.c \ + tools/hciattach_bcm43xx.c +@DEPRECATED_TRUE@@TOOLS_TRUE@am_tools_hciattach_OBJECTS = \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hciattach.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hciattach_st.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hciattach_ti.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hciattach_tialt.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hciattach_ath3k.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hciattach_qualcomm.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hciattach_intel.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hciattach_bcm43xx.$(OBJEXT) +tools_hciattach_OBJECTS = $(am_tools_hciattach_OBJECTS) +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_hciattach_DEPENDENCIES = \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ lib/libbluetooth-internal.la +am__tools_hciconfig_SOURCES_DIST = tools/hciconfig.c +@DEPRECATED_TRUE@@TOOLS_TRUE@am_tools_hciconfig_OBJECTS = \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hciconfig.$(OBJEXT) +tools_hciconfig_OBJECTS = $(am_tools_hciconfig_OBJECTS) +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_hciconfig_DEPENDENCIES = \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ lib/libbluetooth-internal.la +am__tools_hcidump_SOURCES_DIST = tools/hcidump.c tools/parser/parser.h \ + tools/parser/parser.c tools/parser/lmp.c tools/parser/hci.c \ + tools/parser/l2cap.h tools/parser/l2cap.c tools/parser/amp.c \ + tools/parser/smp.c tools/parser/att.c tools/parser/sdp.h \ + tools/parser/sdp.c tools/parser/rfcomm.h tools/parser/rfcomm.c \ + tools/parser/bnep.c tools/parser/cmtp.c tools/parser/hidp.c \ + tools/parser/hcrp.c tools/parser/avdtp.c tools/parser/avctp.c \ + tools/parser/avrcp.c tools/parser/sap.c tools/parser/obex.c \ + tools/parser/capi.c tools/parser/ppp.c tools/parser/tcpip.c \ + tools/parser/ericsson.c tools/parser/csr.c tools/parser/bpa.c +@DEPRECATED_TRUE@@TOOLS_TRUE@am_tools_hcidump_OBJECTS = \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hcidump.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/parser.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/lmp.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/hci.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/l2cap.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/amp.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/smp.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/att.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/sdp.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/rfcomm.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/bnep.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/cmtp.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/hidp.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/hcrp.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/avdtp.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/avctp.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/avrcp.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/sap.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/obex.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/capi.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/ppp.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/tcpip.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/ericsson.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/csr.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/bpa.$(OBJEXT) +tools_hcidump_OBJECTS = $(am_tools_hcidump_OBJECTS) +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_hcidump_DEPENDENCIES = \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ lib/libbluetooth-internal.la +tools_hcieventmask_SOURCES = tools/hcieventmask.c +tools_hcieventmask_OBJECTS = tools/hcieventmask.$(OBJEXT) +@TOOLS_TRUE@tools_hcieventmask_DEPENDENCIES = \ +@TOOLS_TRUE@ lib/libbluetooth-internal.la +tools_hcisecfilter_SOURCES = tools/hcisecfilter.c +tools_hcisecfilter_OBJECTS = tools/hcisecfilter.$(OBJEXT) +tools_hcisecfilter_LDADD = $(LDADD) +am__tools_hcitool_SOURCES_DIST = tools/hcitool.c src/oui.h src/oui.c +@DEPRECATED_TRUE@@TOOLS_TRUE@am_tools_hcitool_OBJECTS = \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hcitool.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ src/oui.$(OBJEXT) +tools_hcitool_OBJECTS = $(am_tools_hcitool_OBJECTS) +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_hcitool_DEPENDENCIES = \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ lib/libbluetooth-internal.la \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ $(am__DEPENDENCIES_1) +am__tools_hex2hcd_SOURCES_DIST = tools/hex2hcd.c tools/missing.h +@TOOLS_TRUE@am_tools_hex2hcd_OBJECTS = tools/hex2hcd.$(OBJEXT) +tools_hex2hcd_OBJECTS = $(am_tools_hex2hcd_OBJECTS) +tools_hex2hcd_LDADD = $(LDADD) +tools_hid2hci_SOURCES = tools/hid2hci.c +tools_hid2hci_OBJECTS = tools/hid2hci.$(OBJEXT) +@HID2HCI_TRUE@tools_hid2hci_DEPENDENCIES = $(am__DEPENDENCIES_1) +tools_hwdb_SOURCES = tools/hwdb.c +tools_hwdb_OBJECTS = tools/hwdb.$(OBJEXT) +@TOOLS_TRUE@tools_hwdb_DEPENDENCIES = lib/libbluetooth-internal.la +am__tools_ibeacon_SOURCES_DIST = tools/ibeacon.c monitor/bt.h +@TOOLS_TRUE@am_tools_ibeacon_OBJECTS = tools/ibeacon.$(OBJEXT) +tools_ibeacon_OBJECTS = $(am_tools_ibeacon_OBJECTS) +@TOOLS_TRUE@tools_ibeacon_DEPENDENCIES = src/libshared-mainloop.la +am__tools_ioctl_tester_SOURCES_DIST = tools/ioctl-tester.c \ + monitor/bt.h emulator/hciemu.h emulator/hciemu.c \ + emulator/vhci.h emulator/vhci.c emulator/btdev.h \ + emulator/btdev.c emulator/bthost.h emulator/bthost.c \ + emulator/smp.c +@TESTING_TRUE@am_tools_ioctl_tester_OBJECTS = \ +@TESTING_TRUE@ tools/ioctl-tester.$(OBJEXT) \ +@TESTING_TRUE@ emulator/hciemu.$(OBJEXT) \ +@TESTING_TRUE@ emulator/vhci.$(OBJEXT) emulator/btdev.$(OBJEXT) \ +@TESTING_TRUE@ emulator/bthost.$(OBJEXT) emulator/smp.$(OBJEXT) +tools_ioctl_tester_OBJECTS = $(am_tools_ioctl_tester_OBJECTS) +@TESTING_TRUE@tools_ioctl_tester_DEPENDENCIES = \ +@TESTING_TRUE@ lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +am__tools_iso_tester_SOURCES_DIST = tools/iso-tester.c tools/tester.h \ + monitor/bt.h emulator/hciemu.h emulator/hciemu.c \ + emulator/vhci.h emulator/vhci.c emulator/btdev.h \ + emulator/btdev.c emulator/bthost.h emulator/bthost.c \ + emulator/smp.c +@TESTING_TRUE@am_tools_iso_tester_OBJECTS = \ +@TESTING_TRUE@ tools/iso-tester.$(OBJEXT) \ +@TESTING_TRUE@ emulator/hciemu.$(OBJEXT) \ +@TESTING_TRUE@ emulator/vhci.$(OBJEXT) emulator/btdev.$(OBJEXT) \ +@TESTING_TRUE@ emulator/bthost.$(OBJEXT) emulator/smp.$(OBJEXT) +tools_iso_tester_OBJECTS = $(am_tools_iso_tester_OBJECTS) +@TESTING_TRUE@tools_iso_tester_DEPENDENCIES = \ +@TESTING_TRUE@ lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +tools_isotest_SOURCES = tools/isotest.c +tools_isotest_OBJECTS = tools/isotest.$(OBJEXT) +@TOOLS_TRUE@tools_isotest_DEPENDENCIES = lib/libbluetooth-internal.la +am__tools_l2cap_tester_SOURCES_DIST = tools/l2cap-tester.c \ + tools/tester.h monitor/bt.h emulator/hciemu.h \ + emulator/hciemu.c emulator/vhci.h emulator/vhci.c \ + emulator/btdev.h emulator/btdev.c emulator/bthost.h \ + emulator/bthost.c emulator/smp.c +@TESTING_TRUE@am_tools_l2cap_tester_OBJECTS = \ +@TESTING_TRUE@ tools/l2cap-tester.$(OBJEXT) \ +@TESTING_TRUE@ emulator/hciemu.$(OBJEXT) \ +@TESTING_TRUE@ emulator/vhci.$(OBJEXT) emulator/btdev.$(OBJEXT) \ +@TESTING_TRUE@ emulator/bthost.$(OBJEXT) emulator/smp.$(OBJEXT) +tools_l2cap_tester_OBJECTS = $(am_tools_l2cap_tester_OBJECTS) +@TESTING_TRUE@tools_l2cap_tester_DEPENDENCIES = \ +@TESTING_TRUE@ lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +tools_l2ping_SOURCES = tools/l2ping.c +tools_l2ping_OBJECTS = tools/l2ping.$(OBJEXT) +@TOOLS_TRUE@tools_l2ping_DEPENDENCIES = lib/libbluetooth-internal.la +tools_l2test_SOURCES = tools/l2test.c +tools_l2test_OBJECTS = tools/l2test.$(OBJEXT) +@TOOLS_TRUE@tools_l2test_DEPENDENCIES = lib/libbluetooth-internal.la +am__tools_mcaptest_SOURCES_DIST = tools/mcaptest.c btio/btio.h \ + btio/btio.c src/log.c src/log.h profiles/health/mcap.h \ + profiles/health/mcap.c +@TOOLS_TRUE@am_tools_mcaptest_OBJECTS = tools/mcaptest.$(OBJEXT) \ +@TOOLS_TRUE@ btio/btio.$(OBJEXT) src/log.$(OBJEXT) \ +@TOOLS_TRUE@ profiles/health/mcap.$(OBJEXT) +tools_mcaptest_OBJECTS = $(am_tools_mcaptest_OBJECTS) +@TOOLS_TRUE@tools_mcaptest_DEPENDENCIES = \ +@TOOLS_TRUE@ lib/libbluetooth-internal.la $(am__DEPENDENCIES_1) \ +@TOOLS_TRUE@ src/libshared-mainloop.la +am__tools_mesh_cfgclient_SOURCES_DIST = tools/mesh-cfgclient.c \ + tools/mesh/model.h tools/mesh/config-model.h \ + tools/mesh/cfgcli.h tools/mesh/cfgcli.c tools/mesh/keys.h \ + tools/mesh/keys.c tools/mesh/util.h tools/mesh/util.c \ + tools/mesh/remote.h tools/mesh/remote.c tools/mesh/agent.h \ + tools/mesh/agent.c tools/mesh/mesh-db.h tools/mesh/mesh-db.c \ + mesh/util.h mesh/util.c mesh/crypto.h mesh/crypto.c +@MESH_TRUE@@TOOLS_TRUE@am_tools_mesh_cfgclient_OBJECTS = \ +@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-cfgclient.$(OBJEXT) \ +@MESH_TRUE@@TOOLS_TRUE@ tools/mesh/cfgcli.$(OBJEXT) \ +@MESH_TRUE@@TOOLS_TRUE@ tools/mesh/keys.$(OBJEXT) \ +@MESH_TRUE@@TOOLS_TRUE@ tools/mesh/util.$(OBJEXT) \ +@MESH_TRUE@@TOOLS_TRUE@ tools/mesh/remote.$(OBJEXT) \ +@MESH_TRUE@@TOOLS_TRUE@ tools/mesh/agent.$(OBJEXT) \ +@MESH_TRUE@@TOOLS_TRUE@ tools/mesh/mesh-db.$(OBJEXT) \ +@MESH_TRUE@@TOOLS_TRUE@ mesh/util.$(OBJEXT) \ +@MESH_TRUE@@TOOLS_TRUE@ mesh/crypto.$(OBJEXT) +tools_mesh_cfgclient_OBJECTS = $(am_tools_mesh_cfgclient_OBJECTS) +@MESH_TRUE@@TOOLS_TRUE@tools_mesh_cfgclient_DEPENDENCIES = \ +@MESH_TRUE@@TOOLS_TRUE@ lib/libbluetooth-internal.la \ +@MESH_TRUE@@TOOLS_TRUE@ src/libshared-ell.la \ +@MESH_TRUE@@TOOLS_TRUE@ $(am__DEPENDENCIES_2) +am__tools_mesh_cfgtest_SOURCES_DIST = tools/mesh-cfgtest.c +@MESH_TRUE@@TOOLS_TRUE@am_tools_mesh_cfgtest_OBJECTS = \ +@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-cfgtest.$(OBJEXT) +tools_mesh_cfgtest_OBJECTS = $(am_tools_mesh_cfgtest_OBJECTS) +@MESH_TRUE@@TOOLS_TRUE@tools_mesh_cfgtest_DEPENDENCIES = \ +@MESH_TRUE@@TOOLS_TRUE@ lib/libbluetooth-internal.la \ +@MESH_TRUE@@TOOLS_TRUE@ src/libshared-ell.la \ +@MESH_TRUE@@TOOLS_TRUE@ $(am__DEPENDENCIES_2) +am__tools_mesh_tester_SOURCES_DIST = tools/mesh-tester.c monitor/bt.h \ + emulator/hciemu.h emulator/hciemu.c emulator/vhci.h \ + emulator/vhci.c emulator/btdev.h emulator/btdev.c \ + emulator/bthost.h emulator/bthost.c emulator/smp.c +@TESTING_TRUE@am_tools_mesh_tester_OBJECTS = \ +@TESTING_TRUE@ tools/mesh-tester.$(OBJEXT) \ +@TESTING_TRUE@ emulator/hciemu.$(OBJEXT) \ +@TESTING_TRUE@ emulator/vhci.$(OBJEXT) emulator/btdev.$(OBJEXT) \ +@TESTING_TRUE@ emulator/bthost.$(OBJEXT) emulator/smp.$(OBJEXT) +tools_mesh_tester_OBJECTS = $(am_tools_mesh_tester_OBJECTS) +@TESTING_TRUE@tools_mesh_tester_DEPENDENCIES = \ +@TESTING_TRUE@ lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +am__tools_meshctl_SOURCES_DIST = tools/meshctl.c tools/mesh/agent.h \ + tools/mesh/agent.c tools/mesh/config-model.h \ + tools/mesh-gatt/mesh-net.h tools/mesh-gatt/node.h \ + tools/mesh-gatt/node.c tools/mesh-gatt/gatt.h \ + tools/mesh-gatt/gatt.c tools/mesh-gatt/crypto.h \ + tools/mesh-gatt/crypto.c tools/mesh-gatt/keys.h \ + tools/mesh-gatt/net.h tools/mesh-gatt/net.c \ + tools/mesh-gatt/prov.h tools/mesh-gatt/prov.c \ + tools/mesh-gatt/util.h tools/mesh-gatt/util.c \ + tools/mesh-gatt/prov-db.h tools/mesh-gatt/prov-db.c \ + tools/mesh-gatt/config-client.c \ + tools/mesh-gatt/config-server.c tools/mesh-gatt/onoff-model.h \ + tools/mesh-gatt/onoff-model.c +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@am_tools_meshctl_OBJECTS = tools/meshctl.$(OBJEXT) \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh/agent.$(OBJEXT) \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/node.$(OBJEXT) \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/gatt.$(OBJEXT) \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/crypto.$(OBJEXT) \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/net.$(OBJEXT) \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/prov.$(OBJEXT) \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/util.$(OBJEXT) \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/prov-db.$(OBJEXT) \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/config-client.$(OBJEXT) \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/config-server.$(OBJEXT) \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/onoff-model.$(OBJEXT) +tools_meshctl_OBJECTS = $(am_tools_meshctl_OBJECTS) +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@tools_meshctl_DEPENDENCIES = gdbus/libgdbus-internal.la \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ src/libshared-glib.la \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ lib/libbluetooth-internal.la \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ $(am__DEPENDENCIES_1) \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ $(am__DEPENDENCIES_1) +am__tools_mgmt_tester_SOURCES_DIST = tools/mgmt-tester.c monitor/bt.h \ + emulator/hciemu.h emulator/hciemu.c emulator/vhci.h \ + emulator/vhci.c emulator/btdev.h emulator/btdev.c \ + emulator/bthost.h emulator/bthost.c emulator/smp.c +@TESTING_TRUE@am_tools_mgmt_tester_OBJECTS = \ +@TESTING_TRUE@ tools/mgmt-tester.$(OBJEXT) \ +@TESTING_TRUE@ emulator/hciemu.$(OBJEXT) \ +@TESTING_TRUE@ emulator/vhci.$(OBJEXT) emulator/btdev.$(OBJEXT) \ +@TESTING_TRUE@ emulator/bthost.$(OBJEXT) emulator/smp.$(OBJEXT) +tools_mgmt_tester_OBJECTS = $(am_tools_mgmt_tester_OBJECTS) +@TESTING_TRUE@tools_mgmt_tester_DEPENDENCIES = \ +@TESTING_TRUE@ lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +am__tools_mpris_proxy_SOURCES_DIST = tools/mpris-proxy.c +@TOOLS_TRUE@am_tools_mpris_proxy_OBJECTS = \ +@TOOLS_TRUE@ tools/mpris-proxy.$(OBJEXT) +tools_mpris_proxy_OBJECTS = $(am_tools_mpris_proxy_OBJECTS) +@TOOLS_TRUE@tools_mpris_proxy_DEPENDENCIES = \ +@TOOLS_TRUE@ gdbus/libgdbus-internal.la $(am__DEPENDENCIES_1) \ +@TOOLS_TRUE@ $(am__DEPENDENCIES_1) +am__tools_nokfw_SOURCES_DIST = tools/nokfw.c +@TOOLS_TRUE@am_tools_nokfw_OBJECTS = tools/nokfw.$(OBJEXT) +tools_nokfw_OBJECTS = $(am_tools_nokfw_OBJECTS) +tools_nokfw_LDADD = $(LDADD) +am__tools_obex_client_tool_SOURCES_DIST = gobex/gobex.h gobex/gobex.c \ + gobex/gobex-defs.h gobex/gobex-defs.c gobex/gobex-packet.c \ + gobex/gobex-packet.h gobex/gobex-header.c gobex/gobex-header.h \ + gobex/gobex-transfer.c gobex/gobex-debug.h \ + gobex/gobex-apparam.c gobex/gobex-apparam.h btio/btio.h \ + btio/btio.c tools/obex-client-tool.c +am__objects_39 = gobex/gobex.$(OBJEXT) gobex/gobex-defs.$(OBJEXT) \ + gobex/gobex-packet.$(OBJEXT) gobex/gobex-header.$(OBJEXT) \ + gobex/gobex-transfer.$(OBJEXT) gobex/gobex-apparam.$(OBJEXT) +am__objects_40 = btio/btio.$(OBJEXT) +@READLINE_TRUE@am_tools_obex_client_tool_OBJECTS = $(am__objects_39) \ +@READLINE_TRUE@ $(am__objects_40) \ +@READLINE_TRUE@ tools/obex-client-tool.$(OBJEXT) +tools_obex_client_tool_OBJECTS = $(am_tools_obex_client_tool_OBJECTS) +@READLINE_TRUE@tools_obex_client_tool_DEPENDENCIES = \ +@READLINE_TRUE@ lib/libbluetooth-internal.la \ +@READLINE_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +am__tools_obex_server_tool_SOURCES_DIST = gobex/gobex.h gobex/gobex.c \ + gobex/gobex-defs.h gobex/gobex-defs.c gobex/gobex-packet.c \ + gobex/gobex-packet.h gobex/gobex-header.c gobex/gobex-header.h \ + gobex/gobex-transfer.c gobex/gobex-debug.h \ + gobex/gobex-apparam.c gobex/gobex-apparam.h btio/btio.h \ + btio/btio.c tools/obex-server-tool.c +@READLINE_TRUE@am_tools_obex_server_tool_OBJECTS = $(am__objects_39) \ +@READLINE_TRUE@ $(am__objects_40) \ +@READLINE_TRUE@ tools/obex-server-tool.$(OBJEXT) +tools_obex_server_tool_OBJECTS = $(am_tools_obex_server_tool_OBJECTS) +@READLINE_TRUE@tools_obex_server_tool_DEPENDENCIES = \ +@READLINE_TRUE@ lib/libbluetooth-internal.la \ +@READLINE_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +am__tools_obexctl_SOURCES_DIST = tools/obexctl.c +@READLINE_TRUE@am_tools_obexctl_OBJECTS = tools/obexctl.$(OBJEXT) +tools_obexctl_OBJECTS = $(am_tools_obexctl_OBJECTS) +@READLINE_TRUE@tools_obexctl_DEPENDENCIES = \ +@READLINE_TRUE@ gdbus/libgdbus-internal.la \ +@READLINE_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) \ +@READLINE_TRUE@ $(am__DEPENDENCIES_1) +am__tools_oobtest_SOURCES_DIST = tools/oobtest.c +@TOOLS_TRUE@am_tools_oobtest_OBJECTS = tools/oobtest.$(OBJEXT) +tools_oobtest_OBJECTS = $(am_tools_oobtest_OBJECTS) +@TOOLS_TRUE@tools_oobtest_DEPENDENCIES = lib/libbluetooth-internal.la \ +@TOOLS_TRUE@ src/libshared-mainloop.la +tools_rctest_SOURCES = tools/rctest.c +tools_rctest_OBJECTS = tools/rctest.$(OBJEXT) +@TOOLS_TRUE@tools_rctest_DEPENDENCIES = lib/libbluetooth-internal.la +tools_rfcomm_SOURCES = tools/rfcomm.c +tools_rfcomm_OBJECTS = tools/rfcomm.$(OBJEXT) +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_rfcomm_DEPENDENCIES = \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ lib/libbluetooth-internal.la +am__tools_rfcomm_tester_SOURCES_DIST = tools/rfcomm-tester.c \ + monitor/bt.h emulator/hciemu.h emulator/hciemu.c \ + emulator/vhci.h emulator/vhci.c emulator/btdev.h \ + emulator/btdev.c emulator/bthost.h emulator/bthost.c \ + emulator/smp.c +@TESTING_TRUE@am_tools_rfcomm_tester_OBJECTS = \ +@TESTING_TRUE@ tools/rfcomm-tester.$(OBJEXT) \ +@TESTING_TRUE@ emulator/hciemu.$(OBJEXT) \ +@TESTING_TRUE@ emulator/vhci.$(OBJEXT) emulator/btdev.$(OBJEXT) \ +@TESTING_TRUE@ emulator/bthost.$(OBJEXT) emulator/smp.$(OBJEXT) +tools_rfcomm_tester_OBJECTS = $(am_tools_rfcomm_tester_OBJECTS) +@TESTING_TRUE@tools_rfcomm_tester_DEPENDENCIES = \ +@TESTING_TRUE@ lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +am__tools_rtlfw_SOURCES_DIST = tools/rtlfw.c +@TOOLS_TRUE@am_tools_rtlfw_OBJECTS = tools/rtlfw.$(OBJEXT) +tools_rtlfw_OBJECTS = $(am_tools_rtlfw_OBJECTS) +tools_rtlfw_LDADD = $(LDADD) +am__tools_sco_tester_SOURCES_DIST = tools/sco-tester.c tools/tester.h \ + monitor/bt.h emulator/hciemu.h emulator/hciemu.c \ + emulator/vhci.h emulator/vhci.c emulator/btdev.h \ + emulator/btdev.c emulator/bthost.h emulator/bthost.c \ + emulator/smp.c +@TESTING_TRUE@am_tools_sco_tester_OBJECTS = \ +@TESTING_TRUE@ tools/sco-tester.$(OBJEXT) \ +@TESTING_TRUE@ emulator/hciemu.$(OBJEXT) \ +@TESTING_TRUE@ emulator/vhci.$(OBJEXT) emulator/btdev.$(OBJEXT) \ +@TESTING_TRUE@ emulator/bthost.$(OBJEXT) emulator/smp.$(OBJEXT) +tools_sco_tester_OBJECTS = $(am_tools_sco_tester_OBJECTS) +@TESTING_TRUE@tools_sco_tester_DEPENDENCIES = \ +@TESTING_TRUE@ lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +tools_scotest_SOURCES = tools/scotest.c +tools_scotest_OBJECTS = tools/scotest.$(OBJEXT) +@TOOLS_TRUE@tools_scotest_DEPENDENCIES = lib/libbluetooth-internal.la +am__tools_sdptool_SOURCES_DIST = tools/sdptool.c src/sdp-xml.h \ + src/sdp-xml.c +@DEPRECATED_TRUE@@TOOLS_TRUE@am_tools_sdptool_OBJECTS = \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/sdptool.$(OBJEXT) \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ src/sdp-xml.$(OBJEXT) +tools_sdptool_OBJECTS = $(am_tools_sdptool_OBJECTS) +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_sdptool_DEPENDENCIES = \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ lib/libbluetooth-internal.la \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ $(am__DEPENDENCIES_1) +am__tools_seq2bseq_SOURCES_DIST = tools/seq2bseq.c +@TOOLS_TRUE@am_tools_seq2bseq_OBJECTS = tools/seq2bseq.$(OBJEXT) +tools_seq2bseq_OBJECTS = $(am_tools_seq2bseq_OBJECTS) +tools_seq2bseq_LDADD = $(LDADD) +am__tools_smp_tester_SOURCES_DIST = tools/smp-tester.c monitor/bt.h \ + emulator/hciemu.h emulator/hciemu.c emulator/vhci.h \ + emulator/vhci.c emulator/btdev.h emulator/btdev.c \ + emulator/bthost.h emulator/bthost.c emulator/smp.c +@TESTING_TRUE@am_tools_smp_tester_OBJECTS = \ +@TESTING_TRUE@ tools/smp-tester.$(OBJEXT) \ +@TESTING_TRUE@ emulator/hciemu.$(OBJEXT) \ +@TESTING_TRUE@ emulator/vhci.$(OBJEXT) emulator/btdev.$(OBJEXT) \ +@TESTING_TRUE@ emulator/bthost.$(OBJEXT) emulator/smp.$(OBJEXT) +tools_smp_tester_OBJECTS = $(am_tools_smp_tester_OBJECTS) +@TESTING_TRUE@tools_smp_tester_DEPENDENCIES = \ +@TESTING_TRUE@ lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +tools_test_runner_SOURCES = tools/test-runner.c +tools_test_runner_OBJECTS = tools/test-runner.$(OBJEXT) +tools_test_runner_LDADD = $(LDADD) +am__tools_userchan_tester_SOURCES_DIST = tools/userchan-tester.c \ + monitor/bt.h emulator/hciemu.h emulator/hciemu.c \ + emulator/vhci.h emulator/vhci.c emulator/btdev.h \ + emulator/btdev.c emulator/bthost.h emulator/bthost.c \ + emulator/smp.c +@TESTING_TRUE@am_tools_userchan_tester_OBJECTS = \ +@TESTING_TRUE@ tools/userchan-tester.$(OBJEXT) \ +@TESTING_TRUE@ emulator/hciemu.$(OBJEXT) \ +@TESTING_TRUE@ emulator/vhci.$(OBJEXT) emulator/btdev.$(OBJEXT) \ +@TESTING_TRUE@ emulator/bthost.$(OBJEXT) emulator/smp.$(OBJEXT) +tools_userchan_tester_OBJECTS = $(am_tools_userchan_tester_OBJECTS) +@TESTING_TRUE@tools_userchan_tester_DEPENDENCIES = \ +@TESTING_TRUE@ lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +am_unit_test_avctp_OBJECTS = unit/test-avctp.$(OBJEXT) \ + src/log.$(OBJEXT) android/avctp.$(OBJEXT) +unit_test_avctp_OBJECTS = $(am_unit_test_avctp_OBJECTS) +unit_test_avctp_DEPENDENCIES = src/libshared-glib.la \ + $(am__DEPENDENCIES_1) +am_unit_test_avdtp_OBJECTS = unit/test-avdtp.$(OBJEXT) \ + src/log.$(OBJEXT) android/avdtp.$(OBJEXT) +unit_test_avdtp_OBJECTS = $(am_unit_test_avdtp_OBJECTS) +unit_test_avdtp_DEPENDENCIES = src/libshared-glib.la \ + $(am__DEPENDENCIES_1) +am_unit_test_avrcp_OBJECTS = unit/test-avrcp.$(OBJEXT) \ + src/log.$(OBJEXT) android/avctp.$(OBJEXT) \ + android/avrcp-lib.$(OBJEXT) +unit_test_avrcp_OBJECTS = $(am_unit_test_avrcp_OBJECTS) +unit_test_avrcp_DEPENDENCIES = lib/libbluetooth-internal.la \ + src/libshared-glib.la $(am__DEPENDENCIES_1) +am_unit_test_bap_OBJECTS = unit/test-bap.$(OBJEXT) +unit_test_bap_OBJECTS = $(am_unit_test_bap_OBJECTS) +unit_test_bap_DEPENDENCIES = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(am__DEPENDENCIES_1) +am_unit_test_bass_OBJECTS = unit/test-bass.$(OBJEXT) $(am__objects_40) +unit_test_bass_OBJECTS = $(am_unit_test_bass_OBJECTS) +unit_test_bass_DEPENDENCIES = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(am__DEPENDENCIES_1) +am_unit_test_crc_OBJECTS = unit/test-crc.$(OBJEXT) \ + monitor/crc.$(OBJEXT) +unit_test_crc_OBJECTS = $(am_unit_test_crc_OBJECTS) +unit_test_crc_DEPENDENCIES = src/libshared-glib.la \ + $(am__DEPENDENCIES_1) +am_unit_test_crypto_OBJECTS = unit/test-crypto.$(OBJEXT) +unit_test_crypto_OBJECTS = $(am_unit_test_crypto_OBJECTS) +unit_test_crypto_DEPENDENCIES = src/libshared-glib.la \ + $(am__DEPENDENCIES_1) +am_unit_test_ecc_OBJECTS = unit/test-ecc.$(OBJEXT) +unit_test_ecc_OBJECTS = $(am_unit_test_ecc_OBJECTS) +unit_test_ecc_DEPENDENCIES = src/libshared-glib.la \ + $(am__DEPENDENCIES_1) +am_unit_test_eir_OBJECTS = unit/test-eir.$(OBJEXT) src/eir.$(OBJEXT) \ + src/uuid-helper.$(OBJEXT) +unit_test_eir_OBJECTS = $(am_unit_test_eir_OBJECTS) +unit_test_eir_DEPENDENCIES = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(am__DEPENDENCIES_1) +am_unit_test_gatt_OBJECTS = unit/test-gatt.$(OBJEXT) +unit_test_gatt_OBJECTS = $(am_unit_test_gatt_OBJECTS) +unit_test_gatt_DEPENDENCIES = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(am__DEPENDENCIES_1) +am_unit_test_gattrib_OBJECTS = unit/test-gattrib.$(OBJEXT) \ + attrib/gattrib.$(OBJEXT) $(am__objects_40) src/log.$(OBJEXT) +unit_test_gattrib_OBJECTS = $(am_unit_test_gattrib_OBJECTS) +unit_test_gattrib_DEPENDENCIES = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_unit_test_gdbus_client_OBJECTS = unit/test-gdbus-client.$(OBJEXT) +unit_test_gdbus_client_OBJECTS = $(am_unit_test_gdbus_client_OBJECTS) +unit_test_gdbus_client_DEPENDENCIES = gdbus/libgdbus-internal.la \ + src/libshared-glib.la $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am__unit_test_gobex_SOURCES_DIST = gobex/gobex.h gobex/gobex.c \ + gobex/gobex-defs.h gobex/gobex-defs.c gobex/gobex-packet.c \ + gobex/gobex-packet.h gobex/gobex-header.c gobex/gobex-header.h \ + gobex/gobex-transfer.c gobex/gobex-debug.h \ + gobex/gobex-apparam.c gobex/gobex-apparam.h unit/util.c \ + unit/util.h unit/test-gobex.c +@OBEX_TRUE@am_unit_test_gobex_OBJECTS = $(am__objects_39) \ +@OBEX_TRUE@ unit/util.$(OBJEXT) unit/test-gobex.$(OBJEXT) +unit_test_gobex_OBJECTS = $(am_unit_test_gobex_OBJECTS) +@OBEX_TRUE@unit_test_gobex_DEPENDENCIES = src/libshared-glib.la \ +@OBEX_TRUE@ $(am__DEPENDENCIES_1) +am__unit_test_gobex_apparam_SOURCES_DIST = gobex/gobex.h gobex/gobex.c \ + gobex/gobex-defs.h gobex/gobex-defs.c gobex/gobex-packet.c \ + gobex/gobex-packet.h gobex/gobex-header.c gobex/gobex-header.h \ + gobex/gobex-transfer.c gobex/gobex-debug.h \ + gobex/gobex-apparam.c gobex/gobex-apparam.h unit/util.c \ + unit/util.h unit/test-gobex-apparam.c +@OBEX_TRUE@am_unit_test_gobex_apparam_OBJECTS = $(am__objects_39) \ +@OBEX_TRUE@ unit/util.$(OBJEXT) \ +@OBEX_TRUE@ unit/test-gobex-apparam.$(OBJEXT) +unit_test_gobex_apparam_OBJECTS = \ + $(am_unit_test_gobex_apparam_OBJECTS) +@OBEX_TRUE@unit_test_gobex_apparam_DEPENDENCIES = \ +@OBEX_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +am__unit_test_gobex_header_SOURCES_DIST = gobex/gobex.h gobex/gobex.c \ + gobex/gobex-defs.h gobex/gobex-defs.c gobex/gobex-packet.c \ + gobex/gobex-packet.h gobex/gobex-header.c gobex/gobex-header.h \ + gobex/gobex-transfer.c gobex/gobex-debug.h \ + gobex/gobex-apparam.c gobex/gobex-apparam.h unit/util.c \ + unit/util.h unit/test-gobex-header.c +@OBEX_TRUE@am_unit_test_gobex_header_OBJECTS = $(am__objects_39) \ +@OBEX_TRUE@ unit/util.$(OBJEXT) \ +@OBEX_TRUE@ unit/test-gobex-header.$(OBJEXT) +unit_test_gobex_header_OBJECTS = $(am_unit_test_gobex_header_OBJECTS) +@OBEX_TRUE@unit_test_gobex_header_DEPENDENCIES = \ +@OBEX_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +am__unit_test_gobex_packet_SOURCES_DIST = gobex/gobex.h gobex/gobex.c \ + gobex/gobex-defs.h gobex/gobex-defs.c gobex/gobex-packet.c \ + gobex/gobex-packet.h gobex/gobex-header.c gobex/gobex-header.h \ + gobex/gobex-transfer.c gobex/gobex-debug.h \ + gobex/gobex-apparam.c gobex/gobex-apparam.h unit/util.c \ + unit/util.h unit/test-gobex-packet.c +@OBEX_TRUE@am_unit_test_gobex_packet_OBJECTS = $(am__objects_39) \ +@OBEX_TRUE@ unit/util.$(OBJEXT) \ +@OBEX_TRUE@ unit/test-gobex-packet.$(OBJEXT) +unit_test_gobex_packet_OBJECTS = $(am_unit_test_gobex_packet_OBJECTS) +@OBEX_TRUE@unit_test_gobex_packet_DEPENDENCIES = \ +@OBEX_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +am__unit_test_gobex_transfer_SOURCES_DIST = gobex/gobex.h \ + gobex/gobex.c gobex/gobex-defs.h gobex/gobex-defs.c \ + gobex/gobex-packet.c gobex/gobex-packet.h gobex/gobex-header.c \ + gobex/gobex-header.h gobex/gobex-transfer.c \ + gobex/gobex-debug.h gobex/gobex-apparam.c \ + gobex/gobex-apparam.h unit/util.c unit/util.h \ + unit/test-gobex-transfer.c +@OBEX_TRUE@am_unit_test_gobex_transfer_OBJECTS = $(am__objects_39) \ +@OBEX_TRUE@ unit/util.$(OBJEXT) \ +@OBEX_TRUE@ unit/test-gobex-transfer.$(OBJEXT) +unit_test_gobex_transfer_OBJECTS = \ + $(am_unit_test_gobex_transfer_OBJECTS) +@OBEX_TRUE@unit_test_gobex_transfer_DEPENDENCIES = \ +@OBEX_TRUE@ src/libshared-glib.la $(am__DEPENDENCIES_1) +am_unit_test_hfp_OBJECTS = unit/test-hfp.$(OBJEXT) +unit_test_hfp_OBJECTS = $(am_unit_test_hfp_OBJECTS) +unit_test_hfp_DEPENDENCIES = src/libshared-glib.la \ + $(am__DEPENDENCIES_1) +am_unit_test_hog_OBJECTS = unit/test-hog.$(OBJEXT) $(am__objects_40) \ + profiles/input/hog-lib.$(OBJEXT) \ + profiles/scanparam/scpp.$(OBJEXT) \ + profiles/battery/bas.$(OBJEXT) \ + profiles/deviceinfo/dis.$(OBJEXT) src/log.$(OBJEXT) \ + attrib/att.$(OBJEXT) attrib/gatt.$(OBJEXT) \ + attrib/gattrib.$(OBJEXT) +unit_test_hog_OBJECTS = $(am_unit_test_hog_OBJECTS) +unit_test_hog_DEPENDENCIES = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(am__DEPENDENCIES_1) +am_unit_test_lib_OBJECTS = unit/test-lib.$(OBJEXT) +unit_test_lib_OBJECTS = $(am_unit_test_lib_OBJECTS) +unit_test_lib_DEPENDENCIES = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(am__DEPENDENCIES_1) +am__unit_test_mesh_crypto_SOURCES_DIST = unit/test-mesh-crypto.c \ + mesh/crypto.h ell/internal ell/ell.h +@MESH_TRUE@am_unit_test_mesh_crypto_OBJECTS = \ +@MESH_TRUE@ unit/test_mesh_crypto-test-mesh-crypto.$(OBJEXT) +unit_test_mesh_crypto_OBJECTS = $(am_unit_test_mesh_crypto_OBJECTS) +@MESH_TRUE@unit_test_mesh_crypto_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_unit_test_mgmt_OBJECTS = unit/test-mgmt.$(OBJEXT) +unit_test_mgmt_OBJECTS = $(am_unit_test_mgmt_OBJECTS) +unit_test_mgmt_DEPENDENCIES = src/libshared-glib.la \ + $(am__DEPENDENCIES_1) +am_unit_test_micp_OBJECTS = unit/test-micp.$(OBJEXT) +unit_test_micp_OBJECTS = $(am_unit_test_micp_OBJECTS) +unit_test_micp_DEPENDENCIES = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(am__DEPENDENCIES_1) +am__unit_test_midi_SOURCES_DIST = unit/test-midi.c \ + profiles/midi/libmidi.h profiles/midi/libmidi.c +@MIDI_TRUE@am_unit_test_midi_OBJECTS = \ +@MIDI_TRUE@ unit/test_midi-test-midi.$(OBJEXT) \ +@MIDI_TRUE@ profiles/midi/unit_test_midi-libmidi.$(OBJEXT) +unit_test_midi_OBJECTS = $(am_unit_test_midi_OBJECTS) +@MIDI_TRUE@unit_test_midi_DEPENDENCIES = src/libshared-glib.la \ +@MIDI_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_unit_test_queue_OBJECTS = unit/test-queue.$(OBJEXT) +unit_test_queue_OBJECTS = $(am_unit_test_queue_OBJECTS) +unit_test_queue_DEPENDENCIES = src/libshared-glib.la \ + $(am__DEPENDENCIES_1) +am_unit_test_ringbuf_OBJECTS = unit/test-ringbuf.$(OBJEXT) +unit_test_ringbuf_OBJECTS = $(am_unit_test_ringbuf_OBJECTS) +unit_test_ringbuf_DEPENDENCIES = src/libshared-glib.la \ + $(am__DEPENDENCIES_1) +am_unit_test_sdp_OBJECTS = unit/test-sdp.$(OBJEXT) \ + src/sdpd-database.$(OBJEXT) src/log.$(OBJEXT) \ + src/sdpd-service.$(OBJEXT) src/sdpd-request.$(OBJEXT) +unit_test_sdp_OBJECTS = $(am_unit_test_sdp_OBJECTS) +unit_test_sdp_DEPENDENCIES = lib/libbluetooth-internal.la \ + src/libshared-glib.la $(am__DEPENDENCIES_1) +am_unit_test_tester_OBJECTS = unit/test-tester.$(OBJEXT) +unit_test_tester_OBJECTS = $(am_unit_test_tester_OBJECTS) +unit_test_tester_DEPENDENCIES = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(am__DEPENDENCIES_1) +am_unit_test_textfile_OBJECTS = unit/test-textfile.$(OBJEXT) \ + src/textfile.$(OBJEXT) +unit_test_textfile_OBJECTS = $(am_unit_test_textfile_OBJECTS) +unit_test_textfile_DEPENDENCIES = src/libshared-glib.la \ + $(am__DEPENDENCIES_1) +am_unit_test_uhid_OBJECTS = unit/test-uhid.$(OBJEXT) +unit_test_uhid_OBJECTS = $(am_unit_test_uhid_OBJECTS) +unit_test_uhid_DEPENDENCIES = src/libshared-glib.la \ + $(am__DEPENDENCIES_1) +am_unit_test_uuid_OBJECTS = unit/test-uuid.$(OBJEXT) +unit_test_uuid_OBJECTS = $(am_unit_test_uuid_OBJECTS) +unit_test_uuid_DEPENDENCIES = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(am__DEPENDENCIES_1) +am_unit_test_vcp_OBJECTS = unit/test-vcp.$(OBJEXT) $(am__objects_40) +unit_test_vcp_OBJECTS = $(am_unit_test_vcp_OBJECTS) +unit_test_vcp_DEPENDENCIES = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(am__DEPENDENCIES_1) +SCRIPTS = $(test_SCRIPTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = android/$(DEPDIR)/a2dp-sink.Po \ + android/$(DEPDIR)/a2dp.Po \ + android/$(DEPDIR)/android_tester-tester-a2dp.Po \ + android/$(DEPDIR)/android_tester-tester-avrcp.Po \ + android/$(DEPDIR)/android_tester-tester-bluetooth.Po \ + android/$(DEPDIR)/android_tester-tester-gatt.Po \ + android/$(DEPDIR)/android_tester-tester-hdp.Po \ + android/$(DEPDIR)/android_tester-tester-hidhost.Po \ + android/$(DEPDIR)/android_tester-tester-main.Po \ + android/$(DEPDIR)/android_tester-tester-map-client.Po \ + android/$(DEPDIR)/android_tester-tester-pan.Po \ + android/$(DEPDIR)/android_tester-tester-socket.Po \ + android/$(DEPDIR)/audio_a2dp_default_la-hal-audio-aptx.Plo \ + android/$(DEPDIR)/audio_a2dp_default_la-hal-audio-sbc.Plo \ + android/$(DEPDIR)/audio_a2dp_default_la-hal-audio.Plo \ + android/$(DEPDIR)/audio_sco_default_la-hal-sco.Plo \ + android/$(DEPDIR)/avctp.Po android/$(DEPDIR)/avdtp.Po \ + android/$(DEPDIR)/avdtptest-avdtp.Po \ + android/$(DEPDIR)/avdtptest-avdtptest.Po \ + android/$(DEPDIR)/avrcp-lib.Po android/$(DEPDIR)/avrcp.Po \ + android/$(DEPDIR)/bluetooth.Po \ + android/$(DEPDIR)/bluetooth_default_la-hal-a2dp-sink.Plo \ + android/$(DEPDIR)/bluetooth_default_la-hal-a2dp.Plo \ + android/$(DEPDIR)/bluetooth_default_la-hal-avrcp-ctrl.Plo \ + android/$(DEPDIR)/bluetooth_default_la-hal-avrcp.Plo \ + android/$(DEPDIR)/bluetooth_default_la-hal-bluetooth.Plo \ + android/$(DEPDIR)/bluetooth_default_la-hal-gatt.Plo \ + android/$(DEPDIR)/bluetooth_default_la-hal-handsfree-client.Plo \ + android/$(DEPDIR)/bluetooth_default_la-hal-handsfree.Plo \ + android/$(DEPDIR)/bluetooth_default_la-hal-health.Plo \ + android/$(DEPDIR)/bluetooth_default_la-hal-hidhost.Plo \ + android/$(DEPDIR)/bluetooth_default_la-hal-ipc.Plo \ + android/$(DEPDIR)/bluetooth_default_la-hal-map-client.Plo \ + android/$(DEPDIR)/bluetooth_default_la-hal-pan.Plo \ + android/$(DEPDIR)/bluetooth_default_la-hal-socket.Plo \ + android/$(DEPDIR)/bluetooth_default_la-hal-utils.Plo \ + android/$(DEPDIR)/bluetoothd-snoop.Po \ + android/$(DEPDIR)/gatt.Po \ + android/$(DEPDIR)/haltest-hal-utils.Po \ + android/$(DEPDIR)/handsfree-client.Po \ + android/$(DEPDIR)/handsfree.Po android/$(DEPDIR)/health.Po \ + android/$(DEPDIR)/hidhost.Po android/$(DEPDIR)/ipc.Po \ + android/$(DEPDIR)/ipc_tester-hal-utils.Po \ + android/$(DEPDIR)/ipc_tester-ipc-tester.Po \ + android/$(DEPDIR)/main.Po android/$(DEPDIR)/map-client.Po \ + android/$(DEPDIR)/pan.Po android/$(DEPDIR)/sco.Po \ + android/$(DEPDIR)/socket.Po \ + android/$(DEPDIR)/system-emulator.Po \ + android/$(DEPDIR)/test-ipc.Po \ + android/audio_utils/$(DEPDIR)/audio_sco_default_la-resampler.Plo \ + android/client/$(DEPDIR)/haltest-haltest.Po \ + android/client/$(DEPDIR)/haltest-history.Po \ + android/client/$(DEPDIR)/haltest-if-audio.Po \ + android/client/$(DEPDIR)/haltest-if-av-sink.Po \ + android/client/$(DEPDIR)/haltest-if-av.Po \ + android/client/$(DEPDIR)/haltest-if-bt.Po \ + android/client/$(DEPDIR)/haltest-if-gatt.Po \ + android/client/$(DEPDIR)/haltest-if-hf-client.Po \ + android/client/$(DEPDIR)/haltest-if-hf.Po \ + android/client/$(DEPDIR)/haltest-if-hh.Po \ + android/client/$(DEPDIR)/haltest-if-hl.Po \ + android/client/$(DEPDIR)/haltest-if-mce.Po \ + android/client/$(DEPDIR)/haltest-if-pan.Po \ + android/client/$(DEPDIR)/haltest-if-rc-ctrl.Po \ + android/client/$(DEPDIR)/haltest-if-rc.Po \ + android/client/$(DEPDIR)/haltest-if-sco.Po \ + android/client/$(DEPDIR)/haltest-if-sock.Po \ + android/client/$(DEPDIR)/haltest-pollhandler.Po \ + android/client/$(DEPDIR)/haltest-tabcompletion.Po \ + android/client/$(DEPDIR)/haltest-terminal.Po \ + android/hardware/$(DEPDIR)/android_tester-hardware.Po \ + android/hardware/$(DEPDIR)/haltest-hardware.Po \ + attrib/$(DEPDIR)/att.Po attrib/$(DEPDIR)/bluetoothd-att.Po \ + attrib/$(DEPDIR)/bluetoothd-gatt.Po \ + attrib/$(DEPDIR)/bluetoothd-gattrib.Po \ + attrib/$(DEPDIR)/gatt.Po attrib/$(DEPDIR)/gattrib.Po \ + attrib/$(DEPDIR)/gatttool.Po attrib/$(DEPDIR)/interactive.Po \ + attrib/$(DEPDIR)/utils.Po \ + btio/$(DEPDIR)/android_avdtptest-btio.Po \ + btio/$(DEPDIR)/bluetoothd-btio.Po btio/$(DEPDIR)/btio.Po \ + btio/$(DEPDIR)/obexd-btio.Po client/$(DEPDIR)/admin.Po \ + client/$(DEPDIR)/adv_monitor.Po \ + client/$(DEPDIR)/advertising.Po client/$(DEPDIR)/agent.Po \ + client/$(DEPDIR)/assistant.Po client/$(DEPDIR)/display.Po \ + client/$(DEPDIR)/gatt.Po client/$(DEPDIR)/main.Po \ + client/$(DEPDIR)/mgmt.Po client/$(DEPDIR)/player.Po \ + client/$(DEPDIR)/print.Po ell/$(DEPDIR)/base64.Plo \ + ell/$(DEPDIR)/cert-crypto.Plo ell/$(DEPDIR)/cert.Plo \ + ell/$(DEPDIR)/checksum.Plo ell/$(DEPDIR)/cipher.Plo \ + ell/$(DEPDIR)/dbus-client.Plo ell/$(DEPDIR)/dbus-filter.Plo \ + ell/$(DEPDIR)/dbus-message.Plo \ + ell/$(DEPDIR)/dbus-name-cache.Plo \ + ell/$(DEPDIR)/dbus-service.Plo ell/$(DEPDIR)/dbus-util.Plo \ + ell/$(DEPDIR)/dbus.Plo ell/$(DEPDIR)/ecc-external.Plo \ + ell/$(DEPDIR)/ecc.Plo ell/$(DEPDIR)/ecdh.Plo \ + ell/$(DEPDIR)/gvariant-util.Plo ell/$(DEPDIR)/hashmap.Plo \ + ell/$(DEPDIR)/idle.Plo ell/$(DEPDIR)/io.Plo \ + ell/$(DEPDIR)/key.Plo ell/$(DEPDIR)/log.Plo \ + ell/$(DEPDIR)/main.Plo ell/$(DEPDIR)/pem.Plo \ + ell/$(DEPDIR)/queue.Plo ell/$(DEPDIR)/random.Plo \ + ell/$(DEPDIR)/settings.Plo ell/$(DEPDIR)/signal.Plo \ + ell/$(DEPDIR)/siphash.Plo ell/$(DEPDIR)/string.Plo \ + ell/$(DEPDIR)/strv.Plo ell/$(DEPDIR)/tester.Plo \ + ell/$(DEPDIR)/time.Plo ell/$(DEPDIR)/timeout.Plo \ + ell/$(DEPDIR)/tls-extensions.Plo ell/$(DEPDIR)/tls-record.Plo \ + ell/$(DEPDIR)/tls-suites.Plo ell/$(DEPDIR)/tls.Plo \ + ell/$(DEPDIR)/utf8.Plo ell/$(DEPDIR)/util.Plo \ + ell/$(DEPDIR)/uuid.Plo emulator/$(DEPDIR)/amp.Po \ + emulator/$(DEPDIR)/android_android_tester-btdev.Po \ + emulator/$(DEPDIR)/android_android_tester-bthost.Po \ + emulator/$(DEPDIR)/android_android_tester-hciemu.Po \ + emulator/$(DEPDIR)/android_android_tester-smp.Po \ + emulator/$(DEPDIR)/android_android_tester-vhci.Po \ + emulator/$(DEPDIR)/android_ipc_tester-btdev.Po \ + emulator/$(DEPDIR)/android_ipc_tester-bthost.Po \ + emulator/$(DEPDIR)/android_ipc_tester-hciemu.Po \ + emulator/$(DEPDIR)/android_ipc_tester-smp.Po \ + emulator/$(DEPDIR)/android_ipc_tester-vhci.Po \ + emulator/$(DEPDIR)/b1ee.Po emulator/$(DEPDIR)/btdev.Po \ + emulator/$(DEPDIR)/bthost.Po emulator/$(DEPDIR)/hciemu.Po \ + emulator/$(DEPDIR)/hfp.Po emulator/$(DEPDIR)/le.Po \ + emulator/$(DEPDIR)/main.Po emulator/$(DEPDIR)/phy.Po \ + emulator/$(DEPDIR)/serial.Po emulator/$(DEPDIR)/server.Po \ + emulator/$(DEPDIR)/smp.Po emulator/$(DEPDIR)/vhci.Po \ + gdbus/$(DEPDIR)/client.Plo gdbus/$(DEPDIR)/mainloop.Plo \ + gdbus/$(DEPDIR)/object.Plo gdbus/$(DEPDIR)/polkit.Plo \ + gdbus/$(DEPDIR)/watch.Plo gobex/$(DEPDIR)/gobex-apparam.Po \ + gobex/$(DEPDIR)/gobex-defs.Po gobex/$(DEPDIR)/gobex-header.Po \ + gobex/$(DEPDIR)/gobex-packet.Po \ + gobex/$(DEPDIR)/gobex-transfer.Po gobex/$(DEPDIR)/gobex.Po \ + gobex/$(DEPDIR)/obexd-gobex-apparam.Po \ + gobex/$(DEPDIR)/obexd-gobex-defs.Po \ + gobex/$(DEPDIR)/obexd-gobex-header.Po \ + gobex/$(DEPDIR)/obexd-gobex-packet.Po \ + gobex/$(DEPDIR)/obexd-gobex-transfer.Po \ + gobex/$(DEPDIR)/obexd-gobex.Po lib/$(DEPDIR)/bluetooth.Plo \ + lib/$(DEPDIR)/hci.Plo lib/$(DEPDIR)/sdp.Plo \ + lib/$(DEPDIR)/uuid.Plo mesh/$(DEPDIR)/agent.Po \ + mesh/$(DEPDIR)/appkey.Po mesh/$(DEPDIR)/cfgmod-server.Po \ + mesh/$(DEPDIR)/crypto.Po mesh/$(DEPDIR)/dbus.Po \ + mesh/$(DEPDIR)/friend.Po mesh/$(DEPDIR)/keyring.Po \ + mesh/$(DEPDIR)/main.Po mesh/$(DEPDIR)/manager.Po \ + mesh/$(DEPDIR)/mesh-config-json.Po \ + mesh/$(DEPDIR)/mesh-io-generic.Po \ + mesh/$(DEPDIR)/mesh-io-mgmt.Po mesh/$(DEPDIR)/mesh-io-unit.Po \ + mesh/$(DEPDIR)/mesh-io.Po mesh/$(DEPDIR)/mesh-mgmt.Po \ + mesh/$(DEPDIR)/mesh.Po mesh/$(DEPDIR)/model.Po \ + mesh/$(DEPDIR)/net-keys.Po mesh/$(DEPDIR)/net.Po \ + mesh/$(DEPDIR)/node.Po mesh/$(DEPDIR)/pb-adv.Po \ + mesh/$(DEPDIR)/prov-acceptor.Po \ + mesh/$(DEPDIR)/prov-initiator.Po \ + mesh/$(DEPDIR)/prvbeac-server.Po \ + mesh/$(DEPDIR)/remprv-server.Po mesh/$(DEPDIR)/rpl.Po \ + mesh/$(DEPDIR)/util.Po monitor/$(DEPDIR)/a2dp.Po \ + monitor/$(DEPDIR)/analyze.Po monitor/$(DEPDIR)/att.Po \ + monitor/$(DEPDIR)/avctp.Po monitor/$(DEPDIR)/avdtp.Po \ + monitor/$(DEPDIR)/bnep.Po monitor/$(DEPDIR)/broadcom.Po \ + monitor/$(DEPDIR)/control.Po monitor/$(DEPDIR)/crc.Po \ + monitor/$(DEPDIR)/display.Po monitor/$(DEPDIR)/ellisys.Po \ + monitor/$(DEPDIR)/hcidump.Po monitor/$(DEPDIR)/hwdb.Po \ + monitor/$(DEPDIR)/intel.Po monitor/$(DEPDIR)/jlink.Po \ + monitor/$(DEPDIR)/keys.Po monitor/$(DEPDIR)/l2cap.Po \ + monitor/$(DEPDIR)/ll.Po monitor/$(DEPDIR)/lmp.Po \ + monitor/$(DEPDIR)/main.Po monitor/$(DEPDIR)/msft.Po \ + monitor/$(DEPDIR)/packet.Po monitor/$(DEPDIR)/rfcomm.Po \ + monitor/$(DEPDIR)/sdp.Po monitor/$(DEPDIR)/vendor.Po \ + obexd/client/$(DEPDIR)/obexd-bip-common.Po \ + obexd/client/$(DEPDIR)/obexd-bip.Po \ + obexd/client/$(DEPDIR)/obexd-bluetooth.Po \ + obexd/client/$(DEPDIR)/obexd-driver.Po \ + obexd/client/$(DEPDIR)/obexd-ftp.Po \ + obexd/client/$(DEPDIR)/obexd-manager.Po \ + obexd/client/$(DEPDIR)/obexd-map-event.Po \ + obexd/client/$(DEPDIR)/obexd-map.Po \ + obexd/client/$(DEPDIR)/obexd-mns.Po \ + obexd/client/$(DEPDIR)/obexd-opp.Po \ + obexd/client/$(DEPDIR)/obexd-pbap.Po \ + obexd/client/$(DEPDIR)/obexd-session.Po \ + obexd/client/$(DEPDIR)/obexd-sync.Po \ + obexd/client/$(DEPDIR)/obexd-transfer.Po \ + obexd/client/$(DEPDIR)/obexd-transport.Po \ + obexd/plugins/$(DEPDIR)/obexd-bluetooth.Po \ + obexd/plugins/$(DEPDIR)/obexd-filesystem.Po \ + obexd/plugins/$(DEPDIR)/obexd-ftp.Po \ + obexd/plugins/$(DEPDIR)/obexd-irmc.Po \ + obexd/plugins/$(DEPDIR)/obexd-mas.Po \ + obexd/plugins/$(DEPDIR)/obexd-messages-dummy.Po \ + obexd/plugins/$(DEPDIR)/obexd-opp.Po \ + obexd/plugins/$(DEPDIR)/obexd-pbap.Po \ + obexd/plugins/$(DEPDIR)/obexd-pcsuite.Po \ + obexd/plugins/$(DEPDIR)/obexd-phonebook-@PLUGIN_PHONEBOOK@.Po \ + obexd/plugins/$(DEPDIR)/obexd-vcard.Po \ + obexd/src/$(DEPDIR)/obexd-log.Po \ + obexd/src/$(DEPDIR)/obexd-main.Po \ + obexd/src/$(DEPDIR)/obexd-manager.Po \ + obexd/src/$(DEPDIR)/obexd-mimetype.Po \ + obexd/src/$(DEPDIR)/obexd-obex.Po \ + obexd/src/$(DEPDIR)/obexd-plugin.Po \ + obexd/src/$(DEPDIR)/obexd-server.Po \ + obexd/src/$(DEPDIR)/obexd-service.Po \ + obexd/src/$(DEPDIR)/obexd-transport.Po \ + peripheral/$(DEPDIR)/attach.Po peripheral/$(DEPDIR)/efivars.Po \ + peripheral/$(DEPDIR)/gap.Po peripheral/$(DEPDIR)/gatt.Po \ + peripheral/$(DEPDIR)/log.Po peripheral/$(DEPDIR)/main.Po \ + plugins/$(DEPDIR)/bluetoothd-admin.Po \ + plugins/$(DEPDIR)/bluetoothd-autopair.Po \ + plugins/$(DEPDIR)/bluetoothd-hostname.Po \ + plugins/$(DEPDIR)/bluetoothd-neard.Po \ + plugins/$(DEPDIR)/bluetoothd-policy.Po \ + plugins/$(DEPDIR)/bluetoothd-sixaxis.Po \ + plugins/$(DEPDIR)/bluetoothd-wiimote.Po \ + profiles/audio/$(DEPDIR)/bluetoothd-a2dp.Po \ + profiles/audio/$(DEPDIR)/bluetoothd-asha.Po \ + profiles/audio/$(DEPDIR)/bluetoothd-avctp.Po \ + profiles/audio/$(DEPDIR)/bluetoothd-avdtp.Po \ + profiles/audio/$(DEPDIR)/bluetoothd-avrcp.Po \ + profiles/audio/$(DEPDIR)/bluetoothd-bap.Po \ + profiles/audio/$(DEPDIR)/bluetoothd-bass.Po \ + profiles/audio/$(DEPDIR)/bluetoothd-ccp.Po \ + profiles/audio/$(DEPDIR)/bluetoothd-control.Po \ + profiles/audio/$(DEPDIR)/bluetoothd-csip.Po \ + profiles/audio/$(DEPDIR)/bluetoothd-mcp.Po \ + profiles/audio/$(DEPDIR)/bluetoothd-media.Po \ + profiles/audio/$(DEPDIR)/bluetoothd-micp.Po \ + profiles/audio/$(DEPDIR)/bluetoothd-player.Po \ + profiles/audio/$(DEPDIR)/bluetoothd-sink.Po \ + profiles/audio/$(DEPDIR)/bluetoothd-source.Po \ + profiles/audio/$(DEPDIR)/bluetoothd-transport.Po \ + profiles/audio/$(DEPDIR)/bluetoothd-vcp.Po \ + profiles/battery/$(DEPDIR)/bas.Po \ + profiles/battery/$(DEPDIR)/bluetoothd-bas.Po \ + profiles/battery/$(DEPDIR)/bluetoothd-battery.Po \ + profiles/cups/$(DEPDIR)/hcrp.Po \ + profiles/cups/$(DEPDIR)/main.Po profiles/cups/$(DEPDIR)/sdp.Po \ + profiles/cups/$(DEPDIR)/spp.Po \ + profiles/deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Po \ + profiles/deviceinfo/$(DEPDIR)/bluetoothd-dis.Po \ + profiles/deviceinfo/$(DEPDIR)/dis.Po \ + profiles/gap/$(DEPDIR)/bluetoothd-gas.Po \ + profiles/health/$(DEPDIR)/bluetoothd-hdp.Po \ + profiles/health/$(DEPDIR)/bluetoothd-hdp_main.Po \ + profiles/health/$(DEPDIR)/bluetoothd-hdp_manager.Po \ + profiles/health/$(DEPDIR)/bluetoothd-hdp_util.Po \ + profiles/health/$(DEPDIR)/bluetoothd-mcap.Po \ + profiles/health/$(DEPDIR)/mcap.Po \ + profiles/iap/$(DEPDIR)/main.Po \ + profiles/input/$(DEPDIR)/bluetoothd-device.Po \ + profiles/input/$(DEPDIR)/bluetoothd-hog-lib.Po \ + profiles/input/$(DEPDIR)/bluetoothd-hog.Po \ + profiles/input/$(DEPDIR)/bluetoothd-manager.Po \ + profiles/input/$(DEPDIR)/bluetoothd-server.Po \ + profiles/input/$(DEPDIR)/bluetoothd-suspend-none.Po \ + profiles/input/$(DEPDIR)/hog-lib.Po \ + profiles/midi/$(DEPDIR)/bluetoothd-libmidi.Po \ + profiles/midi/$(DEPDIR)/bluetoothd-midi.Po \ + profiles/midi/$(DEPDIR)/unit_test_midi-libmidi.Po \ + profiles/network/$(DEPDIR)/bluetoothd-bnep.Po \ + profiles/network/$(DEPDIR)/bluetoothd-connection.Po \ + profiles/network/$(DEPDIR)/bluetoothd-manager.Po \ + profiles/network/$(DEPDIR)/bluetoothd-server.Po \ + profiles/network/$(DEPDIR)/bnep.Po \ + profiles/sap/$(DEPDIR)/bluetoothd-main.Po \ + profiles/sap/$(DEPDIR)/bluetoothd-manager.Po \ + profiles/sap/$(DEPDIR)/bluetoothd-sap-dummy.Po \ + profiles/sap/$(DEPDIR)/bluetoothd-server.Po \ + profiles/scanparam/$(DEPDIR)/bluetoothd-scan.Po \ + profiles/scanparam/$(DEPDIR)/bluetoothd-scpp.Po \ + profiles/scanparam/$(DEPDIR)/scpp.Po \ + src/$(DEPDIR)/android_avdtptest-log.Po \ + src/$(DEPDIR)/bluetoothd-adapter.Po \ + src/$(DEPDIR)/bluetoothd-adv_monitor.Po \ + src/$(DEPDIR)/bluetoothd-advertising.Po \ + src/$(DEPDIR)/bluetoothd-agent.Po \ + src/$(DEPDIR)/bluetoothd-backtrace.Po \ + src/$(DEPDIR)/bluetoothd-battery.Po \ + src/$(DEPDIR)/bluetoothd-dbus-common.Po \ + src/$(DEPDIR)/bluetoothd-device.Po \ + src/$(DEPDIR)/bluetoothd-eir.Po \ + src/$(DEPDIR)/bluetoothd-error.Po \ + src/$(DEPDIR)/bluetoothd-gatt-client.Po \ + src/$(DEPDIR)/bluetoothd-gatt-database.Po \ + src/$(DEPDIR)/bluetoothd-log.Po \ + src/$(DEPDIR)/bluetoothd-main.Po \ + src/$(DEPDIR)/bluetoothd-plugin.Po \ + src/$(DEPDIR)/bluetoothd-profile.Po \ + src/$(DEPDIR)/bluetoothd-rfkill.Po \ + src/$(DEPDIR)/bluetoothd-sdp-client.Po \ + src/$(DEPDIR)/bluetoothd-sdp-xml.Po \ + src/$(DEPDIR)/bluetoothd-sdpd-database.Po \ + src/$(DEPDIR)/bluetoothd-sdpd-request.Po \ + src/$(DEPDIR)/bluetoothd-sdpd-server.Po \ + src/$(DEPDIR)/bluetoothd-sdpd-service.Po \ + src/$(DEPDIR)/bluetoothd-service.Po \ + src/$(DEPDIR)/bluetoothd-set.Po \ + src/$(DEPDIR)/bluetoothd-settings.Po \ + src/$(DEPDIR)/bluetoothd-storage.Po \ + src/$(DEPDIR)/bluetoothd-textfile.Po \ + src/$(DEPDIR)/bluetoothd-uuid-helper.Po src/$(DEPDIR)/eir.Po \ + src/$(DEPDIR)/log.Po src/$(DEPDIR)/oui.Po \ + src/$(DEPDIR)/sdp-client.Po src/$(DEPDIR)/sdp-xml.Po \ + src/$(DEPDIR)/sdpd-database.Po src/$(DEPDIR)/sdpd-request.Po \ + src/$(DEPDIR)/sdpd-server.Po src/$(DEPDIR)/sdpd-service.Po \ + src/$(DEPDIR)/settings.Po src/$(DEPDIR)/textfile.Po \ + src/$(DEPDIR)/uuid-helper.Po \ + src/shared/$(DEPDIR)/android_avdtptest-log.Po \ + src/shared/$(DEPDIR)/android_avdtptest-queue.Po \ + src/shared/$(DEPDIR)/android_avdtptest-util.Po \ + src/shared/$(DEPDIR)/btp.Po \ + src/shared/$(DEPDIR)/libshared_ell_la-ad.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-asha.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-att.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-bap-debug.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-bap.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-bass.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-btsnoop.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-ccp.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-crypto.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-csip.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-ecc.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-gap.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-gatt-client.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-gatt-db.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-gatt-helpers.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-gatt-server.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-hci-crypto.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-hci.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-hfp.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-io-ell.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-log.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-mainloop-ell.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-mcp.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-mgmt.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-micp.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-pcap.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-queue.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-ringbuf.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-shell.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-timeout-ell.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-uhid.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-util.Plo \ + src/shared/$(DEPDIR)/libshared_ell_la-vcp.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-ad.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-asha.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-att.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-bap-debug.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-bap.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-bass.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-btsnoop.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-ccp.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-crypto.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-csip.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-ecc.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-gap.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-gatt-client.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-gatt-db.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-gatt-helpers.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-gatt-server.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-hci-crypto.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-hci.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-hfp.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-io-glib.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-log.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-mainloop-glib.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-mainloop-notify.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-mcp.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-mgmt.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-micp.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-pcap.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-queue.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-ringbuf.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-shell.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-tester.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-timeout-glib.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-uhid.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-util.Plo \ + src/shared/$(DEPDIR)/libshared_glib_la-vcp.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-ad.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-asha.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-att.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-bap-debug.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-bap.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-bass.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-btsnoop.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-ccp.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-crypto.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-csip.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-ecc.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-gap.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-client.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-db.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-helpers.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-server.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-hci-crypto.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-hci.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-hfp.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-io-mainloop.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-log.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-mainloop-notify.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-mainloop.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-mcp.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-mgmt.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-micp.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-pcap.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-queue.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-ringbuf.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-shell.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-timeout-mainloop.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-uhid.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-util.Plo \ + src/shared/$(DEPDIR)/libshared_mainloop_la-vcp.Plo \ + tools/$(DEPDIR)/3dsp.Po tools/$(DEPDIR)/advtest.Po \ + tools/$(DEPDIR)/amptest.Po tools/$(DEPDIR)/avinfo.Po \ + tools/$(DEPDIR)/avtest.Po tools/$(DEPDIR)/bcmfw.Po \ + tools/$(DEPDIR)/bdaddr.Po tools/$(DEPDIR)/bluemoon.Po \ + tools/$(DEPDIR)/bluetooth-player.Po \ + tools/$(DEPDIR)/bnep-tester.Po tools/$(DEPDIR)/bneptest.Po \ + tools/$(DEPDIR)/btattach.Po tools/$(DEPDIR)/btconfig.Po \ + tools/$(DEPDIR)/btgatt-client.Po \ + tools/$(DEPDIR)/btgatt-server.Po tools/$(DEPDIR)/btinfo.Po \ + tools/$(DEPDIR)/btiotest.Po tools/$(DEPDIR)/btmgmt.Po \ + tools/$(DEPDIR)/btmon-logger.Po tools/$(DEPDIR)/btpclient.Po \ + tools/$(DEPDIR)/btpclientctl.Po tools/$(DEPDIR)/btproxy.Po \ + tools/$(DEPDIR)/btsnoop.Po tools/$(DEPDIR)/check-selftest.Po \ + tools/$(DEPDIR)/ciptool.Po tools/$(DEPDIR)/cltest.Po \ + tools/$(DEPDIR)/create-image.Po tools/$(DEPDIR)/eddystone.Po \ + tools/$(DEPDIR)/gap-tester.Po tools/$(DEPDIR)/gatt-service.Po \ + tools/$(DEPDIR)/hci-tester.Po tools/$(DEPDIR)/hciattach.Po \ + tools/$(DEPDIR)/hciattach_ath3k.Po \ + tools/$(DEPDIR)/hciattach_bcm43xx.Po \ + tools/$(DEPDIR)/hciattach_intel.Po \ + tools/$(DEPDIR)/hciattach_qualcomm.Po \ + tools/$(DEPDIR)/hciattach_st.Po \ + tools/$(DEPDIR)/hciattach_ti.Po \ + tools/$(DEPDIR)/hciattach_tialt.Po \ + tools/$(DEPDIR)/hciconfig.Po tools/$(DEPDIR)/hcidump.Po \ + tools/$(DEPDIR)/hcieventmask.Po \ + tools/$(DEPDIR)/hcisecfilter.Po tools/$(DEPDIR)/hcitool.Po \ + tools/$(DEPDIR)/hex2hcd.Po tools/$(DEPDIR)/hid2hci.Po \ + tools/$(DEPDIR)/hwdb.Po tools/$(DEPDIR)/ibeacon.Po \ + tools/$(DEPDIR)/ioctl-tester.Po tools/$(DEPDIR)/iso-tester.Po \ + tools/$(DEPDIR)/isotest.Po tools/$(DEPDIR)/l2cap-tester.Po \ + tools/$(DEPDIR)/l2ping.Po tools/$(DEPDIR)/l2test.Po \ + tools/$(DEPDIR)/mcaptest.Po tools/$(DEPDIR)/mesh-cfgclient.Po \ + tools/$(DEPDIR)/mesh-cfgtest.Po tools/$(DEPDIR)/mesh-tester.Po \ + tools/$(DEPDIR)/meshctl.Po tools/$(DEPDIR)/mgmt-tester.Po \ + tools/$(DEPDIR)/mpris-proxy.Po tools/$(DEPDIR)/nokfw.Po \ + tools/$(DEPDIR)/obex-client-tool.Po \ + tools/$(DEPDIR)/obex-server-tool.Po tools/$(DEPDIR)/obexctl.Po \ + tools/$(DEPDIR)/oobtest.Po tools/$(DEPDIR)/rctest.Po \ + tools/$(DEPDIR)/rfcomm-tester.Po tools/$(DEPDIR)/rfcomm.Po \ + tools/$(DEPDIR)/rtlfw.Po tools/$(DEPDIR)/sco-tester.Po \ + tools/$(DEPDIR)/scotest.Po tools/$(DEPDIR)/sdptool.Po \ + tools/$(DEPDIR)/seq2bseq.Po tools/$(DEPDIR)/smp-tester.Po \ + tools/$(DEPDIR)/test-runner.Po \ + tools/$(DEPDIR)/userchan-tester.Po \ + tools/mesh-gatt/$(DEPDIR)/config-client.Po \ + tools/mesh-gatt/$(DEPDIR)/config-server.Po \ + tools/mesh-gatt/$(DEPDIR)/crypto.Po \ + tools/mesh-gatt/$(DEPDIR)/gatt.Po \ + tools/mesh-gatt/$(DEPDIR)/net.Po \ + tools/mesh-gatt/$(DEPDIR)/node.Po \ + tools/mesh-gatt/$(DEPDIR)/onoff-model.Po \ + tools/mesh-gatt/$(DEPDIR)/prov-db.Po \ + tools/mesh-gatt/$(DEPDIR)/prov.Po \ + tools/mesh-gatt/$(DEPDIR)/util.Po \ + tools/mesh/$(DEPDIR)/agent.Po tools/mesh/$(DEPDIR)/cfgcli.Po \ + tools/mesh/$(DEPDIR)/keys.Po tools/mesh/$(DEPDIR)/mesh-db.Po \ + tools/mesh/$(DEPDIR)/remote.Po tools/mesh/$(DEPDIR)/util.Po \ + tools/parser/$(DEPDIR)/amp.Po tools/parser/$(DEPDIR)/att.Po \ + tools/parser/$(DEPDIR)/avctp.Po \ + tools/parser/$(DEPDIR)/avdtp.Po \ + tools/parser/$(DEPDIR)/avrcp.Po tools/parser/$(DEPDIR)/bnep.Po \ + tools/parser/$(DEPDIR)/bpa.Po tools/parser/$(DEPDIR)/capi.Po \ + tools/parser/$(DEPDIR)/cmtp.Po tools/parser/$(DEPDIR)/csr.Po \ + tools/parser/$(DEPDIR)/ericsson.Po \ + tools/parser/$(DEPDIR)/hci.Po tools/parser/$(DEPDIR)/hcrp.Po \ + tools/parser/$(DEPDIR)/hidp.Po tools/parser/$(DEPDIR)/l2cap.Po \ + tools/parser/$(DEPDIR)/lmp.Po tools/parser/$(DEPDIR)/obex.Po \ + tools/parser/$(DEPDIR)/parser.Po tools/parser/$(DEPDIR)/ppp.Po \ + tools/parser/$(DEPDIR)/rfcomm.Po tools/parser/$(DEPDIR)/sap.Po \ + tools/parser/$(DEPDIR)/sdp.Po tools/parser/$(DEPDIR)/smp.Po \ + tools/parser/$(DEPDIR)/tcpip.Po unit/$(DEPDIR)/test-avctp.Po \ + unit/$(DEPDIR)/test-avdtp.Po unit/$(DEPDIR)/test-avrcp.Po \ + unit/$(DEPDIR)/test-bap.Po unit/$(DEPDIR)/test-bass.Po \ + unit/$(DEPDIR)/test-crc.Po unit/$(DEPDIR)/test-crypto.Po \ + unit/$(DEPDIR)/test-ecc.Po unit/$(DEPDIR)/test-eir.Po \ + unit/$(DEPDIR)/test-gatt.Po unit/$(DEPDIR)/test-gattrib.Po \ + unit/$(DEPDIR)/test-gdbus-client.Po \ + unit/$(DEPDIR)/test-gobex-apparam.Po \ + unit/$(DEPDIR)/test-gobex-header.Po \ + unit/$(DEPDIR)/test-gobex-packet.Po \ + unit/$(DEPDIR)/test-gobex-transfer.Po \ + unit/$(DEPDIR)/test-gobex.Po unit/$(DEPDIR)/test-hfp.Po \ + unit/$(DEPDIR)/test-hog.Po unit/$(DEPDIR)/test-lib.Po \ + unit/$(DEPDIR)/test-mgmt.Po unit/$(DEPDIR)/test-micp.Po \ + unit/$(DEPDIR)/test-queue.Po unit/$(DEPDIR)/test-ringbuf.Po \ + unit/$(DEPDIR)/test-sdp.Po unit/$(DEPDIR)/test-tester.Po \ + unit/$(DEPDIR)/test-textfile.Po unit/$(DEPDIR)/test-uhid.Po \ + unit/$(DEPDIR)/test-uuid.Po unit/$(DEPDIR)/test-vcp.Po \ + unit/$(DEPDIR)/test_mesh_crypto-test-mesh-crypto.Po \ + unit/$(DEPDIR)/test_midi-test-midi.Po unit/$(DEPDIR)/util.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(android_audio_a2dp_default_la_SOURCES) \ + $(android_audio_sco_default_la_SOURCES) \ + $(android_bluetooth_default_la_SOURCES) \ + $(ell_libell_internal_la_SOURCES) \ + $(gdbus_libgdbus_internal_la_SOURCES) \ + $(lib_libbluetooth_internal_la_SOURCES) \ + $(lib_libbluetooth_la_SOURCES) $(src_libshared_ell_la_SOURCES) \ + $(src_libshared_glib_la_SOURCES) \ + $(src_libshared_mainloop_la_SOURCES) \ + $(android_android_tester_SOURCES) $(android_avdtptest_SOURCES) \ + $(android_bluetoothd_SOURCES) \ + $(android_bluetoothd_snoop_SOURCES) $(android_haltest_SOURCES) \ + $(android_ipc_tester_SOURCES) \ + $(android_system_emulator_SOURCES) $(android_test_ipc_SOURCES) \ + $(attrib_gatttool_SOURCES) $(client_bluetoothctl_SOURCES) \ + $(emulator_b1ee_SOURCES) $(emulator_btvirt_SOURCES) \ + $(emulator_hfp_SOURCES) $(mesh_bluetooth_meshd_SOURCES) \ + $(monitor_btmon_SOURCES) $(obexd_src_obexd_SOURCES) \ + $(nodist_obexd_src_obexd_SOURCES) \ + $(peripheral_btsensor_SOURCES) \ + $(profiles_cups_bluetooth_SOURCES) \ + $(profiles_iap_iapd_SOURCES) $(src_bluetoothd_SOURCES) \ + $(nodist_src_bluetoothd_SOURCES) $(tools_3dsp_SOURCES) \ + $(tools_advtest_SOURCES) tools/amptest.c tools/avinfo.c \ + tools/avtest.c tools/bcmfw.c $(tools_bdaddr_SOURCES) \ + $(tools_bluemoon_SOURCES) $(tools_bluetooth_player_SOURCES) \ + $(tools_bnep_tester_SOURCES) $(tools_bneptest_SOURCES) \ + $(tools_btattach_SOURCES) $(tools_btconfig_SOURCES) \ + $(tools_btgatt_client_SOURCES) $(tools_btgatt_server_SOURCES) \ + $(tools_btinfo_SOURCES) $(tools_btiotest_SOURCES) \ + $(tools_btmgmt_SOURCES) $(tools_btmon_logger_SOURCES) \ + $(tools_btpclient_SOURCES) $(tools_btpclientctl_SOURCES) \ + $(tools_btproxy_SOURCES) $(tools_btsnoop_SOURCES) \ + tools/check-selftest.c tools/ciptool.c $(tools_cltest_SOURCES) \ + $(tools_create_image_SOURCES) $(tools_eddystone_SOURCES) \ + $(tools_gap_tester_SOURCES) $(tools_gatt_service_SOURCES) \ + $(tools_hci_tester_SOURCES) $(tools_hciattach_SOURCES) \ + $(tools_hciconfig_SOURCES) $(tools_hcidump_SOURCES) \ + tools/hcieventmask.c tools/hcisecfilter.c \ + $(tools_hcitool_SOURCES) $(tools_hex2hcd_SOURCES) \ + tools/hid2hci.c tools/hwdb.c $(tools_ibeacon_SOURCES) \ + $(tools_ioctl_tester_SOURCES) $(tools_iso_tester_SOURCES) \ + tools/isotest.c $(tools_l2cap_tester_SOURCES) tools/l2ping.c \ + tools/l2test.c $(tools_mcaptest_SOURCES) \ + $(tools_mesh_cfgclient_SOURCES) $(tools_mesh_cfgtest_SOURCES) \ + $(tools_mesh_tester_SOURCES) $(tools_meshctl_SOURCES) \ + $(tools_mgmt_tester_SOURCES) $(tools_mpris_proxy_SOURCES) \ + $(tools_nokfw_SOURCES) $(tools_obex_client_tool_SOURCES) \ + $(tools_obex_server_tool_SOURCES) $(tools_obexctl_SOURCES) \ + $(tools_oobtest_SOURCES) tools/rctest.c tools/rfcomm.c \ + $(tools_rfcomm_tester_SOURCES) $(tools_rtlfw_SOURCES) \ + $(tools_sco_tester_SOURCES) tools/scotest.c \ + $(tools_sdptool_SOURCES) $(tools_seq2bseq_SOURCES) \ + $(tools_smp_tester_SOURCES) tools/test-runner.c \ + $(tools_userchan_tester_SOURCES) $(unit_test_avctp_SOURCES) \ + $(unit_test_avdtp_SOURCES) $(unit_test_avrcp_SOURCES) \ + $(unit_test_bap_SOURCES) $(unit_test_bass_SOURCES) \ + $(unit_test_crc_SOURCES) $(unit_test_crypto_SOURCES) \ + $(unit_test_ecc_SOURCES) $(unit_test_eir_SOURCES) \ + $(unit_test_gatt_SOURCES) $(unit_test_gattrib_SOURCES) \ + $(unit_test_gdbus_client_SOURCES) $(unit_test_gobex_SOURCES) \ + $(unit_test_gobex_apparam_SOURCES) \ + $(unit_test_gobex_header_SOURCES) \ + $(unit_test_gobex_packet_SOURCES) \ + $(unit_test_gobex_transfer_SOURCES) $(unit_test_hfp_SOURCES) \ + $(unit_test_hog_SOURCES) $(unit_test_lib_SOURCES) \ + $(unit_test_mesh_crypto_SOURCES) $(unit_test_mgmt_SOURCES) \ + $(unit_test_micp_SOURCES) $(unit_test_midi_SOURCES) \ + $(unit_test_queue_SOURCES) $(unit_test_ringbuf_SOURCES) \ + $(unit_test_sdp_SOURCES) $(unit_test_tester_SOURCES) \ + $(unit_test_textfile_SOURCES) $(unit_test_uhid_SOURCES) \ + $(unit_test_uuid_SOURCES) $(unit_test_vcp_SOURCES) +DIST_SOURCES = $(am__android_audio_a2dp_default_la_SOURCES_DIST) \ + $(am__android_audio_sco_default_la_SOURCES_DIST) \ + $(am__android_bluetooth_default_la_SOURCES_DIST) \ + $(am__ell_libell_internal_la_SOURCES_DIST) \ + $(gdbus_libgdbus_internal_la_SOURCES) \ + $(lib_libbluetooth_internal_la_SOURCES) \ + $(am__lib_libbluetooth_la_SOURCES_DIST) \ + $(am__src_libshared_ell_la_SOURCES_DIST) \ + $(am__src_libshared_glib_la_SOURCES_DIST) \ + $(am__src_libshared_mainloop_la_SOURCES_DIST) \ + $(am__android_android_tester_SOURCES_DIST) \ + $(am__android_avdtptest_SOURCES_DIST) \ + $(am__android_bluetoothd_SOURCES_DIST) \ + $(am__android_bluetoothd_snoop_SOURCES_DIST) \ + $(am__android_haltest_SOURCES_DIST) \ + $(am__android_ipc_tester_SOURCES_DIST) \ + $(am__android_system_emulator_SOURCES_DIST) \ + $(am__android_test_ipc_SOURCES_DIST) \ + $(am__attrib_gatttool_SOURCES_DIST) \ + $(am__client_bluetoothctl_SOURCES_DIST) \ + $(am__emulator_b1ee_SOURCES_DIST) \ + $(am__emulator_btvirt_SOURCES_DIST) \ + $(am__emulator_hfp_SOURCES_DIST) \ + $(am__mesh_bluetooth_meshd_SOURCES_DIST) \ + $(am__monitor_btmon_SOURCES_DIST) \ + $(am__obexd_src_obexd_SOURCES_DIST) \ + $(am__peripheral_btsensor_SOURCES_DIST) \ + $(am__profiles_cups_bluetooth_SOURCES_DIST) \ + $(am__profiles_iap_iapd_SOURCES_DIST) \ + $(am__src_bluetoothd_SOURCES_DIST) \ + $(am__tools_3dsp_SOURCES_DIST) \ + $(am__tools_advtest_SOURCES_DIST) tools/amptest.c \ + tools/avinfo.c tools/avtest.c tools/bcmfw.c \ + $(am__tools_bdaddr_SOURCES_DIST) \ + $(am__tools_bluemoon_SOURCES_DIST) \ + $(am__tools_bluetooth_player_SOURCES_DIST) \ + $(am__tools_bnep_tester_SOURCES_DIST) \ + $(am__tools_bneptest_SOURCES_DIST) \ + $(am__tools_btattach_SOURCES_DIST) \ + $(am__tools_btconfig_SOURCES_DIST) \ + $(am__tools_btgatt_client_SOURCES_DIST) \ + $(am__tools_btgatt_server_SOURCES_DIST) \ + $(am__tools_btinfo_SOURCES_DIST) \ + $(am__tools_btiotest_SOURCES_DIST) \ + $(am__tools_btmgmt_SOURCES_DIST) \ + $(am__tools_btmon_logger_SOURCES_DIST) \ + $(am__tools_btpclient_SOURCES_DIST) \ + $(am__tools_btpclientctl_SOURCES_DIST) \ + $(am__tools_btproxy_SOURCES_DIST) \ + $(am__tools_btsnoop_SOURCES_DIST) tools/check-selftest.c \ + tools/ciptool.c $(am__tools_cltest_SOURCES_DIST) \ + $(am__tools_create_image_SOURCES_DIST) \ + $(am__tools_eddystone_SOURCES_DIST) \ + $(am__tools_gap_tester_SOURCES_DIST) \ + $(am__tools_gatt_service_SOURCES_DIST) \ + $(am__tools_hci_tester_SOURCES_DIST) \ + $(am__tools_hciattach_SOURCES_DIST) \ + $(am__tools_hciconfig_SOURCES_DIST) \ + $(am__tools_hcidump_SOURCES_DIST) tools/hcieventmask.c \ + tools/hcisecfilter.c $(am__tools_hcitool_SOURCES_DIST) \ + $(am__tools_hex2hcd_SOURCES_DIST) tools/hid2hci.c tools/hwdb.c \ + $(am__tools_ibeacon_SOURCES_DIST) \ + $(am__tools_ioctl_tester_SOURCES_DIST) \ + $(am__tools_iso_tester_SOURCES_DIST) tools/isotest.c \ + $(am__tools_l2cap_tester_SOURCES_DIST) tools/l2ping.c \ + tools/l2test.c $(am__tools_mcaptest_SOURCES_DIST) \ + $(am__tools_mesh_cfgclient_SOURCES_DIST) \ + $(am__tools_mesh_cfgtest_SOURCES_DIST) \ + $(am__tools_mesh_tester_SOURCES_DIST) \ + $(am__tools_meshctl_SOURCES_DIST) \ + $(am__tools_mgmt_tester_SOURCES_DIST) \ + $(am__tools_mpris_proxy_SOURCES_DIST) \ + $(am__tools_nokfw_SOURCES_DIST) \ + $(am__tools_obex_client_tool_SOURCES_DIST) \ + $(am__tools_obex_server_tool_SOURCES_DIST) \ + $(am__tools_obexctl_SOURCES_DIST) \ + $(am__tools_oobtest_SOURCES_DIST) tools/rctest.c \ + tools/rfcomm.c $(am__tools_rfcomm_tester_SOURCES_DIST) \ + $(am__tools_rtlfw_SOURCES_DIST) \ + $(am__tools_sco_tester_SOURCES_DIST) tools/scotest.c \ + $(am__tools_sdptool_SOURCES_DIST) \ + $(am__tools_seq2bseq_SOURCES_DIST) \ + $(am__tools_smp_tester_SOURCES_DIST) tools/test-runner.c \ + $(am__tools_userchan_tester_SOURCES_DIST) \ + $(unit_test_avctp_SOURCES) $(unit_test_avdtp_SOURCES) \ + $(unit_test_avrcp_SOURCES) $(unit_test_bap_SOURCES) \ + $(unit_test_bass_SOURCES) $(unit_test_crc_SOURCES) \ + $(unit_test_crypto_SOURCES) $(unit_test_ecc_SOURCES) \ + $(unit_test_eir_SOURCES) $(unit_test_gatt_SOURCES) \ + $(unit_test_gattrib_SOURCES) $(unit_test_gdbus_client_SOURCES) \ + $(am__unit_test_gobex_SOURCES_DIST) \ + $(am__unit_test_gobex_apparam_SOURCES_DIST) \ + $(am__unit_test_gobex_header_SOURCES_DIST) \ + $(am__unit_test_gobex_packet_SOURCES_DIST) \ + $(am__unit_test_gobex_transfer_SOURCES_DIST) \ + $(unit_test_hfp_SOURCES) $(unit_test_hog_SOURCES) \ + $(unit_test_lib_SOURCES) \ + $(am__unit_test_mesh_crypto_SOURCES_DIST) \ + $(unit_test_mgmt_SOURCES) $(unit_test_micp_SOURCES) \ + $(am__unit_test_midi_SOURCES_DIST) $(unit_test_queue_SOURCES) \ + $(unit_test_ringbuf_SOURCES) $(unit_test_sdp_SOURCES) \ + $(unit_test_tester_SOURCES) $(unit_test_textfile_SOURCES) \ + $(unit_test_uhid_SOURCES) $(unit_test_uuid_SOURCES) \ + $(unit_test_vcp_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +man1dir = $(mandir)/man1 +man5dir = $(mandir)/man5 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +NROFF = nroff +MANS = $(man_MANS) +am__dist_zshcompletion_DATA_DIST = completion/zsh/_bluetoothctl +DATA = $(conf_DATA) $(dbus_DATA) $(dbussessionbus_DATA) \ + $(dbussystembus_DATA) $(dist_zshcompletion_DATA) \ + $(pkgconfig_DATA) $(rules_DATA) $(state_DATA) \ + $(systemdsystemunit_DATA) $(systemduserunit_DATA) +am__pkginclude_HEADERS_DIST = lib/bluetooth.h lib/hci.h lib/hci_lib.h \ + lib/sco.h lib/l2cap.h lib/sdp.h lib/sdp_lib.h lib/rfcomm.h \ + lib/bnep.h lib/cmtp.h lib/hidp.h +HEADERS = $(pkginclude_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \ + config.h.in +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +AM_RECURSIVE_TARGETS = cscope check recheck +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red='[0;31m'; \ + grn='[0;32m'; \ + lgn='[1;32m'; \ + blu='[1;34m'; \ + mgn='[0;35m'; \ + brg='[1m'; \ + std='[m'; \ + fi; \ +} +am__recheck_rx = ^[ ]*:recheck:[ ]* +am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* +am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* +# A command that, given a newline-separated list of test names on the +# standard input, print the name of the tests that are to be re-run +# upon "make recheck". +am__list_recheck_tests = $(AWK) '{ \ + recheck = 1; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + { \ + if ((getline line2 < ($$0 ".log")) < 0) \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ + { \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ + { \ + break; \ + } \ + }; \ + if (recheck) \ + print $$0; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# A command that, given a newline-separated list of test names on the +# standard input, create the global log from their .trs and .log files. +am__create_global_log = $(AWK) ' \ +function fatal(msg) \ +{ \ + print "fatal: making $@: " msg | "cat >&2"; \ + exit 1; \ +} \ +function rst_section(header) \ +{ \ + print header; \ + len = length(header); \ + for (i = 1; i <= len; i = i + 1) \ + printf "="; \ + printf "\n\n"; \ +} \ +{ \ + copy_in_global_log = 1; \ + global_test_result = "RUN"; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".trs"); \ + if (line ~ /$(am__global_test_result_rx)/) \ + { \ + sub("$(am__global_test_result_rx)", "", line); \ + sub("[ ]*$$", "", line); \ + global_test_result = line; \ + } \ + else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ + copy_in_global_log = 0; \ + }; \ + if (copy_in_global_log) \ + { \ + rst_section(global_test_result ": " $$0); \ + while ((rc = (getline line < ($$0 ".log"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".log"); \ + print line; \ + }; \ + printf "\n"; \ + }; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# Restructured Text title. +am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } +# Solaris 10 'make', and several other traditional 'make' implementations, +# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it +# by disabling -e (using the XSI extension "set +e") if it's set. +am__sh_e_setup = case $$- in *e*) set +e;; esac +# Default flags passed to test drivers. +am__common_driver_flags = \ + --color-tests "$$am__color_tests" \ + --enable-hard-errors "$$am__enable_hard_errors" \ + --expect-failure "$$am__expect_failure" +# To be inserted before the command running the test. Creates the +# directory for the log if needed. Stores in $dir the directory +# containing $f, in $tst the test, in $log the log. Executes the +# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and +# passes TESTS_ENVIRONMENT. Set up options for the wrapper that +# will run the test scripts (or their associated LOG_COMPILER, if +# thy have one). +am__check_pre = \ +$(am__sh_e_setup); \ +$(am__vpath_adj_setup) $(am__vpath_adj) \ +$(am__tty_colors); \ +srcdir=$(srcdir); export srcdir; \ +case "$@" in \ + */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ + *) am__odir=.;; \ +esac; \ +test "x$$am__odir" = x"." || test -d "$$am__odir" \ + || $(MKDIR_P) "$$am__odir" || exit $$?; \ +if test -f "./$$f"; then dir=./; \ +elif test -f "$$f"; then dir=; \ +else dir="$(srcdir)/"; fi; \ +tst=$$dir$$f; log='$@'; \ +if test -n '$(DISABLE_HARD_ERRORS)'; then \ + am__enable_hard_errors=no; \ +else \ + am__enable_hard_errors=yes; \ +fi; \ +case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ + am__expect_failure=yes;; \ + *) \ + am__expect_failure=no;; \ +esac; \ +$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) +# A shell command to get the names of the tests scripts with any registered +# extension removed (i.e., equivalently, the names of the test logs, with +# the '.log' extension removed). The result is saved in the shell variable +# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, +# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", +# since that might cause problem with VPATH rewrites for suffix-less tests. +# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. +am__set_TESTS_bases = \ + bases='$(TEST_LOGS)'; \ + bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ + bases=`echo $$bases` +AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)' +RECHECK_LOGS = $(TEST_LOGS) +TEST_SUITE_LOG = test-suite.log +TEST_EXTENSIONS = @EXEEXT@ .test +LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver +LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) +am__set_b = \ + case '$@' in \ + */*) \ + case '$*' in \ + */*) b='$*';; \ + *) b=`echo '$@' | sed 's/\.log$$//'`; \ + esac;; \ + *) \ + b='$*';; \ + esac +am__test_logs1 = $(TESTS:=.log) +am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) +TEST_LOGS = $(am__test_logs2:.test.log=.log) +TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver +TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ + $(TEST_LOG_FLAGS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.mesh \ + $(srcdir)/Makefile.obexd $(srcdir)/Makefile.plugins \ + $(srcdir)/Makefile.tools $(srcdir)/android/Makefile.am \ + $(srcdir)/config.h.in $(top_srcdir)/lib/bluez.pc.in \ + $(top_srcdir)/mesh/bluetooth-mesh.service.in \ + $(top_srcdir)/mesh/bluetooth-meshd.rst.in \ + $(top_srcdir)/obexd/src/obex.service.in \ + $(top_srcdir)/obexd/src/org.bluez.obex.service.in \ + $(top_srcdir)/src/bluetooth.service.in \ + $(top_srcdir)/src/bluetoothd.rst.in \ + $(top_srcdir)/tools/bluetooth-logger.service.in \ + $(top_srcdir)/tools/mpris-proxy.service.in AUTHORS COPYING \ + COPYING.LIB ChangeLog INSTALL NEWS README TODO compile \ + config.guess config.sub depcomp install-sh ltmain.sh missing \ + test-driver +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + if test -d "$(distdir)"; then \ + find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -rf "$(distdir)" \ + || { sleep 5 && rm -rf "$(distdir)"; }; \ + else :; fi +am__post_remove_distdir = $(am__remove_distdir) +GZIP_ENV = --best +DIST_ARCHIVES = $(distdir).tar.xz +DIST_TARGETS = dist-xz +# Exists only to be overridden by the user if desired. +AM_DISTCHECK_DVI_TARGET = dvi +distuninstallcheck_listfiles = find . -type f -print +am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ + | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' +distcleancheck_listfiles = find . -type f -print +pkgincludedir = $(includedir)/bluetooth +pkglibexecdir = @PKGLIBEXECDIR@ +ACLOCAL = @ACLOCAL@ +ALSA_CFLAGS = @ALSA_CFLAGS@ +ALSA_LIBS = @ALSA_LIBS@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ASAN_LIB = @ASAN_LIB@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BACKTRACE_CFLAGS = @BACKTRACE_CFLAGS@ +BACKTRACE_LIBS = @BACKTRACE_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONFIGDIR = @CONFIGDIR@ +CPPFLAGS = @CPPFLAGS@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CUPS_SERVERBIN = @CUPS_SERVERBIN@ +CYGPATH_W = @CYGPATH_W@ +DBUS_CFLAGS = @DBUS_CFLAGS@ +DBUS_CONFDIR = @DBUS_CONFDIR@ +DBUS_LIBS = @DBUS_LIBS@ +DBUS_SESSIONBUSDIR = @DBUS_SESSIONBUSDIR@ +DBUS_SYSTEMBUSDIR = @DBUS_SYSTEMBUSDIR@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ELL_CFLAGS = @ELL_CFLAGS@ +ELL_LIBS = @ELL_LIBS@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_LIBS = @GLIB_LIBS@ +GREP = @GREP@ +GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ +GTHREAD_LIBS = @GTHREAD_LIBS@ +ICAL_CFLAGS = @ICAL_CFLAGS@ +ICAL_LIBS = @ICAL_LIBS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JSONC_CFLAGS = @JSONC_CFLAGS@ +JSONC_LIBS = @JSONC_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBEBOOK_CFLAGS = @LIBEBOOK_CFLAGS@ +LIBEBOOK_LIBS = @LIBEBOOK_LIBS@ +LIBEDATESERVER_CFLAGS = @LIBEDATESERVER_CFLAGS@ +LIBEDATESERVER_LIBS = @LIBEDATESERVER_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MESH_STORAGEDIR = @MESH_STORAGEDIR@ +MISC_CFLAGS = @MISC_CFLAGS@ +MISC_LDFLAGS = @MISC_LDFLAGS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKGBINDIR = @PKGBINDIR@ +PKGLIBEXECDIR = @PKGLIBEXECDIR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PLUGIN_PHONEBOOK = @PLUGIN_PHONEBOOK@ +RANLIB = @RANLIB@ +RST2MAN = @RST2MAN@ +SBC_CFLAGS = @SBC_CFLAGS@ +SBC_LIBS = @SBC_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SPEEXDSP_CFLAGS = @SPEEXDSP_CFLAGS@ +SPEEXDSP_LIBS = @SPEEXDSP_LIBS@ +STRIP = @STRIP@ +SYSTEMD_SYSTEMUNITDIR = @SYSTEMD_SYSTEMUNITDIR@ +SYSTEMD_USERUNITDIR = @SYSTEMD_USERUNITDIR@ +UDEV_CFLAGS = @UDEV_CFLAGS@ +UDEV_DIR = @UDEV_DIR@ +UDEV_LIBS = @UDEV_LIBS@ +VERSION = @VERSION@ +WARNING_CFLAGS = @WARNING_CFLAGS@ +ZSH_COMPLETIONDIR = @ZSH_COMPLETIONDIR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +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@ +enable_coverage = @enable_coverage@ +enable_dbus_run_session = @enable_dbus_run_session@ +enable_valgrind = @enable_valgrind@ +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@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# SPDX-License-Identifier: GPL-2.0 +AM_MAKEFLAGS = --no-print-directory +AM_CPPFLAGS = $(am__append_72) $(DBUS_CFLAGS) $(GLIB_CFLAGS) \ + -I$(builddir)/lib +lib_LTLIBRARIES = $(am__append_2) +noinst_LIBRARIES = +noinst_LTLIBRARIES = lib/libbluetooth-internal.la \ + gdbus/libgdbus-internal.la $(am__append_3) \ + src/libshared-glib.la src/libshared-mainloop.la \ + $(am__append_4) +CLEANFILES = $(ell_built_sources) $(builtin_files) obexd/src/builtin.h \ + $(am__append_83) +EXTRA_DIST = src/org.bluez.service src/genbuiltin src/bluetooth.conf \ + src/main.conf profiles/network/network.conf \ + profiles/input/input.conf $(am__append_59) $(am__append_70) \ + obexd/src/genbuiltin android/Android.mk android/README \ + android/compat/readline/history.h \ + android/compat/readline/readline.h android/compat/wordexp.h \ + android/bluetoothd-wrapper.c android/log.c \ + android/bluetoothd.te android/bluetoothd_snoop.te \ + android/init.bluetooth.rc android/hal-ipc-api.txt \ + android/audio-ipc-api.txt android/cts.txt \ + android/pics-rfcomm.txt android/pics-spp.txt \ + android/pics-sdp.txt android/pics-l2cap.txt \ + android/pics-gap.txt android/pics-did.txt android/pics-hid.txt \ + android/pics-pan.txt android/pics-opp.txt android/pics-map.txt \ + android/pics-pbap.txt android/pics-a2dp.txt \ + android/pics-avctp.txt android/pics-avrcp.txt \ + android/pics-hsp.txt android/pics-hfp.txt \ + android/pics-gatt.txt android/pics-mcap.txt \ + android/pics-hdp.txt android/pics-iopt.txt android/pics-sm.txt \ + android/pics-mps.txt android/pics-hogp.txt \ + android/pics-scpp.txt android/pics-dis.txt \ + android/pics-avdtp.txt android/pics-gavdp.txt \ + android/pics-bnep.txt android/pixit-l2cap.txt \ + android/pixit-gap.txt android/pixit-did.txt \ + android/pixit-hid.txt android/pixit-pan.txt \ + android/pixit-opp.txt android/pixit-map.txt \ + android/pixit-pbap.txt android/pixit-a2dp.txt \ + android/pixit-avctp.txt android/pixit-avrcp.txt \ + android/pixit-hsp.txt android/pixit-hfp.txt \ + android/pixit-gatt.txt android/pixit-mcap.txt \ + android/pixit-hdp.txt android/pixit-iopt.txt \ + android/pixit-sm.txt android/pixit-mps.txt \ + android/pixit-hogp.txt android/pixit-scpp.txt \ + android/pixit-dis.txt android/pixit-rfcomm.txt \ + android/pixit-spp.txt android/pixit-avdtp.txt \ + android/pixit-gavdp.txt android/pixit-sdp.txt \ + android/pixit-bnep.txt android/pts-rfcomm.txt \ + android/pts-spp.txt android/pts-l2cap.txt android/pts-gap.txt \ + android/pts-did.txt android/pts-hid.txt android/pts-pan.txt \ + android/pts-opp.txt android/pts-map.txt android/pts-a2dp.txt \ + android/pts-avrcp.txt android/pts-avctp.txt \ + android/pts-pbap.txt android/pts-hfp.txt android/pts-gatt.txt \ + android/pts-hsp.txt android/pts-iopt.txt android/pts-hdp.txt \ + android/pts-mcap.txt android/pts-mps.txt android/pts-sm.txt \ + android/pts-hogp.txt android/pts-scpp.txt android/pts-dis.txt \ + android/pts-avdtp.txt android/pts-gavdp.txt \ + android/pts-sdp.txt android/pts-bnep.txt \ + mesh/bluetooth-mesh.conf mesh/org.bluez.mesh.service \ + mesh/mesh-main.conf tools/hid2hci.rules $(test_scripts) \ + doc/assigned-numbers.txt doc/supported-features.txt \ + doc/test-coverage.txt doc/test-runner.rst \ + doc/settings-storage.txt doc/mgmt-api.txt doc/health-api.txt \ + doc/sap-api.txt doc/hci.rst doc/l2cap.rst doc/rfcomm.rst \ + doc/org.bluez.Adapter.rst doc/org.bluez.Device.rst \ + doc/org.bluez.DeviceSet.rst doc/org.bluez.AgentManager.rst \ + doc/org.bluez.Agent.rst doc/org.bluez.ProfileManager.rst \ + doc/org.bluez.Profile.rst doc/org.bluez.NetworkServer.rst \ + doc/org.bluez.Network.rst doc/org.bluez.Input.rst \ + doc/org.bluez.BatteryProviderManager.rst \ + doc/org.bluez.BatteryProvider.rst doc/org.bluez.Battery.rst \ + doc/org.bluez.AdminPolicySet.rst \ + doc/org.bluez.AdminPolicyStatus.rst doc/org.bluez.Media.rst \ + doc/org.bluez.MediaControl.rst doc/org.bluez.MediaPlayer.rst \ + doc/org.bluez.MediaFolder.rst doc/org.bluez.MediaItem.rst \ + doc/org.bluez.MediaEndpoint.rst \ + doc/org.bluez.MediaTransport.rst \ + doc/org.bluez.MediaAssistant.rst doc/org.bluez.GattManager.rst \ + doc/org.bluez.GattProfile.rst doc/org.bluez.GattService.rst \ + doc/org.bluez.GattCharacteristic.rst \ + doc/org.bluez.GattDescriptor.rst \ + doc/org.bluez.LEAdvertisingManager.rst \ + doc/org.bluez.LEAdvertisement.rst \ + doc/org.bluez.AdvertisementMonitorManager.rst \ + doc/org.bluez.AdvertisementMonitor.rst \ + doc/org.bluez.obex.Client.rst doc/org.bluez.obex.Session.rst \ + doc/org.bluez.obex.Transfer.rst \ + doc/org.bluez.obex.ObjectPush.rst \ + doc/org.bluez.obex.FileTransfer.rst \ + doc/org.bluez.obex.Synchronization.rst \ + doc/org.bluez.obex.PhonebookAccess.rst \ + doc/org.bluez.obex.MessageAccess.rst \ + doc/org.bluez.obex.Message.rst \ + doc/org.bluez.obex.AgentManager.rst \ + doc/org.bluez.obex.Agent.rst doc/org.bluez.obex.Image.rst \ + doc/pics-opp.txt doc/pixit-opp.txt doc/pts-opp.txt \ + doc/btsnoop.txt tools/magic.btsnoop $(manual_pages) $(patsubst \ + %.1,%.rst, $(patsubst %.8,%.rst,$(manual_pages))) +pkginclude_HEADERS = $(am__append_1) +AM_CFLAGS = $(MISC_CFLAGS) $(WARNING_CFLAGS) $(UDEV_CFLAGS) $(LIBEBOOK_CFLAGS) \ + $(LIBEDATASERVER_CFLAGS) $(ell_cflags) + +AM_LDFLAGS = $(MISC_LDFLAGS) +confdir = $(sysconfdir)/bluetooth +statedir = $(localstatedir)/lib/bluetooth +@DATAFILES_TRUE@dbusdir = $(DBUS_CONFDIR)/dbus-1/system.d +@DATAFILES_TRUE@dbus_DATA = src/bluetooth.conf $(am__append_76) +@DATAFILES_TRUE@conf_DATA = src/main.conf profiles/input/input.conf \ +@DATAFILES_TRUE@ profiles/network/network.conf $(am__append_77) +@DATAFILES_TRUE@state_DATA = +@SYSTEMD_TRUE@systemdsystemunitdir = $(SYSTEMD_SYSTEMUNITDIR) +@SYSTEMD_TRUE@systemdsystemunit_DATA = src/bluetooth.service \ +@SYSTEMD_TRUE@ $(am__append_52) $(am__append_78) +@SYSTEMD_TRUE@systemduserunitdir = $(SYSTEMD_USERUNITDIR) +@SYSTEMD_TRUE@systemduserunit_DATA = $(am__append_56) $(am__append_67) +@SYSTEMD_TRUE@dbussystembusdir = $(DBUS_SYSTEMBUSDIR) +@SYSTEMD_TRUE@dbussystembus_DATA = src/org.bluez.service \ +@SYSTEMD_TRUE@ $(am__append_79) +plugindir = $(libdir)/bluetooth/plugins +build_plugindir = $(plugindir) +@MANPAGES_TRUE@man_MANS = src/bluetoothd.8 doc/hci.7 doc/l2cap.7 \ +@MANPAGES_TRUE@ doc/rfcomm.7 doc/org.bluez.Adapter.5 \ +@MANPAGES_TRUE@ doc/org.bluez.Device.5 \ +@MANPAGES_TRUE@ doc/org.bluez.DeviceSet.5 \ +@MANPAGES_TRUE@ doc/org.bluez.AgentManager.5 \ +@MANPAGES_TRUE@ doc/org.bluez.Agent.5 \ +@MANPAGES_TRUE@ doc/org.bluez.ProfileManager.5 \ +@MANPAGES_TRUE@ doc/org.bluez.Profile.5 \ +@MANPAGES_TRUE@ doc/org.bluez.NetworkServer.5 \ +@MANPAGES_TRUE@ doc/org.bluez.Network.5 doc/org.bluez.Input.5 \ +@MANPAGES_TRUE@ doc/org.bluez.BatteryProviderManager.5 \ +@MANPAGES_TRUE@ doc/org.bluez.BatteryProvider.5 \ +@MANPAGES_TRUE@ doc/org.bluez.Battery.5 \ +@MANPAGES_TRUE@ doc/org.bluez.AdminPolicySet.5 \ +@MANPAGES_TRUE@ doc/org.bluez.AdminPolicyStatus.5 \ +@MANPAGES_TRUE@ doc/org.bluez.Media.5 \ +@MANPAGES_TRUE@ doc/org.bluez.MediaControl.5 \ +@MANPAGES_TRUE@ doc/org.bluez.MediaPlayer.5 \ +@MANPAGES_TRUE@ doc/org.bluez.MediaFolder.5 \ +@MANPAGES_TRUE@ doc/org.bluez.MediaItem.5 \ +@MANPAGES_TRUE@ doc/org.bluez.MediaEndpoint.5 \ +@MANPAGES_TRUE@ doc/org.bluez.MediaTransport.5 \ +@MANPAGES_TRUE@ doc/org.bluez.MediaAssistant.5 \ +@MANPAGES_TRUE@ doc/org.bluez.GattManager.5 \ +@MANPAGES_TRUE@ doc/org.bluez.GattProfile.5 \ +@MANPAGES_TRUE@ doc/org.bluez.GattService.5 \ +@MANPAGES_TRUE@ doc/org.bluez.GattCharacteristic.5 \ +@MANPAGES_TRUE@ doc/org.bluez.GattDescriptor.5 \ +@MANPAGES_TRUE@ doc/org.bluez.LEAdvertisingManager.5 \ +@MANPAGES_TRUE@ doc/org.bluez.LEAdvertisement.5 \ +@MANPAGES_TRUE@ doc/org.bluez.AdvertisementMonitorManager.5 \ +@MANPAGES_TRUE@ doc/org.bluez.AdvertisementMonitor.5 \ +@MANPAGES_TRUE@ doc/org.bluez.obex.Client.5 \ +@MANPAGES_TRUE@ doc/org.bluez.obex.Session.5 \ +@MANPAGES_TRUE@ doc/org.bluez.obex.Transfer.5 \ +@MANPAGES_TRUE@ doc/org.bluez.obex.ObjectPush.5 \ +@MANPAGES_TRUE@ doc/org.bluez.obex.FileTransfer.5 \ +@MANPAGES_TRUE@ doc/org.bluez.obex.Synchronization.5 \ +@MANPAGES_TRUE@ doc/org.bluez.obex.PhonebookAccess.5 \ +@MANPAGES_TRUE@ doc/org.bluez.obex.MessageAccess.5 \ +@MANPAGES_TRUE@ doc/org.bluez.obex.Message.5 \ +@MANPAGES_TRUE@ doc/org.bluez.obex.AgentManager.5 \ +@MANPAGES_TRUE@ doc/org.bluez.obex.Agent.5 \ +@MANPAGES_TRUE@ doc/org.bluez.obex.Image.5 $(am__append_50) \ +@MANPAGES_TRUE@ $(am__append_57) $(am__append_62) \ +@MANPAGES_TRUE@ $(am__append_63) $(am__append_81) +manual_pages = src/bluetoothd.8 doc/hci.7 doc/l2cap.7 doc/rfcomm.7 \ + doc/org.bluez.Adapter.5 doc/org.bluez.Device.5 \ + doc/org.bluez.DeviceSet.5 doc/org.bluez.AgentManager.5 \ + doc/org.bluez.Agent.5 doc/org.bluez.ProfileManager.5 \ + doc/org.bluez.Profile.5 doc/org.bluez.NetworkServer.5 \ + doc/org.bluez.Network.5 doc/org.bluez.Input.5 \ + doc/org.bluez.BatteryProviderManager.5 \ + doc/org.bluez.BatteryProvider.5 doc/org.bluez.Battery.5 \ + doc/org.bluez.AdminPolicySet.5 \ + doc/org.bluez.AdminPolicyStatus.5 doc/org.bluez.Media.5 \ + doc/org.bluez.MediaControl.5 doc/org.bluez.MediaPlayer.5 \ + doc/org.bluez.MediaFolder.5 doc/org.bluez.MediaItem.5 \ + doc/org.bluez.MediaEndpoint.5 doc/org.bluez.MediaTransport.5 \ + doc/org.bluez.MediaAssistant.5 doc/org.bluez.GattManager.5 \ + doc/org.bluez.GattProfile.5 doc/org.bluez.GattService.5 \ + doc/org.bluez.GattCharacteristic.5 \ + doc/org.bluez.GattDescriptor.5 \ + doc/org.bluez.LEAdvertisingManager.5 \ + doc/org.bluez.LEAdvertisement.5 \ + doc/org.bluez.AdvertisementMonitorManager.5 \ + doc/org.bluez.AdvertisementMonitor.5 \ + doc/org.bluez.obex.Client.5 doc/org.bluez.obex.Session.5 \ + doc/org.bluez.obex.Transfer.5 doc/org.bluez.obex.ObjectPush.5 \ + doc/org.bluez.obex.FileTransfer.5 \ + doc/org.bluez.obex.Synchronization.5 \ + doc/org.bluez.obex.PhonebookAccess.5 \ + doc/org.bluez.obex.MessageAccess.5 \ + doc/org.bluez.obex.Message.5 doc/org.bluez.obex.AgentManager.5 \ + doc/org.bluez.obex.Agent.5 doc/org.bluez.obex.Image.5 \ + monitor/btmon.1 tools/hciattach.1 tools/hciconfig.1 \ + tools/hcitool.1 tools/hcidump.1 tools/rfcomm.1 tools/sdptool.1 \ + tools/ciptool.1 tools/rctest.1 tools/l2ping.1 tools/btattach.1 \ + tools/bdaddr.1 tools/isotest.1 tools/btmgmt.1 \ + client/bluetoothctl.1 client/bluetoothctl-mgmt.1 \ + client/bluetoothctl-monitor.1 client/bluetoothctl-admin.1 \ + client/bluetoothctl-advertise.1 client/bluetoothctl-endpoint.1 \ + client/bluetoothctl-gatt.1 client/bluetoothctl-player.1 \ + client/bluetoothctl-scan.1 client/bluetoothctl-transport.1 \ + client/bluetoothctl-assistant.1 tools/hid2hci.1 \ + $(am__append_82) +plugin_LTLIBRARIES = $(am__append_74) +lib_sources = lib/bluetooth.c lib/hci.c lib/sdp.c +lib_headers = lib/bluetooth.h lib/hci.h lib/hci_lib.h \ + lib/sco.h lib/l2cap.h lib/sdp.h lib/sdp_lib.h \ + lib/rfcomm.h lib/bnep.h lib/cmtp.h lib/hidp.h + +extra_headers = lib/mgmt.h lib/uuid.h lib/a2mp.h lib/amp.h lib/iso.h +extra_sources = lib/uuid.c +local_headers = $(foreach file,$(lib_headers), lib/bluetooth/$(notdir $(file))) +BUILT_SOURCES = $(local_headers) $(ell_built_sources) src/builtin.h \ + obexd/src/builtin.h +@LIBRARY_TRUE@lib_libbluetooth_la_SOURCES = $(lib_headers) $(lib_sources) +@LIBRARY_TRUE@lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 22:15:19 +lib_libbluetooth_internal_la_SOURCES = $(lib_headers) $(lib_sources) \ + $(extra_headers) $(extra_sources) + +gdbus_libgdbus_internal_la_SOURCES = gdbus/gdbus.h \ + gdbus/mainloop.c gdbus/watch.c \ + gdbus/object.c gdbus/client.c gdbus/polkit.c + +@EXTERNAL_ELL_FALSE@ell_cflags = +@EXTERNAL_ELL_TRUE@ell_cflags = @ELL_CFLAGS@ +@EXTERNAL_ELL_FALSE@ell_ldadd = ell/libell-internal.la +@EXTERNAL_ELL_TRUE@ell_ldadd = @ELL_LIBS@ +@EXTERNAL_ELL_FALSE@ell_built_sources = ell/shared ell/internal ell/ell.h +@EXTERNAL_ELL_TRUE@ell_built_sources = ell/shared +@EXTERNAL_ELL_FALSE@ell_headers = ell/util.h \ +@EXTERNAL_ELL_FALSE@ ell/log.h \ +@EXTERNAL_ELL_FALSE@ ell/queue.h \ +@EXTERNAL_ELL_FALSE@ ell/hashmap.h \ +@EXTERNAL_ELL_FALSE@ ell/random.h \ +@EXTERNAL_ELL_FALSE@ ell/signal.h \ +@EXTERNAL_ELL_FALSE@ ell/time.h \ +@EXTERNAL_ELL_FALSE@ ell/time-private.h \ +@EXTERNAL_ELL_FALSE@ ell/timeout.h \ +@EXTERNAL_ELL_FALSE@ ell/cipher.h \ +@EXTERNAL_ELL_FALSE@ ell/checksum.h \ +@EXTERNAL_ELL_FALSE@ ell/io.h \ +@EXTERNAL_ELL_FALSE@ ell/idle.h \ +@EXTERNAL_ELL_FALSE@ ell/main.h \ +@EXTERNAL_ELL_FALSE@ ell/settings.h \ +@EXTERNAL_ELL_FALSE@ ell/strv.h \ +@EXTERNAL_ELL_FALSE@ ell/string.h \ +@EXTERNAL_ELL_FALSE@ ell/utf8.h \ +@EXTERNAL_ELL_FALSE@ ell/dbus.h \ +@EXTERNAL_ELL_FALSE@ ell/dbus-service.h \ +@EXTERNAL_ELL_FALSE@ ell/dbus-client.h \ +@EXTERNAL_ELL_FALSE@ ell/key.h \ +@EXTERNAL_ELL_FALSE@ ell/cert.h \ +@EXTERNAL_ELL_FALSE@ ell/pem.h \ +@EXTERNAL_ELL_FALSE@ ell/base64.h \ +@EXTERNAL_ELL_FALSE@ ell/asn1-private.h \ +@EXTERNAL_ELL_FALSE@ ell/cert-private.h \ +@EXTERNAL_ELL_FALSE@ ell/pem-private.h \ +@EXTERNAL_ELL_FALSE@ ell/uuid.h \ +@EXTERNAL_ELL_FALSE@ ell/useful.h \ +@EXTERNAL_ELL_FALSE@ ell/main-private.h \ +@EXTERNAL_ELL_FALSE@ ell/tester.h \ +@EXTERNAL_ELL_FALSE@ ell/tls.h \ +@EXTERNAL_ELL_FALSE@ ell/tls-private.h \ +@EXTERNAL_ELL_FALSE@ ell/ecc.h \ +@EXTERNAL_ELL_FALSE@ ell/ecc-private.h \ +@EXTERNAL_ELL_FALSE@ ell/cleanup.h \ +@EXTERNAL_ELL_FALSE@ ell/ecdh.h + +@EXTERNAL_ELL_FALSE@ell_sources = ell/private.h ell/missing.h \ +@EXTERNAL_ELL_FALSE@ ell/util.c \ +@EXTERNAL_ELL_FALSE@ ell/log.c \ +@EXTERNAL_ELL_FALSE@ ell/queue.c \ +@EXTERNAL_ELL_FALSE@ ell/hashmap.c \ +@EXTERNAL_ELL_FALSE@ ell/random.c \ +@EXTERNAL_ELL_FALSE@ ell/signal.c \ +@EXTERNAL_ELL_FALSE@ ell/time.c \ +@EXTERNAL_ELL_FALSE@ ell/timeout.c \ +@EXTERNAL_ELL_FALSE@ ell/io.c \ +@EXTERNAL_ELL_FALSE@ ell/idle.c \ +@EXTERNAL_ELL_FALSE@ ell/main.c \ +@EXTERNAL_ELL_FALSE@ ell/settings.c \ +@EXTERNAL_ELL_FALSE@ ell/strv.c \ +@EXTERNAL_ELL_FALSE@ ell/string.c \ +@EXTERNAL_ELL_FALSE@ ell/cipher.c \ +@EXTERNAL_ELL_FALSE@ ell/checksum.c \ +@EXTERNAL_ELL_FALSE@ ell/pem.c \ +@EXTERNAL_ELL_FALSE@ ell/cert.c \ +@EXTERNAL_ELL_FALSE@ ell/cert-crypto.c \ +@EXTERNAL_ELL_FALSE@ ell/key.c \ +@EXTERNAL_ELL_FALSE@ ell/base64.c \ +@EXTERNAL_ELL_FALSE@ ell/utf8.c \ +@EXTERNAL_ELL_FALSE@ ell/dbus-private.h \ +@EXTERNAL_ELL_FALSE@ ell/dbus.c \ +@EXTERNAL_ELL_FALSE@ ell/dbus-message.c \ +@EXTERNAL_ELL_FALSE@ ell/dbus-util.c \ +@EXTERNAL_ELL_FALSE@ ell/dbus-service.c \ +@EXTERNAL_ELL_FALSE@ ell/dbus-client.c \ +@EXTERNAL_ELL_FALSE@ ell/dbus-name-cache.c \ +@EXTERNAL_ELL_FALSE@ ell/dbus-filter.c \ +@EXTERNAL_ELL_FALSE@ ell/gvariant-private.h \ +@EXTERNAL_ELL_FALSE@ ell/gvariant-util.c \ +@EXTERNAL_ELL_FALSE@ ell/siphash-private.h \ +@EXTERNAL_ELL_FALSE@ ell/siphash.c \ +@EXTERNAL_ELL_FALSE@ ell/uuid.c \ +@EXTERNAL_ELL_FALSE@ ell/tester.c \ +@EXTERNAL_ELL_FALSE@ ell/tls.c \ +@EXTERNAL_ELL_FALSE@ ell/tls-extensions.c \ +@EXTERNAL_ELL_FALSE@ ell/tls-suites.c \ +@EXTERNAL_ELL_FALSE@ ell/tls-record.c \ +@EXTERNAL_ELL_FALSE@ ell/ecc.c \ +@EXTERNAL_ELL_FALSE@ ell/ecc-external.c \ +@EXTERNAL_ELL_FALSE@ ell/ecdh.c + +@EXTERNAL_ELL_FALSE@ell_shared = ell/useful.h +@EXTERNAL_ELL_FALSE@ell_libell_internal_la_SOURCES = $(ell_headers) $(ell_sources) $(ell_shared) +shared_sources = src/shared/io.h src/shared/timeout.h \ + src/shared/queue.h src/shared/queue.c src/shared/util.h \ + src/shared/util.c src/shared/mgmt.h src/shared/mgmt.c \ + src/shared/crypto.h src/shared/crypto.c src/shared/ecc.h \ + src/shared/ecc.c src/shared/ringbuf.h src/shared/ringbuf.c \ + src/shared/tester.h src/shared/hci.h src/shared/hci.c \ + src/shared/hci-crypto.h src/shared/hci-crypto.c \ + src/shared/hfp.h src/shared/hfp.c src/shared/uhid.h \ + src/shared/uhid.c src/shared/pcap.h src/shared/pcap.c \ + src/shared/btsnoop.h src/shared/btsnoop.c src/shared/ad.h \ + src/shared/ad.c src/shared/att-types.h src/shared/att.h \ + src/shared/att.c src/shared/gatt-helpers.h \ + src/shared/gatt-helpers.c src/shared/gatt-client.h \ + src/shared/gatt-client.c src/shared/gatt-server.h \ + src/shared/gatt-server.c src/shared/gatt-db.h \ + src/shared/gatt-db.c src/shared/gap.h src/shared/gap.c \ + src/shared/log.h src/shared/log.c src/shared/bap.h \ + src/shared/bap.c src/shared/ascs.h src/shared/bap-debug.h \ + src/shared/bap-debug.c src/shared/mcs.h src/shared/mcp.h \ + src/shared/mcp.c src/shared/vcp.c src/shared/vcp.h \ + src/shared/micp.c src/shared/micp.h src/shared/csip.c \ + src/shared/csip.h src/shared/bass.h src/shared/bass.c \ + src/shared/ccp.h src/shared/ccp.c src/shared/lc3.h \ + src/shared/tty.h src/shared/bap-defs.h src/shared/asha.h \ + src/shared/asha.c $(am__append_5) +src_libshared_glib_la_SOURCES = $(shared_sources) \ + src/shared/io-glib.c \ + src/shared/timeout-glib.c \ + src/shared/mainloop-glib.c \ + src/shared/mainloop-notify.h \ + src/shared/mainloop-notify.c \ + src/shared/tester.c + +src_libshared_glib_la_LDFLAGS = $(AM_LDFLAGS) +src_libshared_glib_la_CFLAGS = $(AM_CFLAGS) +src_libshared_mainloop_la_SOURCES = $(shared_sources) \ + src/shared/io-mainloop.c \ + src/shared/timeout-mainloop.c \ + src/shared/mainloop.h src/shared/mainloop.c \ + src/shared/mainloop-notify.h \ + src/shared/mainloop-notify.c + +src_libshared_mainloop_la_LDFLAGS = $(AM_LDFLAGS) +src_libshared_mainloop_la_CFLAGS = $(AM_CFLAGS) +@LIBSHARED_ELL_TRUE@src_libshared_ell_la_SOURCES = $(shared_sources) \ +@LIBSHARED_ELL_TRUE@ src/shared/io-ell.c \ +@LIBSHARED_ELL_TRUE@ src/shared/timeout-ell.c \ +@LIBSHARED_ELL_TRUE@ src/shared/mainloop.h \ +@LIBSHARED_ELL_TRUE@ src/shared/mainloop-ell.c + +@LIBSHARED_ELL_TRUE@src_libshared_ell_la_LDFLAGS = $(AM_LDFLAGS) +@LIBSHARED_ELL_TRUE@src_libshared_ell_la_CFLAGS = $(AM_CFLAGS) +attrib_sources = attrib/att.h attrib/att-database.h attrib/att.c \ + attrib/gatt.h attrib/gatt.c \ + attrib/gattrib.h attrib/gattrib.c + +btio_sources = btio/btio.h btio/btio.c +gobex_sources = gobex/gobex.h gobex/gobex.c \ + gobex/gobex-defs.h gobex/gobex-defs.c \ + gobex/gobex-packet.c gobex/gobex-packet.h \ + gobex/gobex-header.c gobex/gobex-header.h \ + gobex/gobex-transfer.c gobex/gobex-debug.h \ + gobex/gobex-apparam.c gobex/gobex-apparam.h + + +# SPDX-License-Identifier: GPL-2.0 +builtin_modules = hostname wiimote autopair policy $(am__append_6) \ + $(am__append_8) $(am__append_10) $(am__append_12) \ + $(am__append_14) $(am__append_16) $(am__append_18) \ + $(am__append_20) $(am__append_22) gap scanparam deviceinfo \ + $(am__append_24) battery $(am__append_28) $(am__append_31) \ + $(am__append_33) $(am__append_35) $(am__append_37) \ + $(am__append_39) $(am__append_41) $(am__append_43) \ + $(am__append_45) +builtin_sources = plugins/hostname.c plugins/wiimote.c \ + plugins/autopair.c plugins/policy.c $(am__append_7) \ + $(am__append_9) $(am__append_11) $(am__append_13) \ + $(am__append_15) $(am__append_17) $(am__append_19) \ + $(am__append_21) $(am__append_23) profiles/gap/gas.c \ + profiles/scanparam/scan.c profiles/deviceinfo/deviceinfo.c \ + $(am__append_25) profiles/battery/battery.c $(am__append_29) \ + $(am__append_32) $(am__append_34) $(am__append_36) \ + $(am__append_38) $(am__append_40) $(am__append_42) \ + $(am__append_44) $(am__append_46) +builtin_cppflags = $(am__append_26) +builtin_ldadd = $(am__append_27) $(am__append_30) +src_bluetoothd_SOURCES = $(builtin_sources) $(attrib_sources) \ + $(btio_sources) src/main.c src/log.h src/log.c src/backtrace.h \ + src/backtrace.c src/rfkill.c src/btd.h src/sdpd.h \ + src/sdpd-server.c src/sdpd-request.c src/sdpd-service.c \ + src/sdpd-database.c src/gatt-database.h src/gatt-database.c \ + src/sdp-xml.h src/sdp-xml.c src/sdp-client.h src/sdp-client.c \ + src/textfile.h src/textfile.c src/uuid-helper.h \ + src/uuid-helper.c src/plugin.h src/plugin.c src/storage.h \ + src/storage.c src/advertising.h src/advertising.c src/agent.h \ + src/agent.c src/error.h src/error.c src/adapter.h \ + src/adapter.c src/profile.h src/profile.c src/service.h \ + src/service.c src/gatt-client.h src/gatt-client.c src/device.h \ + src/device.c src/dbus-common.c src/dbus-common.h src/eir.h \ + src/eir.c src/adv_monitor.h src/adv_monitor.c src/battery.h \ + src/battery.c src/settings.h src/settings.c src/set.h \ + src/set.c $(am__append_47) +src_bluetoothd_LDADD = lib/libbluetooth-internal.la \ + gdbus/libgdbus-internal.la \ + src/libshared-glib.la \ + $(BACKTRACE_LIBS) $(GLIB_LIBS) $(DBUS_LIBS) -ldl -lrt \ + $(builtin_ldadd) + +@EXTERNAL_PLUGINS_TRUE@src_bluetoothd_LDFLAGS = $(AM_LDFLAGS) -Wl,--export-dynamic \ +@EXTERNAL_PLUGINS_TRUE@ -Wl,--version-script=$(srcdir)/src/bluetooth.ver + +src_bluetoothd_CPPFLAGS = $(AM_CPPFLAGS) -DBLUETOOTH_PLUGIN_BUILTIN \ + -DPLUGINDIR=\""$(build_plugindir)"\" \ + $(BACKTRACE_CFLAGS) $(builtin_cppflags) + +src_bluetoothd_SHORTNAME = bluetoothd +builtin_files = src/builtin.h +nodist_src_bluetoothd_SOURCES = $(builtin_files) +test_scripts = test/sap_client.py test/bluezutils.py test/dbusdef.py \ + test/monitor-bluetooth test/list-devices test/test-discovery \ + test/test-manager test/test-adapter test/test-device \ + test/simple-agent test/simple-endpoint test/test-sap-server \ + test/test-network test/test-profile test/test-health \ + test/test-health-sink test/service-record.dtd \ + test/service-did.xml test/service-spp.xml test/service-opp.xml \ + test/service-ftp.xml test/simple-player test/test-nap \ + test/test-hfp test/opp-client test/ftp-client test/pbap-client \ + test/map-client test/example-advertisement \ + test/example-gatt-server test/example-gatt-client \ + test/test-gatt-profile test/test-mesh test/agent.py +unit_tests = $(am__append_75) unit/test-tester unit/test-eir \ + unit/test-uuid unit/test-textfile unit/test-crc \ + unit/test-crypto unit/test-ecc unit/test-ringbuf \ + unit/test-queue unit/test-mgmt unit/test-uhid unit/test-sdp \ + unit/test-avdtp unit/test-avctp unit/test-avrcp unit/test-hfp \ + unit/test-gdbus-client $(am__append_84) unit/test-lib \ + unit/test-gatt unit/test-hog unit/test-gattrib unit/test-bap \ + unit/test-micp unit/test-bass unit/test-vcp $(am__append_85) \ + $(am__append_86) +@CLIENT_TRUE@client_bluetoothctl_SOURCES = client/main.c \ +@CLIENT_TRUE@ client/print.h client/print.c \ +@CLIENT_TRUE@ client/display.h client/display.c \ +@CLIENT_TRUE@ client/agent.h client/agent.c \ +@CLIENT_TRUE@ client/advertising.h \ +@CLIENT_TRUE@ client/advertising.c \ +@CLIENT_TRUE@ client/adv_monitor.h \ +@CLIENT_TRUE@ client/adv_monitor.c \ +@CLIENT_TRUE@ client/gatt.h client/gatt.c \ +@CLIENT_TRUE@ client/admin.h client/admin.c \ +@CLIENT_TRUE@ client/player.h client/player.c \ +@CLIENT_TRUE@ client/mgmt.h client/mgmt.c \ +@CLIENT_TRUE@ client/assistant.h client/assistant.c + +@CLIENT_TRUE@client_bluetoothctl_LDADD = lib/libbluetooth-internal.la \ +@CLIENT_TRUE@ gdbus/libgdbus-internal.la src/libshared-glib.la \ +@CLIENT_TRUE@ $(GLIB_LIBS) $(DBUS_LIBS) -lreadline + +@ZSH_COMPLETIONS_TRUE@zshcompletiondir = $(ZSH_COMPLETIONDIR) +@ZSH_COMPLETIONS_TRUE@dist_zshcompletion_DATA = completion/zsh/_bluetoothctl +@MONITOR_TRUE@monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \ +@MONITOR_TRUE@ monitor/display.h monitor/display.c \ +@MONITOR_TRUE@ monitor/hcidump.h monitor/hcidump.c \ +@MONITOR_TRUE@ monitor/ellisys.h monitor/ellisys.c \ +@MONITOR_TRUE@ monitor/control.h monitor/control.c \ +@MONITOR_TRUE@ monitor/packet.h monitor/packet.c \ +@MONITOR_TRUE@ monitor/vendor.h monitor/vendor.c \ +@MONITOR_TRUE@ monitor/lmp.h monitor/lmp.c \ +@MONITOR_TRUE@ monitor/crc.h monitor/crc.c \ +@MONITOR_TRUE@ monitor/ll.h monitor/ll.c \ +@MONITOR_TRUE@ monitor/l2cap.h monitor/l2cap.c \ +@MONITOR_TRUE@ monitor/sdp.h monitor/sdp.c \ +@MONITOR_TRUE@ monitor/avctp.h monitor/avctp.c \ +@MONITOR_TRUE@ monitor/avdtp.h monitor/avdtp.c \ +@MONITOR_TRUE@ monitor/a2dp.h monitor/a2dp.c \ +@MONITOR_TRUE@ monitor/rfcomm.h monitor/rfcomm.c \ +@MONITOR_TRUE@ monitor/bnep.h monitor/bnep.c \ +@MONITOR_TRUE@ monitor/hwdb.h monitor/hwdb.c \ +@MONITOR_TRUE@ monitor/keys.h monitor/keys.c \ +@MONITOR_TRUE@ monitor/analyze.h monitor/analyze.c \ +@MONITOR_TRUE@ monitor/intel.h monitor/intel.c \ +@MONITOR_TRUE@ monitor/broadcom.h monitor/broadcom.c \ +@MONITOR_TRUE@ monitor/msft.h monitor/msft.c \ +@MONITOR_TRUE@ monitor/jlink.h monitor/jlink.c \ +@MONITOR_TRUE@ monitor/tty.h monitor/emulator.h \ +@MONITOR_TRUE@ monitor/att.h monitor/att.c \ +@MONITOR_TRUE@ src/log.h src/log.c \ +@MONITOR_TRUE@ src/textfile.h src/textfile.c \ +@MONITOR_TRUE@ src/settings.h src/settings.c + +@MONITOR_TRUE@monitor_btmon_LDADD = lib/libbluetooth-internal.la \ +@MONITOR_TRUE@ src/libshared-mainloop.la \ +@MONITOR_TRUE@ $(GLIB_LIBS) $(UDEV_LIBS) -ldl + +@LOGGER_TRUE@tools_btmon_logger_SOURCES = tools/btmon-logger.c +@LOGGER_TRUE@tools_btmon_logger_LDADD = src/libshared-mainloop.la +@TESTING_TRUE@emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \ +@TESTING_TRUE@ emulator/serial.h emulator/serial.c \ +@TESTING_TRUE@ emulator/server.h emulator/server.c \ +@TESTING_TRUE@ emulator/vhci.h emulator/vhci.c \ +@TESTING_TRUE@ emulator/btdev.h emulator/btdev.c \ +@TESTING_TRUE@ emulator/bthost.h emulator/bthost.c \ +@TESTING_TRUE@ emulator/smp.c \ +@TESTING_TRUE@ emulator/phy.h emulator/phy.c \ +@TESTING_TRUE@ emulator/amp.h emulator/amp.c \ +@TESTING_TRUE@ emulator/le.h emulator/le.c + +@TESTING_TRUE@emulator_btvirt_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la +@TESTING_TRUE@emulator_b1ee_SOURCES = emulator/b1ee.c +@TESTING_TRUE@emulator_b1ee_LDADD = src/libshared-mainloop.la +@TESTING_TRUE@emulator_hfp_SOURCES = emulator/hfp.c +@TESTING_TRUE@emulator_hfp_LDADD = src/libshared-mainloop.la +@TESTING_TRUE@peripheral_btsensor_SOURCES = peripheral/main.c \ +@TESTING_TRUE@ peripheral/efivars.h peripheral/efivars.c \ +@TESTING_TRUE@ peripheral/attach.h peripheral/attach.c \ +@TESTING_TRUE@ peripheral/log.h peripheral/log.c \ +@TESTING_TRUE@ peripheral/gap.h peripheral/gap.c \ +@TESTING_TRUE@ peripheral/gatt.h peripheral/gatt.c + +@TESTING_TRUE@peripheral_btsensor_LDADD = src/libshared-mainloop.la \ +@TESTING_TRUE@ lib/libbluetooth-internal.la + +@TESTING_TRUE@tools_3dsp_SOURCES = tools/3dsp.c monitor/bt.h +@TESTING_TRUE@tools_3dsp_LDADD = src/libshared-mainloop.la +@TESTING_TRUE@tools_mgmt_tester_SOURCES = tools/mgmt-tester.c monitor/bt.h \ +@TESTING_TRUE@ emulator/hciemu.h emulator/hciemu.c \ +@TESTING_TRUE@ emulator/vhci.h emulator/vhci.c \ +@TESTING_TRUE@ emulator/btdev.h emulator/btdev.c \ +@TESTING_TRUE@ emulator/bthost.h emulator/bthost.c \ +@TESTING_TRUE@ emulator/smp.c + +@TESTING_TRUE@tools_mgmt_tester_LDADD = lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(GLIB_LIBS) + +@TESTING_TRUE@tools_mesh_tester_SOURCES = tools/mesh-tester.c monitor/bt.h \ +@TESTING_TRUE@ emulator/hciemu.h emulator/hciemu.c \ +@TESTING_TRUE@ emulator/vhci.h emulator/vhci.c \ +@TESTING_TRUE@ emulator/btdev.h emulator/btdev.c \ +@TESTING_TRUE@ emulator/bthost.h emulator/bthost.c \ +@TESTING_TRUE@ emulator/smp.c + +@TESTING_TRUE@tools_mesh_tester_LDADD = lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(GLIB_LIBS) + +@TESTING_TRUE@tools_l2cap_tester_SOURCES = tools/l2cap-tester.c tools/tester.h monitor/bt.h \ +@TESTING_TRUE@ emulator/hciemu.h emulator/hciemu.c \ +@TESTING_TRUE@ emulator/vhci.h emulator/vhci.c \ +@TESTING_TRUE@ emulator/btdev.h emulator/btdev.c \ +@TESTING_TRUE@ emulator/bthost.h emulator/bthost.c \ +@TESTING_TRUE@ emulator/smp.c + +@TESTING_TRUE@tools_l2cap_tester_LDADD = lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(GLIB_LIBS) + +@TESTING_TRUE@tools_rfcomm_tester_SOURCES = tools/rfcomm-tester.c monitor/bt.h \ +@TESTING_TRUE@ emulator/hciemu.h emulator/hciemu.c \ +@TESTING_TRUE@ emulator/vhci.h emulator/vhci.c \ +@TESTING_TRUE@ emulator/btdev.h emulator/btdev.c \ +@TESTING_TRUE@ emulator/bthost.h emulator/bthost.c \ +@TESTING_TRUE@ emulator/smp.c + +@TESTING_TRUE@tools_rfcomm_tester_LDADD = lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(GLIB_LIBS) + +@TESTING_TRUE@tools_bnep_tester_SOURCES = tools/bnep-tester.c monitor/bt.h \ +@TESTING_TRUE@ emulator/hciemu.h emulator/hciemu.c \ +@TESTING_TRUE@ emulator/vhci.h emulator/vhci.c \ +@TESTING_TRUE@ emulator/btdev.h emulator/btdev.c \ +@TESTING_TRUE@ emulator/bthost.h emulator/bthost.c \ +@TESTING_TRUE@ emulator/smp.c + +@TESTING_TRUE@tools_bnep_tester_LDADD = lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(GLIB_LIBS) + +@TESTING_TRUE@tools_smp_tester_SOURCES = tools/smp-tester.c monitor/bt.h \ +@TESTING_TRUE@ emulator/hciemu.h emulator/hciemu.c \ +@TESTING_TRUE@ emulator/vhci.h emulator/vhci.c \ +@TESTING_TRUE@ emulator/btdev.h emulator/btdev.c \ +@TESTING_TRUE@ emulator/bthost.h emulator/bthost.c \ +@TESTING_TRUE@ emulator/smp.c + +@TESTING_TRUE@tools_smp_tester_LDADD = lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(GLIB_LIBS) + +@TESTING_TRUE@tools_gap_tester_SOURCES = tools/gap-tester.c monitor/bt.h \ +@TESTING_TRUE@ emulator/hciemu.h emulator/hciemu.c \ +@TESTING_TRUE@ emulator/vhci.h emulator/vhci.c \ +@TESTING_TRUE@ emulator/btdev.h emulator/btdev.c \ +@TESTING_TRUE@ emulator/bthost.h emulator/bthost.c \ +@TESTING_TRUE@ emulator/smp.c + +@TESTING_TRUE@tools_gap_tester_LDADD = lib/libbluetooth-internal.la \ +@TESTING_TRUE@ gdbus/libgdbus-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la \ +@TESTING_TRUE@ $(GLIB_LIBS) $(DBUS_LIBS) + +@TESTING_TRUE@tools_sco_tester_SOURCES = tools/sco-tester.c tools/tester.h monitor/bt.h \ +@TESTING_TRUE@ emulator/hciemu.h emulator/hciemu.c \ +@TESTING_TRUE@ emulator/vhci.h emulator/vhci.c \ +@TESTING_TRUE@ emulator/btdev.h emulator/btdev.c \ +@TESTING_TRUE@ emulator/bthost.h emulator/bthost.c \ +@TESTING_TRUE@ emulator/smp.c + +@TESTING_TRUE@tools_sco_tester_LDADD = lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(GLIB_LIBS) + +@TESTING_TRUE@tools_hci_tester_SOURCES = tools/hci-tester.c monitor/bt.h +@TESTING_TRUE@tools_hci_tester_LDADD = src/libshared-glib.la $(GLIB_LIBS) +@TESTING_TRUE@tools_userchan_tester_SOURCES = tools/userchan-tester.c monitor/bt.h \ +@TESTING_TRUE@ emulator/hciemu.h emulator/hciemu.c \ +@TESTING_TRUE@ emulator/vhci.h emulator/vhci.c \ +@TESTING_TRUE@ emulator/btdev.h emulator/btdev.c \ +@TESTING_TRUE@ emulator/bthost.h emulator/bthost.c \ +@TESTING_TRUE@ emulator/smp.c + +@TESTING_TRUE@tools_userchan_tester_LDADD = lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(GLIB_LIBS) + +@TESTING_TRUE@tools_iso_tester_SOURCES = tools/iso-tester.c tools/tester.h monitor/bt.h \ +@TESTING_TRUE@ emulator/hciemu.h emulator/hciemu.c \ +@TESTING_TRUE@ emulator/vhci.h emulator/vhci.c \ +@TESTING_TRUE@ emulator/btdev.h emulator/btdev.c \ +@TESTING_TRUE@ emulator/bthost.h emulator/bthost.c \ +@TESTING_TRUE@ emulator/smp.c + +@TESTING_TRUE@tools_iso_tester_LDADD = lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(GLIB_LIBS) + +@TESTING_TRUE@tools_ioctl_tester_SOURCES = tools/ioctl-tester.c monitor/bt.h \ +@TESTING_TRUE@ emulator/hciemu.h emulator/hciemu.c \ +@TESTING_TRUE@ emulator/vhci.h emulator/vhci.c \ +@TESTING_TRUE@ emulator/btdev.h emulator/btdev.c \ +@TESTING_TRUE@ emulator/bthost.h emulator/bthost.c \ +@TESTING_TRUE@ emulator/smp.c + +@TESTING_TRUE@tools_ioctl_tester_LDADD = lib/libbluetooth-internal.la \ +@TESTING_TRUE@ src/libshared-glib.la $(GLIB_LIBS) + +@TOOLS_TRUE@tools_bdaddr_SOURCES = tools/bdaddr.c src/oui.h src/oui.c +@TOOLS_TRUE@tools_bdaddr_LDADD = lib/libbluetooth-internal.la $(UDEV_LIBS) +@TOOLS_TRUE@tools_avinfo_LDADD = lib/libbluetooth-internal.la +@TOOLS_TRUE@tools_avtest_LDADD = lib/libbluetooth-internal.la +@TOOLS_TRUE@tools_scotest_LDADD = lib/libbluetooth-internal.la +@TOOLS_TRUE@tools_amptest_LDADD = lib/libbluetooth-internal.la +@TOOLS_TRUE@tools_hwdb_LDADD = lib/libbluetooth-internal.la +@TOOLS_TRUE@tools_hcieventmask_LDADD = lib/libbluetooth-internal.la +@TOOLS_TRUE@tools_btinfo_SOURCES = tools/btinfo.c monitor/bt.h +@TOOLS_TRUE@tools_btinfo_LDADD = src/libshared-mainloop.la +@TOOLS_TRUE@tools_btattach_SOURCES = tools/btattach.c monitor/bt.h +@TOOLS_TRUE@tools_btattach_LDADD = src/libshared-mainloop.la +@TOOLS_TRUE@tools_btconfig_SOURCES = tools/btconfig.c +@TOOLS_TRUE@tools_btconfig_LDADD = src/libshared-mainloop.la +@TOOLS_TRUE@tools_btsnoop_SOURCES = tools/btsnoop.c +@TOOLS_TRUE@tools_btsnoop_LDADD = src/libshared-mainloop.la +@TOOLS_TRUE@tools_btproxy_SOURCES = tools/btproxy.c monitor/bt.h +@TOOLS_TRUE@tools_btproxy_LDADD = src/libshared-mainloop.la +@TOOLS_TRUE@tools_btiotest_SOURCES = tools/btiotest.c btio/btio.h btio/btio.c +@TOOLS_TRUE@tools_btiotest_LDADD = lib/libbluetooth-internal.la $(GLIB_LIBS) +@TOOLS_TRUE@tools_mcaptest_SOURCES = tools/mcaptest.c \ +@TOOLS_TRUE@ btio/btio.h btio/btio.c \ +@TOOLS_TRUE@ src/log.c src/log.h \ +@TOOLS_TRUE@ profiles/health/mcap.h profiles/health/mcap.c + +@TOOLS_TRUE@tools_mcaptest_LDADD = lib/libbluetooth-internal.la $(GLIB_LIBS) \ +@TOOLS_TRUE@ src/libshared-mainloop.la -lrt + +@TOOLS_TRUE@tools_bneptest_SOURCES = tools/bneptest.c \ +@TOOLS_TRUE@ btio/btio.h btio/btio.c \ +@TOOLS_TRUE@ src/log.h src/log.c \ +@TOOLS_TRUE@ profiles/network/bnep.h profiles/network/bnep.c + +@TOOLS_TRUE@tools_bneptest_LDADD = lib/libbluetooth-internal.la $(GLIB_LIBS) \ +@TOOLS_TRUE@ src/libshared-mainloop.la + +@TOOLS_TRUE@tools_cltest_SOURCES = tools/cltest.c +@TOOLS_TRUE@tools_cltest_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la +@TOOLS_TRUE@tools_oobtest_SOURCES = tools/oobtest.c +@TOOLS_TRUE@tools_oobtest_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la +@TOOLS_TRUE@tools_advtest_SOURCES = tools/advtest.c +@TOOLS_TRUE@tools_advtest_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la +@TOOLS_TRUE@tools_seq2bseq_SOURCES = tools/seq2bseq.c +@TOOLS_TRUE@tools_nokfw_SOURCES = tools/nokfw.c +@TOOLS_TRUE@tools_rtlfw_SOURCES = tools/rtlfw.c +@TOOLS_TRUE@tools_create_image_SOURCES = tools/create-image.c +@TOOLS_TRUE@tools_eddystone_SOURCES = tools/eddystone.c monitor/bt.h +@TOOLS_TRUE@tools_eddystone_LDADD = src/libshared-mainloop.la +@TOOLS_TRUE@tools_ibeacon_SOURCES = tools/ibeacon.c monitor/bt.h +@TOOLS_TRUE@tools_ibeacon_LDADD = src/libshared-mainloop.la +@TOOLS_TRUE@tools_btgatt_client_SOURCES = tools/btgatt-client.c src/uuid-helper.c +@TOOLS_TRUE@tools_btgatt_client_LDADD = src/libshared-mainloop.la \ +@TOOLS_TRUE@ lib/libbluetooth-internal.la + +@TOOLS_TRUE@tools_btgatt_server_SOURCES = tools/btgatt-server.c src/uuid-helper.c +@TOOLS_TRUE@tools_btgatt_server_LDADD = src/libshared-mainloop.la \ +@TOOLS_TRUE@ lib/libbluetooth-internal.la + +@TOOLS_TRUE@tools_rctest_LDADD = lib/libbluetooth-internal.la +@TOOLS_TRUE@tools_l2test_LDADD = lib/libbluetooth-internal.la +@TOOLS_TRUE@tools_l2ping_LDADD = lib/libbluetooth-internal.la +@TOOLS_TRUE@tools_bluemoon_SOURCES = tools/bluemoon.c monitor/bt.h +@TOOLS_TRUE@tools_bluemoon_LDADD = src/libshared-mainloop.la +@TOOLS_TRUE@tools_hex2hcd_SOURCES = tools/hex2hcd.c tools/missing.h +@TOOLS_TRUE@tools_mpris_proxy_SOURCES = tools/mpris-proxy.c +@TOOLS_TRUE@tools_mpris_proxy_LDADD = gdbus/libgdbus-internal.la $(GLIB_LIBS) $(DBUS_LIBS) +@TOOLS_TRUE@tools_gatt_service_SOURCES = tools/gatt-service.c +@TOOLS_TRUE@tools_gatt_service_LDADD = gdbus/libgdbus-internal.la \ +@TOOLS_TRUE@ src/libshared-mainloop.la $(GLIB_LIBS) $(DBUS_LIBS) + +@TOOLS_TRUE@tools_isotest_LDADD = lib/libbluetooth-internal.la +@TOOLS_TRUE@profiles_iap_iapd_SOURCES = profiles/iap/main.c +@TOOLS_TRUE@profiles_iap_iapd_LDADD = gdbus/libgdbus-internal.la $(GLIB_LIBS) $(DBUS_LIBS) +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@tools_meshctl_SOURCES = tools/meshctl.c \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh/agent.h tools/mesh/agent.c \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh/config-model.h\ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/mesh-net.h \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/node.h tools/mesh-gatt/node.c \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/gatt.h tools/mesh-gatt/gatt.c \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/crypto.h\ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/crypto.c \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/keys.h \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/net.h tools/mesh-gatt/net.c \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/prov.h tools/mesh-gatt/prov.c \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/util.h tools/mesh-gatt/util.c \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/prov-db.h \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/prov-db.c \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/config-client.c \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/config-server.c \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/onoff-model.h \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ tools/mesh-gatt/onoff-model.c + +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@tools_meshctl_LDADD = gdbus/libgdbus-internal.la src/libshared-glib.la \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ lib/libbluetooth-internal.la \ +@DEPRECATED_TRUE@@MESH_TRUE@@TOOLS_TRUE@ $(GLIB_LIBS) $(DBUS_LIBS) -ljson-c -lreadline + +@MESH_TRUE@@TOOLS_TRUE@tools_mesh_cfgclient_SOURCES = tools/mesh-cfgclient.c \ +@MESH_TRUE@@TOOLS_TRUE@ tools/mesh/model.h tools/mesh/config-model.h \ +@MESH_TRUE@@TOOLS_TRUE@ tools/mesh/cfgcli.h tools/mesh/cfgcli.c \ +@MESH_TRUE@@TOOLS_TRUE@ tools/mesh/keys.h tools/mesh/keys.c \ +@MESH_TRUE@@TOOLS_TRUE@ tools/mesh/util.h tools/mesh/util.c \ +@MESH_TRUE@@TOOLS_TRUE@ tools/mesh/remote.h tools/mesh/remote.c \ +@MESH_TRUE@@TOOLS_TRUE@ tools/mesh/agent.h tools/mesh/agent.c \ +@MESH_TRUE@@TOOLS_TRUE@ tools/mesh/mesh-db.h tools/mesh/mesh-db.c \ +@MESH_TRUE@@TOOLS_TRUE@ mesh/util.h mesh/util.c \ +@MESH_TRUE@@TOOLS_TRUE@ mesh/crypto.h mesh/crypto.c + +@MESH_TRUE@@TOOLS_TRUE@tools_mesh_cfgclient_LDADD = lib/libbluetooth-internal.la src/libshared-ell.la \ +@MESH_TRUE@@TOOLS_TRUE@ $(ell_ldadd) -ljson-c -lreadline + +@MESH_TRUE@@TOOLS_TRUE@tools_mesh_cfgtest_SOURCES = tools/mesh-cfgtest.c +@MESH_TRUE@@TOOLS_TRUE@tools_mesh_cfgtest_LDADD = lib/libbluetooth-internal.la src/libshared-ell.la \ +@MESH_TRUE@@TOOLS_TRUE@ $(ell_ldadd) + +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hciattach_st.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hciattach_ti.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hciattach_tialt.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hciattach_ath3k.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hciattach_qualcomm.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hciattach_intel.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/hciattach_bcm43xx.c + +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_hciattach_LDADD = lib/libbluetooth-internal.la +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_hciconfig_SOURCES = tools/hciconfig.c +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_hciconfig_LDADD = lib/libbluetooth-internal.la +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_hcitool_SOURCES = tools/hcitool.c src/oui.h src/oui.c +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_hcitool_LDADD = lib/libbluetooth-internal.la $(UDEV_LIBS) +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_hcidump_SOURCES = tools/hcidump.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/parser.h tools/parser/parser.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/lmp.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/hci.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/l2cap.h tools/parser/l2cap.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/amp.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/smp.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/att.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/sdp.h tools/parser/sdp.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/rfcomm.h tools/parser/rfcomm.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/bnep.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/cmtp.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/hidp.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/hcrp.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/avdtp.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/avctp.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/avrcp.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/sap.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/obex.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/capi.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/ppp.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/tcpip.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/ericsson.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/csr.c \ +@DEPRECATED_TRUE@@TOOLS_TRUE@ tools/parser/bpa.c + +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_sdptool_SOURCES = tools/sdptool.c src/sdp-xml.h src/sdp-xml.c +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_sdptool_LDADD = lib/libbluetooth-internal.la $(GLIB_LIBS) +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_ciptool_LDADD = lib/libbluetooth-internal.la +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_hcidump_LDADD = lib/libbluetooth-internal.la +@DEPRECATED_TRUE@@TOOLS_TRUE@tools_rfcomm_LDADD = lib/libbluetooth-internal.la +@HID2HCI_TRUE@udevdir = $(UDEV_DIR) +@HID2HCI_TRUE@tools_hid2hci_LDADD = $(UDEV_LIBS) +@READLINE_TRUE@tools_obex_client_tool_SOURCES = $(gobex_sources) $(btio_sources) \ +@READLINE_TRUE@ tools/obex-client-tool.c + +@READLINE_TRUE@tools_obex_client_tool_LDADD = lib/libbluetooth-internal.la \ +@READLINE_TRUE@ src/libshared-glib.la $(GLIB_LIBS) -lreadline + +@READLINE_TRUE@tools_obex_server_tool_SOURCES = $(gobex_sources) $(btio_sources) \ +@READLINE_TRUE@ tools/obex-server-tool.c + +@READLINE_TRUE@tools_obex_server_tool_LDADD = lib/libbluetooth-internal.la \ +@READLINE_TRUE@ src/libshared-glib.la $(GLIB_LIBS) + +@READLINE_TRUE@tools_bluetooth_player_SOURCES = tools/bluetooth-player.c client/print.c \ +@READLINE_TRUE@ client/player.c + +@READLINE_TRUE@tools_bluetooth_player_LDADD = gdbus/libgdbus-internal.la \ +@READLINE_TRUE@ src/libshared-glib.la \ +@READLINE_TRUE@ $(GLIB_LIBS) $(DBUS_LIBS) -lreadline + +@READLINE_TRUE@tools_obexctl_SOURCES = tools/obexctl.c +@READLINE_TRUE@tools_obexctl_LDADD = gdbus/libgdbus-internal.la src/libshared-glib.la \ +@READLINE_TRUE@ $(GLIB_LIBS) $(DBUS_LIBS) -lreadline + +@READLINE_TRUE@tools_btmgmt_SOURCES = tools/btmgmt.c src/uuid-helper.c client/display.c \ +@READLINE_TRUE@ client/mgmt.c + +@READLINE_TRUE@tools_btmgmt_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la \ +@READLINE_TRUE@ -lreadline + +@DEPRECATED_TRUE@@READLINE_TRUE@attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \ +@DEPRECATED_TRUE@@READLINE_TRUE@ attrib/gattrib.c btio/btio.c \ +@DEPRECATED_TRUE@@READLINE_TRUE@ attrib/gatttool.h attrib/interactive.c \ +@DEPRECATED_TRUE@@READLINE_TRUE@ attrib/utils.c src/log.c client/display.c \ +@DEPRECATED_TRUE@@READLINE_TRUE@ client/display.h + +@DEPRECATED_TRUE@@READLINE_TRUE@attrib_gatttool_LDADD = lib/libbluetooth-internal.la \ +@DEPRECATED_TRUE@@READLINE_TRUE@ src/libshared-glib.la $(GLIB_LIBS) -lreadline + +@CUPS_SERVERBIN_FALSE@@CUPS_TRUE@cupsdir = $(libdir)/cups/backend +@CUPS_SERVERBIN_TRUE@@CUPS_TRUE@cupsdir = $(CUPS_SERVERBIN)/backend +@CUPS_TRUE@profiles_cups_bluetooth_SOURCES = profiles/cups/main.c \ +@CUPS_TRUE@ profiles/cups/cups.h \ +@CUPS_TRUE@ profiles/cups/sdp.c \ +@CUPS_TRUE@ profiles/cups/spp.c \ +@CUPS_TRUE@ profiles/cups/hcrp.c + +@CUPS_TRUE@profiles_cups_bluetooth_LDADD = $(GLIB_LIBS) $(DBUS_LIBS) \ +@CUPS_TRUE@ lib/libbluetooth-internal.la \ +@CUPS_TRUE@ gdbus/libgdbus-internal.la + +@BTPCLIENT_TRUE@tools_btpclient_SOURCES = tools/btpclient.c src/shared/btp.c src/shared/btp.h +@BTPCLIENT_TRUE@tools_btpclient_LDADD = lib/libbluetooth-internal.la \ +@BTPCLIENT_TRUE@ src/libshared-ell.la $(ell_ldadd) + +@BTPCLIENT_TRUE@tools_btpclientctl_SOURCES = tools/btpclientctl.c client/display.c +@BTPCLIENT_TRUE@tools_btpclientctl_LDADD = src/libshared-mainloop.la src/libshared-glib.la \ +@BTPCLIENT_TRUE@ lib/libbluetooth-internal.la -lreadline + +@OBEX_TRUE@@SYSTEMD_TRUE@dbussessionbusdir = $(DBUS_SESSIONBUSDIR) +@OBEX_TRUE@@SYSTEMD_TRUE@dbussessionbus_DATA = obexd/src/org.bluez.obex.service +@OBEX_TRUE@obex_plugindir = $(libdir)/obex/plugins +@OBEX_TRUE@obexd_builtin_modules = filesystem bluetooth \ +@OBEX_TRUE@ $(am__append_68) opp ftp irmc pbap mas mns +@OBEX_TRUE@obexd_builtin_sources = obexd/plugins/filesystem.c \ +@OBEX_TRUE@ obexd/plugins/filesystem.h \ +@OBEX_TRUE@ obexd/plugins/bluetooth.c $(am__append_69) \ +@OBEX_TRUE@ obexd/plugins/opp.c obexd/plugins/ftp.c \ +@OBEX_TRUE@ obexd/plugins/ftp.h obexd/plugins/irmc.c \ +@OBEX_TRUE@ obexd/plugins/pbap.c obexd/plugins/vcard.h \ +@OBEX_TRUE@ obexd/plugins/vcard.c obexd/plugins/phonebook.h \ +@OBEX_TRUE@ obexd/plugins/phonebook-@PLUGIN_PHONEBOOK@.c \ +@OBEX_TRUE@ obexd/plugins/mas.c obexd/src/map_ap.h \ +@OBEX_TRUE@ obexd/plugins/messages.h \ +@OBEX_TRUE@ obexd/plugins/messages-dummy.c obexd/client/mns.c \ +@OBEX_TRUE@ obexd/src/map_ap.h obexd/client/map-event.h +@OBEX_TRUE@obexd_builtin_nodist = +@OBEX_TRUE@obexd_src_obexd_SOURCES = $(btio_sources) $(gobex_sources) \ +@OBEX_TRUE@ $(obexd_builtin_sources) \ +@OBEX_TRUE@ obexd/src/main.c obexd/src/obexd.h \ +@OBEX_TRUE@ obexd/src/plugin.h obexd/src/plugin.c \ +@OBEX_TRUE@ obexd/src/log.h obexd/src/log.c \ +@OBEX_TRUE@ obexd/src/manager.h obexd/src/manager.c \ +@OBEX_TRUE@ obexd/src/obex.h obexd/src/obex.c obexd/src/obex-priv.h \ +@OBEX_TRUE@ obexd/src/mimetype.h obexd/src/mimetype.c \ +@OBEX_TRUE@ obexd/src/service.h obexd/src/service.c \ +@OBEX_TRUE@ obexd/src/transport.h obexd/src/transport.c \ +@OBEX_TRUE@ obexd/src/server.h obexd/src/server.c \ +@OBEX_TRUE@ obexd/client/manager.h obexd/client/manager.c \ +@OBEX_TRUE@ obexd/client/session.h obexd/client/session.c \ +@OBEX_TRUE@ obexd/client/bluetooth.h obexd/client/bluetooth.c \ +@OBEX_TRUE@ obexd/client/sync.h obexd/client/sync.c \ +@OBEX_TRUE@ obexd/client/pbap.h obexd/client/pbap.c \ +@OBEX_TRUE@ obexd/client/ftp.h obexd/client/ftp.c \ +@OBEX_TRUE@ obexd/client/opp.h obexd/client/opp.c \ +@OBEX_TRUE@ obexd/client/map.h obexd/client/map.c \ +@OBEX_TRUE@ obexd/client/bip.h obexd/client/bip.c \ +@OBEX_TRUE@ obexd/client/bip-common.h obexd/client/bip-common.c \ +@OBEX_TRUE@ obexd/client/map-event.h obexd/client/map-event.c \ +@OBEX_TRUE@ obexd/client/transfer.h obexd/client/transfer.c \ +@OBEX_TRUE@ obexd/client/transport.h obexd/client/transport.c \ +@OBEX_TRUE@ obexd/client/driver.h obexd/client/driver.c \ +@OBEX_TRUE@ obexd/src/map_ap.h + +@OBEX_TRUE@obexd_src_obexd_LDADD = lib/libbluetooth-internal.la \ +@OBEX_TRUE@ gdbus/libgdbus-internal.la \ +@OBEX_TRUE@ src/libshared-glib.la \ +@OBEX_TRUE@ $(ICAL_LIBS) $(DBUS_LIBS) $(LIBEBOOK_LIBS) \ +@OBEX_TRUE@ $(LIBEDATASERVER_LIBS) $(GLIB_LIBS) -ldl + +@EXTERNAL_PLUGINS_TRUE@@OBEX_TRUE@obexd_src_obexd_LDFLAGS = $(AM_LDFLAGS) -Wl,--export-dynamic +@OBEX_TRUE@obexd_src_obexd_CPPFLAGS = $(AM_CPPFLAGS) $(GLIB_CFLAGS) $(DBUS_CFLAGS) \ +@OBEX_TRUE@ $(ICAL_CFLAGS) -DOBEX_PLUGIN_BUILTIN \ +@OBEX_TRUE@ -DPLUGINDIR=\""$(obex_plugindir)"\" \ +@OBEX_TRUE@ -D_FILE_OFFSET_BITS=64 \ +@OBEX_TRUE@ -I$(builddir)/obexd/src + +obexd_src_obexd_SHORTNAME = obexd +obexd_builtin_files = obexd/src/builtin.h $(obexd_builtin_nodist) +nodist_obexd_src_obexd_SOURCES = $(obexd_builtin_files) +@ANDROID_TRUE@android_plugindir = $(abs_top_srcdir)/android/.libs +@ANDROID_TRUE@android_system_emulator_SOURCES = android/system-emulator.c +@ANDROID_TRUE@android_system_emulator_LDADD = src/libshared-mainloop.la +@ANDROID_TRUE@android_bluetoothd_snoop_SOURCES = android/bluetoothd-snoop.c src/log.c +@ANDROID_TRUE@android_bluetoothd_snoop_LDADD = src/libshared-mainloop.la $(GLIB_LIBS) +@ANDROID_TRUE@android_bluetoothd_SOURCES = android/main.c \ +@ANDROID_TRUE@ src/log.c \ +@ANDROID_TRUE@ android/hal-msg.h \ +@ANDROID_TRUE@ android/audio-msg.h \ +@ANDROID_TRUE@ android/sco-msg.h \ +@ANDROID_TRUE@ android/utils.h \ +@ANDROID_TRUE@ src/sdpd-database.c src/sdpd-server.c \ +@ANDROID_TRUE@ src/sdpd-service.c src/sdpd-request.c \ +@ANDROID_TRUE@ src/uuid-helper.h src/uuid-helper.c \ +@ANDROID_TRUE@ src/eir.h src/eir.c \ +@ANDROID_TRUE@ android/bluetooth.h android/bluetooth.c \ +@ANDROID_TRUE@ android/hidhost.h android/hidhost.c \ +@ANDROID_TRUE@ profiles/scanparam/scpp.h \ +@ANDROID_TRUE@ profiles/scanparam/scpp.c \ +@ANDROID_TRUE@ profiles/deviceinfo/dis.h \ +@ANDROID_TRUE@ profiles/deviceinfo/dis.c \ +@ANDROID_TRUE@ profiles/battery/bas.h profiles/battery/bas.c \ +@ANDROID_TRUE@ profiles/input/hog-lib.h \ +@ANDROID_TRUE@ profiles/input/hog-lib.c \ +@ANDROID_TRUE@ android/ipc-common.h \ +@ANDROID_TRUE@ android/ipc.h android/ipc.c \ +@ANDROID_TRUE@ android/avdtp.h android/avdtp.c \ +@ANDROID_TRUE@ android/a2dp.h android/a2dp.c \ +@ANDROID_TRUE@ android/a2dp-sink.h android/a2dp-sink.c \ +@ANDROID_TRUE@ android/avctp.h android/avctp.c \ +@ANDROID_TRUE@ android/avrcp.h android/avrcp.c \ +@ANDROID_TRUE@ android/avrcp-lib.h android/avrcp-lib.c \ +@ANDROID_TRUE@ android/socket.h android/socket.c \ +@ANDROID_TRUE@ android/sco.h android/sco.c \ +@ANDROID_TRUE@ android/pan.h android/pan.c \ +@ANDROID_TRUE@ android/handsfree.h android/handsfree.c \ +@ANDROID_TRUE@ android/handsfree-client.c android/handsfree-client.h \ +@ANDROID_TRUE@ android/gatt.h android/gatt.c \ +@ANDROID_TRUE@ android/health.h android/health.c \ +@ANDROID_TRUE@ profiles/health/mcap.h profiles/health/mcap.c \ +@ANDROID_TRUE@ android/map-client.h android/map-client.c \ +@ANDROID_TRUE@ attrib/att.c attrib/att.h \ +@ANDROID_TRUE@ attrib/gatt.c attrib/gatt.h \ +@ANDROID_TRUE@ attrib/gattrib.c attrib/gattrib.h \ +@ANDROID_TRUE@ btio/btio.h btio/btio.c \ +@ANDROID_TRUE@ src/sdp-client.h src/sdp-client.c \ +@ANDROID_TRUE@ profiles/network/bnep.h profiles/network/bnep.c + +@ANDROID_TRUE@android_bluetoothd_LDADD = lib/libbluetooth-internal.la \ +@ANDROID_TRUE@ src/libshared-glib.la $(GLIB_LIBS) + +@ANDROID_TRUE@android_bluetooth_default_la_SOURCES = android/hal.h android/hal-bluetooth.c \ +@ANDROID_TRUE@ android/hal-socket.c \ +@ANDROID_TRUE@ android/hal-hidhost.c \ +@ANDROID_TRUE@ android/hal-health.c \ +@ANDROID_TRUE@ android/hal-pan.c \ +@ANDROID_TRUE@ android/hal-a2dp.c \ +@ANDROID_TRUE@ android/hal-a2dp-sink.c \ +@ANDROID_TRUE@ android/hal-avrcp.c \ +@ANDROID_TRUE@ android/hal-avrcp-ctrl.c \ +@ANDROID_TRUE@ android/hal-handsfree.c \ +@ANDROID_TRUE@ android/hal-handsfree-client.c \ +@ANDROID_TRUE@ android/hal-gatt.c \ +@ANDROID_TRUE@ android/hal-map-client.c \ +@ANDROID_TRUE@ android/hardware/bluetooth.h \ +@ANDROID_TRUE@ android/hardware/bt_av.h \ +@ANDROID_TRUE@ android/hardware/bt_gatt.h \ +@ANDROID_TRUE@ android/hardware/bt_gatt_client.h \ +@ANDROID_TRUE@ android/hardware/bt_gatt_server.h \ +@ANDROID_TRUE@ android/hardware/bt_gatt_types.h \ +@ANDROID_TRUE@ android/hardware/bt_hf.h \ +@ANDROID_TRUE@ android/hardware/bt_hh.h \ +@ANDROID_TRUE@ android/hardware/bt_hl.h \ +@ANDROID_TRUE@ android/hardware/bt_pan.h \ +@ANDROID_TRUE@ android/hardware/bt_rc.h \ +@ANDROID_TRUE@ android/hardware/bt_sock.h \ +@ANDROID_TRUE@ android/hardware/bt_hf_client.h \ +@ANDROID_TRUE@ android/hardware/bt_mce.h \ +@ANDROID_TRUE@ android/hardware/hardware.h \ +@ANDROID_TRUE@ android/cutils/properties.h \ +@ANDROID_TRUE@ android/ipc-common.h \ +@ANDROID_TRUE@ android/hal-log.h \ +@ANDROID_TRUE@ android/hal-ipc.h android/hal-ipc.c \ +@ANDROID_TRUE@ android/hal-utils.h android/hal-utils.c + +@ANDROID_TRUE@android_bluetooth_default_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden +@ANDROID_TRUE@android_bluetooth_default_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/android +@ANDROID_TRUE@android_bluetooth_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \ +@ANDROID_TRUE@ -no-undefined + +@ANDROID_TRUE@android_avdtptest_SOURCES = android/avdtptest.c \ +@ANDROID_TRUE@ src/log.h src/log.c \ +@ANDROID_TRUE@ btio/btio.h btio/btio.c \ +@ANDROID_TRUE@ src/shared/util.h src/shared/util.c \ +@ANDROID_TRUE@ src/shared/queue.h src/shared/queue.c \ +@ANDROID_TRUE@ src/shared/log.h src/shared/log.c \ +@ANDROID_TRUE@ android/avdtp.h android/avdtp.c + +@ANDROID_TRUE@android_avdtptest_CFLAGS = $(AM_CFLAGS) +@ANDROID_TRUE@android_avdtptest_LDADD = lib/libbluetooth-internal.la $(GLIB_LIBS) +@ANDROID_TRUE@android_haltest_SOURCES = android/client/haltest.c \ +@ANDROID_TRUE@ android/client/pollhandler.h \ +@ANDROID_TRUE@ android/client/pollhandler.c \ +@ANDROID_TRUE@ android/client/terminal.h \ +@ANDROID_TRUE@ android/client/terminal.c \ +@ANDROID_TRUE@ android/client/history.h \ +@ANDROID_TRUE@ android/client/history.c \ +@ANDROID_TRUE@ android/client/tabcompletion.c \ +@ANDROID_TRUE@ android/client/if-main.h \ +@ANDROID_TRUE@ android/client/if-av.c \ +@ANDROID_TRUE@ android/client/if-av-sink.c \ +@ANDROID_TRUE@ android/client/if-rc.c \ +@ANDROID_TRUE@ android/client/if-rc-ctrl.c \ +@ANDROID_TRUE@ android/client/if-bt.c \ +@ANDROID_TRUE@ android/client/if-gatt.c \ +@ANDROID_TRUE@ android/client/if-hf.c \ +@ANDROID_TRUE@ android/client/if-hf-client.c \ +@ANDROID_TRUE@ android/client/if-hh.c \ +@ANDROID_TRUE@ android/client/if-pan.c \ +@ANDROID_TRUE@ android/client/if-hl.c \ +@ANDROID_TRUE@ android/client/if-sock.c \ +@ANDROID_TRUE@ android/client/if-audio.c \ +@ANDROID_TRUE@ android/client/if-sco.c \ +@ANDROID_TRUE@ android/client/if-mce.c \ +@ANDROID_TRUE@ android/hardware/hardware.c \ +@ANDROID_TRUE@ android/hal-utils.h android/hal-utils.c + +@ANDROID_TRUE@android_haltest_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/android \ +@ANDROID_TRUE@ -DPLUGINDIR=\""$(android_plugindir)"\" + +@ANDROID_TRUE@android_haltest_LDFLAGS = $(AM_LDFLAGS) -pthread +@ANDROID_TRUE@android_haltest_LDADD = -ldl -lm +@ANDROID_TRUE@android_android_tester_SOURCES = emulator/hciemu.h emulator/hciemu.c \ +@ANDROID_TRUE@ emulator/vhci.h emulator/vhci.c \ +@ANDROID_TRUE@ emulator/btdev.h emulator/btdev.c \ +@ANDROID_TRUE@ emulator/bthost.h emulator/bthost.c \ +@ANDROID_TRUE@ emulator/smp.c \ +@ANDROID_TRUE@ monitor/rfcomm.h \ +@ANDROID_TRUE@ android/hardware/hardware.c \ +@ANDROID_TRUE@ android/tester-bluetooth.c \ +@ANDROID_TRUE@ android/tester-socket.c \ +@ANDROID_TRUE@ android/tester-hidhost.c \ +@ANDROID_TRUE@ android/tester-pan.c \ +@ANDROID_TRUE@ android/tester-hdp.c \ +@ANDROID_TRUE@ android/tester-a2dp.c \ +@ANDROID_TRUE@ android/tester-avrcp.c \ +@ANDROID_TRUE@ android/tester-gatt.c \ +@ANDROID_TRUE@ android/tester-map-client.c \ +@ANDROID_TRUE@ android/tester-main.h android/tester-main.c + +@ANDROID_TRUE@android_android_tester_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/android \ +@ANDROID_TRUE@ -DPLUGINDIR=\""$(android_plugindir)"\" + +@ANDROID_TRUE@android_android_tester_LDADD = lib/libbluetooth-internal.la \ +@ANDROID_TRUE@ src/libshared-glib.la $(GLIB_LIBS) -ldl + +@ANDROID_TRUE@android_android_tester_LDFLAGS = $(AM_LDFLAGS) -pthread +@ANDROID_TRUE@android_ipc_tester_SOURCES = emulator/hciemu.h emulator/hciemu.c \ +@ANDROID_TRUE@ emulator/vhci.h emulator/vhci.c \ +@ANDROID_TRUE@ emulator/btdev.h emulator/btdev.c \ +@ANDROID_TRUE@ emulator/bthost.h emulator/bthost.c \ +@ANDROID_TRUE@ emulator/smp.c \ +@ANDROID_TRUE@ android/hal-utils.h android/hal-utils.c \ +@ANDROID_TRUE@ android/ipc-common.h android/ipc-tester.c + +@ANDROID_TRUE@android_ipc_tester_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/android +@ANDROID_TRUE@android_ipc_tester_LDADD = lib/libbluetooth-internal.la \ +@ANDROID_TRUE@ src/libshared-glib.la $(GLIB_LIBS) + +@ANDROID_TRUE@android_audio_a2dp_default_la_SOURCES = android/audio-msg.h \ +@ANDROID_TRUE@ android/hal-msg.h \ +@ANDROID_TRUE@ android/hal-audio.h \ +@ANDROID_TRUE@ android/hal-audio.c \ +@ANDROID_TRUE@ android/hal-audio-sbc.c \ +@ANDROID_TRUE@ android/hal-audio-aptx.c \ +@ANDROID_TRUE@ android/hardware/audio.h \ +@ANDROID_TRUE@ android/hardware/audio_effect.h \ +@ANDROID_TRUE@ android/hardware/hardware.h \ +@ANDROID_TRUE@ android/system/audio.h + +@ANDROID_TRUE@android_audio_a2dp_default_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden +@ANDROID_TRUE@android_audio_a2dp_default_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/android \ +@ANDROID_TRUE@ $(SBC_CFLAGS) + +@ANDROID_TRUE@android_audio_a2dp_default_la_LIBADD = $(SBC_LIBS) -lrt +@ANDROID_TRUE@android_audio_a2dp_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \ +@ANDROID_TRUE@ -no-undefined -pthread + +@ANDROID_TRUE@android_audio_sco_default_la_SOURCES = android/hal-log.h \ +@ANDROID_TRUE@ android/sco-msg.h \ +@ANDROID_TRUE@ android/hal-sco.c \ +@ANDROID_TRUE@ android/hardware/audio.h \ +@ANDROID_TRUE@ android/hardware/audio_effect.h \ +@ANDROID_TRUE@ android/hardware/hardware.h \ +@ANDROID_TRUE@ android/audio_utils/resampler.c \ +@ANDROID_TRUE@ android/audio_utils/resampler.h \ +@ANDROID_TRUE@ android/system/audio.h + +@ANDROID_TRUE@android_audio_sco_default_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden +@ANDROID_TRUE@android_audio_sco_default_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/android +@ANDROID_TRUE@android_audio_sco_default_la_LIBADD = $(SPEEXDSP_LIBS) -lrt +@ANDROID_TRUE@android_audio_sco_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \ +@ANDROID_TRUE@ -no-undefined + +@ANDROID_TRUE@android_test_ipc_SOURCES = android/test-ipc.c \ +@ANDROID_TRUE@ src/log.h src/log.c \ +@ANDROID_TRUE@ android/ipc-common.h \ +@ANDROID_TRUE@ android/ipc.c android/ipc.h + +@ANDROID_TRUE@android_test_ipc_LDADD = src/libshared-glib.la $(GLIB_LIBS) +@MESH_TRUE@mesh_sources = mesh/mesh.h mesh/mesh.c \ +@MESH_TRUE@ mesh/net-keys.h mesh/net-keys.c \ +@MESH_TRUE@ mesh/mesh-io.h mesh/mesh-io.c \ +@MESH_TRUE@ mesh/mesh-mgmt.h mesh/mesh-mgmt.c \ +@MESH_TRUE@ mesh/error.h mesh/mesh-io-api.h \ +@MESH_TRUE@ mesh/mesh-io-unit.h mesh/mesh-io-unit.c \ +@MESH_TRUE@ mesh/mesh-io-mgmt.h mesh/mesh-io-mgmt.c \ +@MESH_TRUE@ mesh/mesh-io-generic.h mesh/mesh-io-generic.c \ +@MESH_TRUE@ mesh/net.h mesh/net.c \ +@MESH_TRUE@ mesh/crypto.h mesh/crypto.c \ +@MESH_TRUE@ mesh/friend.h mesh/friend.c \ +@MESH_TRUE@ mesh/appkey.h mesh/appkey.c \ +@MESH_TRUE@ mesh/node.h mesh/node.c \ +@MESH_TRUE@ mesh/provision.h mesh/prov.h \ +@MESH_TRUE@ mesh/model.h mesh/model.c \ +@MESH_TRUE@ mesh/cfgmod.h mesh/cfgmod-server.c \ +@MESH_TRUE@ mesh/remprv.h mesh/remprv-server.c \ +@MESH_TRUE@ mesh/mesh-config.h mesh/mesh-config-json.c \ +@MESH_TRUE@ mesh/util.h mesh/util.c \ +@MESH_TRUE@ mesh/dbus.h mesh/dbus.c \ +@MESH_TRUE@ mesh/agent.h mesh/agent.c \ +@MESH_TRUE@ mesh/prov-acceptor.c mesh/prov-initiator.c \ +@MESH_TRUE@ mesh/manager.h mesh/manager.c \ +@MESH_TRUE@ mesh/pb-adv.h mesh/pb-adv.c \ +@MESH_TRUE@ mesh/keyring.h mesh/keyring.c \ +@MESH_TRUE@ mesh/rpl.h mesh/rpl.c \ +@MESH_TRUE@ mesh/prv-beacon.h mesh/prvbeac-server.c \ +@MESH_TRUE@ mesh/mesh-defs.h + +@MESH_TRUE@mesh_bluetooth_meshd_SOURCES = $(mesh_sources) mesh/main.c +@MESH_TRUE@mesh_bluetooth_meshd_LDADD = src/libshared-ell.la $(ell_ldadd) -ljson-c +@HID2HCI_TRUE@rulesdir = $(UDEV_DIR)/rules.d +@HID2HCI_TRUE@rules_DATA = tools/97-hid2hci.rules +@TEST_TRUE@testdir = $(pkglibdir)/test +@TEST_TRUE@test_SCRIPTS = $(test_scripts) +unit_test_tester_SOURCES = unit/test-tester.c +unit_test_tester_LDADD = src/libshared-glib.la lib/libbluetooth-internal.la \ + $(GLIB_LIBS) + +unit_test_eir_SOURCES = unit/test-eir.c src/eir.c src/uuid-helper.c +unit_test_eir_LDADD = src/libshared-glib.la lib/libbluetooth-internal.la \ + $(GLIB_LIBS) + +unit_test_uuid_SOURCES = unit/test-uuid.c +unit_test_uuid_LDADD = src/libshared-glib.la lib/libbluetooth-internal.la \ + $(GLIB_LIBS) + +unit_test_textfile_SOURCES = unit/test-textfile.c src/textfile.h src/textfile.c +unit_test_textfile_LDADD = src/libshared-glib.la $(GLIB_LIBS) +unit_test_crc_SOURCES = unit/test-crc.c monitor/crc.h monitor/crc.c +unit_test_crc_LDADD = src/libshared-glib.la $(GLIB_LIBS) +unit_test_crypto_SOURCES = unit/test-crypto.c +unit_test_crypto_LDADD = src/libshared-glib.la $(GLIB_LIBS) +unit_test_ecc_SOURCES = unit/test-ecc.c +unit_test_ecc_LDADD = src/libshared-glib.la $(GLIB_LIBS) +unit_test_ringbuf_SOURCES = unit/test-ringbuf.c +unit_test_ringbuf_LDADD = src/libshared-glib.la $(GLIB_LIBS) +unit_test_queue_SOURCES = unit/test-queue.c +unit_test_queue_LDADD = src/libshared-glib.la $(GLIB_LIBS) +unit_test_mgmt_SOURCES = unit/test-mgmt.c +unit_test_mgmt_LDADD = src/libshared-glib.la $(GLIB_LIBS) +unit_test_uhid_SOURCES = unit/test-uhid.c +unit_test_uhid_LDADD = src/libshared-glib.la $(GLIB_LIBS) +unit_test_sdp_SOURCES = unit/test-sdp.c \ + src/sdpd.h src/sdpd-database.c \ + src/log.h src/log.c \ + src/sdpd-service.c src/sdpd-request.c + +unit_test_sdp_LDADD = lib/libbluetooth-internal.la \ + src/libshared-glib.la $(GLIB_LIBS) + +unit_test_avdtp_SOURCES = unit/test-avdtp.c \ + src/log.h src/log.c \ + android/avdtp.c android/avdtp.h + +unit_test_avdtp_LDADD = src/libshared-glib.la $(GLIB_LIBS) +unit_test_avctp_SOURCES = unit/test-avctp.c \ + src/log.h src/log.c \ + android/avctp.c android/avctp.h + +unit_test_avctp_LDADD = src/libshared-glib.la $(GLIB_LIBS) +unit_test_avrcp_SOURCES = unit/test-avrcp.c \ + src/log.h src/log.c \ + android/avctp.c android/avctp.h \ + android/avrcp-lib.c android/avrcp-lib.h + +unit_test_avrcp_LDADD = lib/libbluetooth-internal.la \ + src/libshared-glib.la $(GLIB_LIBS) + +unit_test_hfp_SOURCES = unit/test-hfp.c +unit_test_hfp_LDADD = src/libshared-glib.la $(GLIB_LIBS) +unit_test_gdbus_client_SOURCES = unit/test-gdbus-client.c +unit_test_gdbus_client_LDADD = gdbus/libgdbus-internal.la \ + src/libshared-glib.la $(GLIB_LIBS) $(DBUS_LIBS) + +@OBEX_TRUE@unit_test_gobex_SOURCES = $(gobex_sources) unit/util.c unit/util.h \ +@OBEX_TRUE@ unit/test-gobex.c + +@OBEX_TRUE@unit_test_gobex_LDADD = src/libshared-glib.la $(GLIB_LIBS) +@OBEX_TRUE@unit_test_gobex_packet_SOURCES = $(gobex_sources) unit/util.c unit/util.h \ +@OBEX_TRUE@ unit/test-gobex-packet.c + +@OBEX_TRUE@unit_test_gobex_packet_LDADD = src/libshared-glib.la $(GLIB_LIBS) +@OBEX_TRUE@unit_test_gobex_header_SOURCES = $(gobex_sources) unit/util.c unit/util.h \ +@OBEX_TRUE@ unit/test-gobex-header.c + +@OBEX_TRUE@unit_test_gobex_header_LDADD = src/libshared-glib.la $(GLIB_LIBS) +@OBEX_TRUE@unit_test_gobex_transfer_SOURCES = $(gobex_sources) unit/util.c unit/util.h \ +@OBEX_TRUE@ unit/test-gobex-transfer.c + +@OBEX_TRUE@unit_test_gobex_transfer_LDADD = src/libshared-glib.la $(GLIB_LIBS) +@OBEX_TRUE@unit_test_gobex_apparam_SOURCES = $(gobex_sources) unit/util.c unit/util.h \ +@OBEX_TRUE@ unit/test-gobex-apparam.c + +@OBEX_TRUE@unit_test_gobex_apparam_LDADD = src/libshared-glib.la $(GLIB_LIBS) +unit_test_lib_SOURCES = unit/test-lib.c +unit_test_lib_LDADD = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(GLIB_LIBS) + +unit_test_gatt_SOURCES = unit/test-gatt.c +unit_test_gatt_LDADD = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(GLIB_LIBS) + +unit_test_hog_SOURCES = unit/test-hog.c \ + $(btio_sources) \ + profiles/input/hog-lib.h profiles/input/hog-lib.c \ + profiles/scanparam/scpp.h profiles/scanparam/scpp.c \ + profiles/battery/bas.h profiles/battery/bas.c \ + profiles/deviceinfo/dis.h profiles/deviceinfo/dis.c \ + src/log.h src/log.c \ + attrib/att.h attrib/att.c \ + attrib/gatt.h attrib/gatt.c \ + attrib/gattrib.h attrib/gattrib.c + +unit_test_hog_LDADD = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(GLIB_LIBS) + +unit_test_gattrib_SOURCES = unit/test-gattrib.c attrib/gattrib.c \ + $(btio_sources) src/log.h src/log.c + +unit_test_gattrib_LDADD = src/libshared-glib.la \ + lib/libbluetooth-internal.la \ + $(GLIB_LIBS) $(DBUS_LIBS) -ldl -lrt + +unit_test_bap_SOURCES = unit/test-bap.c +unit_test_bap_LDADD = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(GLIB_LIBS) + +unit_test_micp_SOURCES = unit/test-micp.c +unit_test_micp_LDADD = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(GLIB_LIBS) + +unit_test_bass_SOURCES = unit/test-bass.c $(btio_sources) +unit_test_bass_LDADD = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(GLIB_LIBS) + +unit_test_vcp_SOURCES = unit/test-vcp.c $(btio_sources) +unit_test_vcp_LDADD = src/libshared-glib.la \ + lib/libbluetooth-internal.la $(GLIB_LIBS) + +@MIDI_TRUE@unit_test_midi_CPPFLAGS = $(AM_CPPFLAGS) $(ALSA_CFLAGS) -DMIDI_TEST +@MIDI_TRUE@unit_test_midi_SOURCES = unit/test-midi.c \ +@MIDI_TRUE@ profiles/midi/libmidi.h \ +@MIDI_TRUE@ profiles/midi/libmidi.c + +@MIDI_TRUE@unit_test_midi_LDADD = src/libshared-glib.la \ +@MIDI_TRUE@ $(GLIB_LIBS) $(ALSA_LIBS) + +@MESH_TRUE@unit_test_mesh_crypto_CPPFLAGS = $(ell_cflags) +@MESH_TRUE@unit_test_mesh_crypto_SOURCES = unit/test-mesh-crypto.c \ +@MESH_TRUE@ mesh/crypto.h ell/internal ell/ell.h + +@MESH_TRUE@unit_test_mesh_crypto_LDADD = $(ell_ldadd) +AM_TESTS_ENVIRONMENT = MALLOC_CHECK_=3 MALLOC_PERTURB_=69 \ + $(am__append_88) +@VALGRIND_TRUE@LOG_COMPILER = valgrind --error-exitcode=1 --num-callers=30 +@VALGRIND_TRUE@LOG_FLAGS = --trace-children=yes --leak-check=full --show-reachable=no \ +@VALGRIND_TRUE@ --suppressions=$(srcdir)/tools/valgrind.supp --quiet + +pkgconfigdir = $(libdir)/pkgconfig +@LIBRARY_TRUE@pkgconfig_DATA = lib/bluez.pc +DISTCHECK_CONFIGURE_FLAGS = --disable-datafiles --enable-library \ + --enable-health \ + --enable-midi \ + --enable-manpages \ + --enable-android \ + --enable-mesh \ + --enable-btpclient \ + --disable-systemd \ + --disable-udev + +DISTCLEANFILES = $(pkgconfig_DATA) $(unit_tests) $(manual_pages) +MAINTAINERCLEANFILES = Makefile.in \ + aclocal.m4 configure config.h.in config.sub config.guess \ + ltmain.sh depcomp compile missing install-sh mkinstalldirs test-driver + +@RUN_RST2MAN_FALSE@RST2MAN_PROCESS = $(AM_V_GEN)test -f $@ || \ +@RUN_RST2MAN_FALSE@ { echo "Generated manual page $@ does not exist"; false; } + +@RUN_RST2MAN_TRUE@RST2MAN_PROCESS = $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ +@RUN_RST2MAN_TRUE@ $(RST2MAN) --strict --no-raw \ +@RUN_RST2MAN_TRUE@ --no-generator --no-datestamp $< $@ + +all: $(BUILT_SOURCES) config.h + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs +am--refresh: Makefile + @: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile.plugins $(srcdir)/Makefile.tools $(srcdir)/Makefile.obexd $(srcdir)/android/Makefile.am $(srcdir)/Makefile.mesh $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign 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__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ + esac; +$(srcdir)/Makefile.plugins $(srcdir)/Makefile.tools $(srcdir)/Makefile.obexd $(srcdir)/android/Makefile.am $(srcdir)/Makefile.mesh $(am__empty): + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +config.h: stamp-h1 + @test -f $@ || rm -f stamp-h1 + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 + +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) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 +lib/bluez.pc: $(top_builddir)/config.status $(top_srcdir)/lib/bluez.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +mesh/bluetooth-meshd.rst: $(top_builddir)/config.status $(top_srcdir)/mesh/bluetooth-meshd.rst.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +mesh/bluetooth-mesh.service: $(top_builddir)/config.status $(top_srcdir)/mesh/bluetooth-mesh.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +obexd/src/obex.service: $(top_builddir)/config.status $(top_srcdir)/obexd/src/obex.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +obexd/src/org.bluez.obex.service: $(top_builddir)/config.status $(top_srcdir)/obexd/src/org.bluez.obex.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +src/bluetoothd.rst: $(top_builddir)/config.status $(top_srcdir)/src/bluetoothd.rst.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +src/bluetooth.service: $(top_builddir)/config.status $(top_srcdir)/src/bluetooth.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +tools/bluetooth-logger.service: $(top_builddir)/config.status $(top_srcdir)/tools/bluetooth-logger.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +tools/mpris-proxy.service: $(top_builddir)/config.status $(top_srcdir)/tools/mpris-proxy.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-cupsPROGRAMS: $(cups_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(cups_PROGRAMS)'; test -n "$(cupsdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(cupsdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(cupsdir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(cupsdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(cupsdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-cupsPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(cups_PROGRAMS)'; test -n "$(cupsdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(cupsdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(cupsdir)" && rm -f $$files + +clean-cupsPROGRAMS: + @list='$(cups_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-pkglibexecPROGRAMS: $(pkglibexec_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkglibexecdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkglibexecdir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(pkglibexecdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(pkglibexecdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-pkglibexecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkglibexecdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkglibexecdir)" && rm -f $$files + +clean-pkglibexecPROGRAMS: + @list='$(pkglibexec_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-udevPROGRAMS: $(udev_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(udev_PROGRAMS)'; test -n "$(udevdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(udevdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(udevdir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(udevdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(udevdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-udevPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(udev_PROGRAMS)'; test -n "$(udevdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(udevdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(udevdir)" && rm -f $$files + +clean-udevPROGRAMS: + @list='$(udev_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(plugindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(plugindir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } +android/$(am__dirstamp): + @$(MKDIR_P) android + @: > android/$(am__dirstamp) +android/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) android/$(DEPDIR) + @: > android/$(DEPDIR)/$(am__dirstamp) +android/audio_a2dp_default_la-hal-audio.lo: android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/audio_a2dp_default_la-hal-audio-sbc.lo: \ + android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp) +android/audio_a2dp_default_la-hal-audio-aptx.lo: \ + android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp) + +android/audio.a2dp.default.la: $(android_audio_a2dp_default_la_OBJECTS) $(android_audio_a2dp_default_la_DEPENDENCIES) $(EXTRA_android_audio_a2dp_default_la_DEPENDENCIES) android/$(am__dirstamp) + $(AM_V_CCLD)$(android_audio_a2dp_default_la_LINK) $(am_android_audio_a2dp_default_la_rpath) $(android_audio_a2dp_default_la_OBJECTS) $(android_audio_a2dp_default_la_LIBADD) $(LIBS) +android/audio_sco_default_la-hal-sco.lo: android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/audio_utils/$(am__dirstamp): + @$(MKDIR_P) android/audio_utils + @: > android/audio_utils/$(am__dirstamp) +android/audio_utils/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) android/audio_utils/$(DEPDIR) + @: > android/audio_utils/$(DEPDIR)/$(am__dirstamp) +android/audio_utils/audio_sco_default_la-resampler.lo: \ + android/audio_utils/$(am__dirstamp) \ + android/audio_utils/$(DEPDIR)/$(am__dirstamp) + +android/audio.sco.default.la: $(android_audio_sco_default_la_OBJECTS) $(android_audio_sco_default_la_DEPENDENCIES) $(EXTRA_android_audio_sco_default_la_DEPENDENCIES) android/$(am__dirstamp) + $(AM_V_CCLD)$(android_audio_sco_default_la_LINK) $(am_android_audio_sco_default_la_rpath) $(android_audio_sco_default_la_OBJECTS) $(android_audio_sco_default_la_LIBADD) $(LIBS) +android/bluetooth_default_la-hal-bluetooth.lo: \ + android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp) +android/bluetooth_default_la-hal-socket.lo: android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/bluetooth_default_la-hal-hidhost.lo: android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/bluetooth_default_la-hal-health.lo: android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/bluetooth_default_la-hal-pan.lo: android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/bluetooth_default_la-hal-a2dp.lo: android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/bluetooth_default_la-hal-a2dp-sink.lo: \ + android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp) +android/bluetooth_default_la-hal-avrcp.lo: android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/bluetooth_default_la-hal-avrcp-ctrl.lo: \ + android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp) +android/bluetooth_default_la-hal-handsfree.lo: \ + android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp) +android/bluetooth_default_la-hal-handsfree-client.lo: \ + android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp) +android/bluetooth_default_la-hal-gatt.lo: android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/bluetooth_default_la-hal-map-client.lo: \ + android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp) +android/bluetooth_default_la-hal-ipc.lo: android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/bluetooth_default_la-hal-utils.lo: android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) + +android/bluetooth.default.la: $(android_bluetooth_default_la_OBJECTS) $(android_bluetooth_default_la_DEPENDENCIES) $(EXTRA_android_bluetooth_default_la_DEPENDENCIES) android/$(am__dirstamp) + $(AM_V_CCLD)$(android_bluetooth_default_la_LINK) $(am_android_bluetooth_default_la_rpath) $(android_bluetooth_default_la_OBJECTS) $(android_bluetooth_default_la_LIBADD) $(LIBS) +ell/$(am__dirstamp): + @$(MKDIR_P) ell + @: > ell/$(am__dirstamp) +ell/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) ell/$(DEPDIR) + @: > ell/$(DEPDIR)/$(am__dirstamp) +ell/util.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/log.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/queue.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/hashmap.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/random.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/signal.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/time.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/timeout.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/io.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/idle.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/main.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/settings.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/strv.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/string.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/cipher.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/checksum.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/pem.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/cert.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/cert-crypto.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/key.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/base64.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/utf8.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/dbus.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/dbus-message.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/dbus-util.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/dbus-service.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/dbus-client.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/dbus-name-cache.lo: ell/$(am__dirstamp) \ + ell/$(DEPDIR)/$(am__dirstamp) +ell/dbus-filter.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/gvariant-util.lo: ell/$(am__dirstamp) \ + ell/$(DEPDIR)/$(am__dirstamp) +ell/siphash.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/uuid.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/tester.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/tls.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/tls-extensions.lo: ell/$(am__dirstamp) \ + ell/$(DEPDIR)/$(am__dirstamp) +ell/tls-suites.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/tls-record.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/ecc.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/ecc-external.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) +ell/ecdh.lo: ell/$(am__dirstamp) ell/$(DEPDIR)/$(am__dirstamp) + +ell/libell-internal.la: $(ell_libell_internal_la_OBJECTS) $(ell_libell_internal_la_DEPENDENCIES) $(EXTRA_ell_libell_internal_la_DEPENDENCIES) ell/$(am__dirstamp) + $(AM_V_CCLD)$(LINK) $(am_ell_libell_internal_la_rpath) $(ell_libell_internal_la_OBJECTS) $(ell_libell_internal_la_LIBADD) $(LIBS) +gdbus/$(am__dirstamp): + @$(MKDIR_P) gdbus + @: > gdbus/$(am__dirstamp) +gdbus/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) gdbus/$(DEPDIR) + @: > gdbus/$(DEPDIR)/$(am__dirstamp) +gdbus/mainloop.lo: gdbus/$(am__dirstamp) \ + gdbus/$(DEPDIR)/$(am__dirstamp) +gdbus/watch.lo: gdbus/$(am__dirstamp) gdbus/$(DEPDIR)/$(am__dirstamp) +gdbus/object.lo: gdbus/$(am__dirstamp) gdbus/$(DEPDIR)/$(am__dirstamp) +gdbus/client.lo: gdbus/$(am__dirstamp) gdbus/$(DEPDIR)/$(am__dirstamp) +gdbus/polkit.lo: gdbus/$(am__dirstamp) gdbus/$(DEPDIR)/$(am__dirstamp) + +gdbus/libgdbus-internal.la: $(gdbus_libgdbus_internal_la_OBJECTS) $(gdbus_libgdbus_internal_la_DEPENDENCIES) $(EXTRA_gdbus_libgdbus_internal_la_DEPENDENCIES) gdbus/$(am__dirstamp) + $(AM_V_CCLD)$(LINK) $(gdbus_libgdbus_internal_la_OBJECTS) $(gdbus_libgdbus_internal_la_LIBADD) $(LIBS) +lib/$(am__dirstamp): + @$(MKDIR_P) lib + @: > lib/$(am__dirstamp) +lib/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) lib/$(DEPDIR) + @: > lib/$(DEPDIR)/$(am__dirstamp) +lib/bluetooth.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp) +lib/hci.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp) +lib/sdp.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp) +lib/uuid.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp) + +lib/libbluetooth-internal.la: $(lib_libbluetooth_internal_la_OBJECTS) $(lib_libbluetooth_internal_la_DEPENDENCIES) $(EXTRA_lib_libbluetooth_internal_la_DEPENDENCIES) lib/$(am__dirstamp) + $(AM_V_CCLD)$(LINK) $(lib_libbluetooth_internal_la_OBJECTS) $(lib_libbluetooth_internal_la_LIBADD) $(LIBS) + +lib/libbluetooth.la: $(lib_libbluetooth_la_OBJECTS) $(lib_libbluetooth_la_DEPENDENCIES) $(EXTRA_lib_libbluetooth_la_DEPENDENCIES) lib/$(am__dirstamp) + $(AM_V_CCLD)$(lib_libbluetooth_la_LINK) $(am_lib_libbluetooth_la_rpath) $(lib_libbluetooth_la_OBJECTS) $(lib_libbluetooth_la_LIBADD) $(LIBS) +src/shared/$(am__dirstamp): + @$(MKDIR_P) src/shared + @: > src/shared/$(am__dirstamp) +src/shared/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/shared/$(DEPDIR) + @: > src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-queue.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-util.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-mgmt.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-crypto.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-ecc.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-ringbuf.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-hci.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-hci-crypto.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-hfp.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-uhid.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-pcap.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-btsnoop.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-ad.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-att.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-gatt-helpers.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-gatt-client.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-gatt-server.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-gatt-db.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-gap.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-log.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-bap.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-bap-debug.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-mcp.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-vcp.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-micp.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-csip.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-bass.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-ccp.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-asha.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-shell.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-io-ell.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-timeout-ell.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_ell_la-mainloop-ell.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/$(am__dirstamp): + @$(MKDIR_P) src + @: > src/$(am__dirstamp) + +src/libshared-ell.la: $(src_libshared_ell_la_OBJECTS) $(src_libshared_ell_la_DEPENDENCIES) $(EXTRA_src_libshared_ell_la_DEPENDENCIES) src/$(am__dirstamp) + $(AM_V_CCLD)$(src_libshared_ell_la_LINK) $(am_src_libshared_ell_la_rpath) $(src_libshared_ell_la_OBJECTS) $(src_libshared_ell_la_LIBADD) $(LIBS) +src/shared/libshared_glib_la-queue.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-util.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-mgmt.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-crypto.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-ecc.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-ringbuf.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-hci.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-hci-crypto.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-hfp.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-uhid.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-pcap.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-btsnoop.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-ad.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-att.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-gatt-helpers.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-gatt-client.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-gatt-server.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-gatt-db.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-gap.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-log.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-bap.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-bap-debug.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-mcp.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-vcp.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-micp.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-csip.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-bass.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-ccp.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-asha.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-shell.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-io-glib.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-timeout-glib.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-mainloop-glib.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-mainloop-notify.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_glib_la-tester.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) + +src/libshared-glib.la: $(src_libshared_glib_la_OBJECTS) $(src_libshared_glib_la_DEPENDENCIES) $(EXTRA_src_libshared_glib_la_DEPENDENCIES) src/$(am__dirstamp) + $(AM_V_CCLD)$(src_libshared_glib_la_LINK) $(src_libshared_glib_la_OBJECTS) $(src_libshared_glib_la_LIBADD) $(LIBS) +src/shared/libshared_mainloop_la-queue.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-util.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-mgmt.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-crypto.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-ecc.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-ringbuf.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-hci.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-hci-crypto.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-hfp.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-uhid.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-pcap.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-btsnoop.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-ad.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-att.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-gatt-helpers.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-gatt-client.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-gatt-server.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-gatt-db.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-gap.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-log.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-bap.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-bap-debug.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-mcp.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-vcp.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-micp.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-csip.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-bass.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-ccp.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-asha.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-shell.lo: src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-io-mainloop.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-timeout-mainloop.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-mainloop.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/libshared_mainloop_la-mainloop-notify.lo: \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) + +src/libshared-mainloop.la: $(src_libshared_mainloop_la_OBJECTS) $(src_libshared_mainloop_la_DEPENDENCIES) $(EXTRA_src_libshared_mainloop_la_DEPENDENCIES) src/$(am__dirstamp) + $(AM_V_CCLD)$(src_libshared_mainloop_la_LINK) $(src_libshared_mainloop_la_OBJECTS) $(src_libshared_mainloop_la_LIBADD) $(LIBS) +emulator/$(am__dirstamp): + @$(MKDIR_P) emulator + @: > emulator/$(am__dirstamp) +emulator/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) emulator/$(DEPDIR) + @: > emulator/$(DEPDIR)/$(am__dirstamp) +emulator/android_android_tester-hciemu.$(OBJEXT): \ + emulator/$(am__dirstamp) emulator/$(DEPDIR)/$(am__dirstamp) +emulator/android_android_tester-vhci.$(OBJEXT): \ + emulator/$(am__dirstamp) emulator/$(DEPDIR)/$(am__dirstamp) +emulator/android_android_tester-btdev.$(OBJEXT): \ + emulator/$(am__dirstamp) emulator/$(DEPDIR)/$(am__dirstamp) +emulator/android_android_tester-bthost.$(OBJEXT): \ + emulator/$(am__dirstamp) emulator/$(DEPDIR)/$(am__dirstamp) +emulator/android_android_tester-smp.$(OBJEXT): \ + emulator/$(am__dirstamp) emulator/$(DEPDIR)/$(am__dirstamp) +android/hardware/$(am__dirstamp): + @$(MKDIR_P) android/hardware + @: > android/hardware/$(am__dirstamp) +android/hardware/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) android/hardware/$(DEPDIR) + @: > android/hardware/$(DEPDIR)/$(am__dirstamp) +android/hardware/android_tester-hardware.$(OBJEXT): \ + android/hardware/$(am__dirstamp) \ + android/hardware/$(DEPDIR)/$(am__dirstamp) +android/android_tester-tester-bluetooth.$(OBJEXT): \ + android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp) +android/android_tester-tester-socket.$(OBJEXT): \ + android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp) +android/android_tester-tester-hidhost.$(OBJEXT): \ + android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp) +android/android_tester-tester-pan.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/android_tester-tester-hdp.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/android_tester-tester-a2dp.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/android_tester-tester-avrcp.$(OBJEXT): \ + android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp) +android/android_tester-tester-gatt.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/android_tester-tester-map-client.$(OBJEXT): \ + android/$(am__dirstamp) android/$(DEPDIR)/$(am__dirstamp) +android/android_tester-tester-main.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) + +android/android-tester$(EXEEXT): $(android_android_tester_OBJECTS) $(android_android_tester_DEPENDENCIES) $(EXTRA_android_android_tester_DEPENDENCIES) android/$(am__dirstamp) + @rm -f android/android-tester$(EXEEXT) + $(AM_V_CCLD)$(android_android_tester_LINK) $(android_android_tester_OBJECTS) $(android_android_tester_LDADD) $(LIBS) +android/avdtptest-avdtptest.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +src/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/$(DEPDIR) + @: > src/$(DEPDIR)/$(am__dirstamp) +src/android_avdtptest-log.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +btio/$(am__dirstamp): + @$(MKDIR_P) btio + @: > btio/$(am__dirstamp) +btio/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) btio/$(DEPDIR) + @: > btio/$(DEPDIR)/$(am__dirstamp) +btio/android_avdtptest-btio.$(OBJEXT): btio/$(am__dirstamp) \ + btio/$(DEPDIR)/$(am__dirstamp) +src/shared/android_avdtptest-util.$(OBJEXT): \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/android_avdtptest-queue.$(OBJEXT): \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +src/shared/android_avdtptest-log.$(OBJEXT): \ + src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) +android/avdtptest-avdtp.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) + +android/avdtptest$(EXEEXT): $(android_avdtptest_OBJECTS) $(android_avdtptest_DEPENDENCIES) $(EXTRA_android_avdtptest_DEPENDENCIES) android/$(am__dirstamp) + @rm -f android/avdtptest$(EXEEXT) + $(AM_V_CCLD)$(android_avdtptest_LINK) $(android_avdtptest_OBJECTS) $(android_avdtptest_LDADD) $(LIBS) +android/main.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +src/log.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) +src/sdpd-database.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/sdpd-server.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/sdpd-service.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/sdpd-request.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/uuid-helper.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/eir.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) +android/bluetooth.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/hidhost.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +profiles/scanparam/$(am__dirstamp): + @$(MKDIR_P) profiles/scanparam + @: > profiles/scanparam/$(am__dirstamp) +profiles/scanparam/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) profiles/scanparam/$(DEPDIR) + @: > profiles/scanparam/$(DEPDIR)/$(am__dirstamp) +profiles/scanparam/scpp.$(OBJEXT): profiles/scanparam/$(am__dirstamp) \ + profiles/scanparam/$(DEPDIR)/$(am__dirstamp) +profiles/deviceinfo/$(am__dirstamp): + @$(MKDIR_P) profiles/deviceinfo + @: > profiles/deviceinfo/$(am__dirstamp) +profiles/deviceinfo/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) profiles/deviceinfo/$(DEPDIR) + @: > profiles/deviceinfo/$(DEPDIR)/$(am__dirstamp) +profiles/deviceinfo/dis.$(OBJEXT): \ + profiles/deviceinfo/$(am__dirstamp) \ + profiles/deviceinfo/$(DEPDIR)/$(am__dirstamp) +profiles/battery/$(am__dirstamp): + @$(MKDIR_P) profiles/battery + @: > profiles/battery/$(am__dirstamp) +profiles/battery/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) profiles/battery/$(DEPDIR) + @: > profiles/battery/$(DEPDIR)/$(am__dirstamp) +profiles/battery/bas.$(OBJEXT): profiles/battery/$(am__dirstamp) \ + profiles/battery/$(DEPDIR)/$(am__dirstamp) +profiles/input/$(am__dirstamp): + @$(MKDIR_P) profiles/input + @: > profiles/input/$(am__dirstamp) +profiles/input/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) profiles/input/$(DEPDIR) + @: > profiles/input/$(DEPDIR)/$(am__dirstamp) +profiles/input/hog-lib.$(OBJEXT): profiles/input/$(am__dirstamp) \ + profiles/input/$(DEPDIR)/$(am__dirstamp) +android/ipc.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/avdtp.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/a2dp.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/a2dp-sink.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/avctp.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/avrcp.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/avrcp-lib.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/socket.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/sco.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/pan.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/handsfree.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/handsfree-client.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/gatt.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/health.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +profiles/health/$(am__dirstamp): + @$(MKDIR_P) profiles/health + @: > profiles/health/$(am__dirstamp) +profiles/health/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) profiles/health/$(DEPDIR) + @: > profiles/health/$(DEPDIR)/$(am__dirstamp) +profiles/health/mcap.$(OBJEXT): profiles/health/$(am__dirstamp) \ + profiles/health/$(DEPDIR)/$(am__dirstamp) +android/map-client.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +attrib/$(am__dirstamp): + @$(MKDIR_P) attrib + @: > attrib/$(am__dirstamp) +attrib/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) attrib/$(DEPDIR) + @: > attrib/$(DEPDIR)/$(am__dirstamp) +attrib/att.$(OBJEXT): attrib/$(am__dirstamp) \ + attrib/$(DEPDIR)/$(am__dirstamp) +attrib/gatt.$(OBJEXT): attrib/$(am__dirstamp) \ + attrib/$(DEPDIR)/$(am__dirstamp) +attrib/gattrib.$(OBJEXT): attrib/$(am__dirstamp) \ + attrib/$(DEPDIR)/$(am__dirstamp) +btio/btio.$(OBJEXT): btio/$(am__dirstamp) \ + btio/$(DEPDIR)/$(am__dirstamp) +src/sdp-client.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +profiles/network/$(am__dirstamp): + @$(MKDIR_P) profiles/network + @: > profiles/network/$(am__dirstamp) +profiles/network/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) profiles/network/$(DEPDIR) + @: > profiles/network/$(DEPDIR)/$(am__dirstamp) +profiles/network/bnep.$(OBJEXT): profiles/network/$(am__dirstamp) \ + profiles/network/$(DEPDIR)/$(am__dirstamp) + +android/bluetoothd$(EXEEXT): $(android_bluetoothd_OBJECTS) $(android_bluetoothd_DEPENDENCIES) $(EXTRA_android_bluetoothd_DEPENDENCIES) android/$(am__dirstamp) + @rm -f android/bluetoothd$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(android_bluetoothd_OBJECTS) $(android_bluetoothd_LDADD) $(LIBS) +android/bluetoothd-snoop.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) + +android/bluetoothd-snoop$(EXEEXT): $(android_bluetoothd_snoop_OBJECTS) $(android_bluetoothd_snoop_DEPENDENCIES) $(EXTRA_android_bluetoothd_snoop_DEPENDENCIES) android/$(am__dirstamp) + @rm -f android/bluetoothd-snoop$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(android_bluetoothd_snoop_OBJECTS) $(android_bluetoothd_snoop_LDADD) $(LIBS) +android/client/$(am__dirstamp): + @$(MKDIR_P) android/client + @: > android/client/$(am__dirstamp) +android/client/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) android/client/$(DEPDIR) + @: > android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-haltest.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-pollhandler.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-terminal.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-history.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-tabcompletion.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-if-av.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-if-av-sink.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-if-rc.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-if-rc-ctrl.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-if-bt.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-if-gatt.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-if-hf.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-if-hf-client.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-if-hh.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-if-pan.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-if-hl.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-if-sock.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-if-audio.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-if-sco.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/client/haltest-if-mce.$(OBJEXT): \ + android/client/$(am__dirstamp) \ + android/client/$(DEPDIR)/$(am__dirstamp) +android/hardware/haltest-hardware.$(OBJEXT): \ + android/hardware/$(am__dirstamp) \ + android/hardware/$(DEPDIR)/$(am__dirstamp) +android/haltest-hal-utils.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) + +android/haltest$(EXEEXT): $(android_haltest_OBJECTS) $(android_haltest_DEPENDENCIES) $(EXTRA_android_haltest_DEPENDENCIES) android/$(am__dirstamp) + @rm -f android/haltest$(EXEEXT) + $(AM_V_CCLD)$(android_haltest_LINK) $(android_haltest_OBJECTS) $(android_haltest_LDADD) $(LIBS) +emulator/android_ipc_tester-hciemu.$(OBJEXT): \ + emulator/$(am__dirstamp) emulator/$(DEPDIR)/$(am__dirstamp) +emulator/android_ipc_tester-vhci.$(OBJEXT): emulator/$(am__dirstamp) \ + emulator/$(DEPDIR)/$(am__dirstamp) +emulator/android_ipc_tester-btdev.$(OBJEXT): emulator/$(am__dirstamp) \ + emulator/$(DEPDIR)/$(am__dirstamp) +emulator/android_ipc_tester-bthost.$(OBJEXT): \ + emulator/$(am__dirstamp) emulator/$(DEPDIR)/$(am__dirstamp) +emulator/android_ipc_tester-smp.$(OBJEXT): emulator/$(am__dirstamp) \ + emulator/$(DEPDIR)/$(am__dirstamp) +android/ipc_tester-hal-utils.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +android/ipc_tester-ipc-tester.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) + +android/ipc-tester$(EXEEXT): $(android_ipc_tester_OBJECTS) $(android_ipc_tester_DEPENDENCIES) $(EXTRA_android_ipc_tester_DEPENDENCIES) android/$(am__dirstamp) + @rm -f android/ipc-tester$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(android_ipc_tester_OBJECTS) $(android_ipc_tester_LDADD) $(LIBS) +android/system-emulator.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) + +android/system-emulator$(EXEEXT): $(android_system_emulator_OBJECTS) $(android_system_emulator_DEPENDENCIES) $(EXTRA_android_system_emulator_DEPENDENCIES) android/$(am__dirstamp) + @rm -f android/system-emulator$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(android_system_emulator_OBJECTS) $(android_system_emulator_LDADD) $(LIBS) +android/test-ipc.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) + +android/test-ipc$(EXEEXT): $(android_test_ipc_OBJECTS) $(android_test_ipc_DEPENDENCIES) $(EXTRA_android_test_ipc_DEPENDENCIES) android/$(am__dirstamp) + @rm -f android/test-ipc$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(android_test_ipc_OBJECTS) $(android_test_ipc_LDADD) $(LIBS) +attrib/gatttool.$(OBJEXT): attrib/$(am__dirstamp) \ + attrib/$(DEPDIR)/$(am__dirstamp) +attrib/interactive.$(OBJEXT): attrib/$(am__dirstamp) \ + attrib/$(DEPDIR)/$(am__dirstamp) +attrib/utils.$(OBJEXT): attrib/$(am__dirstamp) \ + attrib/$(DEPDIR)/$(am__dirstamp) +client/$(am__dirstamp): + @$(MKDIR_P) client + @: > client/$(am__dirstamp) +client/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) client/$(DEPDIR) + @: > client/$(DEPDIR)/$(am__dirstamp) +client/display.$(OBJEXT): client/$(am__dirstamp) \ + client/$(DEPDIR)/$(am__dirstamp) + +attrib/gatttool$(EXEEXT): $(attrib_gatttool_OBJECTS) $(attrib_gatttool_DEPENDENCIES) $(EXTRA_attrib_gatttool_DEPENDENCIES) attrib/$(am__dirstamp) + @rm -f attrib/gatttool$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(attrib_gatttool_OBJECTS) $(attrib_gatttool_LDADD) $(LIBS) +client/main.$(OBJEXT): client/$(am__dirstamp) \ + client/$(DEPDIR)/$(am__dirstamp) +client/print.$(OBJEXT): client/$(am__dirstamp) \ + client/$(DEPDIR)/$(am__dirstamp) +client/agent.$(OBJEXT): client/$(am__dirstamp) \ + client/$(DEPDIR)/$(am__dirstamp) +client/advertising.$(OBJEXT): client/$(am__dirstamp) \ + client/$(DEPDIR)/$(am__dirstamp) +client/adv_monitor.$(OBJEXT): client/$(am__dirstamp) \ + client/$(DEPDIR)/$(am__dirstamp) +client/gatt.$(OBJEXT): client/$(am__dirstamp) \ + client/$(DEPDIR)/$(am__dirstamp) +client/admin.$(OBJEXT): client/$(am__dirstamp) \ + client/$(DEPDIR)/$(am__dirstamp) +client/player.$(OBJEXT): client/$(am__dirstamp) \ + client/$(DEPDIR)/$(am__dirstamp) +client/mgmt.$(OBJEXT): client/$(am__dirstamp) \ + client/$(DEPDIR)/$(am__dirstamp) +client/assistant.$(OBJEXT): client/$(am__dirstamp) \ + client/$(DEPDIR)/$(am__dirstamp) + +client/bluetoothctl$(EXEEXT): $(client_bluetoothctl_OBJECTS) $(client_bluetoothctl_DEPENDENCIES) $(EXTRA_client_bluetoothctl_DEPENDENCIES) client/$(am__dirstamp) + @rm -f client/bluetoothctl$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(client_bluetoothctl_OBJECTS) $(client_bluetoothctl_LDADD) $(LIBS) +emulator/b1ee.$(OBJEXT): emulator/$(am__dirstamp) \ + emulator/$(DEPDIR)/$(am__dirstamp) + +emulator/b1ee$(EXEEXT): $(emulator_b1ee_OBJECTS) $(emulator_b1ee_DEPENDENCIES) $(EXTRA_emulator_b1ee_DEPENDENCIES) emulator/$(am__dirstamp) + @rm -f emulator/b1ee$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(emulator_b1ee_OBJECTS) $(emulator_b1ee_LDADD) $(LIBS) +emulator/main.$(OBJEXT): emulator/$(am__dirstamp) \ + emulator/$(DEPDIR)/$(am__dirstamp) +emulator/serial.$(OBJEXT): emulator/$(am__dirstamp) \ + emulator/$(DEPDIR)/$(am__dirstamp) +emulator/server.$(OBJEXT): emulator/$(am__dirstamp) \ + emulator/$(DEPDIR)/$(am__dirstamp) +emulator/vhci.$(OBJEXT): emulator/$(am__dirstamp) \ + emulator/$(DEPDIR)/$(am__dirstamp) +emulator/btdev.$(OBJEXT): emulator/$(am__dirstamp) \ + emulator/$(DEPDIR)/$(am__dirstamp) +emulator/bthost.$(OBJEXT): emulator/$(am__dirstamp) \ + emulator/$(DEPDIR)/$(am__dirstamp) +emulator/smp.$(OBJEXT): emulator/$(am__dirstamp) \ + emulator/$(DEPDIR)/$(am__dirstamp) +emulator/phy.$(OBJEXT): emulator/$(am__dirstamp) \ + emulator/$(DEPDIR)/$(am__dirstamp) +emulator/amp.$(OBJEXT): emulator/$(am__dirstamp) \ + emulator/$(DEPDIR)/$(am__dirstamp) +emulator/le.$(OBJEXT): emulator/$(am__dirstamp) \ + emulator/$(DEPDIR)/$(am__dirstamp) + +emulator/btvirt$(EXEEXT): $(emulator_btvirt_OBJECTS) $(emulator_btvirt_DEPENDENCIES) $(EXTRA_emulator_btvirt_DEPENDENCIES) emulator/$(am__dirstamp) + @rm -f emulator/btvirt$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(emulator_btvirt_OBJECTS) $(emulator_btvirt_LDADD) $(LIBS) +emulator/hfp.$(OBJEXT): emulator/$(am__dirstamp) \ + emulator/$(DEPDIR)/$(am__dirstamp) + +emulator/hfp$(EXEEXT): $(emulator_hfp_OBJECTS) $(emulator_hfp_DEPENDENCIES) $(EXTRA_emulator_hfp_DEPENDENCIES) emulator/$(am__dirstamp) + @rm -f emulator/hfp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(emulator_hfp_OBJECTS) $(emulator_hfp_LDADD) $(LIBS) +mesh/$(am__dirstamp): + @$(MKDIR_P) mesh + @: > mesh/$(am__dirstamp) +mesh/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) mesh/$(DEPDIR) + @: > mesh/$(DEPDIR)/$(am__dirstamp) +mesh/mesh.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/net-keys.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/mesh-io.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/mesh-mgmt.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/mesh-io-unit.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/mesh-io-mgmt.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/mesh-io-generic.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/net.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/crypto.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/friend.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/appkey.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/node.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/model.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/cfgmod-server.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/remprv-server.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/mesh-config-json.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/util.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/dbus.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/agent.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/prov-acceptor.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/prov-initiator.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/manager.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/pb-adv.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/keyring.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/rpl.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/prvbeac-server.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) +mesh/main.$(OBJEXT): mesh/$(am__dirstamp) \ + mesh/$(DEPDIR)/$(am__dirstamp) + +mesh/bluetooth-meshd$(EXEEXT): $(mesh_bluetooth_meshd_OBJECTS) $(mesh_bluetooth_meshd_DEPENDENCIES) $(EXTRA_mesh_bluetooth_meshd_DEPENDENCIES) mesh/$(am__dirstamp) + @rm -f mesh/bluetooth-meshd$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(mesh_bluetooth_meshd_OBJECTS) $(mesh_bluetooth_meshd_LDADD) $(LIBS) +monitor/$(am__dirstamp): + @$(MKDIR_P) monitor + @: > monitor/$(am__dirstamp) +monitor/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) monitor/$(DEPDIR) + @: > monitor/$(DEPDIR)/$(am__dirstamp) +monitor/main.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/display.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/hcidump.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/ellisys.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/control.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/packet.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/vendor.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/lmp.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/crc.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/ll.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/l2cap.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/sdp.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/avctp.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/avdtp.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/a2dp.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/rfcomm.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/bnep.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/hwdb.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/keys.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/analyze.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/intel.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/broadcom.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/msft.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/jlink.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +monitor/att.$(OBJEXT): monitor/$(am__dirstamp) \ + monitor/$(DEPDIR)/$(am__dirstamp) +src/textfile.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/settings.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +monitor/btmon$(EXEEXT): $(monitor_btmon_OBJECTS) $(monitor_btmon_DEPENDENCIES) $(EXTRA_monitor_btmon_DEPENDENCIES) monitor/$(am__dirstamp) + @rm -f monitor/btmon$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(monitor_btmon_OBJECTS) $(monitor_btmon_LDADD) $(LIBS) +btio/obexd-btio.$(OBJEXT): btio/$(am__dirstamp) \ + btio/$(DEPDIR)/$(am__dirstamp) +gobex/$(am__dirstamp): + @$(MKDIR_P) gobex + @: > gobex/$(am__dirstamp) +gobex/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) gobex/$(DEPDIR) + @: > gobex/$(DEPDIR)/$(am__dirstamp) +gobex/obexd-gobex.$(OBJEXT): gobex/$(am__dirstamp) \ + gobex/$(DEPDIR)/$(am__dirstamp) +gobex/obexd-gobex-defs.$(OBJEXT): gobex/$(am__dirstamp) \ + gobex/$(DEPDIR)/$(am__dirstamp) +gobex/obexd-gobex-packet.$(OBJEXT): gobex/$(am__dirstamp) \ + gobex/$(DEPDIR)/$(am__dirstamp) +gobex/obexd-gobex-header.$(OBJEXT): gobex/$(am__dirstamp) \ + gobex/$(DEPDIR)/$(am__dirstamp) +gobex/obexd-gobex-transfer.$(OBJEXT): gobex/$(am__dirstamp) \ + gobex/$(DEPDIR)/$(am__dirstamp) +gobex/obexd-gobex-apparam.$(OBJEXT): gobex/$(am__dirstamp) \ + gobex/$(DEPDIR)/$(am__dirstamp) +obexd/plugins/$(am__dirstamp): + @$(MKDIR_P) obexd/plugins + @: > obexd/plugins/$(am__dirstamp) +obexd/plugins/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) obexd/plugins/$(DEPDIR) + @: > obexd/plugins/$(DEPDIR)/$(am__dirstamp) +obexd/plugins/obexd-filesystem.$(OBJEXT): \ + obexd/plugins/$(am__dirstamp) \ + obexd/plugins/$(DEPDIR)/$(am__dirstamp) +obexd/plugins/obexd-bluetooth.$(OBJEXT): \ + obexd/plugins/$(am__dirstamp) \ + obexd/plugins/$(DEPDIR)/$(am__dirstamp) +obexd/plugins/obexd-pcsuite.$(OBJEXT): obexd/plugins/$(am__dirstamp) \ + obexd/plugins/$(DEPDIR)/$(am__dirstamp) +obexd/plugins/obexd-opp.$(OBJEXT): obexd/plugins/$(am__dirstamp) \ + obexd/plugins/$(DEPDIR)/$(am__dirstamp) +obexd/plugins/obexd-ftp.$(OBJEXT): obexd/plugins/$(am__dirstamp) \ + obexd/plugins/$(DEPDIR)/$(am__dirstamp) +obexd/plugins/obexd-irmc.$(OBJEXT): obexd/plugins/$(am__dirstamp) \ + obexd/plugins/$(DEPDIR)/$(am__dirstamp) +obexd/plugins/obexd-pbap.$(OBJEXT): obexd/plugins/$(am__dirstamp) \ + obexd/plugins/$(DEPDIR)/$(am__dirstamp) +obexd/plugins/obexd-vcard.$(OBJEXT): obexd/plugins/$(am__dirstamp) \ + obexd/plugins/$(DEPDIR)/$(am__dirstamp) +obexd/plugins/obexd-phonebook-@PLUGIN_PHONEBOOK@.$(OBJEXT): \ + obexd/plugins/$(am__dirstamp) \ + obexd/plugins/$(DEPDIR)/$(am__dirstamp) +obexd/plugins/obexd-mas.$(OBJEXT): obexd/plugins/$(am__dirstamp) \ + obexd/plugins/$(DEPDIR)/$(am__dirstamp) +obexd/plugins/obexd-messages-dummy.$(OBJEXT): \ + obexd/plugins/$(am__dirstamp) \ + obexd/plugins/$(DEPDIR)/$(am__dirstamp) +obexd/client/$(am__dirstamp): + @$(MKDIR_P) obexd/client + @: > obexd/client/$(am__dirstamp) +obexd/client/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) obexd/client/$(DEPDIR) + @: > obexd/client/$(DEPDIR)/$(am__dirstamp) +obexd/client/obexd-mns.$(OBJEXT): obexd/client/$(am__dirstamp) \ + obexd/client/$(DEPDIR)/$(am__dirstamp) +obexd/src/$(am__dirstamp): + @$(MKDIR_P) obexd/src + @: > obexd/src/$(am__dirstamp) +obexd/src/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) obexd/src/$(DEPDIR) + @: > obexd/src/$(DEPDIR)/$(am__dirstamp) +obexd/src/obexd-main.$(OBJEXT): obexd/src/$(am__dirstamp) \ + obexd/src/$(DEPDIR)/$(am__dirstamp) +obexd/src/obexd-plugin.$(OBJEXT): obexd/src/$(am__dirstamp) \ + obexd/src/$(DEPDIR)/$(am__dirstamp) +obexd/src/obexd-log.$(OBJEXT): obexd/src/$(am__dirstamp) \ + obexd/src/$(DEPDIR)/$(am__dirstamp) +obexd/src/obexd-manager.$(OBJEXT): obexd/src/$(am__dirstamp) \ + obexd/src/$(DEPDIR)/$(am__dirstamp) +obexd/src/obexd-obex.$(OBJEXT): obexd/src/$(am__dirstamp) \ + obexd/src/$(DEPDIR)/$(am__dirstamp) +obexd/src/obexd-mimetype.$(OBJEXT): obexd/src/$(am__dirstamp) \ + obexd/src/$(DEPDIR)/$(am__dirstamp) +obexd/src/obexd-service.$(OBJEXT): obexd/src/$(am__dirstamp) \ + obexd/src/$(DEPDIR)/$(am__dirstamp) +obexd/src/obexd-transport.$(OBJEXT): obexd/src/$(am__dirstamp) \ + obexd/src/$(DEPDIR)/$(am__dirstamp) +obexd/src/obexd-server.$(OBJEXT): obexd/src/$(am__dirstamp) \ + obexd/src/$(DEPDIR)/$(am__dirstamp) +obexd/client/obexd-manager.$(OBJEXT): obexd/client/$(am__dirstamp) \ + obexd/client/$(DEPDIR)/$(am__dirstamp) +obexd/client/obexd-session.$(OBJEXT): obexd/client/$(am__dirstamp) \ + obexd/client/$(DEPDIR)/$(am__dirstamp) +obexd/client/obexd-bluetooth.$(OBJEXT): obexd/client/$(am__dirstamp) \ + obexd/client/$(DEPDIR)/$(am__dirstamp) +obexd/client/obexd-sync.$(OBJEXT): obexd/client/$(am__dirstamp) \ + obexd/client/$(DEPDIR)/$(am__dirstamp) +obexd/client/obexd-pbap.$(OBJEXT): obexd/client/$(am__dirstamp) \ + obexd/client/$(DEPDIR)/$(am__dirstamp) +obexd/client/obexd-ftp.$(OBJEXT): obexd/client/$(am__dirstamp) \ + obexd/client/$(DEPDIR)/$(am__dirstamp) +obexd/client/obexd-opp.$(OBJEXT): obexd/client/$(am__dirstamp) \ + obexd/client/$(DEPDIR)/$(am__dirstamp) +obexd/client/obexd-map.$(OBJEXT): obexd/client/$(am__dirstamp) \ + obexd/client/$(DEPDIR)/$(am__dirstamp) +obexd/client/obexd-bip.$(OBJEXT): obexd/client/$(am__dirstamp) \ + obexd/client/$(DEPDIR)/$(am__dirstamp) +obexd/client/obexd-bip-common.$(OBJEXT): obexd/client/$(am__dirstamp) \ + obexd/client/$(DEPDIR)/$(am__dirstamp) +obexd/client/obexd-map-event.$(OBJEXT): obexd/client/$(am__dirstamp) \ + obexd/client/$(DEPDIR)/$(am__dirstamp) +obexd/client/obexd-transfer.$(OBJEXT): obexd/client/$(am__dirstamp) \ + obexd/client/$(DEPDIR)/$(am__dirstamp) +obexd/client/obexd-transport.$(OBJEXT): obexd/client/$(am__dirstamp) \ + obexd/client/$(DEPDIR)/$(am__dirstamp) +obexd/client/obexd-driver.$(OBJEXT): obexd/client/$(am__dirstamp) \ + obexd/client/$(DEPDIR)/$(am__dirstamp) + +obexd/src/obexd$(EXEEXT): $(obexd_src_obexd_OBJECTS) $(obexd_src_obexd_DEPENDENCIES) $(EXTRA_obexd_src_obexd_DEPENDENCIES) obexd/src/$(am__dirstamp) + @rm -f obexd/src/obexd$(EXEEXT) + $(AM_V_CCLD)$(obexd_src_obexd_LINK) $(obexd_src_obexd_OBJECTS) $(obexd_src_obexd_LDADD) $(LIBS) +peripheral/$(am__dirstamp): + @$(MKDIR_P) peripheral + @: > peripheral/$(am__dirstamp) +peripheral/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) peripheral/$(DEPDIR) + @: > peripheral/$(DEPDIR)/$(am__dirstamp) +peripheral/main.$(OBJEXT): peripheral/$(am__dirstamp) \ + peripheral/$(DEPDIR)/$(am__dirstamp) +peripheral/efivars.$(OBJEXT): peripheral/$(am__dirstamp) \ + peripheral/$(DEPDIR)/$(am__dirstamp) +peripheral/attach.$(OBJEXT): peripheral/$(am__dirstamp) \ + peripheral/$(DEPDIR)/$(am__dirstamp) +peripheral/log.$(OBJEXT): peripheral/$(am__dirstamp) \ + peripheral/$(DEPDIR)/$(am__dirstamp) +peripheral/gap.$(OBJEXT): peripheral/$(am__dirstamp) \ + peripheral/$(DEPDIR)/$(am__dirstamp) +peripheral/gatt.$(OBJEXT): peripheral/$(am__dirstamp) \ + peripheral/$(DEPDIR)/$(am__dirstamp) + +peripheral/btsensor$(EXEEXT): $(peripheral_btsensor_OBJECTS) $(peripheral_btsensor_DEPENDENCIES) $(EXTRA_peripheral_btsensor_DEPENDENCIES) peripheral/$(am__dirstamp) + @rm -f peripheral/btsensor$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(peripheral_btsensor_OBJECTS) $(peripheral_btsensor_LDADD) $(LIBS) +profiles/cups/$(am__dirstamp): + @$(MKDIR_P) profiles/cups + @: > profiles/cups/$(am__dirstamp) +profiles/cups/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) profiles/cups/$(DEPDIR) + @: > profiles/cups/$(DEPDIR)/$(am__dirstamp) +profiles/cups/main.$(OBJEXT): profiles/cups/$(am__dirstamp) \ + profiles/cups/$(DEPDIR)/$(am__dirstamp) +profiles/cups/sdp.$(OBJEXT): profiles/cups/$(am__dirstamp) \ + profiles/cups/$(DEPDIR)/$(am__dirstamp) +profiles/cups/spp.$(OBJEXT): profiles/cups/$(am__dirstamp) \ + profiles/cups/$(DEPDIR)/$(am__dirstamp) +profiles/cups/hcrp.$(OBJEXT): profiles/cups/$(am__dirstamp) \ + profiles/cups/$(DEPDIR)/$(am__dirstamp) + +profiles/cups/bluetooth$(EXEEXT): $(profiles_cups_bluetooth_OBJECTS) $(profiles_cups_bluetooth_DEPENDENCIES) $(EXTRA_profiles_cups_bluetooth_DEPENDENCIES) profiles/cups/$(am__dirstamp) + @rm -f profiles/cups/bluetooth$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(profiles_cups_bluetooth_OBJECTS) $(profiles_cups_bluetooth_LDADD) $(LIBS) +profiles/iap/$(am__dirstamp): + @$(MKDIR_P) profiles/iap + @: > profiles/iap/$(am__dirstamp) +profiles/iap/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) profiles/iap/$(DEPDIR) + @: > profiles/iap/$(DEPDIR)/$(am__dirstamp) +profiles/iap/main.$(OBJEXT): profiles/iap/$(am__dirstamp) \ + profiles/iap/$(DEPDIR)/$(am__dirstamp) + +profiles/iap/iapd$(EXEEXT): $(profiles_iap_iapd_OBJECTS) $(profiles_iap_iapd_DEPENDENCIES) $(EXTRA_profiles_iap_iapd_DEPENDENCIES) profiles/iap/$(am__dirstamp) + @rm -f profiles/iap/iapd$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(profiles_iap_iapd_OBJECTS) $(profiles_iap_iapd_LDADD) $(LIBS) +plugins/$(am__dirstamp): + @$(MKDIR_P) plugins + @: > plugins/$(am__dirstamp) +plugins/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) plugins/$(DEPDIR) + @: > plugins/$(DEPDIR)/$(am__dirstamp) +plugins/bluetoothd-hostname.$(OBJEXT): plugins/$(am__dirstamp) \ + plugins/$(DEPDIR)/$(am__dirstamp) +plugins/bluetoothd-wiimote.$(OBJEXT): plugins/$(am__dirstamp) \ + plugins/$(DEPDIR)/$(am__dirstamp) +plugins/bluetoothd-autopair.$(OBJEXT): plugins/$(am__dirstamp) \ + plugins/$(DEPDIR)/$(am__dirstamp) +plugins/bluetoothd-policy.$(OBJEXT): plugins/$(am__dirstamp) \ + plugins/$(DEPDIR)/$(am__dirstamp) +plugins/bluetoothd-admin.$(OBJEXT): plugins/$(am__dirstamp) \ + plugins/$(DEPDIR)/$(am__dirstamp) +plugins/bluetoothd-neard.$(OBJEXT): plugins/$(am__dirstamp) \ + plugins/$(DEPDIR)/$(am__dirstamp) +profiles/sap/$(am__dirstamp): + @$(MKDIR_P) profiles/sap + @: > profiles/sap/$(am__dirstamp) +profiles/sap/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) profiles/sap/$(DEPDIR) + @: > profiles/sap/$(DEPDIR)/$(am__dirstamp) +profiles/sap/bluetoothd-main.$(OBJEXT): profiles/sap/$(am__dirstamp) \ + profiles/sap/$(DEPDIR)/$(am__dirstamp) +profiles/sap/bluetoothd-manager.$(OBJEXT): \ + profiles/sap/$(am__dirstamp) \ + profiles/sap/$(DEPDIR)/$(am__dirstamp) +profiles/sap/bluetoothd-server.$(OBJEXT): \ + profiles/sap/$(am__dirstamp) \ + profiles/sap/$(DEPDIR)/$(am__dirstamp) +profiles/sap/bluetoothd-sap-dummy.$(OBJEXT): \ + profiles/sap/$(am__dirstamp) \ + profiles/sap/$(DEPDIR)/$(am__dirstamp) +profiles/audio/$(am__dirstamp): + @$(MKDIR_P) profiles/audio + @: > profiles/audio/$(am__dirstamp) +profiles/audio/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) profiles/audio/$(DEPDIR) + @: > profiles/audio/$(DEPDIR)/$(am__dirstamp) +profiles/audio/bluetoothd-source.$(OBJEXT): \ + profiles/audio/$(am__dirstamp) \ + profiles/audio/$(DEPDIR)/$(am__dirstamp) +profiles/audio/bluetoothd-sink.$(OBJEXT): \ + profiles/audio/$(am__dirstamp) \ + profiles/audio/$(DEPDIR)/$(am__dirstamp) +profiles/audio/bluetoothd-a2dp.$(OBJEXT): \ + profiles/audio/$(am__dirstamp) \ + profiles/audio/$(DEPDIR)/$(am__dirstamp) +profiles/audio/bluetoothd-avdtp.$(OBJEXT): \ + profiles/audio/$(am__dirstamp) \ + profiles/audio/$(DEPDIR)/$(am__dirstamp) +profiles/audio/bluetoothd-media.$(OBJEXT): \ + profiles/audio/$(am__dirstamp) \ + profiles/audio/$(DEPDIR)/$(am__dirstamp) +profiles/audio/bluetoothd-transport.$(OBJEXT): \ + profiles/audio/$(am__dirstamp) \ + profiles/audio/$(DEPDIR)/$(am__dirstamp) +profiles/audio/bluetoothd-control.$(OBJEXT): \ + profiles/audio/$(am__dirstamp) \ + profiles/audio/$(DEPDIR)/$(am__dirstamp) +profiles/audio/bluetoothd-avctp.$(OBJEXT): \ + profiles/audio/$(am__dirstamp) \ + profiles/audio/$(DEPDIR)/$(am__dirstamp) +profiles/audio/bluetoothd-avrcp.$(OBJEXT): \ + profiles/audio/$(am__dirstamp) \ + profiles/audio/$(DEPDIR)/$(am__dirstamp) +profiles/audio/bluetoothd-player.$(OBJEXT): \ + profiles/audio/$(am__dirstamp) \ + profiles/audio/$(DEPDIR)/$(am__dirstamp) +profiles/network/bluetoothd-manager.$(OBJEXT): \ + profiles/network/$(am__dirstamp) \ + profiles/network/$(DEPDIR)/$(am__dirstamp) +profiles/network/bluetoothd-bnep.$(OBJEXT): \ + profiles/network/$(am__dirstamp) \ + profiles/network/$(DEPDIR)/$(am__dirstamp) +profiles/network/bluetoothd-server.$(OBJEXT): \ + profiles/network/$(am__dirstamp) \ + profiles/network/$(DEPDIR)/$(am__dirstamp) +profiles/network/bluetoothd-connection.$(OBJEXT): \ + profiles/network/$(am__dirstamp) \ + profiles/network/$(DEPDIR)/$(am__dirstamp) +profiles/input/bluetoothd-manager.$(OBJEXT): \ + profiles/input/$(am__dirstamp) \ + profiles/input/$(DEPDIR)/$(am__dirstamp) +profiles/input/bluetoothd-server.$(OBJEXT): \ + profiles/input/$(am__dirstamp) \ + profiles/input/$(DEPDIR)/$(am__dirstamp) +profiles/input/bluetoothd-device.$(OBJEXT): \ + profiles/input/$(am__dirstamp) \ + profiles/input/$(DEPDIR)/$(am__dirstamp) +profiles/input/bluetoothd-hog.$(OBJEXT): \ + profiles/input/$(am__dirstamp) \ + profiles/input/$(DEPDIR)/$(am__dirstamp) +profiles/input/bluetoothd-hog-lib.$(OBJEXT): \ + profiles/input/$(am__dirstamp) \ + profiles/input/$(DEPDIR)/$(am__dirstamp) +profiles/deviceinfo/bluetoothd-dis.$(OBJEXT): \ + profiles/deviceinfo/$(am__dirstamp) \ + profiles/deviceinfo/$(DEPDIR)/$(am__dirstamp) +profiles/battery/bluetoothd-bas.$(OBJEXT): \ + profiles/battery/$(am__dirstamp) \ + profiles/battery/$(DEPDIR)/$(am__dirstamp) +profiles/scanparam/bluetoothd-scpp.$(OBJEXT): \ + profiles/scanparam/$(am__dirstamp) \ + profiles/scanparam/$(DEPDIR)/$(am__dirstamp) +profiles/input/bluetoothd-suspend-none.$(OBJEXT): \ + profiles/input/$(am__dirstamp) \ + profiles/input/$(DEPDIR)/$(am__dirstamp) +profiles/health/bluetoothd-mcap.$(OBJEXT): \ + profiles/health/$(am__dirstamp) \ + profiles/health/$(DEPDIR)/$(am__dirstamp) +profiles/health/bluetoothd-hdp_main.$(OBJEXT): \ + profiles/health/$(am__dirstamp) \ + profiles/health/$(DEPDIR)/$(am__dirstamp) +profiles/health/bluetoothd-hdp_manager.$(OBJEXT): \ + profiles/health/$(am__dirstamp) \ + profiles/health/$(DEPDIR)/$(am__dirstamp) +profiles/health/bluetoothd-hdp.$(OBJEXT): \ + profiles/health/$(am__dirstamp) \ + profiles/health/$(DEPDIR)/$(am__dirstamp) +profiles/health/bluetoothd-hdp_util.$(OBJEXT): \ + profiles/health/$(am__dirstamp) \ + profiles/health/$(DEPDIR)/$(am__dirstamp) +profiles/gap/$(am__dirstamp): + @$(MKDIR_P) profiles/gap + @: > profiles/gap/$(am__dirstamp) +profiles/gap/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) profiles/gap/$(DEPDIR) + @: > profiles/gap/$(DEPDIR)/$(am__dirstamp) +profiles/gap/bluetoothd-gas.$(OBJEXT): profiles/gap/$(am__dirstamp) \ + profiles/gap/$(DEPDIR)/$(am__dirstamp) +profiles/scanparam/bluetoothd-scan.$(OBJEXT): \ + profiles/scanparam/$(am__dirstamp) \ + profiles/scanparam/$(DEPDIR)/$(am__dirstamp) +profiles/deviceinfo/bluetoothd-deviceinfo.$(OBJEXT): \ + profiles/deviceinfo/$(am__dirstamp) \ + profiles/deviceinfo/$(DEPDIR)/$(am__dirstamp) +profiles/midi/$(am__dirstamp): + @$(MKDIR_P) profiles/midi + @: > profiles/midi/$(am__dirstamp) +profiles/midi/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) profiles/midi/$(DEPDIR) + @: > profiles/midi/$(DEPDIR)/$(am__dirstamp) +profiles/midi/bluetoothd-midi.$(OBJEXT): \ + profiles/midi/$(am__dirstamp) \ + profiles/midi/$(DEPDIR)/$(am__dirstamp) +profiles/midi/bluetoothd-libmidi.$(OBJEXT): \ + profiles/midi/$(am__dirstamp) \ + profiles/midi/$(DEPDIR)/$(am__dirstamp) +profiles/battery/bluetoothd-battery.$(OBJEXT): \ + profiles/battery/$(am__dirstamp) \ + profiles/battery/$(DEPDIR)/$(am__dirstamp) +plugins/bluetoothd-sixaxis.$(OBJEXT): plugins/$(am__dirstamp) \ + plugins/$(DEPDIR)/$(am__dirstamp) +profiles/audio/bluetoothd-bap.$(OBJEXT): \ + profiles/audio/$(am__dirstamp) \ + profiles/audio/$(DEPDIR)/$(am__dirstamp) +profiles/audio/bluetoothd-bass.$(OBJEXT): \ + profiles/audio/$(am__dirstamp) \ + profiles/audio/$(DEPDIR)/$(am__dirstamp) +profiles/audio/bluetoothd-mcp.$(OBJEXT): \ + profiles/audio/$(am__dirstamp) \ + profiles/audio/$(DEPDIR)/$(am__dirstamp) +profiles/audio/bluetoothd-vcp.$(OBJEXT): \ + profiles/audio/$(am__dirstamp) \ + profiles/audio/$(DEPDIR)/$(am__dirstamp) +profiles/audio/bluetoothd-micp.$(OBJEXT): \ + profiles/audio/$(am__dirstamp) \ + profiles/audio/$(DEPDIR)/$(am__dirstamp) +profiles/audio/bluetoothd-ccp.$(OBJEXT): \ + profiles/audio/$(am__dirstamp) \ + profiles/audio/$(DEPDIR)/$(am__dirstamp) +profiles/audio/bluetoothd-csip.$(OBJEXT): \ + profiles/audio/$(am__dirstamp) \ + profiles/audio/$(DEPDIR)/$(am__dirstamp) +profiles/audio/bluetoothd-asha.$(OBJEXT): \ + profiles/audio/$(am__dirstamp) \ + profiles/audio/$(DEPDIR)/$(am__dirstamp) +attrib/bluetoothd-att.$(OBJEXT): attrib/$(am__dirstamp) \ + attrib/$(DEPDIR)/$(am__dirstamp) +attrib/bluetoothd-gatt.$(OBJEXT): attrib/$(am__dirstamp) \ + attrib/$(DEPDIR)/$(am__dirstamp) +attrib/bluetoothd-gattrib.$(OBJEXT): attrib/$(am__dirstamp) \ + attrib/$(DEPDIR)/$(am__dirstamp) +btio/bluetoothd-btio.$(OBJEXT): btio/$(am__dirstamp) \ + btio/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-main.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-log.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-backtrace.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-rfkill.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-sdpd-server.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-sdpd-request.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-sdpd-service.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-sdpd-database.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-gatt-database.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-sdp-xml.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-sdp-client.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-textfile.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-uuid-helper.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-plugin.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-storage.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-advertising.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-agent.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-error.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-adapter.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-profile.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-service.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-gatt-client.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-device.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-dbus-common.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-eir.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-adv_monitor.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-battery.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-settings.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) +src/bluetoothd-set.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +src/bluetoothd$(EXEEXT): $(src_bluetoothd_OBJECTS) $(src_bluetoothd_DEPENDENCIES) $(EXTRA_src_bluetoothd_DEPENDENCIES) src/$(am__dirstamp) + @rm -f src/bluetoothd$(EXEEXT) + $(AM_V_CCLD)$(src_bluetoothd_LINK) $(src_bluetoothd_OBJECTS) $(src_bluetoothd_LDADD) $(LIBS) +tools/$(am__dirstamp): + @$(MKDIR_P) tools + @: > tools/$(am__dirstamp) +tools/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) tools/$(DEPDIR) + @: > tools/$(DEPDIR)/$(am__dirstamp) +tools/3dsp.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/3dsp$(EXEEXT): $(tools_3dsp_OBJECTS) $(tools_3dsp_DEPENDENCIES) $(EXTRA_tools_3dsp_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/3dsp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_3dsp_OBJECTS) $(tools_3dsp_LDADD) $(LIBS) +tools/advtest.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/advtest$(EXEEXT): $(tools_advtest_OBJECTS) $(tools_advtest_DEPENDENCIES) $(EXTRA_tools_advtest_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/advtest$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_advtest_OBJECTS) $(tools_advtest_LDADD) $(LIBS) +tools/amptest.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/amptest$(EXEEXT): $(tools_amptest_OBJECTS) $(tools_amptest_DEPENDENCIES) $(EXTRA_tools_amptest_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/amptest$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_amptest_OBJECTS) $(tools_amptest_LDADD) $(LIBS) +tools/avinfo.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/avinfo$(EXEEXT): $(tools_avinfo_OBJECTS) $(tools_avinfo_DEPENDENCIES) $(EXTRA_tools_avinfo_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/avinfo$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_avinfo_OBJECTS) $(tools_avinfo_LDADD) $(LIBS) +tools/avtest.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/avtest$(EXEEXT): $(tools_avtest_OBJECTS) $(tools_avtest_DEPENDENCIES) $(EXTRA_tools_avtest_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/avtest$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_avtest_OBJECTS) $(tools_avtest_LDADD) $(LIBS) +tools/bcmfw.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/bcmfw$(EXEEXT): $(tools_bcmfw_OBJECTS) $(tools_bcmfw_DEPENDENCIES) $(EXTRA_tools_bcmfw_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/bcmfw$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_bcmfw_OBJECTS) $(tools_bcmfw_LDADD) $(LIBS) +tools/bdaddr.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) +src/oui.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) + +tools/bdaddr$(EXEEXT): $(tools_bdaddr_OBJECTS) $(tools_bdaddr_DEPENDENCIES) $(EXTRA_tools_bdaddr_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/bdaddr$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_bdaddr_OBJECTS) $(tools_bdaddr_LDADD) $(LIBS) +tools/bluemoon.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/bluemoon$(EXEEXT): $(tools_bluemoon_OBJECTS) $(tools_bluemoon_DEPENDENCIES) $(EXTRA_tools_bluemoon_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/bluemoon$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_bluemoon_OBJECTS) $(tools_bluemoon_LDADD) $(LIBS) +tools/bluetooth-player.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/bluetooth-player$(EXEEXT): $(tools_bluetooth_player_OBJECTS) $(tools_bluetooth_player_DEPENDENCIES) $(EXTRA_tools_bluetooth_player_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/bluetooth-player$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_bluetooth_player_OBJECTS) $(tools_bluetooth_player_LDADD) $(LIBS) +tools/bnep-tester.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) +emulator/hciemu.$(OBJEXT): emulator/$(am__dirstamp) \ + emulator/$(DEPDIR)/$(am__dirstamp) + +tools/bnep-tester$(EXEEXT): $(tools_bnep_tester_OBJECTS) $(tools_bnep_tester_DEPENDENCIES) $(EXTRA_tools_bnep_tester_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/bnep-tester$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_bnep_tester_OBJECTS) $(tools_bnep_tester_LDADD) $(LIBS) +tools/bneptest.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/bneptest$(EXEEXT): $(tools_bneptest_OBJECTS) $(tools_bneptest_DEPENDENCIES) $(EXTRA_tools_bneptest_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/bneptest$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_bneptest_OBJECTS) $(tools_bneptest_LDADD) $(LIBS) +tools/btattach.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/btattach$(EXEEXT): $(tools_btattach_OBJECTS) $(tools_btattach_DEPENDENCIES) $(EXTRA_tools_btattach_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/btattach$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_btattach_OBJECTS) $(tools_btattach_LDADD) $(LIBS) +tools/btconfig.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/btconfig$(EXEEXT): $(tools_btconfig_OBJECTS) $(tools_btconfig_DEPENDENCIES) $(EXTRA_tools_btconfig_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/btconfig$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_btconfig_OBJECTS) $(tools_btconfig_LDADD) $(LIBS) +tools/btgatt-client.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/btgatt-client$(EXEEXT): $(tools_btgatt_client_OBJECTS) $(tools_btgatt_client_DEPENDENCIES) $(EXTRA_tools_btgatt_client_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/btgatt-client$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_btgatt_client_OBJECTS) $(tools_btgatt_client_LDADD) $(LIBS) +tools/btgatt-server.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/btgatt-server$(EXEEXT): $(tools_btgatt_server_OBJECTS) $(tools_btgatt_server_DEPENDENCIES) $(EXTRA_tools_btgatt_server_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/btgatt-server$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_btgatt_server_OBJECTS) $(tools_btgatt_server_LDADD) $(LIBS) +tools/btinfo.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/btinfo$(EXEEXT): $(tools_btinfo_OBJECTS) $(tools_btinfo_DEPENDENCIES) $(EXTRA_tools_btinfo_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/btinfo$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_btinfo_OBJECTS) $(tools_btinfo_LDADD) $(LIBS) +tools/btiotest.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/btiotest$(EXEEXT): $(tools_btiotest_OBJECTS) $(tools_btiotest_DEPENDENCIES) $(EXTRA_tools_btiotest_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/btiotest$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_btiotest_OBJECTS) $(tools_btiotest_LDADD) $(LIBS) +tools/btmgmt.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/btmgmt$(EXEEXT): $(tools_btmgmt_OBJECTS) $(tools_btmgmt_DEPENDENCIES) $(EXTRA_tools_btmgmt_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/btmgmt$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_btmgmt_OBJECTS) $(tools_btmgmt_LDADD) $(LIBS) +tools/btmon-logger.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/btmon-logger$(EXEEXT): $(tools_btmon_logger_OBJECTS) $(tools_btmon_logger_DEPENDENCIES) $(EXTRA_tools_btmon_logger_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/btmon-logger$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_btmon_logger_OBJECTS) $(tools_btmon_logger_LDADD) $(LIBS) +tools/btpclient.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) +src/shared/btp.$(OBJEXT): src/shared/$(am__dirstamp) \ + src/shared/$(DEPDIR)/$(am__dirstamp) + +tools/btpclient$(EXEEXT): $(tools_btpclient_OBJECTS) $(tools_btpclient_DEPENDENCIES) $(EXTRA_tools_btpclient_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/btpclient$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_btpclient_OBJECTS) $(tools_btpclient_LDADD) $(LIBS) +tools/btpclientctl.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/btpclientctl$(EXEEXT): $(tools_btpclientctl_OBJECTS) $(tools_btpclientctl_DEPENDENCIES) $(EXTRA_tools_btpclientctl_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/btpclientctl$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_btpclientctl_OBJECTS) $(tools_btpclientctl_LDADD) $(LIBS) +tools/btproxy.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/btproxy$(EXEEXT): $(tools_btproxy_OBJECTS) $(tools_btproxy_DEPENDENCIES) $(EXTRA_tools_btproxy_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/btproxy$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_btproxy_OBJECTS) $(tools_btproxy_LDADD) $(LIBS) +tools/btsnoop.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/btsnoop$(EXEEXT): $(tools_btsnoop_OBJECTS) $(tools_btsnoop_DEPENDENCIES) $(EXTRA_tools_btsnoop_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/btsnoop$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_btsnoop_OBJECTS) $(tools_btsnoop_LDADD) $(LIBS) +tools/check-selftest.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/check-selftest$(EXEEXT): $(tools_check_selftest_OBJECTS) $(tools_check_selftest_DEPENDENCIES) $(EXTRA_tools_check_selftest_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/check-selftest$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_check_selftest_OBJECTS) $(tools_check_selftest_LDADD) $(LIBS) +tools/ciptool.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/ciptool$(EXEEXT): $(tools_ciptool_OBJECTS) $(tools_ciptool_DEPENDENCIES) $(EXTRA_tools_ciptool_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/ciptool$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_ciptool_OBJECTS) $(tools_ciptool_LDADD) $(LIBS) +tools/cltest.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/cltest$(EXEEXT): $(tools_cltest_OBJECTS) $(tools_cltest_DEPENDENCIES) $(EXTRA_tools_cltest_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/cltest$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_cltest_OBJECTS) $(tools_cltest_LDADD) $(LIBS) +tools/create-image.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/create-image$(EXEEXT): $(tools_create_image_OBJECTS) $(tools_create_image_DEPENDENCIES) $(EXTRA_tools_create_image_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/create-image$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_create_image_OBJECTS) $(tools_create_image_LDADD) $(LIBS) +tools/eddystone.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/eddystone$(EXEEXT): $(tools_eddystone_OBJECTS) $(tools_eddystone_DEPENDENCIES) $(EXTRA_tools_eddystone_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/eddystone$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_eddystone_OBJECTS) $(tools_eddystone_LDADD) $(LIBS) +tools/gap-tester.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/gap-tester$(EXEEXT): $(tools_gap_tester_OBJECTS) $(tools_gap_tester_DEPENDENCIES) $(EXTRA_tools_gap_tester_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/gap-tester$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_gap_tester_OBJECTS) $(tools_gap_tester_LDADD) $(LIBS) +tools/gatt-service.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/gatt-service$(EXEEXT): $(tools_gatt_service_OBJECTS) $(tools_gatt_service_DEPENDENCIES) $(EXTRA_tools_gatt_service_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/gatt-service$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_gatt_service_OBJECTS) $(tools_gatt_service_LDADD) $(LIBS) +tools/hci-tester.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/hci-tester$(EXEEXT): $(tools_hci_tester_OBJECTS) $(tools_hci_tester_DEPENDENCIES) $(EXTRA_tools_hci_tester_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/hci-tester$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_hci_tester_OBJECTS) $(tools_hci_tester_LDADD) $(LIBS) +tools/hciattach.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) +tools/hciattach_st.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) +tools/hciattach_ti.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) +tools/hciattach_tialt.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) +tools/hciattach_ath3k.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) +tools/hciattach_qualcomm.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) +tools/hciattach_intel.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) +tools/hciattach_bcm43xx.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/hciattach$(EXEEXT): $(tools_hciattach_OBJECTS) $(tools_hciattach_DEPENDENCIES) $(EXTRA_tools_hciattach_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/hciattach$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_hciattach_OBJECTS) $(tools_hciattach_LDADD) $(LIBS) +tools/hciconfig.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/hciconfig$(EXEEXT): $(tools_hciconfig_OBJECTS) $(tools_hciconfig_DEPENDENCIES) $(EXTRA_tools_hciconfig_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/hciconfig$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_hciconfig_OBJECTS) $(tools_hciconfig_LDADD) $(LIBS) +tools/hcidump.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) +tools/parser/$(am__dirstamp): + @$(MKDIR_P) tools/parser + @: > tools/parser/$(am__dirstamp) +tools/parser/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) tools/parser/$(DEPDIR) + @: > tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/parser.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/lmp.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/hci.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/l2cap.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/amp.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/smp.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/att.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/sdp.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/rfcomm.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/bnep.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/cmtp.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/hidp.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/hcrp.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/avdtp.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/avctp.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/avrcp.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/sap.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/obex.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/capi.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/ppp.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/tcpip.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/ericsson.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/csr.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) +tools/parser/bpa.$(OBJEXT): tools/parser/$(am__dirstamp) \ + tools/parser/$(DEPDIR)/$(am__dirstamp) + +tools/hcidump$(EXEEXT): $(tools_hcidump_OBJECTS) $(tools_hcidump_DEPENDENCIES) $(EXTRA_tools_hcidump_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/hcidump$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_hcidump_OBJECTS) $(tools_hcidump_LDADD) $(LIBS) +tools/hcieventmask.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/hcieventmask$(EXEEXT): $(tools_hcieventmask_OBJECTS) $(tools_hcieventmask_DEPENDENCIES) $(EXTRA_tools_hcieventmask_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/hcieventmask$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_hcieventmask_OBJECTS) $(tools_hcieventmask_LDADD) $(LIBS) +tools/hcisecfilter.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/hcisecfilter$(EXEEXT): $(tools_hcisecfilter_OBJECTS) $(tools_hcisecfilter_DEPENDENCIES) $(EXTRA_tools_hcisecfilter_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/hcisecfilter$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_hcisecfilter_OBJECTS) $(tools_hcisecfilter_LDADD) $(LIBS) +tools/hcitool.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/hcitool$(EXEEXT): $(tools_hcitool_OBJECTS) $(tools_hcitool_DEPENDENCIES) $(EXTRA_tools_hcitool_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/hcitool$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_hcitool_OBJECTS) $(tools_hcitool_LDADD) $(LIBS) +tools/hex2hcd.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/hex2hcd$(EXEEXT): $(tools_hex2hcd_OBJECTS) $(tools_hex2hcd_DEPENDENCIES) $(EXTRA_tools_hex2hcd_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/hex2hcd$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_hex2hcd_OBJECTS) $(tools_hex2hcd_LDADD) $(LIBS) +tools/hid2hci.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/hid2hci$(EXEEXT): $(tools_hid2hci_OBJECTS) $(tools_hid2hci_DEPENDENCIES) $(EXTRA_tools_hid2hci_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/hid2hci$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_hid2hci_OBJECTS) $(tools_hid2hci_LDADD) $(LIBS) +tools/hwdb.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/hwdb$(EXEEXT): $(tools_hwdb_OBJECTS) $(tools_hwdb_DEPENDENCIES) $(EXTRA_tools_hwdb_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/hwdb$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_hwdb_OBJECTS) $(tools_hwdb_LDADD) $(LIBS) +tools/ibeacon.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/ibeacon$(EXEEXT): $(tools_ibeacon_OBJECTS) $(tools_ibeacon_DEPENDENCIES) $(EXTRA_tools_ibeacon_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/ibeacon$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_ibeacon_OBJECTS) $(tools_ibeacon_LDADD) $(LIBS) +tools/ioctl-tester.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/ioctl-tester$(EXEEXT): $(tools_ioctl_tester_OBJECTS) $(tools_ioctl_tester_DEPENDENCIES) $(EXTRA_tools_ioctl_tester_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/ioctl-tester$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_ioctl_tester_OBJECTS) $(tools_ioctl_tester_LDADD) $(LIBS) +tools/iso-tester.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/iso-tester$(EXEEXT): $(tools_iso_tester_OBJECTS) $(tools_iso_tester_DEPENDENCIES) $(EXTRA_tools_iso_tester_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/iso-tester$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_iso_tester_OBJECTS) $(tools_iso_tester_LDADD) $(LIBS) +tools/isotest.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/isotest$(EXEEXT): $(tools_isotest_OBJECTS) $(tools_isotest_DEPENDENCIES) $(EXTRA_tools_isotest_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/isotest$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_isotest_OBJECTS) $(tools_isotest_LDADD) $(LIBS) +tools/l2cap-tester.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/l2cap-tester$(EXEEXT): $(tools_l2cap_tester_OBJECTS) $(tools_l2cap_tester_DEPENDENCIES) $(EXTRA_tools_l2cap_tester_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/l2cap-tester$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_l2cap_tester_OBJECTS) $(tools_l2cap_tester_LDADD) $(LIBS) +tools/l2ping.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/l2ping$(EXEEXT): $(tools_l2ping_OBJECTS) $(tools_l2ping_DEPENDENCIES) $(EXTRA_tools_l2ping_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/l2ping$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_l2ping_OBJECTS) $(tools_l2ping_LDADD) $(LIBS) +tools/l2test.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/l2test$(EXEEXT): $(tools_l2test_OBJECTS) $(tools_l2test_DEPENDENCIES) $(EXTRA_tools_l2test_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/l2test$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_l2test_OBJECTS) $(tools_l2test_LDADD) $(LIBS) +tools/mcaptest.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/mcaptest$(EXEEXT): $(tools_mcaptest_OBJECTS) $(tools_mcaptest_DEPENDENCIES) $(EXTRA_tools_mcaptest_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/mcaptest$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_mcaptest_OBJECTS) $(tools_mcaptest_LDADD) $(LIBS) +tools/mesh-cfgclient.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) +tools/mesh/$(am__dirstamp): + @$(MKDIR_P) tools/mesh + @: > tools/mesh/$(am__dirstamp) +tools/mesh/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) tools/mesh/$(DEPDIR) + @: > tools/mesh/$(DEPDIR)/$(am__dirstamp) +tools/mesh/cfgcli.$(OBJEXT): tools/mesh/$(am__dirstamp) \ + tools/mesh/$(DEPDIR)/$(am__dirstamp) +tools/mesh/keys.$(OBJEXT): tools/mesh/$(am__dirstamp) \ + tools/mesh/$(DEPDIR)/$(am__dirstamp) +tools/mesh/util.$(OBJEXT): tools/mesh/$(am__dirstamp) \ + tools/mesh/$(DEPDIR)/$(am__dirstamp) +tools/mesh/remote.$(OBJEXT): tools/mesh/$(am__dirstamp) \ + tools/mesh/$(DEPDIR)/$(am__dirstamp) +tools/mesh/agent.$(OBJEXT): tools/mesh/$(am__dirstamp) \ + tools/mesh/$(DEPDIR)/$(am__dirstamp) +tools/mesh/mesh-db.$(OBJEXT): tools/mesh/$(am__dirstamp) \ + tools/mesh/$(DEPDIR)/$(am__dirstamp) + +tools/mesh-cfgclient$(EXEEXT): $(tools_mesh_cfgclient_OBJECTS) $(tools_mesh_cfgclient_DEPENDENCIES) $(EXTRA_tools_mesh_cfgclient_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/mesh-cfgclient$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_mesh_cfgclient_OBJECTS) $(tools_mesh_cfgclient_LDADD) $(LIBS) +tools/mesh-cfgtest.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/mesh-cfgtest$(EXEEXT): $(tools_mesh_cfgtest_OBJECTS) $(tools_mesh_cfgtest_DEPENDENCIES) $(EXTRA_tools_mesh_cfgtest_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/mesh-cfgtest$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_mesh_cfgtest_OBJECTS) $(tools_mesh_cfgtest_LDADD) $(LIBS) +tools/mesh-tester.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/mesh-tester$(EXEEXT): $(tools_mesh_tester_OBJECTS) $(tools_mesh_tester_DEPENDENCIES) $(EXTRA_tools_mesh_tester_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/mesh-tester$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_mesh_tester_OBJECTS) $(tools_mesh_tester_LDADD) $(LIBS) +tools/meshctl.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) +tools/mesh-gatt/$(am__dirstamp): + @$(MKDIR_P) tools/mesh-gatt + @: > tools/mesh-gatt/$(am__dirstamp) +tools/mesh-gatt/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) tools/mesh-gatt/$(DEPDIR) + @: > tools/mesh-gatt/$(DEPDIR)/$(am__dirstamp) +tools/mesh-gatt/node.$(OBJEXT): tools/mesh-gatt/$(am__dirstamp) \ + tools/mesh-gatt/$(DEPDIR)/$(am__dirstamp) +tools/mesh-gatt/gatt.$(OBJEXT): tools/mesh-gatt/$(am__dirstamp) \ + tools/mesh-gatt/$(DEPDIR)/$(am__dirstamp) +tools/mesh-gatt/crypto.$(OBJEXT): tools/mesh-gatt/$(am__dirstamp) \ + tools/mesh-gatt/$(DEPDIR)/$(am__dirstamp) +tools/mesh-gatt/net.$(OBJEXT): tools/mesh-gatt/$(am__dirstamp) \ + tools/mesh-gatt/$(DEPDIR)/$(am__dirstamp) +tools/mesh-gatt/prov.$(OBJEXT): tools/mesh-gatt/$(am__dirstamp) \ + tools/mesh-gatt/$(DEPDIR)/$(am__dirstamp) +tools/mesh-gatt/util.$(OBJEXT): tools/mesh-gatt/$(am__dirstamp) \ + tools/mesh-gatt/$(DEPDIR)/$(am__dirstamp) +tools/mesh-gatt/prov-db.$(OBJEXT): tools/mesh-gatt/$(am__dirstamp) \ + tools/mesh-gatt/$(DEPDIR)/$(am__dirstamp) +tools/mesh-gatt/config-client.$(OBJEXT): \ + tools/mesh-gatt/$(am__dirstamp) \ + tools/mesh-gatt/$(DEPDIR)/$(am__dirstamp) +tools/mesh-gatt/config-server.$(OBJEXT): \ + tools/mesh-gatt/$(am__dirstamp) \ + tools/mesh-gatt/$(DEPDIR)/$(am__dirstamp) +tools/mesh-gatt/onoff-model.$(OBJEXT): \ + tools/mesh-gatt/$(am__dirstamp) \ + tools/mesh-gatt/$(DEPDIR)/$(am__dirstamp) + +tools/meshctl$(EXEEXT): $(tools_meshctl_OBJECTS) $(tools_meshctl_DEPENDENCIES) $(EXTRA_tools_meshctl_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/meshctl$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_meshctl_OBJECTS) $(tools_meshctl_LDADD) $(LIBS) +tools/mgmt-tester.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/mgmt-tester$(EXEEXT): $(tools_mgmt_tester_OBJECTS) $(tools_mgmt_tester_DEPENDENCIES) $(EXTRA_tools_mgmt_tester_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/mgmt-tester$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_mgmt_tester_OBJECTS) $(tools_mgmt_tester_LDADD) $(LIBS) +tools/mpris-proxy.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/mpris-proxy$(EXEEXT): $(tools_mpris_proxy_OBJECTS) $(tools_mpris_proxy_DEPENDENCIES) $(EXTRA_tools_mpris_proxy_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/mpris-proxy$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_mpris_proxy_OBJECTS) $(tools_mpris_proxy_LDADD) $(LIBS) +tools/nokfw.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/nokfw$(EXEEXT): $(tools_nokfw_OBJECTS) $(tools_nokfw_DEPENDENCIES) $(EXTRA_tools_nokfw_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/nokfw$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_nokfw_OBJECTS) $(tools_nokfw_LDADD) $(LIBS) +gobex/gobex.$(OBJEXT): gobex/$(am__dirstamp) \ + gobex/$(DEPDIR)/$(am__dirstamp) +gobex/gobex-defs.$(OBJEXT): gobex/$(am__dirstamp) \ + gobex/$(DEPDIR)/$(am__dirstamp) +gobex/gobex-packet.$(OBJEXT): gobex/$(am__dirstamp) \ + gobex/$(DEPDIR)/$(am__dirstamp) +gobex/gobex-header.$(OBJEXT): gobex/$(am__dirstamp) \ + gobex/$(DEPDIR)/$(am__dirstamp) +gobex/gobex-transfer.$(OBJEXT): gobex/$(am__dirstamp) \ + gobex/$(DEPDIR)/$(am__dirstamp) +gobex/gobex-apparam.$(OBJEXT): gobex/$(am__dirstamp) \ + gobex/$(DEPDIR)/$(am__dirstamp) +tools/obex-client-tool.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/obex-client-tool$(EXEEXT): $(tools_obex_client_tool_OBJECTS) $(tools_obex_client_tool_DEPENDENCIES) $(EXTRA_tools_obex_client_tool_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/obex-client-tool$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_obex_client_tool_OBJECTS) $(tools_obex_client_tool_LDADD) $(LIBS) +tools/obex-server-tool.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/obex-server-tool$(EXEEXT): $(tools_obex_server_tool_OBJECTS) $(tools_obex_server_tool_DEPENDENCIES) $(EXTRA_tools_obex_server_tool_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/obex-server-tool$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_obex_server_tool_OBJECTS) $(tools_obex_server_tool_LDADD) $(LIBS) +tools/obexctl.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/obexctl$(EXEEXT): $(tools_obexctl_OBJECTS) $(tools_obexctl_DEPENDENCIES) $(EXTRA_tools_obexctl_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/obexctl$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_obexctl_OBJECTS) $(tools_obexctl_LDADD) $(LIBS) +tools/oobtest.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/oobtest$(EXEEXT): $(tools_oobtest_OBJECTS) $(tools_oobtest_DEPENDENCIES) $(EXTRA_tools_oobtest_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/oobtest$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_oobtest_OBJECTS) $(tools_oobtest_LDADD) $(LIBS) +tools/rctest.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/rctest$(EXEEXT): $(tools_rctest_OBJECTS) $(tools_rctest_DEPENDENCIES) $(EXTRA_tools_rctest_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/rctest$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_rctest_OBJECTS) $(tools_rctest_LDADD) $(LIBS) +tools/rfcomm.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/rfcomm$(EXEEXT): $(tools_rfcomm_OBJECTS) $(tools_rfcomm_DEPENDENCIES) $(EXTRA_tools_rfcomm_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/rfcomm$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_rfcomm_OBJECTS) $(tools_rfcomm_LDADD) $(LIBS) +tools/rfcomm-tester.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/rfcomm-tester$(EXEEXT): $(tools_rfcomm_tester_OBJECTS) $(tools_rfcomm_tester_DEPENDENCIES) $(EXTRA_tools_rfcomm_tester_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/rfcomm-tester$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_rfcomm_tester_OBJECTS) $(tools_rfcomm_tester_LDADD) $(LIBS) +tools/rtlfw.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/rtlfw$(EXEEXT): $(tools_rtlfw_OBJECTS) $(tools_rtlfw_DEPENDENCIES) $(EXTRA_tools_rtlfw_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/rtlfw$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_rtlfw_OBJECTS) $(tools_rtlfw_LDADD) $(LIBS) +tools/sco-tester.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/sco-tester$(EXEEXT): $(tools_sco_tester_OBJECTS) $(tools_sco_tester_DEPENDENCIES) $(EXTRA_tools_sco_tester_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/sco-tester$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_sco_tester_OBJECTS) $(tools_sco_tester_LDADD) $(LIBS) +tools/scotest.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/scotest$(EXEEXT): $(tools_scotest_OBJECTS) $(tools_scotest_DEPENDENCIES) $(EXTRA_tools_scotest_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/scotest$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_scotest_OBJECTS) $(tools_scotest_LDADD) $(LIBS) +tools/sdptool.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) +src/sdp-xml.$(OBJEXT): src/$(am__dirstamp) \ + src/$(DEPDIR)/$(am__dirstamp) + +tools/sdptool$(EXEEXT): $(tools_sdptool_OBJECTS) $(tools_sdptool_DEPENDENCIES) $(EXTRA_tools_sdptool_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/sdptool$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_sdptool_OBJECTS) $(tools_sdptool_LDADD) $(LIBS) +tools/seq2bseq.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/seq2bseq$(EXEEXT): $(tools_seq2bseq_OBJECTS) $(tools_seq2bseq_DEPENDENCIES) $(EXTRA_tools_seq2bseq_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/seq2bseq$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_seq2bseq_OBJECTS) $(tools_seq2bseq_LDADD) $(LIBS) +tools/smp-tester.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/smp-tester$(EXEEXT): $(tools_smp_tester_OBJECTS) $(tools_smp_tester_DEPENDENCIES) $(EXTRA_tools_smp_tester_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/smp-tester$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_smp_tester_OBJECTS) $(tools_smp_tester_LDADD) $(LIBS) +tools/test-runner.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/test-runner$(EXEEXT): $(tools_test_runner_OBJECTS) $(tools_test_runner_DEPENDENCIES) $(EXTRA_tools_test_runner_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/test-runner$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_test_runner_OBJECTS) $(tools_test_runner_LDADD) $(LIBS) +tools/userchan-tester.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) + +tools/userchan-tester$(EXEEXT): $(tools_userchan_tester_OBJECTS) $(tools_userchan_tester_DEPENDENCIES) $(EXTRA_tools_userchan_tester_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/userchan-tester$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_userchan_tester_OBJECTS) $(tools_userchan_tester_LDADD) $(LIBS) +unit/$(am__dirstamp): + @$(MKDIR_P) unit + @: > unit/$(am__dirstamp) +unit/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) unit/$(DEPDIR) + @: > unit/$(DEPDIR)/$(am__dirstamp) +unit/test-avctp.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-avctp$(EXEEXT): $(unit_test_avctp_OBJECTS) $(unit_test_avctp_DEPENDENCIES) $(EXTRA_unit_test_avctp_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-avctp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_avctp_OBJECTS) $(unit_test_avctp_LDADD) $(LIBS) +unit/test-avdtp.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-avdtp$(EXEEXT): $(unit_test_avdtp_OBJECTS) $(unit_test_avdtp_DEPENDENCIES) $(EXTRA_unit_test_avdtp_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-avdtp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_avdtp_OBJECTS) $(unit_test_avdtp_LDADD) $(LIBS) +unit/test-avrcp.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-avrcp$(EXEEXT): $(unit_test_avrcp_OBJECTS) $(unit_test_avrcp_DEPENDENCIES) $(EXTRA_unit_test_avrcp_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-avrcp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_avrcp_OBJECTS) $(unit_test_avrcp_LDADD) $(LIBS) +unit/test-bap.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-bap$(EXEEXT): $(unit_test_bap_OBJECTS) $(unit_test_bap_DEPENDENCIES) $(EXTRA_unit_test_bap_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-bap$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_bap_OBJECTS) $(unit_test_bap_LDADD) $(LIBS) +unit/test-bass.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-bass$(EXEEXT): $(unit_test_bass_OBJECTS) $(unit_test_bass_DEPENDENCIES) $(EXTRA_unit_test_bass_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-bass$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_bass_OBJECTS) $(unit_test_bass_LDADD) $(LIBS) +unit/test-crc.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-crc$(EXEEXT): $(unit_test_crc_OBJECTS) $(unit_test_crc_DEPENDENCIES) $(EXTRA_unit_test_crc_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-crc$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_crc_OBJECTS) $(unit_test_crc_LDADD) $(LIBS) +unit/test-crypto.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-crypto$(EXEEXT): $(unit_test_crypto_OBJECTS) $(unit_test_crypto_DEPENDENCIES) $(EXTRA_unit_test_crypto_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-crypto$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_crypto_OBJECTS) $(unit_test_crypto_LDADD) $(LIBS) +unit/test-ecc.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-ecc$(EXEEXT): $(unit_test_ecc_OBJECTS) $(unit_test_ecc_DEPENDENCIES) $(EXTRA_unit_test_ecc_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-ecc$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_ecc_OBJECTS) $(unit_test_ecc_LDADD) $(LIBS) +unit/test-eir.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-eir$(EXEEXT): $(unit_test_eir_OBJECTS) $(unit_test_eir_DEPENDENCIES) $(EXTRA_unit_test_eir_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-eir$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_eir_OBJECTS) $(unit_test_eir_LDADD) $(LIBS) +unit/test-gatt.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-gatt$(EXEEXT): $(unit_test_gatt_OBJECTS) $(unit_test_gatt_DEPENDENCIES) $(EXTRA_unit_test_gatt_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-gatt$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_gatt_OBJECTS) $(unit_test_gatt_LDADD) $(LIBS) +unit/test-gattrib.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-gattrib$(EXEEXT): $(unit_test_gattrib_OBJECTS) $(unit_test_gattrib_DEPENDENCIES) $(EXTRA_unit_test_gattrib_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-gattrib$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_gattrib_OBJECTS) $(unit_test_gattrib_LDADD) $(LIBS) +unit/test-gdbus-client.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-gdbus-client$(EXEEXT): $(unit_test_gdbus_client_OBJECTS) $(unit_test_gdbus_client_DEPENDENCIES) $(EXTRA_unit_test_gdbus_client_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-gdbus-client$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_gdbus_client_OBJECTS) $(unit_test_gdbus_client_LDADD) $(LIBS) +unit/util.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) +unit/test-gobex.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-gobex$(EXEEXT): $(unit_test_gobex_OBJECTS) $(unit_test_gobex_DEPENDENCIES) $(EXTRA_unit_test_gobex_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-gobex$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_gobex_OBJECTS) $(unit_test_gobex_LDADD) $(LIBS) +unit/test-gobex-apparam.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-gobex-apparam$(EXEEXT): $(unit_test_gobex_apparam_OBJECTS) $(unit_test_gobex_apparam_DEPENDENCIES) $(EXTRA_unit_test_gobex_apparam_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-gobex-apparam$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_gobex_apparam_OBJECTS) $(unit_test_gobex_apparam_LDADD) $(LIBS) +unit/test-gobex-header.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-gobex-header$(EXEEXT): $(unit_test_gobex_header_OBJECTS) $(unit_test_gobex_header_DEPENDENCIES) $(EXTRA_unit_test_gobex_header_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-gobex-header$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_gobex_header_OBJECTS) $(unit_test_gobex_header_LDADD) $(LIBS) +unit/test-gobex-packet.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-gobex-packet$(EXEEXT): $(unit_test_gobex_packet_OBJECTS) $(unit_test_gobex_packet_DEPENDENCIES) $(EXTRA_unit_test_gobex_packet_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-gobex-packet$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_gobex_packet_OBJECTS) $(unit_test_gobex_packet_LDADD) $(LIBS) +unit/test-gobex-transfer.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-gobex-transfer$(EXEEXT): $(unit_test_gobex_transfer_OBJECTS) $(unit_test_gobex_transfer_DEPENDENCIES) $(EXTRA_unit_test_gobex_transfer_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-gobex-transfer$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_gobex_transfer_OBJECTS) $(unit_test_gobex_transfer_LDADD) $(LIBS) +unit/test-hfp.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-hfp$(EXEEXT): $(unit_test_hfp_OBJECTS) $(unit_test_hfp_DEPENDENCIES) $(EXTRA_unit_test_hfp_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-hfp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_hfp_OBJECTS) $(unit_test_hfp_LDADD) $(LIBS) +unit/test-hog.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-hog$(EXEEXT): $(unit_test_hog_OBJECTS) $(unit_test_hog_DEPENDENCIES) $(EXTRA_unit_test_hog_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-hog$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_hog_OBJECTS) $(unit_test_hog_LDADD) $(LIBS) +unit/test-lib.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-lib$(EXEEXT): $(unit_test_lib_OBJECTS) $(unit_test_lib_DEPENDENCIES) $(EXTRA_unit_test_lib_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-lib$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_lib_OBJECTS) $(unit_test_lib_LDADD) $(LIBS) +unit/test_mesh_crypto-test-mesh-crypto.$(OBJEXT): \ + unit/$(am__dirstamp) unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-mesh-crypto$(EXEEXT): $(unit_test_mesh_crypto_OBJECTS) $(unit_test_mesh_crypto_DEPENDENCIES) $(EXTRA_unit_test_mesh_crypto_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-mesh-crypto$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_mesh_crypto_OBJECTS) $(unit_test_mesh_crypto_LDADD) $(LIBS) +unit/test-mgmt.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-mgmt$(EXEEXT): $(unit_test_mgmt_OBJECTS) $(unit_test_mgmt_DEPENDENCIES) $(EXTRA_unit_test_mgmt_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-mgmt$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_mgmt_OBJECTS) $(unit_test_mgmt_LDADD) $(LIBS) +unit/test-micp.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-micp$(EXEEXT): $(unit_test_micp_OBJECTS) $(unit_test_micp_DEPENDENCIES) $(EXTRA_unit_test_micp_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-micp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_micp_OBJECTS) $(unit_test_micp_LDADD) $(LIBS) +unit/test_midi-test-midi.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) +profiles/midi/unit_test_midi-libmidi.$(OBJEXT): \ + profiles/midi/$(am__dirstamp) \ + profiles/midi/$(DEPDIR)/$(am__dirstamp) + +unit/test-midi$(EXEEXT): $(unit_test_midi_OBJECTS) $(unit_test_midi_DEPENDENCIES) $(EXTRA_unit_test_midi_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-midi$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_midi_OBJECTS) $(unit_test_midi_LDADD) $(LIBS) +unit/test-queue.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-queue$(EXEEXT): $(unit_test_queue_OBJECTS) $(unit_test_queue_DEPENDENCIES) $(EXTRA_unit_test_queue_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-queue$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_queue_OBJECTS) $(unit_test_queue_LDADD) $(LIBS) +unit/test-ringbuf.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-ringbuf$(EXEEXT): $(unit_test_ringbuf_OBJECTS) $(unit_test_ringbuf_DEPENDENCIES) $(EXTRA_unit_test_ringbuf_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-ringbuf$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_ringbuf_OBJECTS) $(unit_test_ringbuf_LDADD) $(LIBS) +unit/test-sdp.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-sdp$(EXEEXT): $(unit_test_sdp_OBJECTS) $(unit_test_sdp_DEPENDENCIES) $(EXTRA_unit_test_sdp_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-sdp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_sdp_OBJECTS) $(unit_test_sdp_LDADD) $(LIBS) +unit/test-tester.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-tester$(EXEEXT): $(unit_test_tester_OBJECTS) $(unit_test_tester_DEPENDENCIES) $(EXTRA_unit_test_tester_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-tester$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_tester_OBJECTS) $(unit_test_tester_LDADD) $(LIBS) +unit/test-textfile.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-textfile$(EXEEXT): $(unit_test_textfile_OBJECTS) $(unit_test_textfile_DEPENDENCIES) $(EXTRA_unit_test_textfile_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-textfile$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_textfile_OBJECTS) $(unit_test_textfile_LDADD) $(LIBS) +unit/test-uhid.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-uhid$(EXEEXT): $(unit_test_uhid_OBJECTS) $(unit_test_uhid_DEPENDENCIES) $(EXTRA_unit_test_uhid_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-uhid$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_uhid_OBJECTS) $(unit_test_uhid_LDADD) $(LIBS) +unit/test-uuid.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-uuid$(EXEEXT): $(unit_test_uuid_OBJECTS) $(unit_test_uuid_DEPENDENCIES) $(EXTRA_unit_test_uuid_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-uuid$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_uuid_OBJECTS) $(unit_test_uuid_LDADD) $(LIBS) +unit/test-vcp.$(OBJEXT): unit/$(am__dirstamp) \ + unit/$(DEPDIR)/$(am__dirstamp) + +unit/test-vcp$(EXEEXT): $(unit_test_vcp_OBJECTS) $(unit_test_vcp_DEPENDENCIES) $(EXTRA_unit_test_vcp_DEPENDENCIES) unit/$(am__dirstamp) + @rm -f unit/test-vcp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(unit_test_vcp_OBJECTS) $(unit_test_vcp_LDADD) $(LIBS) +install-testSCRIPTS: $(test_SCRIPTS) + @$(NORMAL_INSTALL) + @list='$(test_SCRIPTS)'; test -n "$(testdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(testdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(testdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n' \ + -e 'h;s|.*|.|' \ + -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) { files[d] = files[d] " " $$1; \ + if (++n[d] == $(am__install_max)) { \ + print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ + else { print "f", d "/" $$4, $$1 } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(testdir)$$dir'"; \ + $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(testdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-testSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(test_SCRIPTS)'; test -n "$(testdir)" || exit 0; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 's,.*/,,;$(transform)'`; \ + dir='$(DESTDIR)$(testdir)'; $(am__uninstall_files_from_dir) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f android/*.$(OBJEXT) + -rm -f android/*.lo + -rm -f android/audio_utils/*.$(OBJEXT) + -rm -f android/audio_utils/*.lo + -rm -f android/client/*.$(OBJEXT) + -rm -f android/hardware/*.$(OBJEXT) + -rm -f attrib/*.$(OBJEXT) + -rm -f btio/*.$(OBJEXT) + -rm -f client/*.$(OBJEXT) + -rm -f ell/*.$(OBJEXT) + -rm -f ell/*.lo + -rm -f emulator/*.$(OBJEXT) + -rm -f gdbus/*.$(OBJEXT) + -rm -f gdbus/*.lo + -rm -f gobex/*.$(OBJEXT) + -rm -f lib/*.$(OBJEXT) + -rm -f lib/*.lo + -rm -f mesh/*.$(OBJEXT) + -rm -f monitor/*.$(OBJEXT) + -rm -f obexd/client/*.$(OBJEXT) + -rm -f obexd/plugins/*.$(OBJEXT) + -rm -f obexd/src/*.$(OBJEXT) + -rm -f peripheral/*.$(OBJEXT) + -rm -f plugins/*.$(OBJEXT) + -rm -f profiles/audio/*.$(OBJEXT) + -rm -f profiles/battery/*.$(OBJEXT) + -rm -f profiles/cups/*.$(OBJEXT) + -rm -f profiles/deviceinfo/*.$(OBJEXT) + -rm -f profiles/gap/*.$(OBJEXT) + -rm -f profiles/health/*.$(OBJEXT) + -rm -f profiles/iap/*.$(OBJEXT) + -rm -f profiles/input/*.$(OBJEXT) + -rm -f profiles/midi/*.$(OBJEXT) + -rm -f profiles/network/*.$(OBJEXT) + -rm -f profiles/sap/*.$(OBJEXT) + -rm -f profiles/scanparam/*.$(OBJEXT) + -rm -f src/*.$(OBJEXT) + -rm -f src/shared/*.$(OBJEXT) + -rm -f src/shared/*.lo + -rm -f tools/*.$(OBJEXT) + -rm -f tools/mesh-gatt/*.$(OBJEXT) + -rm -f tools/mesh/*.$(OBJEXT) + -rm -f tools/parser/*.$(OBJEXT) + -rm -f unit/*.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/a2dp-sink.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/a2dp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/android_tester-tester-a2dp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/android_tester-tester-avrcp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/android_tester-tester-bluetooth.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/android_tester-tester-gatt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/android_tester-tester-hdp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/android_tester-tester-hidhost.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/android_tester-tester-main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/android_tester-tester-map-client.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/android_tester-tester-pan.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/android_tester-tester-socket.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/audio_a2dp_default_la-hal-audio-aptx.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/audio_a2dp_default_la-hal-audio-sbc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/audio_a2dp_default_la-hal-audio.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/audio_sco_default_la-hal-sco.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/avctp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/avdtp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/avdtptest-avdtp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/avdtptest-avdtptest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/avrcp-lib.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/avrcp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/bluetooth.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/bluetooth_default_la-hal-a2dp-sink.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/bluetooth_default_la-hal-a2dp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/bluetooth_default_la-hal-avrcp-ctrl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/bluetooth_default_la-hal-avrcp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/bluetooth_default_la-hal-bluetooth.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/bluetooth_default_la-hal-gatt.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/bluetooth_default_la-hal-handsfree-client.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/bluetooth_default_la-hal-handsfree.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/bluetooth_default_la-hal-health.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/bluetooth_default_la-hal-hidhost.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/bluetooth_default_la-hal-ipc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/bluetooth_default_la-hal-map-client.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/bluetooth_default_la-hal-pan.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/bluetooth_default_la-hal-socket.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/bluetooth_default_la-hal-utils.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/bluetoothd-snoop.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/gatt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/haltest-hal-utils.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/handsfree-client.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/handsfree.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/health.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/hidhost.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/ipc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/ipc_tester-hal-utils.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/ipc_tester-ipc-tester.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/map-client.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/pan.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/sco.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/socket.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/system-emulator.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/test-ipc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/audio_utils/$(DEPDIR)/audio_sco_default_la-resampler.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-haltest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-history.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-if-audio.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-if-av-sink.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-if-av.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-if-bt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-if-gatt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-if-hf-client.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-if-hf.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-if-hh.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-if-hl.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-if-mce.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-if-pan.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-if-rc-ctrl.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-if-rc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-if-sco.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-if-sock.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-pollhandler.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-tabcompletion.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/client/$(DEPDIR)/haltest-terminal.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/hardware/$(DEPDIR)/android_tester-hardware.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@android/hardware/$(DEPDIR)/haltest-hardware.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/att.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-att.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-gatt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-gattrib.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/gatt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/gattrib.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/gatttool.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/interactive.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/utils.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@btio/$(DEPDIR)/android_avdtptest-btio.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@btio/$(DEPDIR)/bluetoothd-btio.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@btio/$(DEPDIR)/btio.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@btio/$(DEPDIR)/obexd-btio.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/admin.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/adv_monitor.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/advertising.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/agent.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/assistant.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/display.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/gatt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/mgmt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/player.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/print.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/base64.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/cert-crypto.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/cert.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/checksum.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/cipher.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/dbus-client.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/dbus-filter.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/dbus-message.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/dbus-name-cache.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/dbus-service.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/dbus-util.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/dbus.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/ecc-external.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/ecc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/ecdh.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/gvariant-util.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/hashmap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/idle.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/io.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/key.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/log.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/main.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/pem.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/queue.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/random.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/settings.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/signal.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/siphash.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/string.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/strv.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/tester.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/time.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/timeout.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/tls-extensions.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/tls-record.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/tls-suites.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/tls.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/utf8.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/util.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@ell/$(DEPDIR)/uuid.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/amp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/android_android_tester-btdev.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/android_android_tester-bthost.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/android_android_tester-hciemu.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/android_android_tester-smp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/android_android_tester-vhci.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/android_ipc_tester-btdev.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/android_ipc_tester-bthost.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/android_ipc_tester-hciemu.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/android_ipc_tester-smp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/android_ipc_tester-vhci.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/b1ee.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/btdev.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/bthost.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/hciemu.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/hfp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/le.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/phy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/serial.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/server.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/smp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/vhci.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/client.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/mainloop.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/object.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/polkit.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/watch.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex-apparam.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex-defs.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex-header.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex-packet.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex-transfer.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/obexd-gobex-apparam.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/obexd-gobex-defs.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/obexd-gobex-header.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/obexd-gobex-packet.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/obexd-gobex-transfer.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/obexd-gobex.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/bluetooth.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/hci.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/sdp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/uuid.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/agent.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/appkey.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/cfgmod-server.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/crypto.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/dbus.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/friend.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/keyring.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/manager.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/mesh-config-json.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/mesh-io-generic.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/mesh-io-mgmt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/mesh-io-unit.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/mesh-io.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/mesh-mgmt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/mesh.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/model.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/net-keys.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/net.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/node.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/pb-adv.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/prov-acceptor.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/prov-initiator.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/prvbeac-server.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/remprv-server.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/rpl.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@mesh/$(DEPDIR)/util.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/a2dp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/analyze.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/att.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/avctp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/avdtp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/bnep.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/broadcom.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/control.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/crc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/display.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/ellisys.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/hcidump.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/hwdb.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/intel.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/jlink.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/keys.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/l2cap.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/ll.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/lmp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/msft.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/packet.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/rfcomm.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/sdp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/vendor.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-bip-common.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-bip.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-bluetooth.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-driver.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-ftp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-manager.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-map-event.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-map.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-mns.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-opp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-pbap.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-session.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-sync.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-transfer.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-transport.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-bluetooth.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-filesystem.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-ftp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-irmc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-mas.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-messages-dummy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-opp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-pbap.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-pcsuite.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-phonebook-@PLUGIN_PHONEBOOK@.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-vcard.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/src/$(DEPDIR)/obexd-log.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/src/$(DEPDIR)/obexd-main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/src/$(DEPDIR)/obexd-manager.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/src/$(DEPDIR)/obexd-mimetype.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/src/$(DEPDIR)/obexd-obex.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/src/$(DEPDIR)/obexd-plugin.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/src/$(DEPDIR)/obexd-server.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/src/$(DEPDIR)/obexd-service.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@obexd/src/$(DEPDIR)/obexd-transport.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@peripheral/$(DEPDIR)/attach.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@peripheral/$(DEPDIR)/efivars.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@peripheral/$(DEPDIR)/gap.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@peripheral/$(DEPDIR)/gatt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@peripheral/$(DEPDIR)/log.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@peripheral/$(DEPDIR)/main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-admin.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-autopair.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-hostname.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-neard.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-policy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-sixaxis.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-wiimote.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-a2dp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-asha.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-avctp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-avdtp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-avrcp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-bap.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-bass.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-ccp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-control.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-csip.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-mcp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-media.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-micp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-player.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-sink.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-source.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-transport.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-vcp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/battery/$(DEPDIR)/bas.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/battery/$(DEPDIR)/bluetoothd-bas.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/battery/$(DEPDIR)/bluetoothd-battery.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/cups/$(DEPDIR)/hcrp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/cups/$(DEPDIR)/main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/cups/$(DEPDIR)/sdp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/cups/$(DEPDIR)/spp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/deviceinfo/$(DEPDIR)/bluetoothd-dis.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/deviceinfo/$(DEPDIR)/dis.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/gap/$(DEPDIR)/bluetoothd-gas.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/health/$(DEPDIR)/bluetoothd-hdp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/health/$(DEPDIR)/bluetoothd-hdp_main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/health/$(DEPDIR)/bluetoothd-hdp_manager.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/health/$(DEPDIR)/bluetoothd-hdp_util.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/health/$(DEPDIR)/bluetoothd-mcap.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/health/$(DEPDIR)/mcap.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/iap/$(DEPDIR)/main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/input/$(DEPDIR)/bluetoothd-device.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/input/$(DEPDIR)/bluetoothd-hog-lib.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/input/$(DEPDIR)/bluetoothd-hog.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/input/$(DEPDIR)/bluetoothd-manager.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/input/$(DEPDIR)/bluetoothd-server.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/input/$(DEPDIR)/bluetoothd-suspend-none.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/input/$(DEPDIR)/hog-lib.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/midi/$(DEPDIR)/bluetoothd-libmidi.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/midi/$(DEPDIR)/bluetoothd-midi.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/midi/$(DEPDIR)/unit_test_midi-libmidi.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/network/$(DEPDIR)/bluetoothd-bnep.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/network/$(DEPDIR)/bluetoothd-connection.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/network/$(DEPDIR)/bluetoothd-manager.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/network/$(DEPDIR)/bluetoothd-server.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/network/$(DEPDIR)/bnep.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/sap/$(DEPDIR)/bluetoothd-main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/sap/$(DEPDIR)/bluetoothd-manager.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/sap/$(DEPDIR)/bluetoothd-sap-dummy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/sap/$(DEPDIR)/bluetoothd-server.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/scanparam/$(DEPDIR)/bluetoothd-scan.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/scanparam/$(DEPDIR)/bluetoothd-scpp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@profiles/scanparam/$(DEPDIR)/scpp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/android_avdtptest-log.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-adapter.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-adv_monitor.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-advertising.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-agent.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-backtrace.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-battery.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-dbus-common.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-device.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-eir.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-error.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-gatt-client.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-gatt-database.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-log.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-plugin.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-profile.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-rfkill.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-sdp-client.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-sdp-xml.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-sdpd-database.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-sdpd-request.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-sdpd-server.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-sdpd-service.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-service.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-set.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-settings.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-storage.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-textfile.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-uuid-helper.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/eir.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/log.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/oui.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sdp-client.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sdp-xml.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sdpd-database.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sdpd-request.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sdpd-server.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sdpd-service.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/settings.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/textfile.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/uuid-helper.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/android_avdtptest-log.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/android_avdtptest-queue.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/android_avdtptest-util.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/btp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-ad.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-asha.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-att.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-bap-debug.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-bap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-bass.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-btsnoop.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-ccp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-crypto.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-csip.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-ecc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-gap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-gatt-client.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-gatt-db.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-gatt-helpers.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-gatt-server.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-hci-crypto.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-hci.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-hfp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-io-ell.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-log.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-mainloop-ell.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-mcp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-mgmt.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-micp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-pcap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-queue.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-ringbuf.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-shell.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-timeout-ell.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-uhid.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-util.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_ell_la-vcp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-ad.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-asha.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-att.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-bap-debug.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-bap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-bass.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-btsnoop.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-ccp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-crypto.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-csip.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-ecc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-gap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-gatt-client.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-gatt-db.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-gatt-helpers.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-gatt-server.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-hci-crypto.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-hci.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-hfp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-io-glib.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-log.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-mainloop-glib.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-mainloop-notify.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-mcp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-mgmt.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-micp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-pcap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-queue.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-ringbuf.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-shell.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-tester.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-timeout-glib.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-uhid.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-util.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_glib_la-vcp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-ad.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-asha.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-att.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-bap-debug.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-bap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-bass.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-btsnoop.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-ccp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-crypto.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-csip.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-ecc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-gap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-client.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-db.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-helpers.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-server.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-hci-crypto.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-hci.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-hfp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-io-mainloop.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-log.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-mainloop-notify.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-mainloop.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-mcp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-mgmt.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-micp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-pcap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-queue.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-ringbuf.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-shell.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-timeout-mainloop.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-uhid.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-util.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/libshared_mainloop_la-vcp.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/3dsp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/advtest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/amptest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/avinfo.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/avtest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/bcmfw.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/bdaddr.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/bluemoon.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/bluetooth-player.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/bnep-tester.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/bneptest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btattach.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btconfig.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btgatt-client.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btgatt-server.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btinfo.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btiotest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btmgmt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btmon-logger.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btpclient.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btpclientctl.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btproxy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btsnoop.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/check-selftest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/ciptool.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/cltest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/create-image.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/eddystone.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/gap-tester.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/gatt-service.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hci-tester.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_ath3k.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_bcm43xx.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_intel.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_qualcomm.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_st.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_ti.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_tialt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciconfig.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hcidump.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hcieventmask.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hcisecfilter.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hcitool.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hex2hcd.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hid2hci.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hwdb.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/ibeacon.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/ioctl-tester.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/iso-tester.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/isotest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/l2cap-tester.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/l2ping.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/l2test.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/mcaptest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/mesh-cfgclient.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/mesh-cfgtest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/mesh-tester.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/meshctl.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/mgmt-tester.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/mpris-proxy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/nokfw.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/obex-client-tool.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/obex-server-tool.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/obexctl.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/oobtest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/rctest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/rfcomm-tester.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/rfcomm.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/rtlfw.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/sco-tester.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/scotest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/sdptool.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/seq2bseq.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/smp-tester.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/test-runner.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/userchan-tester.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/mesh-gatt/$(DEPDIR)/config-client.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/mesh-gatt/$(DEPDIR)/config-server.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/mesh-gatt/$(DEPDIR)/crypto.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/mesh-gatt/$(DEPDIR)/gatt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/mesh-gatt/$(DEPDIR)/net.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/mesh-gatt/$(DEPDIR)/node.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/mesh-gatt/$(DEPDIR)/onoff-model.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/mesh-gatt/$(DEPDIR)/prov-db.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/mesh-gatt/$(DEPDIR)/prov.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/mesh-gatt/$(DEPDIR)/util.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/mesh/$(DEPDIR)/agent.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/mesh/$(DEPDIR)/cfgcli.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/mesh/$(DEPDIR)/keys.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/mesh/$(DEPDIR)/mesh-db.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/mesh/$(DEPDIR)/remote.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/mesh/$(DEPDIR)/util.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/amp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/att.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/avctp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/avdtp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/avrcp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/bnep.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/bpa.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/capi.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/cmtp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/csr.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/ericsson.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/hci.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/hcrp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/hidp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/l2cap.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/lmp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/obex.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/parser.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/ppp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/rfcomm.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/sap.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/sdp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/smp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/tcpip.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-avctp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-avdtp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-avrcp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-bap.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-bass.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-crc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-crypto.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-ecc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-eir.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gatt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gattrib.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gdbus-client.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gobex-apparam.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gobex-header.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gobex-packet.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gobex-transfer.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gobex.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-hfp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-hog.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-lib.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-mgmt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-micp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-queue.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-ringbuf.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-sdp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-tester.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-textfile.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-uhid.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-uuid.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-vcp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test_mesh_crypto-test-mesh-crypto.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test_midi-test-midi.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/util.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +android/audio_a2dp_default_la-hal-audio.lo: android/hal-audio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_audio_a2dp_default_la_CPPFLAGS) $(CPPFLAGS) $(android_audio_a2dp_default_la_CFLAGS) $(CFLAGS) -MT android/audio_a2dp_default_la-hal-audio.lo -MD -MP -MF android/$(DEPDIR)/audio_a2dp_default_la-hal-audio.Tpo -c -o android/audio_a2dp_default_la-hal-audio.lo `test -f 'android/hal-audio.c' || echo '$(srcdir)/'`android/hal-audio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/audio_a2dp_default_la-hal-audio.Tpo android/$(DEPDIR)/audio_a2dp_default_la-hal-audio.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-audio.c' object='android/audio_a2dp_default_la-hal-audio.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_audio_a2dp_default_la_CPPFLAGS) $(CPPFLAGS) $(android_audio_a2dp_default_la_CFLAGS) $(CFLAGS) -c -o android/audio_a2dp_default_la-hal-audio.lo `test -f 'android/hal-audio.c' || echo '$(srcdir)/'`android/hal-audio.c + +android/audio_a2dp_default_la-hal-audio-sbc.lo: android/hal-audio-sbc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_audio_a2dp_default_la_CPPFLAGS) $(CPPFLAGS) $(android_audio_a2dp_default_la_CFLAGS) $(CFLAGS) -MT android/audio_a2dp_default_la-hal-audio-sbc.lo -MD -MP -MF android/$(DEPDIR)/audio_a2dp_default_la-hal-audio-sbc.Tpo -c -o android/audio_a2dp_default_la-hal-audio-sbc.lo `test -f 'android/hal-audio-sbc.c' || echo '$(srcdir)/'`android/hal-audio-sbc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/audio_a2dp_default_la-hal-audio-sbc.Tpo android/$(DEPDIR)/audio_a2dp_default_la-hal-audio-sbc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-audio-sbc.c' object='android/audio_a2dp_default_la-hal-audio-sbc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_audio_a2dp_default_la_CPPFLAGS) $(CPPFLAGS) $(android_audio_a2dp_default_la_CFLAGS) $(CFLAGS) -c -o android/audio_a2dp_default_la-hal-audio-sbc.lo `test -f 'android/hal-audio-sbc.c' || echo '$(srcdir)/'`android/hal-audio-sbc.c + +android/audio_a2dp_default_la-hal-audio-aptx.lo: android/hal-audio-aptx.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_audio_a2dp_default_la_CPPFLAGS) $(CPPFLAGS) $(android_audio_a2dp_default_la_CFLAGS) $(CFLAGS) -MT android/audio_a2dp_default_la-hal-audio-aptx.lo -MD -MP -MF android/$(DEPDIR)/audio_a2dp_default_la-hal-audio-aptx.Tpo -c -o android/audio_a2dp_default_la-hal-audio-aptx.lo `test -f 'android/hal-audio-aptx.c' || echo '$(srcdir)/'`android/hal-audio-aptx.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/audio_a2dp_default_la-hal-audio-aptx.Tpo android/$(DEPDIR)/audio_a2dp_default_la-hal-audio-aptx.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-audio-aptx.c' object='android/audio_a2dp_default_la-hal-audio-aptx.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_audio_a2dp_default_la_CPPFLAGS) $(CPPFLAGS) $(android_audio_a2dp_default_la_CFLAGS) $(CFLAGS) -c -o android/audio_a2dp_default_la-hal-audio-aptx.lo `test -f 'android/hal-audio-aptx.c' || echo '$(srcdir)/'`android/hal-audio-aptx.c + +android/audio_sco_default_la-hal-sco.lo: android/hal-sco.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_audio_sco_default_la_CPPFLAGS) $(CPPFLAGS) $(android_audio_sco_default_la_CFLAGS) $(CFLAGS) -MT android/audio_sco_default_la-hal-sco.lo -MD -MP -MF android/$(DEPDIR)/audio_sco_default_la-hal-sco.Tpo -c -o android/audio_sco_default_la-hal-sco.lo `test -f 'android/hal-sco.c' || echo '$(srcdir)/'`android/hal-sco.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/audio_sco_default_la-hal-sco.Tpo android/$(DEPDIR)/audio_sco_default_la-hal-sco.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-sco.c' object='android/audio_sco_default_la-hal-sco.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_audio_sco_default_la_CPPFLAGS) $(CPPFLAGS) $(android_audio_sco_default_la_CFLAGS) $(CFLAGS) -c -o android/audio_sco_default_la-hal-sco.lo `test -f 'android/hal-sco.c' || echo '$(srcdir)/'`android/hal-sco.c + +android/audio_utils/audio_sco_default_la-resampler.lo: android/audio_utils/resampler.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_audio_sco_default_la_CPPFLAGS) $(CPPFLAGS) $(android_audio_sco_default_la_CFLAGS) $(CFLAGS) -MT android/audio_utils/audio_sco_default_la-resampler.lo -MD -MP -MF android/audio_utils/$(DEPDIR)/audio_sco_default_la-resampler.Tpo -c -o android/audio_utils/audio_sco_default_la-resampler.lo `test -f 'android/audio_utils/resampler.c' || echo '$(srcdir)/'`android/audio_utils/resampler.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/audio_utils/$(DEPDIR)/audio_sco_default_la-resampler.Tpo android/audio_utils/$(DEPDIR)/audio_sco_default_la-resampler.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/audio_utils/resampler.c' object='android/audio_utils/audio_sco_default_la-resampler.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_audio_sco_default_la_CPPFLAGS) $(CPPFLAGS) $(android_audio_sco_default_la_CFLAGS) $(CFLAGS) -c -o android/audio_utils/audio_sco_default_la-resampler.lo `test -f 'android/audio_utils/resampler.c' || echo '$(srcdir)/'`android/audio_utils/resampler.c + +android/bluetooth_default_la-hal-bluetooth.lo: android/hal-bluetooth.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -MT android/bluetooth_default_la-hal-bluetooth.lo -MD -MP -MF android/$(DEPDIR)/bluetooth_default_la-hal-bluetooth.Tpo -c -o android/bluetooth_default_la-hal-bluetooth.lo `test -f 'android/hal-bluetooth.c' || echo '$(srcdir)/'`android/hal-bluetooth.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/bluetooth_default_la-hal-bluetooth.Tpo android/$(DEPDIR)/bluetooth_default_la-hal-bluetooth.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-bluetooth.c' object='android/bluetooth_default_la-hal-bluetooth.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -c -o android/bluetooth_default_la-hal-bluetooth.lo `test -f 'android/hal-bluetooth.c' || echo '$(srcdir)/'`android/hal-bluetooth.c + +android/bluetooth_default_la-hal-socket.lo: android/hal-socket.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -MT android/bluetooth_default_la-hal-socket.lo -MD -MP -MF android/$(DEPDIR)/bluetooth_default_la-hal-socket.Tpo -c -o android/bluetooth_default_la-hal-socket.lo `test -f 'android/hal-socket.c' || echo '$(srcdir)/'`android/hal-socket.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/bluetooth_default_la-hal-socket.Tpo android/$(DEPDIR)/bluetooth_default_la-hal-socket.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-socket.c' object='android/bluetooth_default_la-hal-socket.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -c -o android/bluetooth_default_la-hal-socket.lo `test -f 'android/hal-socket.c' || echo '$(srcdir)/'`android/hal-socket.c + +android/bluetooth_default_la-hal-hidhost.lo: android/hal-hidhost.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -MT android/bluetooth_default_la-hal-hidhost.lo -MD -MP -MF android/$(DEPDIR)/bluetooth_default_la-hal-hidhost.Tpo -c -o android/bluetooth_default_la-hal-hidhost.lo `test -f 'android/hal-hidhost.c' || echo '$(srcdir)/'`android/hal-hidhost.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/bluetooth_default_la-hal-hidhost.Tpo android/$(DEPDIR)/bluetooth_default_la-hal-hidhost.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-hidhost.c' object='android/bluetooth_default_la-hal-hidhost.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -c -o android/bluetooth_default_la-hal-hidhost.lo `test -f 'android/hal-hidhost.c' || echo '$(srcdir)/'`android/hal-hidhost.c + +android/bluetooth_default_la-hal-health.lo: android/hal-health.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -MT android/bluetooth_default_la-hal-health.lo -MD -MP -MF android/$(DEPDIR)/bluetooth_default_la-hal-health.Tpo -c -o android/bluetooth_default_la-hal-health.lo `test -f 'android/hal-health.c' || echo '$(srcdir)/'`android/hal-health.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/bluetooth_default_la-hal-health.Tpo android/$(DEPDIR)/bluetooth_default_la-hal-health.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-health.c' object='android/bluetooth_default_la-hal-health.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -c -o android/bluetooth_default_la-hal-health.lo `test -f 'android/hal-health.c' || echo '$(srcdir)/'`android/hal-health.c + +android/bluetooth_default_la-hal-pan.lo: android/hal-pan.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -MT android/bluetooth_default_la-hal-pan.lo -MD -MP -MF android/$(DEPDIR)/bluetooth_default_la-hal-pan.Tpo -c -o android/bluetooth_default_la-hal-pan.lo `test -f 'android/hal-pan.c' || echo '$(srcdir)/'`android/hal-pan.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/bluetooth_default_la-hal-pan.Tpo android/$(DEPDIR)/bluetooth_default_la-hal-pan.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-pan.c' object='android/bluetooth_default_la-hal-pan.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -c -o android/bluetooth_default_la-hal-pan.lo `test -f 'android/hal-pan.c' || echo '$(srcdir)/'`android/hal-pan.c + +android/bluetooth_default_la-hal-a2dp.lo: android/hal-a2dp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -MT android/bluetooth_default_la-hal-a2dp.lo -MD -MP -MF android/$(DEPDIR)/bluetooth_default_la-hal-a2dp.Tpo -c -o android/bluetooth_default_la-hal-a2dp.lo `test -f 'android/hal-a2dp.c' || echo '$(srcdir)/'`android/hal-a2dp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/bluetooth_default_la-hal-a2dp.Tpo android/$(DEPDIR)/bluetooth_default_la-hal-a2dp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-a2dp.c' object='android/bluetooth_default_la-hal-a2dp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -c -o android/bluetooth_default_la-hal-a2dp.lo `test -f 'android/hal-a2dp.c' || echo '$(srcdir)/'`android/hal-a2dp.c + +android/bluetooth_default_la-hal-a2dp-sink.lo: android/hal-a2dp-sink.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -MT android/bluetooth_default_la-hal-a2dp-sink.lo -MD -MP -MF android/$(DEPDIR)/bluetooth_default_la-hal-a2dp-sink.Tpo -c -o android/bluetooth_default_la-hal-a2dp-sink.lo `test -f 'android/hal-a2dp-sink.c' || echo '$(srcdir)/'`android/hal-a2dp-sink.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/bluetooth_default_la-hal-a2dp-sink.Tpo android/$(DEPDIR)/bluetooth_default_la-hal-a2dp-sink.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-a2dp-sink.c' object='android/bluetooth_default_la-hal-a2dp-sink.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -c -o android/bluetooth_default_la-hal-a2dp-sink.lo `test -f 'android/hal-a2dp-sink.c' || echo '$(srcdir)/'`android/hal-a2dp-sink.c + +android/bluetooth_default_la-hal-avrcp.lo: android/hal-avrcp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -MT android/bluetooth_default_la-hal-avrcp.lo -MD -MP -MF android/$(DEPDIR)/bluetooth_default_la-hal-avrcp.Tpo -c -o android/bluetooth_default_la-hal-avrcp.lo `test -f 'android/hal-avrcp.c' || echo '$(srcdir)/'`android/hal-avrcp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/bluetooth_default_la-hal-avrcp.Tpo android/$(DEPDIR)/bluetooth_default_la-hal-avrcp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-avrcp.c' object='android/bluetooth_default_la-hal-avrcp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -c -o android/bluetooth_default_la-hal-avrcp.lo `test -f 'android/hal-avrcp.c' || echo '$(srcdir)/'`android/hal-avrcp.c + +android/bluetooth_default_la-hal-avrcp-ctrl.lo: android/hal-avrcp-ctrl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -MT android/bluetooth_default_la-hal-avrcp-ctrl.lo -MD -MP -MF android/$(DEPDIR)/bluetooth_default_la-hal-avrcp-ctrl.Tpo -c -o android/bluetooth_default_la-hal-avrcp-ctrl.lo `test -f 'android/hal-avrcp-ctrl.c' || echo '$(srcdir)/'`android/hal-avrcp-ctrl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/bluetooth_default_la-hal-avrcp-ctrl.Tpo android/$(DEPDIR)/bluetooth_default_la-hal-avrcp-ctrl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-avrcp-ctrl.c' object='android/bluetooth_default_la-hal-avrcp-ctrl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -c -o android/bluetooth_default_la-hal-avrcp-ctrl.lo `test -f 'android/hal-avrcp-ctrl.c' || echo '$(srcdir)/'`android/hal-avrcp-ctrl.c + +android/bluetooth_default_la-hal-handsfree.lo: android/hal-handsfree.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -MT android/bluetooth_default_la-hal-handsfree.lo -MD -MP -MF android/$(DEPDIR)/bluetooth_default_la-hal-handsfree.Tpo -c -o android/bluetooth_default_la-hal-handsfree.lo `test -f 'android/hal-handsfree.c' || echo '$(srcdir)/'`android/hal-handsfree.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/bluetooth_default_la-hal-handsfree.Tpo android/$(DEPDIR)/bluetooth_default_la-hal-handsfree.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-handsfree.c' object='android/bluetooth_default_la-hal-handsfree.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -c -o android/bluetooth_default_la-hal-handsfree.lo `test -f 'android/hal-handsfree.c' || echo '$(srcdir)/'`android/hal-handsfree.c + +android/bluetooth_default_la-hal-handsfree-client.lo: android/hal-handsfree-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -MT android/bluetooth_default_la-hal-handsfree-client.lo -MD -MP -MF android/$(DEPDIR)/bluetooth_default_la-hal-handsfree-client.Tpo -c -o android/bluetooth_default_la-hal-handsfree-client.lo `test -f 'android/hal-handsfree-client.c' || echo '$(srcdir)/'`android/hal-handsfree-client.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/bluetooth_default_la-hal-handsfree-client.Tpo android/$(DEPDIR)/bluetooth_default_la-hal-handsfree-client.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-handsfree-client.c' object='android/bluetooth_default_la-hal-handsfree-client.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -c -o android/bluetooth_default_la-hal-handsfree-client.lo `test -f 'android/hal-handsfree-client.c' || echo '$(srcdir)/'`android/hal-handsfree-client.c + +android/bluetooth_default_la-hal-gatt.lo: android/hal-gatt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -MT android/bluetooth_default_la-hal-gatt.lo -MD -MP -MF android/$(DEPDIR)/bluetooth_default_la-hal-gatt.Tpo -c -o android/bluetooth_default_la-hal-gatt.lo `test -f 'android/hal-gatt.c' || echo '$(srcdir)/'`android/hal-gatt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/bluetooth_default_la-hal-gatt.Tpo android/$(DEPDIR)/bluetooth_default_la-hal-gatt.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-gatt.c' object='android/bluetooth_default_la-hal-gatt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -c -o android/bluetooth_default_la-hal-gatt.lo `test -f 'android/hal-gatt.c' || echo '$(srcdir)/'`android/hal-gatt.c + +android/bluetooth_default_la-hal-map-client.lo: android/hal-map-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -MT android/bluetooth_default_la-hal-map-client.lo -MD -MP -MF android/$(DEPDIR)/bluetooth_default_la-hal-map-client.Tpo -c -o android/bluetooth_default_la-hal-map-client.lo `test -f 'android/hal-map-client.c' || echo '$(srcdir)/'`android/hal-map-client.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/bluetooth_default_la-hal-map-client.Tpo android/$(DEPDIR)/bluetooth_default_la-hal-map-client.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-map-client.c' object='android/bluetooth_default_la-hal-map-client.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -c -o android/bluetooth_default_la-hal-map-client.lo `test -f 'android/hal-map-client.c' || echo '$(srcdir)/'`android/hal-map-client.c + +android/bluetooth_default_la-hal-ipc.lo: android/hal-ipc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -MT android/bluetooth_default_la-hal-ipc.lo -MD -MP -MF android/$(DEPDIR)/bluetooth_default_la-hal-ipc.Tpo -c -o android/bluetooth_default_la-hal-ipc.lo `test -f 'android/hal-ipc.c' || echo '$(srcdir)/'`android/hal-ipc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/bluetooth_default_la-hal-ipc.Tpo android/$(DEPDIR)/bluetooth_default_la-hal-ipc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-ipc.c' object='android/bluetooth_default_la-hal-ipc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -c -o android/bluetooth_default_la-hal-ipc.lo `test -f 'android/hal-ipc.c' || echo '$(srcdir)/'`android/hal-ipc.c + +android/bluetooth_default_la-hal-utils.lo: android/hal-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -MT android/bluetooth_default_la-hal-utils.lo -MD -MP -MF android/$(DEPDIR)/bluetooth_default_la-hal-utils.Tpo -c -o android/bluetooth_default_la-hal-utils.lo `test -f 'android/hal-utils.c' || echo '$(srcdir)/'`android/hal-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/bluetooth_default_la-hal-utils.Tpo android/$(DEPDIR)/bluetooth_default_la-hal-utils.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-utils.c' object='android/bluetooth_default_la-hal-utils.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_bluetooth_default_la_CPPFLAGS) $(CPPFLAGS) $(android_bluetooth_default_la_CFLAGS) $(CFLAGS) -c -o android/bluetooth_default_la-hal-utils.lo `test -f 'android/hal-utils.c' || echo '$(srcdir)/'`android/hal-utils.c + +src/shared/libshared_ell_la-queue.lo: src/shared/queue.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-queue.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-queue.Tpo -c -o src/shared/libshared_ell_la-queue.lo `test -f 'src/shared/queue.c' || echo '$(srcdir)/'`src/shared/queue.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-queue.Tpo src/shared/$(DEPDIR)/libshared_ell_la-queue.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/queue.c' object='src/shared/libshared_ell_la-queue.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-queue.lo `test -f 'src/shared/queue.c' || echo '$(srcdir)/'`src/shared/queue.c + +src/shared/libshared_ell_la-util.lo: src/shared/util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-util.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-util.Tpo -c -o src/shared/libshared_ell_la-util.lo `test -f 'src/shared/util.c' || echo '$(srcdir)/'`src/shared/util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-util.Tpo src/shared/$(DEPDIR)/libshared_ell_la-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/util.c' object='src/shared/libshared_ell_la-util.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-util.lo `test -f 'src/shared/util.c' || echo '$(srcdir)/'`src/shared/util.c + +src/shared/libshared_ell_la-mgmt.lo: src/shared/mgmt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-mgmt.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-mgmt.Tpo -c -o src/shared/libshared_ell_la-mgmt.lo `test -f 'src/shared/mgmt.c' || echo '$(srcdir)/'`src/shared/mgmt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-mgmt.Tpo src/shared/$(DEPDIR)/libshared_ell_la-mgmt.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/mgmt.c' object='src/shared/libshared_ell_la-mgmt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-mgmt.lo `test -f 'src/shared/mgmt.c' || echo '$(srcdir)/'`src/shared/mgmt.c + +src/shared/libshared_ell_la-crypto.lo: src/shared/crypto.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-crypto.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-crypto.Tpo -c -o src/shared/libshared_ell_la-crypto.lo `test -f 'src/shared/crypto.c' || echo '$(srcdir)/'`src/shared/crypto.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-crypto.Tpo src/shared/$(DEPDIR)/libshared_ell_la-crypto.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/crypto.c' object='src/shared/libshared_ell_la-crypto.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-crypto.lo `test -f 'src/shared/crypto.c' || echo '$(srcdir)/'`src/shared/crypto.c + +src/shared/libshared_ell_la-ecc.lo: src/shared/ecc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-ecc.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-ecc.Tpo -c -o src/shared/libshared_ell_la-ecc.lo `test -f 'src/shared/ecc.c' || echo '$(srcdir)/'`src/shared/ecc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-ecc.Tpo src/shared/$(DEPDIR)/libshared_ell_la-ecc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/ecc.c' object='src/shared/libshared_ell_la-ecc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-ecc.lo `test -f 'src/shared/ecc.c' || echo '$(srcdir)/'`src/shared/ecc.c + +src/shared/libshared_ell_la-ringbuf.lo: src/shared/ringbuf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-ringbuf.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-ringbuf.Tpo -c -o src/shared/libshared_ell_la-ringbuf.lo `test -f 'src/shared/ringbuf.c' || echo '$(srcdir)/'`src/shared/ringbuf.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-ringbuf.Tpo src/shared/$(DEPDIR)/libshared_ell_la-ringbuf.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/ringbuf.c' object='src/shared/libshared_ell_la-ringbuf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-ringbuf.lo `test -f 'src/shared/ringbuf.c' || echo '$(srcdir)/'`src/shared/ringbuf.c + +src/shared/libshared_ell_la-hci.lo: src/shared/hci.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-hci.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-hci.Tpo -c -o src/shared/libshared_ell_la-hci.lo `test -f 'src/shared/hci.c' || echo '$(srcdir)/'`src/shared/hci.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-hci.Tpo src/shared/$(DEPDIR)/libshared_ell_la-hci.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/hci.c' object='src/shared/libshared_ell_la-hci.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-hci.lo `test -f 'src/shared/hci.c' || echo '$(srcdir)/'`src/shared/hci.c + +src/shared/libshared_ell_la-hci-crypto.lo: src/shared/hci-crypto.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-hci-crypto.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-hci-crypto.Tpo -c -o src/shared/libshared_ell_la-hci-crypto.lo `test -f 'src/shared/hci-crypto.c' || echo '$(srcdir)/'`src/shared/hci-crypto.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-hci-crypto.Tpo src/shared/$(DEPDIR)/libshared_ell_la-hci-crypto.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/hci-crypto.c' object='src/shared/libshared_ell_la-hci-crypto.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-hci-crypto.lo `test -f 'src/shared/hci-crypto.c' || echo '$(srcdir)/'`src/shared/hci-crypto.c + +src/shared/libshared_ell_la-hfp.lo: src/shared/hfp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-hfp.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-hfp.Tpo -c -o src/shared/libshared_ell_la-hfp.lo `test -f 'src/shared/hfp.c' || echo '$(srcdir)/'`src/shared/hfp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-hfp.Tpo src/shared/$(DEPDIR)/libshared_ell_la-hfp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/hfp.c' object='src/shared/libshared_ell_la-hfp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-hfp.lo `test -f 'src/shared/hfp.c' || echo '$(srcdir)/'`src/shared/hfp.c + +src/shared/libshared_ell_la-uhid.lo: src/shared/uhid.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-uhid.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-uhid.Tpo -c -o src/shared/libshared_ell_la-uhid.lo `test -f 'src/shared/uhid.c' || echo '$(srcdir)/'`src/shared/uhid.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-uhid.Tpo src/shared/$(DEPDIR)/libshared_ell_la-uhid.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/uhid.c' object='src/shared/libshared_ell_la-uhid.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-uhid.lo `test -f 'src/shared/uhid.c' || echo '$(srcdir)/'`src/shared/uhid.c + +src/shared/libshared_ell_la-pcap.lo: src/shared/pcap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-pcap.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-pcap.Tpo -c -o src/shared/libshared_ell_la-pcap.lo `test -f 'src/shared/pcap.c' || echo '$(srcdir)/'`src/shared/pcap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-pcap.Tpo src/shared/$(DEPDIR)/libshared_ell_la-pcap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/pcap.c' object='src/shared/libshared_ell_la-pcap.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-pcap.lo `test -f 'src/shared/pcap.c' || echo '$(srcdir)/'`src/shared/pcap.c + +src/shared/libshared_ell_la-btsnoop.lo: src/shared/btsnoop.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-btsnoop.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-btsnoop.Tpo -c -o src/shared/libshared_ell_la-btsnoop.lo `test -f 'src/shared/btsnoop.c' || echo '$(srcdir)/'`src/shared/btsnoop.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-btsnoop.Tpo src/shared/$(DEPDIR)/libshared_ell_la-btsnoop.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/btsnoop.c' object='src/shared/libshared_ell_la-btsnoop.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-btsnoop.lo `test -f 'src/shared/btsnoop.c' || echo '$(srcdir)/'`src/shared/btsnoop.c + +src/shared/libshared_ell_la-ad.lo: src/shared/ad.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-ad.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-ad.Tpo -c -o src/shared/libshared_ell_la-ad.lo `test -f 'src/shared/ad.c' || echo '$(srcdir)/'`src/shared/ad.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-ad.Tpo src/shared/$(DEPDIR)/libshared_ell_la-ad.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/ad.c' object='src/shared/libshared_ell_la-ad.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-ad.lo `test -f 'src/shared/ad.c' || echo '$(srcdir)/'`src/shared/ad.c + +src/shared/libshared_ell_la-att.lo: src/shared/att.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-att.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-att.Tpo -c -o src/shared/libshared_ell_la-att.lo `test -f 'src/shared/att.c' || echo '$(srcdir)/'`src/shared/att.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-att.Tpo src/shared/$(DEPDIR)/libshared_ell_la-att.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/att.c' object='src/shared/libshared_ell_la-att.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-att.lo `test -f 'src/shared/att.c' || echo '$(srcdir)/'`src/shared/att.c + +src/shared/libshared_ell_la-gatt-helpers.lo: src/shared/gatt-helpers.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-gatt-helpers.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-gatt-helpers.Tpo -c -o src/shared/libshared_ell_la-gatt-helpers.lo `test -f 'src/shared/gatt-helpers.c' || echo '$(srcdir)/'`src/shared/gatt-helpers.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-gatt-helpers.Tpo src/shared/$(DEPDIR)/libshared_ell_la-gatt-helpers.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/gatt-helpers.c' object='src/shared/libshared_ell_la-gatt-helpers.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-gatt-helpers.lo `test -f 'src/shared/gatt-helpers.c' || echo '$(srcdir)/'`src/shared/gatt-helpers.c + +src/shared/libshared_ell_la-gatt-client.lo: src/shared/gatt-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-gatt-client.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-gatt-client.Tpo -c -o src/shared/libshared_ell_la-gatt-client.lo `test -f 'src/shared/gatt-client.c' || echo '$(srcdir)/'`src/shared/gatt-client.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-gatt-client.Tpo src/shared/$(DEPDIR)/libshared_ell_la-gatt-client.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/gatt-client.c' object='src/shared/libshared_ell_la-gatt-client.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-gatt-client.lo `test -f 'src/shared/gatt-client.c' || echo '$(srcdir)/'`src/shared/gatt-client.c + +src/shared/libshared_ell_la-gatt-server.lo: src/shared/gatt-server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-gatt-server.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-gatt-server.Tpo -c -o src/shared/libshared_ell_la-gatt-server.lo `test -f 'src/shared/gatt-server.c' || echo '$(srcdir)/'`src/shared/gatt-server.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-gatt-server.Tpo src/shared/$(DEPDIR)/libshared_ell_la-gatt-server.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/gatt-server.c' object='src/shared/libshared_ell_la-gatt-server.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-gatt-server.lo `test -f 'src/shared/gatt-server.c' || echo '$(srcdir)/'`src/shared/gatt-server.c + +src/shared/libshared_ell_la-gatt-db.lo: src/shared/gatt-db.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-gatt-db.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-gatt-db.Tpo -c -o src/shared/libshared_ell_la-gatt-db.lo `test -f 'src/shared/gatt-db.c' || echo '$(srcdir)/'`src/shared/gatt-db.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-gatt-db.Tpo src/shared/$(DEPDIR)/libshared_ell_la-gatt-db.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/gatt-db.c' object='src/shared/libshared_ell_la-gatt-db.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-gatt-db.lo `test -f 'src/shared/gatt-db.c' || echo '$(srcdir)/'`src/shared/gatt-db.c + +src/shared/libshared_ell_la-gap.lo: src/shared/gap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-gap.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-gap.Tpo -c -o src/shared/libshared_ell_la-gap.lo `test -f 'src/shared/gap.c' || echo '$(srcdir)/'`src/shared/gap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-gap.Tpo src/shared/$(DEPDIR)/libshared_ell_la-gap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/gap.c' object='src/shared/libshared_ell_la-gap.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-gap.lo `test -f 'src/shared/gap.c' || echo '$(srcdir)/'`src/shared/gap.c + +src/shared/libshared_ell_la-log.lo: src/shared/log.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-log.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-log.Tpo -c -o src/shared/libshared_ell_la-log.lo `test -f 'src/shared/log.c' || echo '$(srcdir)/'`src/shared/log.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-log.Tpo src/shared/$(DEPDIR)/libshared_ell_la-log.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/log.c' object='src/shared/libshared_ell_la-log.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-log.lo `test -f 'src/shared/log.c' || echo '$(srcdir)/'`src/shared/log.c + +src/shared/libshared_ell_la-bap.lo: src/shared/bap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-bap.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-bap.Tpo -c -o src/shared/libshared_ell_la-bap.lo `test -f 'src/shared/bap.c' || echo '$(srcdir)/'`src/shared/bap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-bap.Tpo src/shared/$(DEPDIR)/libshared_ell_la-bap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/bap.c' object='src/shared/libshared_ell_la-bap.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-bap.lo `test -f 'src/shared/bap.c' || echo '$(srcdir)/'`src/shared/bap.c + +src/shared/libshared_ell_la-bap-debug.lo: src/shared/bap-debug.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-bap-debug.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-bap-debug.Tpo -c -o src/shared/libshared_ell_la-bap-debug.lo `test -f 'src/shared/bap-debug.c' || echo '$(srcdir)/'`src/shared/bap-debug.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-bap-debug.Tpo src/shared/$(DEPDIR)/libshared_ell_la-bap-debug.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/bap-debug.c' object='src/shared/libshared_ell_la-bap-debug.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-bap-debug.lo `test -f 'src/shared/bap-debug.c' || echo '$(srcdir)/'`src/shared/bap-debug.c + +src/shared/libshared_ell_la-mcp.lo: src/shared/mcp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-mcp.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-mcp.Tpo -c -o src/shared/libshared_ell_la-mcp.lo `test -f 'src/shared/mcp.c' || echo '$(srcdir)/'`src/shared/mcp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-mcp.Tpo src/shared/$(DEPDIR)/libshared_ell_la-mcp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/mcp.c' object='src/shared/libshared_ell_la-mcp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-mcp.lo `test -f 'src/shared/mcp.c' || echo '$(srcdir)/'`src/shared/mcp.c + +src/shared/libshared_ell_la-vcp.lo: src/shared/vcp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-vcp.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-vcp.Tpo -c -o src/shared/libshared_ell_la-vcp.lo `test -f 'src/shared/vcp.c' || echo '$(srcdir)/'`src/shared/vcp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-vcp.Tpo src/shared/$(DEPDIR)/libshared_ell_la-vcp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/vcp.c' object='src/shared/libshared_ell_la-vcp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-vcp.lo `test -f 'src/shared/vcp.c' || echo '$(srcdir)/'`src/shared/vcp.c + +src/shared/libshared_ell_la-micp.lo: src/shared/micp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-micp.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-micp.Tpo -c -o src/shared/libshared_ell_la-micp.lo `test -f 'src/shared/micp.c' || echo '$(srcdir)/'`src/shared/micp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-micp.Tpo src/shared/$(DEPDIR)/libshared_ell_la-micp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/micp.c' object='src/shared/libshared_ell_la-micp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-micp.lo `test -f 'src/shared/micp.c' || echo '$(srcdir)/'`src/shared/micp.c + +src/shared/libshared_ell_la-csip.lo: src/shared/csip.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-csip.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-csip.Tpo -c -o src/shared/libshared_ell_la-csip.lo `test -f 'src/shared/csip.c' || echo '$(srcdir)/'`src/shared/csip.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-csip.Tpo src/shared/$(DEPDIR)/libshared_ell_la-csip.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/csip.c' object='src/shared/libshared_ell_la-csip.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-csip.lo `test -f 'src/shared/csip.c' || echo '$(srcdir)/'`src/shared/csip.c + +src/shared/libshared_ell_la-bass.lo: src/shared/bass.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-bass.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-bass.Tpo -c -o src/shared/libshared_ell_la-bass.lo `test -f 'src/shared/bass.c' || echo '$(srcdir)/'`src/shared/bass.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-bass.Tpo src/shared/$(DEPDIR)/libshared_ell_la-bass.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/bass.c' object='src/shared/libshared_ell_la-bass.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-bass.lo `test -f 'src/shared/bass.c' || echo '$(srcdir)/'`src/shared/bass.c + +src/shared/libshared_ell_la-ccp.lo: src/shared/ccp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-ccp.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-ccp.Tpo -c -o src/shared/libshared_ell_la-ccp.lo `test -f 'src/shared/ccp.c' || echo '$(srcdir)/'`src/shared/ccp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-ccp.Tpo src/shared/$(DEPDIR)/libshared_ell_la-ccp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/ccp.c' object='src/shared/libshared_ell_la-ccp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-ccp.lo `test -f 'src/shared/ccp.c' || echo '$(srcdir)/'`src/shared/ccp.c + +src/shared/libshared_ell_la-asha.lo: src/shared/asha.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-asha.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-asha.Tpo -c -o src/shared/libshared_ell_la-asha.lo `test -f 'src/shared/asha.c' || echo '$(srcdir)/'`src/shared/asha.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-asha.Tpo src/shared/$(DEPDIR)/libshared_ell_la-asha.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/asha.c' object='src/shared/libshared_ell_la-asha.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-asha.lo `test -f 'src/shared/asha.c' || echo '$(srcdir)/'`src/shared/asha.c + +src/shared/libshared_ell_la-shell.lo: src/shared/shell.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-shell.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-shell.Tpo -c -o src/shared/libshared_ell_la-shell.lo `test -f 'src/shared/shell.c' || echo '$(srcdir)/'`src/shared/shell.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-shell.Tpo src/shared/$(DEPDIR)/libshared_ell_la-shell.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/shell.c' object='src/shared/libshared_ell_la-shell.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-shell.lo `test -f 'src/shared/shell.c' || echo '$(srcdir)/'`src/shared/shell.c + +src/shared/libshared_ell_la-io-ell.lo: src/shared/io-ell.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-io-ell.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-io-ell.Tpo -c -o src/shared/libshared_ell_la-io-ell.lo `test -f 'src/shared/io-ell.c' || echo '$(srcdir)/'`src/shared/io-ell.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-io-ell.Tpo src/shared/$(DEPDIR)/libshared_ell_la-io-ell.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/io-ell.c' object='src/shared/libshared_ell_la-io-ell.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-io-ell.lo `test -f 'src/shared/io-ell.c' || echo '$(srcdir)/'`src/shared/io-ell.c + +src/shared/libshared_ell_la-timeout-ell.lo: src/shared/timeout-ell.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-timeout-ell.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-timeout-ell.Tpo -c -o src/shared/libshared_ell_la-timeout-ell.lo `test -f 'src/shared/timeout-ell.c' || echo '$(srcdir)/'`src/shared/timeout-ell.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-timeout-ell.Tpo src/shared/$(DEPDIR)/libshared_ell_la-timeout-ell.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/timeout-ell.c' object='src/shared/libshared_ell_la-timeout-ell.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-timeout-ell.lo `test -f 'src/shared/timeout-ell.c' || echo '$(srcdir)/'`src/shared/timeout-ell.c + +src/shared/libshared_ell_la-mainloop-ell.lo: src/shared/mainloop-ell.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_ell_la-mainloop-ell.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_ell_la-mainloop-ell.Tpo -c -o src/shared/libshared_ell_la-mainloop-ell.lo `test -f 'src/shared/mainloop-ell.c' || echo '$(srcdir)/'`src/shared/mainloop-ell.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_ell_la-mainloop-ell.Tpo src/shared/$(DEPDIR)/libshared_ell_la-mainloop-ell.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/mainloop-ell.c' object='src/shared/libshared_ell_la-mainloop-ell.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_ell_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_ell_la-mainloop-ell.lo `test -f 'src/shared/mainloop-ell.c' || echo '$(srcdir)/'`src/shared/mainloop-ell.c + +src/shared/libshared_glib_la-queue.lo: src/shared/queue.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-queue.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-queue.Tpo -c -o src/shared/libshared_glib_la-queue.lo `test -f 'src/shared/queue.c' || echo '$(srcdir)/'`src/shared/queue.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-queue.Tpo src/shared/$(DEPDIR)/libshared_glib_la-queue.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/queue.c' object='src/shared/libshared_glib_la-queue.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-queue.lo `test -f 'src/shared/queue.c' || echo '$(srcdir)/'`src/shared/queue.c + +src/shared/libshared_glib_la-util.lo: src/shared/util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-util.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-util.Tpo -c -o src/shared/libshared_glib_la-util.lo `test -f 'src/shared/util.c' || echo '$(srcdir)/'`src/shared/util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-util.Tpo src/shared/$(DEPDIR)/libshared_glib_la-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/util.c' object='src/shared/libshared_glib_la-util.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-util.lo `test -f 'src/shared/util.c' || echo '$(srcdir)/'`src/shared/util.c + +src/shared/libshared_glib_la-mgmt.lo: src/shared/mgmt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-mgmt.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-mgmt.Tpo -c -o src/shared/libshared_glib_la-mgmt.lo `test -f 'src/shared/mgmt.c' || echo '$(srcdir)/'`src/shared/mgmt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-mgmt.Tpo src/shared/$(DEPDIR)/libshared_glib_la-mgmt.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/mgmt.c' object='src/shared/libshared_glib_la-mgmt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-mgmt.lo `test -f 'src/shared/mgmt.c' || echo '$(srcdir)/'`src/shared/mgmt.c + +src/shared/libshared_glib_la-crypto.lo: src/shared/crypto.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-crypto.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-crypto.Tpo -c -o src/shared/libshared_glib_la-crypto.lo `test -f 'src/shared/crypto.c' || echo '$(srcdir)/'`src/shared/crypto.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-crypto.Tpo src/shared/$(DEPDIR)/libshared_glib_la-crypto.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/crypto.c' object='src/shared/libshared_glib_la-crypto.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-crypto.lo `test -f 'src/shared/crypto.c' || echo '$(srcdir)/'`src/shared/crypto.c + +src/shared/libshared_glib_la-ecc.lo: src/shared/ecc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-ecc.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-ecc.Tpo -c -o src/shared/libshared_glib_la-ecc.lo `test -f 'src/shared/ecc.c' || echo '$(srcdir)/'`src/shared/ecc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-ecc.Tpo src/shared/$(DEPDIR)/libshared_glib_la-ecc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/ecc.c' object='src/shared/libshared_glib_la-ecc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-ecc.lo `test -f 'src/shared/ecc.c' || echo '$(srcdir)/'`src/shared/ecc.c + +src/shared/libshared_glib_la-ringbuf.lo: src/shared/ringbuf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-ringbuf.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-ringbuf.Tpo -c -o src/shared/libshared_glib_la-ringbuf.lo `test -f 'src/shared/ringbuf.c' || echo '$(srcdir)/'`src/shared/ringbuf.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-ringbuf.Tpo src/shared/$(DEPDIR)/libshared_glib_la-ringbuf.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/ringbuf.c' object='src/shared/libshared_glib_la-ringbuf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-ringbuf.lo `test -f 'src/shared/ringbuf.c' || echo '$(srcdir)/'`src/shared/ringbuf.c + +src/shared/libshared_glib_la-hci.lo: src/shared/hci.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-hci.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-hci.Tpo -c -o src/shared/libshared_glib_la-hci.lo `test -f 'src/shared/hci.c' || echo '$(srcdir)/'`src/shared/hci.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-hci.Tpo src/shared/$(DEPDIR)/libshared_glib_la-hci.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/hci.c' object='src/shared/libshared_glib_la-hci.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-hci.lo `test -f 'src/shared/hci.c' || echo '$(srcdir)/'`src/shared/hci.c + +src/shared/libshared_glib_la-hci-crypto.lo: src/shared/hci-crypto.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-hci-crypto.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-hci-crypto.Tpo -c -o src/shared/libshared_glib_la-hci-crypto.lo `test -f 'src/shared/hci-crypto.c' || echo '$(srcdir)/'`src/shared/hci-crypto.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-hci-crypto.Tpo src/shared/$(DEPDIR)/libshared_glib_la-hci-crypto.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/hci-crypto.c' object='src/shared/libshared_glib_la-hci-crypto.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-hci-crypto.lo `test -f 'src/shared/hci-crypto.c' || echo '$(srcdir)/'`src/shared/hci-crypto.c + +src/shared/libshared_glib_la-hfp.lo: src/shared/hfp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-hfp.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-hfp.Tpo -c -o src/shared/libshared_glib_la-hfp.lo `test -f 'src/shared/hfp.c' || echo '$(srcdir)/'`src/shared/hfp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-hfp.Tpo src/shared/$(DEPDIR)/libshared_glib_la-hfp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/hfp.c' object='src/shared/libshared_glib_la-hfp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-hfp.lo `test -f 'src/shared/hfp.c' || echo '$(srcdir)/'`src/shared/hfp.c + +src/shared/libshared_glib_la-uhid.lo: src/shared/uhid.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-uhid.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-uhid.Tpo -c -o src/shared/libshared_glib_la-uhid.lo `test -f 'src/shared/uhid.c' || echo '$(srcdir)/'`src/shared/uhid.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-uhid.Tpo src/shared/$(DEPDIR)/libshared_glib_la-uhid.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/uhid.c' object='src/shared/libshared_glib_la-uhid.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-uhid.lo `test -f 'src/shared/uhid.c' || echo '$(srcdir)/'`src/shared/uhid.c + +src/shared/libshared_glib_la-pcap.lo: src/shared/pcap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-pcap.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-pcap.Tpo -c -o src/shared/libshared_glib_la-pcap.lo `test -f 'src/shared/pcap.c' || echo '$(srcdir)/'`src/shared/pcap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-pcap.Tpo src/shared/$(DEPDIR)/libshared_glib_la-pcap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/pcap.c' object='src/shared/libshared_glib_la-pcap.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-pcap.lo `test -f 'src/shared/pcap.c' || echo '$(srcdir)/'`src/shared/pcap.c + +src/shared/libshared_glib_la-btsnoop.lo: src/shared/btsnoop.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-btsnoop.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-btsnoop.Tpo -c -o src/shared/libshared_glib_la-btsnoop.lo `test -f 'src/shared/btsnoop.c' || echo '$(srcdir)/'`src/shared/btsnoop.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-btsnoop.Tpo src/shared/$(DEPDIR)/libshared_glib_la-btsnoop.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/btsnoop.c' object='src/shared/libshared_glib_la-btsnoop.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-btsnoop.lo `test -f 'src/shared/btsnoop.c' || echo '$(srcdir)/'`src/shared/btsnoop.c + +src/shared/libshared_glib_la-ad.lo: src/shared/ad.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-ad.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-ad.Tpo -c -o src/shared/libshared_glib_la-ad.lo `test -f 'src/shared/ad.c' || echo '$(srcdir)/'`src/shared/ad.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-ad.Tpo src/shared/$(DEPDIR)/libshared_glib_la-ad.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/ad.c' object='src/shared/libshared_glib_la-ad.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-ad.lo `test -f 'src/shared/ad.c' || echo '$(srcdir)/'`src/shared/ad.c + +src/shared/libshared_glib_la-att.lo: src/shared/att.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-att.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-att.Tpo -c -o src/shared/libshared_glib_la-att.lo `test -f 'src/shared/att.c' || echo '$(srcdir)/'`src/shared/att.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-att.Tpo src/shared/$(DEPDIR)/libshared_glib_la-att.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/att.c' object='src/shared/libshared_glib_la-att.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-att.lo `test -f 'src/shared/att.c' || echo '$(srcdir)/'`src/shared/att.c + +src/shared/libshared_glib_la-gatt-helpers.lo: src/shared/gatt-helpers.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-gatt-helpers.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-gatt-helpers.Tpo -c -o src/shared/libshared_glib_la-gatt-helpers.lo `test -f 'src/shared/gatt-helpers.c' || echo '$(srcdir)/'`src/shared/gatt-helpers.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-gatt-helpers.Tpo src/shared/$(DEPDIR)/libshared_glib_la-gatt-helpers.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/gatt-helpers.c' object='src/shared/libshared_glib_la-gatt-helpers.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-gatt-helpers.lo `test -f 'src/shared/gatt-helpers.c' || echo '$(srcdir)/'`src/shared/gatt-helpers.c + +src/shared/libshared_glib_la-gatt-client.lo: src/shared/gatt-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-gatt-client.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-gatt-client.Tpo -c -o src/shared/libshared_glib_la-gatt-client.lo `test -f 'src/shared/gatt-client.c' || echo '$(srcdir)/'`src/shared/gatt-client.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-gatt-client.Tpo src/shared/$(DEPDIR)/libshared_glib_la-gatt-client.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/gatt-client.c' object='src/shared/libshared_glib_la-gatt-client.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-gatt-client.lo `test -f 'src/shared/gatt-client.c' || echo '$(srcdir)/'`src/shared/gatt-client.c + +src/shared/libshared_glib_la-gatt-server.lo: src/shared/gatt-server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-gatt-server.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-gatt-server.Tpo -c -o src/shared/libshared_glib_la-gatt-server.lo `test -f 'src/shared/gatt-server.c' || echo '$(srcdir)/'`src/shared/gatt-server.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-gatt-server.Tpo src/shared/$(DEPDIR)/libshared_glib_la-gatt-server.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/gatt-server.c' object='src/shared/libshared_glib_la-gatt-server.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-gatt-server.lo `test -f 'src/shared/gatt-server.c' || echo '$(srcdir)/'`src/shared/gatt-server.c + +src/shared/libshared_glib_la-gatt-db.lo: src/shared/gatt-db.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-gatt-db.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-gatt-db.Tpo -c -o src/shared/libshared_glib_la-gatt-db.lo `test -f 'src/shared/gatt-db.c' || echo '$(srcdir)/'`src/shared/gatt-db.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-gatt-db.Tpo src/shared/$(DEPDIR)/libshared_glib_la-gatt-db.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/gatt-db.c' object='src/shared/libshared_glib_la-gatt-db.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-gatt-db.lo `test -f 'src/shared/gatt-db.c' || echo '$(srcdir)/'`src/shared/gatt-db.c + +src/shared/libshared_glib_la-gap.lo: src/shared/gap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-gap.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-gap.Tpo -c -o src/shared/libshared_glib_la-gap.lo `test -f 'src/shared/gap.c' || echo '$(srcdir)/'`src/shared/gap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-gap.Tpo src/shared/$(DEPDIR)/libshared_glib_la-gap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/gap.c' object='src/shared/libshared_glib_la-gap.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-gap.lo `test -f 'src/shared/gap.c' || echo '$(srcdir)/'`src/shared/gap.c + +src/shared/libshared_glib_la-log.lo: src/shared/log.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-log.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-log.Tpo -c -o src/shared/libshared_glib_la-log.lo `test -f 'src/shared/log.c' || echo '$(srcdir)/'`src/shared/log.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-log.Tpo src/shared/$(DEPDIR)/libshared_glib_la-log.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/log.c' object='src/shared/libshared_glib_la-log.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-log.lo `test -f 'src/shared/log.c' || echo '$(srcdir)/'`src/shared/log.c + +src/shared/libshared_glib_la-bap.lo: src/shared/bap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-bap.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-bap.Tpo -c -o src/shared/libshared_glib_la-bap.lo `test -f 'src/shared/bap.c' || echo '$(srcdir)/'`src/shared/bap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-bap.Tpo src/shared/$(DEPDIR)/libshared_glib_la-bap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/bap.c' object='src/shared/libshared_glib_la-bap.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-bap.lo `test -f 'src/shared/bap.c' || echo '$(srcdir)/'`src/shared/bap.c + +src/shared/libshared_glib_la-bap-debug.lo: src/shared/bap-debug.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-bap-debug.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-bap-debug.Tpo -c -o src/shared/libshared_glib_la-bap-debug.lo `test -f 'src/shared/bap-debug.c' || echo '$(srcdir)/'`src/shared/bap-debug.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-bap-debug.Tpo src/shared/$(DEPDIR)/libshared_glib_la-bap-debug.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/bap-debug.c' object='src/shared/libshared_glib_la-bap-debug.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-bap-debug.lo `test -f 'src/shared/bap-debug.c' || echo '$(srcdir)/'`src/shared/bap-debug.c + +src/shared/libshared_glib_la-mcp.lo: src/shared/mcp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-mcp.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-mcp.Tpo -c -o src/shared/libshared_glib_la-mcp.lo `test -f 'src/shared/mcp.c' || echo '$(srcdir)/'`src/shared/mcp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-mcp.Tpo src/shared/$(DEPDIR)/libshared_glib_la-mcp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/mcp.c' object='src/shared/libshared_glib_la-mcp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-mcp.lo `test -f 'src/shared/mcp.c' || echo '$(srcdir)/'`src/shared/mcp.c + +src/shared/libshared_glib_la-vcp.lo: src/shared/vcp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-vcp.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-vcp.Tpo -c -o src/shared/libshared_glib_la-vcp.lo `test -f 'src/shared/vcp.c' || echo '$(srcdir)/'`src/shared/vcp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-vcp.Tpo src/shared/$(DEPDIR)/libshared_glib_la-vcp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/vcp.c' object='src/shared/libshared_glib_la-vcp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-vcp.lo `test -f 'src/shared/vcp.c' || echo '$(srcdir)/'`src/shared/vcp.c + +src/shared/libshared_glib_la-micp.lo: src/shared/micp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-micp.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-micp.Tpo -c -o src/shared/libshared_glib_la-micp.lo `test -f 'src/shared/micp.c' || echo '$(srcdir)/'`src/shared/micp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-micp.Tpo src/shared/$(DEPDIR)/libshared_glib_la-micp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/micp.c' object='src/shared/libshared_glib_la-micp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-micp.lo `test -f 'src/shared/micp.c' || echo '$(srcdir)/'`src/shared/micp.c + +src/shared/libshared_glib_la-csip.lo: src/shared/csip.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-csip.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-csip.Tpo -c -o src/shared/libshared_glib_la-csip.lo `test -f 'src/shared/csip.c' || echo '$(srcdir)/'`src/shared/csip.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-csip.Tpo src/shared/$(DEPDIR)/libshared_glib_la-csip.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/csip.c' object='src/shared/libshared_glib_la-csip.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-csip.lo `test -f 'src/shared/csip.c' || echo '$(srcdir)/'`src/shared/csip.c + +src/shared/libshared_glib_la-bass.lo: src/shared/bass.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-bass.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-bass.Tpo -c -o src/shared/libshared_glib_la-bass.lo `test -f 'src/shared/bass.c' || echo '$(srcdir)/'`src/shared/bass.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-bass.Tpo src/shared/$(DEPDIR)/libshared_glib_la-bass.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/bass.c' object='src/shared/libshared_glib_la-bass.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-bass.lo `test -f 'src/shared/bass.c' || echo '$(srcdir)/'`src/shared/bass.c + +src/shared/libshared_glib_la-ccp.lo: src/shared/ccp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-ccp.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-ccp.Tpo -c -o src/shared/libshared_glib_la-ccp.lo `test -f 'src/shared/ccp.c' || echo '$(srcdir)/'`src/shared/ccp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-ccp.Tpo src/shared/$(DEPDIR)/libshared_glib_la-ccp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/ccp.c' object='src/shared/libshared_glib_la-ccp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-ccp.lo `test -f 'src/shared/ccp.c' || echo '$(srcdir)/'`src/shared/ccp.c + +src/shared/libshared_glib_la-asha.lo: src/shared/asha.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-asha.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-asha.Tpo -c -o src/shared/libshared_glib_la-asha.lo `test -f 'src/shared/asha.c' || echo '$(srcdir)/'`src/shared/asha.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-asha.Tpo src/shared/$(DEPDIR)/libshared_glib_la-asha.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/asha.c' object='src/shared/libshared_glib_la-asha.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-asha.lo `test -f 'src/shared/asha.c' || echo '$(srcdir)/'`src/shared/asha.c + +src/shared/libshared_glib_la-shell.lo: src/shared/shell.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-shell.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-shell.Tpo -c -o src/shared/libshared_glib_la-shell.lo `test -f 'src/shared/shell.c' || echo '$(srcdir)/'`src/shared/shell.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-shell.Tpo src/shared/$(DEPDIR)/libshared_glib_la-shell.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/shell.c' object='src/shared/libshared_glib_la-shell.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-shell.lo `test -f 'src/shared/shell.c' || echo '$(srcdir)/'`src/shared/shell.c + +src/shared/libshared_glib_la-io-glib.lo: src/shared/io-glib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-io-glib.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-io-glib.Tpo -c -o src/shared/libshared_glib_la-io-glib.lo `test -f 'src/shared/io-glib.c' || echo '$(srcdir)/'`src/shared/io-glib.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-io-glib.Tpo src/shared/$(DEPDIR)/libshared_glib_la-io-glib.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/io-glib.c' object='src/shared/libshared_glib_la-io-glib.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-io-glib.lo `test -f 'src/shared/io-glib.c' || echo '$(srcdir)/'`src/shared/io-glib.c + +src/shared/libshared_glib_la-timeout-glib.lo: src/shared/timeout-glib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-timeout-glib.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-timeout-glib.Tpo -c -o src/shared/libshared_glib_la-timeout-glib.lo `test -f 'src/shared/timeout-glib.c' || echo '$(srcdir)/'`src/shared/timeout-glib.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-timeout-glib.Tpo src/shared/$(DEPDIR)/libshared_glib_la-timeout-glib.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/timeout-glib.c' object='src/shared/libshared_glib_la-timeout-glib.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-timeout-glib.lo `test -f 'src/shared/timeout-glib.c' || echo '$(srcdir)/'`src/shared/timeout-glib.c + +src/shared/libshared_glib_la-mainloop-glib.lo: src/shared/mainloop-glib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-mainloop-glib.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-mainloop-glib.Tpo -c -o src/shared/libshared_glib_la-mainloop-glib.lo `test -f 'src/shared/mainloop-glib.c' || echo '$(srcdir)/'`src/shared/mainloop-glib.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-mainloop-glib.Tpo src/shared/$(DEPDIR)/libshared_glib_la-mainloop-glib.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/mainloop-glib.c' object='src/shared/libshared_glib_la-mainloop-glib.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-mainloop-glib.lo `test -f 'src/shared/mainloop-glib.c' || echo '$(srcdir)/'`src/shared/mainloop-glib.c + +src/shared/libshared_glib_la-mainloop-notify.lo: src/shared/mainloop-notify.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-mainloop-notify.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-mainloop-notify.Tpo -c -o src/shared/libshared_glib_la-mainloop-notify.lo `test -f 'src/shared/mainloop-notify.c' || echo '$(srcdir)/'`src/shared/mainloop-notify.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-mainloop-notify.Tpo src/shared/$(DEPDIR)/libshared_glib_la-mainloop-notify.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/mainloop-notify.c' object='src/shared/libshared_glib_la-mainloop-notify.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-mainloop-notify.lo `test -f 'src/shared/mainloop-notify.c' || echo '$(srcdir)/'`src/shared/mainloop-notify.c + +src/shared/libshared_glib_la-tester.lo: src/shared/tester.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_glib_la-tester.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_glib_la-tester.Tpo -c -o src/shared/libshared_glib_la-tester.lo `test -f 'src/shared/tester.c' || echo '$(srcdir)/'`src/shared/tester.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_glib_la-tester.Tpo src/shared/$(DEPDIR)/libshared_glib_la-tester.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/tester.c' object='src/shared/libshared_glib_la-tester.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_glib_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_glib_la-tester.lo `test -f 'src/shared/tester.c' || echo '$(srcdir)/'`src/shared/tester.c + +src/shared/libshared_mainloop_la-queue.lo: src/shared/queue.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-queue.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-queue.Tpo -c -o src/shared/libshared_mainloop_la-queue.lo `test -f 'src/shared/queue.c' || echo '$(srcdir)/'`src/shared/queue.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-queue.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-queue.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/queue.c' object='src/shared/libshared_mainloop_la-queue.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-queue.lo `test -f 'src/shared/queue.c' || echo '$(srcdir)/'`src/shared/queue.c + +src/shared/libshared_mainloop_la-util.lo: src/shared/util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-util.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-util.Tpo -c -o src/shared/libshared_mainloop_la-util.lo `test -f 'src/shared/util.c' || echo '$(srcdir)/'`src/shared/util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-util.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/util.c' object='src/shared/libshared_mainloop_la-util.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-util.lo `test -f 'src/shared/util.c' || echo '$(srcdir)/'`src/shared/util.c + +src/shared/libshared_mainloop_la-mgmt.lo: src/shared/mgmt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-mgmt.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-mgmt.Tpo -c -o src/shared/libshared_mainloop_la-mgmt.lo `test -f 'src/shared/mgmt.c' || echo '$(srcdir)/'`src/shared/mgmt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-mgmt.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-mgmt.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/mgmt.c' object='src/shared/libshared_mainloop_la-mgmt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-mgmt.lo `test -f 'src/shared/mgmt.c' || echo '$(srcdir)/'`src/shared/mgmt.c + +src/shared/libshared_mainloop_la-crypto.lo: src/shared/crypto.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-crypto.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-crypto.Tpo -c -o src/shared/libshared_mainloop_la-crypto.lo `test -f 'src/shared/crypto.c' || echo '$(srcdir)/'`src/shared/crypto.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-crypto.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-crypto.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/crypto.c' object='src/shared/libshared_mainloop_la-crypto.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-crypto.lo `test -f 'src/shared/crypto.c' || echo '$(srcdir)/'`src/shared/crypto.c + +src/shared/libshared_mainloop_la-ecc.lo: src/shared/ecc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-ecc.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-ecc.Tpo -c -o src/shared/libshared_mainloop_la-ecc.lo `test -f 'src/shared/ecc.c' || echo '$(srcdir)/'`src/shared/ecc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-ecc.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-ecc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/ecc.c' object='src/shared/libshared_mainloop_la-ecc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-ecc.lo `test -f 'src/shared/ecc.c' || echo '$(srcdir)/'`src/shared/ecc.c + +src/shared/libshared_mainloop_la-ringbuf.lo: src/shared/ringbuf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-ringbuf.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-ringbuf.Tpo -c -o src/shared/libshared_mainloop_la-ringbuf.lo `test -f 'src/shared/ringbuf.c' || echo '$(srcdir)/'`src/shared/ringbuf.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-ringbuf.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-ringbuf.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/ringbuf.c' object='src/shared/libshared_mainloop_la-ringbuf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-ringbuf.lo `test -f 'src/shared/ringbuf.c' || echo '$(srcdir)/'`src/shared/ringbuf.c + +src/shared/libshared_mainloop_la-hci.lo: src/shared/hci.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-hci.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-hci.Tpo -c -o src/shared/libshared_mainloop_la-hci.lo `test -f 'src/shared/hci.c' || echo '$(srcdir)/'`src/shared/hci.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-hci.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-hci.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/hci.c' object='src/shared/libshared_mainloop_la-hci.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-hci.lo `test -f 'src/shared/hci.c' || echo '$(srcdir)/'`src/shared/hci.c + +src/shared/libshared_mainloop_la-hci-crypto.lo: src/shared/hci-crypto.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-hci-crypto.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-hci-crypto.Tpo -c -o src/shared/libshared_mainloop_la-hci-crypto.lo `test -f 'src/shared/hci-crypto.c' || echo '$(srcdir)/'`src/shared/hci-crypto.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-hci-crypto.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-hci-crypto.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/hci-crypto.c' object='src/shared/libshared_mainloop_la-hci-crypto.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-hci-crypto.lo `test -f 'src/shared/hci-crypto.c' || echo '$(srcdir)/'`src/shared/hci-crypto.c + +src/shared/libshared_mainloop_la-hfp.lo: src/shared/hfp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-hfp.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-hfp.Tpo -c -o src/shared/libshared_mainloop_la-hfp.lo `test -f 'src/shared/hfp.c' || echo '$(srcdir)/'`src/shared/hfp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-hfp.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-hfp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/hfp.c' object='src/shared/libshared_mainloop_la-hfp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-hfp.lo `test -f 'src/shared/hfp.c' || echo '$(srcdir)/'`src/shared/hfp.c + +src/shared/libshared_mainloop_la-uhid.lo: src/shared/uhid.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-uhid.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-uhid.Tpo -c -o src/shared/libshared_mainloop_la-uhid.lo `test -f 'src/shared/uhid.c' || echo '$(srcdir)/'`src/shared/uhid.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-uhid.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-uhid.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/uhid.c' object='src/shared/libshared_mainloop_la-uhid.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-uhid.lo `test -f 'src/shared/uhid.c' || echo '$(srcdir)/'`src/shared/uhid.c + +src/shared/libshared_mainloop_la-pcap.lo: src/shared/pcap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-pcap.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-pcap.Tpo -c -o src/shared/libshared_mainloop_la-pcap.lo `test -f 'src/shared/pcap.c' || echo '$(srcdir)/'`src/shared/pcap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-pcap.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-pcap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/pcap.c' object='src/shared/libshared_mainloop_la-pcap.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-pcap.lo `test -f 'src/shared/pcap.c' || echo '$(srcdir)/'`src/shared/pcap.c + +src/shared/libshared_mainloop_la-btsnoop.lo: src/shared/btsnoop.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-btsnoop.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-btsnoop.Tpo -c -o src/shared/libshared_mainloop_la-btsnoop.lo `test -f 'src/shared/btsnoop.c' || echo '$(srcdir)/'`src/shared/btsnoop.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-btsnoop.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-btsnoop.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/btsnoop.c' object='src/shared/libshared_mainloop_la-btsnoop.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-btsnoop.lo `test -f 'src/shared/btsnoop.c' || echo '$(srcdir)/'`src/shared/btsnoop.c + +src/shared/libshared_mainloop_la-ad.lo: src/shared/ad.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-ad.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-ad.Tpo -c -o src/shared/libshared_mainloop_la-ad.lo `test -f 'src/shared/ad.c' || echo '$(srcdir)/'`src/shared/ad.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-ad.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-ad.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/ad.c' object='src/shared/libshared_mainloop_la-ad.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-ad.lo `test -f 'src/shared/ad.c' || echo '$(srcdir)/'`src/shared/ad.c + +src/shared/libshared_mainloop_la-att.lo: src/shared/att.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-att.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-att.Tpo -c -o src/shared/libshared_mainloop_la-att.lo `test -f 'src/shared/att.c' || echo '$(srcdir)/'`src/shared/att.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-att.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-att.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/att.c' object='src/shared/libshared_mainloop_la-att.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-att.lo `test -f 'src/shared/att.c' || echo '$(srcdir)/'`src/shared/att.c + +src/shared/libshared_mainloop_la-gatt-helpers.lo: src/shared/gatt-helpers.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-gatt-helpers.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-helpers.Tpo -c -o src/shared/libshared_mainloop_la-gatt-helpers.lo `test -f 'src/shared/gatt-helpers.c' || echo '$(srcdir)/'`src/shared/gatt-helpers.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-helpers.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-helpers.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/gatt-helpers.c' object='src/shared/libshared_mainloop_la-gatt-helpers.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-gatt-helpers.lo `test -f 'src/shared/gatt-helpers.c' || echo '$(srcdir)/'`src/shared/gatt-helpers.c + +src/shared/libshared_mainloop_la-gatt-client.lo: src/shared/gatt-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-gatt-client.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-client.Tpo -c -o src/shared/libshared_mainloop_la-gatt-client.lo `test -f 'src/shared/gatt-client.c' || echo '$(srcdir)/'`src/shared/gatt-client.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-client.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-client.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/gatt-client.c' object='src/shared/libshared_mainloop_la-gatt-client.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-gatt-client.lo `test -f 'src/shared/gatt-client.c' || echo '$(srcdir)/'`src/shared/gatt-client.c + +src/shared/libshared_mainloop_la-gatt-server.lo: src/shared/gatt-server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-gatt-server.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-server.Tpo -c -o src/shared/libshared_mainloop_la-gatt-server.lo `test -f 'src/shared/gatt-server.c' || echo '$(srcdir)/'`src/shared/gatt-server.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-server.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-server.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/gatt-server.c' object='src/shared/libshared_mainloop_la-gatt-server.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-gatt-server.lo `test -f 'src/shared/gatt-server.c' || echo '$(srcdir)/'`src/shared/gatt-server.c + +src/shared/libshared_mainloop_la-gatt-db.lo: src/shared/gatt-db.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-gatt-db.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-db.Tpo -c -o src/shared/libshared_mainloop_la-gatt-db.lo `test -f 'src/shared/gatt-db.c' || echo '$(srcdir)/'`src/shared/gatt-db.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-db.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-db.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/gatt-db.c' object='src/shared/libshared_mainloop_la-gatt-db.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-gatt-db.lo `test -f 'src/shared/gatt-db.c' || echo '$(srcdir)/'`src/shared/gatt-db.c + +src/shared/libshared_mainloop_la-gap.lo: src/shared/gap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-gap.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-gap.Tpo -c -o src/shared/libshared_mainloop_la-gap.lo `test -f 'src/shared/gap.c' || echo '$(srcdir)/'`src/shared/gap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-gap.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-gap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/gap.c' object='src/shared/libshared_mainloop_la-gap.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-gap.lo `test -f 'src/shared/gap.c' || echo '$(srcdir)/'`src/shared/gap.c + +src/shared/libshared_mainloop_la-log.lo: src/shared/log.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-log.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-log.Tpo -c -o src/shared/libshared_mainloop_la-log.lo `test -f 'src/shared/log.c' || echo '$(srcdir)/'`src/shared/log.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-log.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-log.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/log.c' object='src/shared/libshared_mainloop_la-log.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-log.lo `test -f 'src/shared/log.c' || echo '$(srcdir)/'`src/shared/log.c + +src/shared/libshared_mainloop_la-bap.lo: src/shared/bap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-bap.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-bap.Tpo -c -o src/shared/libshared_mainloop_la-bap.lo `test -f 'src/shared/bap.c' || echo '$(srcdir)/'`src/shared/bap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-bap.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-bap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/bap.c' object='src/shared/libshared_mainloop_la-bap.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-bap.lo `test -f 'src/shared/bap.c' || echo '$(srcdir)/'`src/shared/bap.c + +src/shared/libshared_mainloop_la-bap-debug.lo: src/shared/bap-debug.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-bap-debug.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-bap-debug.Tpo -c -o src/shared/libshared_mainloop_la-bap-debug.lo `test -f 'src/shared/bap-debug.c' || echo '$(srcdir)/'`src/shared/bap-debug.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-bap-debug.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-bap-debug.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/bap-debug.c' object='src/shared/libshared_mainloop_la-bap-debug.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-bap-debug.lo `test -f 'src/shared/bap-debug.c' || echo '$(srcdir)/'`src/shared/bap-debug.c + +src/shared/libshared_mainloop_la-mcp.lo: src/shared/mcp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-mcp.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-mcp.Tpo -c -o src/shared/libshared_mainloop_la-mcp.lo `test -f 'src/shared/mcp.c' || echo '$(srcdir)/'`src/shared/mcp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-mcp.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-mcp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/mcp.c' object='src/shared/libshared_mainloop_la-mcp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-mcp.lo `test -f 'src/shared/mcp.c' || echo '$(srcdir)/'`src/shared/mcp.c + +src/shared/libshared_mainloop_la-vcp.lo: src/shared/vcp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-vcp.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-vcp.Tpo -c -o src/shared/libshared_mainloop_la-vcp.lo `test -f 'src/shared/vcp.c' || echo '$(srcdir)/'`src/shared/vcp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-vcp.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-vcp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/vcp.c' object='src/shared/libshared_mainloop_la-vcp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-vcp.lo `test -f 'src/shared/vcp.c' || echo '$(srcdir)/'`src/shared/vcp.c + +src/shared/libshared_mainloop_la-micp.lo: src/shared/micp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-micp.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-micp.Tpo -c -o src/shared/libshared_mainloop_la-micp.lo `test -f 'src/shared/micp.c' || echo '$(srcdir)/'`src/shared/micp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-micp.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-micp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/micp.c' object='src/shared/libshared_mainloop_la-micp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-micp.lo `test -f 'src/shared/micp.c' || echo '$(srcdir)/'`src/shared/micp.c + +src/shared/libshared_mainloop_la-csip.lo: src/shared/csip.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-csip.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-csip.Tpo -c -o src/shared/libshared_mainloop_la-csip.lo `test -f 'src/shared/csip.c' || echo '$(srcdir)/'`src/shared/csip.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-csip.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-csip.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/csip.c' object='src/shared/libshared_mainloop_la-csip.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-csip.lo `test -f 'src/shared/csip.c' || echo '$(srcdir)/'`src/shared/csip.c + +src/shared/libshared_mainloop_la-bass.lo: src/shared/bass.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-bass.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-bass.Tpo -c -o src/shared/libshared_mainloop_la-bass.lo `test -f 'src/shared/bass.c' || echo '$(srcdir)/'`src/shared/bass.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-bass.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-bass.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/bass.c' object='src/shared/libshared_mainloop_la-bass.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-bass.lo `test -f 'src/shared/bass.c' || echo '$(srcdir)/'`src/shared/bass.c + +src/shared/libshared_mainloop_la-ccp.lo: src/shared/ccp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-ccp.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-ccp.Tpo -c -o src/shared/libshared_mainloop_la-ccp.lo `test -f 'src/shared/ccp.c' || echo '$(srcdir)/'`src/shared/ccp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-ccp.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-ccp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/ccp.c' object='src/shared/libshared_mainloop_la-ccp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-ccp.lo `test -f 'src/shared/ccp.c' || echo '$(srcdir)/'`src/shared/ccp.c + +src/shared/libshared_mainloop_la-asha.lo: src/shared/asha.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-asha.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-asha.Tpo -c -o src/shared/libshared_mainloop_la-asha.lo `test -f 'src/shared/asha.c' || echo '$(srcdir)/'`src/shared/asha.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-asha.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-asha.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/asha.c' object='src/shared/libshared_mainloop_la-asha.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-asha.lo `test -f 'src/shared/asha.c' || echo '$(srcdir)/'`src/shared/asha.c + +src/shared/libshared_mainloop_la-shell.lo: src/shared/shell.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-shell.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-shell.Tpo -c -o src/shared/libshared_mainloop_la-shell.lo `test -f 'src/shared/shell.c' || echo '$(srcdir)/'`src/shared/shell.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-shell.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-shell.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/shell.c' object='src/shared/libshared_mainloop_la-shell.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-shell.lo `test -f 'src/shared/shell.c' || echo '$(srcdir)/'`src/shared/shell.c + +src/shared/libshared_mainloop_la-io-mainloop.lo: src/shared/io-mainloop.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-io-mainloop.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-io-mainloop.Tpo -c -o src/shared/libshared_mainloop_la-io-mainloop.lo `test -f 'src/shared/io-mainloop.c' || echo '$(srcdir)/'`src/shared/io-mainloop.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-io-mainloop.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-io-mainloop.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/io-mainloop.c' object='src/shared/libshared_mainloop_la-io-mainloop.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-io-mainloop.lo `test -f 'src/shared/io-mainloop.c' || echo '$(srcdir)/'`src/shared/io-mainloop.c + +src/shared/libshared_mainloop_la-timeout-mainloop.lo: src/shared/timeout-mainloop.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-timeout-mainloop.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-timeout-mainloop.Tpo -c -o src/shared/libshared_mainloop_la-timeout-mainloop.lo `test -f 'src/shared/timeout-mainloop.c' || echo '$(srcdir)/'`src/shared/timeout-mainloop.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-timeout-mainloop.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-timeout-mainloop.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/timeout-mainloop.c' object='src/shared/libshared_mainloop_la-timeout-mainloop.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-timeout-mainloop.lo `test -f 'src/shared/timeout-mainloop.c' || echo '$(srcdir)/'`src/shared/timeout-mainloop.c + +src/shared/libshared_mainloop_la-mainloop.lo: src/shared/mainloop.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-mainloop.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-mainloop.Tpo -c -o src/shared/libshared_mainloop_la-mainloop.lo `test -f 'src/shared/mainloop.c' || echo '$(srcdir)/'`src/shared/mainloop.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-mainloop.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-mainloop.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/mainloop.c' object='src/shared/libshared_mainloop_la-mainloop.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-mainloop.lo `test -f 'src/shared/mainloop.c' || echo '$(srcdir)/'`src/shared/mainloop.c + +src/shared/libshared_mainloop_la-mainloop-notify.lo: src/shared/mainloop-notify.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -MT src/shared/libshared_mainloop_la-mainloop-notify.lo -MD -MP -MF src/shared/$(DEPDIR)/libshared_mainloop_la-mainloop-notify.Tpo -c -o src/shared/libshared_mainloop_la-mainloop-notify.lo `test -f 'src/shared/mainloop-notify.c' || echo '$(srcdir)/'`src/shared/mainloop-notify.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/libshared_mainloop_la-mainloop-notify.Tpo src/shared/$(DEPDIR)/libshared_mainloop_la-mainloop-notify.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/mainloop-notify.c' object='src/shared/libshared_mainloop_la-mainloop-notify.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libshared_mainloop_la_CFLAGS) $(CFLAGS) -c -o src/shared/libshared_mainloop_la-mainloop-notify.lo `test -f 'src/shared/mainloop-notify.c' || echo '$(srcdir)/'`src/shared/mainloop-notify.c + +emulator/android_android_tester-hciemu.o: emulator/hciemu.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_android_tester-hciemu.o -MD -MP -MF emulator/$(DEPDIR)/android_android_tester-hciemu.Tpo -c -o emulator/android_android_tester-hciemu.o `test -f 'emulator/hciemu.c' || echo '$(srcdir)/'`emulator/hciemu.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_android_tester-hciemu.Tpo emulator/$(DEPDIR)/android_android_tester-hciemu.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/hciemu.c' object='emulator/android_android_tester-hciemu.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_android_tester-hciemu.o `test -f 'emulator/hciemu.c' || echo '$(srcdir)/'`emulator/hciemu.c + +emulator/android_android_tester-hciemu.obj: emulator/hciemu.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_android_tester-hciemu.obj -MD -MP -MF emulator/$(DEPDIR)/android_android_tester-hciemu.Tpo -c -o emulator/android_android_tester-hciemu.obj `if test -f 'emulator/hciemu.c'; then $(CYGPATH_W) 'emulator/hciemu.c'; else $(CYGPATH_W) '$(srcdir)/emulator/hciemu.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_android_tester-hciemu.Tpo emulator/$(DEPDIR)/android_android_tester-hciemu.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/hciemu.c' object='emulator/android_android_tester-hciemu.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_android_tester-hciemu.obj `if test -f 'emulator/hciemu.c'; then $(CYGPATH_W) 'emulator/hciemu.c'; else $(CYGPATH_W) '$(srcdir)/emulator/hciemu.c'; fi` + +emulator/android_android_tester-vhci.o: emulator/vhci.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_android_tester-vhci.o -MD -MP -MF emulator/$(DEPDIR)/android_android_tester-vhci.Tpo -c -o emulator/android_android_tester-vhci.o `test -f 'emulator/vhci.c' || echo '$(srcdir)/'`emulator/vhci.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_android_tester-vhci.Tpo emulator/$(DEPDIR)/android_android_tester-vhci.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/vhci.c' object='emulator/android_android_tester-vhci.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_android_tester-vhci.o `test -f 'emulator/vhci.c' || echo '$(srcdir)/'`emulator/vhci.c + +emulator/android_android_tester-vhci.obj: emulator/vhci.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_android_tester-vhci.obj -MD -MP -MF emulator/$(DEPDIR)/android_android_tester-vhci.Tpo -c -o emulator/android_android_tester-vhci.obj `if test -f 'emulator/vhci.c'; then $(CYGPATH_W) 'emulator/vhci.c'; else $(CYGPATH_W) '$(srcdir)/emulator/vhci.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_android_tester-vhci.Tpo emulator/$(DEPDIR)/android_android_tester-vhci.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/vhci.c' object='emulator/android_android_tester-vhci.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_android_tester-vhci.obj `if test -f 'emulator/vhci.c'; then $(CYGPATH_W) 'emulator/vhci.c'; else $(CYGPATH_W) '$(srcdir)/emulator/vhci.c'; fi` + +emulator/android_android_tester-btdev.o: emulator/btdev.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_android_tester-btdev.o -MD -MP -MF emulator/$(DEPDIR)/android_android_tester-btdev.Tpo -c -o emulator/android_android_tester-btdev.o `test -f 'emulator/btdev.c' || echo '$(srcdir)/'`emulator/btdev.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_android_tester-btdev.Tpo emulator/$(DEPDIR)/android_android_tester-btdev.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/btdev.c' object='emulator/android_android_tester-btdev.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_android_tester-btdev.o `test -f 'emulator/btdev.c' || echo '$(srcdir)/'`emulator/btdev.c + +emulator/android_android_tester-btdev.obj: emulator/btdev.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_android_tester-btdev.obj -MD -MP -MF emulator/$(DEPDIR)/android_android_tester-btdev.Tpo -c -o emulator/android_android_tester-btdev.obj `if test -f 'emulator/btdev.c'; then $(CYGPATH_W) 'emulator/btdev.c'; else $(CYGPATH_W) '$(srcdir)/emulator/btdev.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_android_tester-btdev.Tpo emulator/$(DEPDIR)/android_android_tester-btdev.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/btdev.c' object='emulator/android_android_tester-btdev.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_android_tester-btdev.obj `if test -f 'emulator/btdev.c'; then $(CYGPATH_W) 'emulator/btdev.c'; else $(CYGPATH_W) '$(srcdir)/emulator/btdev.c'; fi` + +emulator/android_android_tester-bthost.o: emulator/bthost.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_android_tester-bthost.o -MD -MP -MF emulator/$(DEPDIR)/android_android_tester-bthost.Tpo -c -o emulator/android_android_tester-bthost.o `test -f 'emulator/bthost.c' || echo '$(srcdir)/'`emulator/bthost.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_android_tester-bthost.Tpo emulator/$(DEPDIR)/android_android_tester-bthost.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/bthost.c' object='emulator/android_android_tester-bthost.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_android_tester-bthost.o `test -f 'emulator/bthost.c' || echo '$(srcdir)/'`emulator/bthost.c + +emulator/android_android_tester-bthost.obj: emulator/bthost.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_android_tester-bthost.obj -MD -MP -MF emulator/$(DEPDIR)/android_android_tester-bthost.Tpo -c -o emulator/android_android_tester-bthost.obj `if test -f 'emulator/bthost.c'; then $(CYGPATH_W) 'emulator/bthost.c'; else $(CYGPATH_W) '$(srcdir)/emulator/bthost.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_android_tester-bthost.Tpo emulator/$(DEPDIR)/android_android_tester-bthost.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/bthost.c' object='emulator/android_android_tester-bthost.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_android_tester-bthost.obj `if test -f 'emulator/bthost.c'; then $(CYGPATH_W) 'emulator/bthost.c'; else $(CYGPATH_W) '$(srcdir)/emulator/bthost.c'; fi` + +emulator/android_android_tester-smp.o: emulator/smp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_android_tester-smp.o -MD -MP -MF emulator/$(DEPDIR)/android_android_tester-smp.Tpo -c -o emulator/android_android_tester-smp.o `test -f 'emulator/smp.c' || echo '$(srcdir)/'`emulator/smp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_android_tester-smp.Tpo emulator/$(DEPDIR)/android_android_tester-smp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/smp.c' object='emulator/android_android_tester-smp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_android_tester-smp.o `test -f 'emulator/smp.c' || echo '$(srcdir)/'`emulator/smp.c + +emulator/android_android_tester-smp.obj: emulator/smp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_android_tester-smp.obj -MD -MP -MF emulator/$(DEPDIR)/android_android_tester-smp.Tpo -c -o emulator/android_android_tester-smp.obj `if test -f 'emulator/smp.c'; then $(CYGPATH_W) 'emulator/smp.c'; else $(CYGPATH_W) '$(srcdir)/emulator/smp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_android_tester-smp.Tpo emulator/$(DEPDIR)/android_android_tester-smp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/smp.c' object='emulator/android_android_tester-smp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_android_tester-smp.obj `if test -f 'emulator/smp.c'; then $(CYGPATH_W) 'emulator/smp.c'; else $(CYGPATH_W) '$(srcdir)/emulator/smp.c'; fi` + +android/hardware/android_tester-hardware.o: android/hardware/hardware.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/hardware/android_tester-hardware.o -MD -MP -MF android/hardware/$(DEPDIR)/android_tester-hardware.Tpo -c -o android/hardware/android_tester-hardware.o `test -f 'android/hardware/hardware.c' || echo '$(srcdir)/'`android/hardware/hardware.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/hardware/$(DEPDIR)/android_tester-hardware.Tpo android/hardware/$(DEPDIR)/android_tester-hardware.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hardware/hardware.c' object='android/hardware/android_tester-hardware.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/hardware/android_tester-hardware.o `test -f 'android/hardware/hardware.c' || echo '$(srcdir)/'`android/hardware/hardware.c + +android/hardware/android_tester-hardware.obj: android/hardware/hardware.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/hardware/android_tester-hardware.obj -MD -MP -MF android/hardware/$(DEPDIR)/android_tester-hardware.Tpo -c -o android/hardware/android_tester-hardware.obj `if test -f 'android/hardware/hardware.c'; then $(CYGPATH_W) 'android/hardware/hardware.c'; else $(CYGPATH_W) '$(srcdir)/android/hardware/hardware.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/hardware/$(DEPDIR)/android_tester-hardware.Tpo android/hardware/$(DEPDIR)/android_tester-hardware.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hardware/hardware.c' object='android/hardware/android_tester-hardware.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/hardware/android_tester-hardware.obj `if test -f 'android/hardware/hardware.c'; then $(CYGPATH_W) 'android/hardware/hardware.c'; else $(CYGPATH_W) '$(srcdir)/android/hardware/hardware.c'; fi` + +android/android_tester-tester-bluetooth.o: android/tester-bluetooth.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-bluetooth.o -MD -MP -MF android/$(DEPDIR)/android_tester-tester-bluetooth.Tpo -c -o android/android_tester-tester-bluetooth.o `test -f 'android/tester-bluetooth.c' || echo '$(srcdir)/'`android/tester-bluetooth.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-bluetooth.Tpo android/$(DEPDIR)/android_tester-tester-bluetooth.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-bluetooth.c' object='android/android_tester-tester-bluetooth.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-bluetooth.o `test -f 'android/tester-bluetooth.c' || echo '$(srcdir)/'`android/tester-bluetooth.c + +android/android_tester-tester-bluetooth.obj: android/tester-bluetooth.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-bluetooth.obj -MD -MP -MF android/$(DEPDIR)/android_tester-tester-bluetooth.Tpo -c -o android/android_tester-tester-bluetooth.obj `if test -f 'android/tester-bluetooth.c'; then $(CYGPATH_W) 'android/tester-bluetooth.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-bluetooth.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-bluetooth.Tpo android/$(DEPDIR)/android_tester-tester-bluetooth.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-bluetooth.c' object='android/android_tester-tester-bluetooth.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-bluetooth.obj `if test -f 'android/tester-bluetooth.c'; then $(CYGPATH_W) 'android/tester-bluetooth.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-bluetooth.c'; fi` + +android/android_tester-tester-socket.o: android/tester-socket.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-socket.o -MD -MP -MF android/$(DEPDIR)/android_tester-tester-socket.Tpo -c -o android/android_tester-tester-socket.o `test -f 'android/tester-socket.c' || echo '$(srcdir)/'`android/tester-socket.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-socket.Tpo android/$(DEPDIR)/android_tester-tester-socket.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-socket.c' object='android/android_tester-tester-socket.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-socket.o `test -f 'android/tester-socket.c' || echo '$(srcdir)/'`android/tester-socket.c + +android/android_tester-tester-socket.obj: android/tester-socket.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-socket.obj -MD -MP -MF android/$(DEPDIR)/android_tester-tester-socket.Tpo -c -o android/android_tester-tester-socket.obj `if test -f 'android/tester-socket.c'; then $(CYGPATH_W) 'android/tester-socket.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-socket.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-socket.Tpo android/$(DEPDIR)/android_tester-tester-socket.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-socket.c' object='android/android_tester-tester-socket.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-socket.obj `if test -f 'android/tester-socket.c'; then $(CYGPATH_W) 'android/tester-socket.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-socket.c'; fi` + +android/android_tester-tester-hidhost.o: android/tester-hidhost.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-hidhost.o -MD -MP -MF android/$(DEPDIR)/android_tester-tester-hidhost.Tpo -c -o android/android_tester-tester-hidhost.o `test -f 'android/tester-hidhost.c' || echo '$(srcdir)/'`android/tester-hidhost.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-hidhost.Tpo android/$(DEPDIR)/android_tester-tester-hidhost.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-hidhost.c' object='android/android_tester-tester-hidhost.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-hidhost.o `test -f 'android/tester-hidhost.c' || echo '$(srcdir)/'`android/tester-hidhost.c + +android/android_tester-tester-hidhost.obj: android/tester-hidhost.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-hidhost.obj -MD -MP -MF android/$(DEPDIR)/android_tester-tester-hidhost.Tpo -c -o android/android_tester-tester-hidhost.obj `if test -f 'android/tester-hidhost.c'; then $(CYGPATH_W) 'android/tester-hidhost.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-hidhost.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-hidhost.Tpo android/$(DEPDIR)/android_tester-tester-hidhost.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-hidhost.c' object='android/android_tester-tester-hidhost.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-hidhost.obj `if test -f 'android/tester-hidhost.c'; then $(CYGPATH_W) 'android/tester-hidhost.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-hidhost.c'; fi` + +android/android_tester-tester-pan.o: android/tester-pan.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-pan.o -MD -MP -MF android/$(DEPDIR)/android_tester-tester-pan.Tpo -c -o android/android_tester-tester-pan.o `test -f 'android/tester-pan.c' || echo '$(srcdir)/'`android/tester-pan.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-pan.Tpo android/$(DEPDIR)/android_tester-tester-pan.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-pan.c' object='android/android_tester-tester-pan.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-pan.o `test -f 'android/tester-pan.c' || echo '$(srcdir)/'`android/tester-pan.c + +android/android_tester-tester-pan.obj: android/tester-pan.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-pan.obj -MD -MP -MF android/$(DEPDIR)/android_tester-tester-pan.Tpo -c -o android/android_tester-tester-pan.obj `if test -f 'android/tester-pan.c'; then $(CYGPATH_W) 'android/tester-pan.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-pan.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-pan.Tpo android/$(DEPDIR)/android_tester-tester-pan.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-pan.c' object='android/android_tester-tester-pan.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-pan.obj `if test -f 'android/tester-pan.c'; then $(CYGPATH_W) 'android/tester-pan.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-pan.c'; fi` + +android/android_tester-tester-hdp.o: android/tester-hdp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-hdp.o -MD -MP -MF android/$(DEPDIR)/android_tester-tester-hdp.Tpo -c -o android/android_tester-tester-hdp.o `test -f 'android/tester-hdp.c' || echo '$(srcdir)/'`android/tester-hdp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-hdp.Tpo android/$(DEPDIR)/android_tester-tester-hdp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-hdp.c' object='android/android_tester-tester-hdp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-hdp.o `test -f 'android/tester-hdp.c' || echo '$(srcdir)/'`android/tester-hdp.c + +android/android_tester-tester-hdp.obj: android/tester-hdp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-hdp.obj -MD -MP -MF android/$(DEPDIR)/android_tester-tester-hdp.Tpo -c -o android/android_tester-tester-hdp.obj `if test -f 'android/tester-hdp.c'; then $(CYGPATH_W) 'android/tester-hdp.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-hdp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-hdp.Tpo android/$(DEPDIR)/android_tester-tester-hdp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-hdp.c' object='android/android_tester-tester-hdp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-hdp.obj `if test -f 'android/tester-hdp.c'; then $(CYGPATH_W) 'android/tester-hdp.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-hdp.c'; fi` + +android/android_tester-tester-a2dp.o: android/tester-a2dp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-a2dp.o -MD -MP -MF android/$(DEPDIR)/android_tester-tester-a2dp.Tpo -c -o android/android_tester-tester-a2dp.o `test -f 'android/tester-a2dp.c' || echo '$(srcdir)/'`android/tester-a2dp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-a2dp.Tpo android/$(DEPDIR)/android_tester-tester-a2dp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-a2dp.c' object='android/android_tester-tester-a2dp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-a2dp.o `test -f 'android/tester-a2dp.c' || echo '$(srcdir)/'`android/tester-a2dp.c + +android/android_tester-tester-a2dp.obj: android/tester-a2dp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-a2dp.obj -MD -MP -MF android/$(DEPDIR)/android_tester-tester-a2dp.Tpo -c -o android/android_tester-tester-a2dp.obj `if test -f 'android/tester-a2dp.c'; then $(CYGPATH_W) 'android/tester-a2dp.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-a2dp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-a2dp.Tpo android/$(DEPDIR)/android_tester-tester-a2dp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-a2dp.c' object='android/android_tester-tester-a2dp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-a2dp.obj `if test -f 'android/tester-a2dp.c'; then $(CYGPATH_W) 'android/tester-a2dp.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-a2dp.c'; fi` + +android/android_tester-tester-avrcp.o: android/tester-avrcp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-avrcp.o -MD -MP -MF android/$(DEPDIR)/android_tester-tester-avrcp.Tpo -c -o android/android_tester-tester-avrcp.o `test -f 'android/tester-avrcp.c' || echo '$(srcdir)/'`android/tester-avrcp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-avrcp.Tpo android/$(DEPDIR)/android_tester-tester-avrcp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-avrcp.c' object='android/android_tester-tester-avrcp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-avrcp.o `test -f 'android/tester-avrcp.c' || echo '$(srcdir)/'`android/tester-avrcp.c + +android/android_tester-tester-avrcp.obj: android/tester-avrcp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-avrcp.obj -MD -MP -MF android/$(DEPDIR)/android_tester-tester-avrcp.Tpo -c -o android/android_tester-tester-avrcp.obj `if test -f 'android/tester-avrcp.c'; then $(CYGPATH_W) 'android/tester-avrcp.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-avrcp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-avrcp.Tpo android/$(DEPDIR)/android_tester-tester-avrcp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-avrcp.c' object='android/android_tester-tester-avrcp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-avrcp.obj `if test -f 'android/tester-avrcp.c'; then $(CYGPATH_W) 'android/tester-avrcp.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-avrcp.c'; fi` + +android/android_tester-tester-gatt.o: android/tester-gatt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-gatt.o -MD -MP -MF android/$(DEPDIR)/android_tester-tester-gatt.Tpo -c -o android/android_tester-tester-gatt.o `test -f 'android/tester-gatt.c' || echo '$(srcdir)/'`android/tester-gatt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-gatt.Tpo android/$(DEPDIR)/android_tester-tester-gatt.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-gatt.c' object='android/android_tester-tester-gatt.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-gatt.o `test -f 'android/tester-gatt.c' || echo '$(srcdir)/'`android/tester-gatt.c + +android/android_tester-tester-gatt.obj: android/tester-gatt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-gatt.obj -MD -MP -MF android/$(DEPDIR)/android_tester-tester-gatt.Tpo -c -o android/android_tester-tester-gatt.obj `if test -f 'android/tester-gatt.c'; then $(CYGPATH_W) 'android/tester-gatt.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-gatt.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-gatt.Tpo android/$(DEPDIR)/android_tester-tester-gatt.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-gatt.c' object='android/android_tester-tester-gatt.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-gatt.obj `if test -f 'android/tester-gatt.c'; then $(CYGPATH_W) 'android/tester-gatt.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-gatt.c'; fi` + +android/android_tester-tester-map-client.o: android/tester-map-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-map-client.o -MD -MP -MF android/$(DEPDIR)/android_tester-tester-map-client.Tpo -c -o android/android_tester-tester-map-client.o `test -f 'android/tester-map-client.c' || echo '$(srcdir)/'`android/tester-map-client.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-map-client.Tpo android/$(DEPDIR)/android_tester-tester-map-client.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-map-client.c' object='android/android_tester-tester-map-client.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-map-client.o `test -f 'android/tester-map-client.c' || echo '$(srcdir)/'`android/tester-map-client.c + +android/android_tester-tester-map-client.obj: android/tester-map-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-map-client.obj -MD -MP -MF android/$(DEPDIR)/android_tester-tester-map-client.Tpo -c -o android/android_tester-tester-map-client.obj `if test -f 'android/tester-map-client.c'; then $(CYGPATH_W) 'android/tester-map-client.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-map-client.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-map-client.Tpo android/$(DEPDIR)/android_tester-tester-map-client.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-map-client.c' object='android/android_tester-tester-map-client.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-map-client.obj `if test -f 'android/tester-map-client.c'; then $(CYGPATH_W) 'android/tester-map-client.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-map-client.c'; fi` + +android/android_tester-tester-main.o: android/tester-main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-main.o -MD -MP -MF android/$(DEPDIR)/android_tester-tester-main.Tpo -c -o android/android_tester-tester-main.o `test -f 'android/tester-main.c' || echo '$(srcdir)/'`android/tester-main.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-main.Tpo android/$(DEPDIR)/android_tester-tester-main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-main.c' object='android/android_tester-tester-main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-main.o `test -f 'android/tester-main.c' || echo '$(srcdir)/'`android/tester-main.c + +android/android_tester-tester-main.obj: android/tester-main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/android_tester-tester-main.obj -MD -MP -MF android/$(DEPDIR)/android_tester-tester-main.Tpo -c -o android/android_tester-tester-main.obj `if test -f 'android/tester-main.c'; then $(CYGPATH_W) 'android/tester-main.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-main.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/android_tester-tester-main.Tpo android/$(DEPDIR)/android_tester-tester-main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/tester-main.c' object='android/android_tester-tester-main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_android_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/android_tester-tester-main.obj `if test -f 'android/tester-main.c'; then $(CYGPATH_W) 'android/tester-main.c'; else $(CYGPATH_W) '$(srcdir)/android/tester-main.c'; fi` + +android/avdtptest-avdtptest.o: android/avdtptest.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -MT android/avdtptest-avdtptest.o -MD -MP -MF android/$(DEPDIR)/avdtptest-avdtptest.Tpo -c -o android/avdtptest-avdtptest.o `test -f 'android/avdtptest.c' || echo '$(srcdir)/'`android/avdtptest.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/avdtptest-avdtptest.Tpo android/$(DEPDIR)/avdtptest-avdtptest.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/avdtptest.c' object='android/avdtptest-avdtptest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -c -o android/avdtptest-avdtptest.o `test -f 'android/avdtptest.c' || echo '$(srcdir)/'`android/avdtptest.c + +android/avdtptest-avdtptest.obj: android/avdtptest.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -MT android/avdtptest-avdtptest.obj -MD -MP -MF android/$(DEPDIR)/avdtptest-avdtptest.Tpo -c -o android/avdtptest-avdtptest.obj `if test -f 'android/avdtptest.c'; then $(CYGPATH_W) 'android/avdtptest.c'; else $(CYGPATH_W) '$(srcdir)/android/avdtptest.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/avdtptest-avdtptest.Tpo android/$(DEPDIR)/avdtptest-avdtptest.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/avdtptest.c' object='android/avdtptest-avdtptest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -c -o android/avdtptest-avdtptest.obj `if test -f 'android/avdtptest.c'; then $(CYGPATH_W) 'android/avdtptest.c'; else $(CYGPATH_W) '$(srcdir)/android/avdtptest.c'; fi` + +src/android_avdtptest-log.o: src/log.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -MT src/android_avdtptest-log.o -MD -MP -MF src/$(DEPDIR)/android_avdtptest-log.Tpo -c -o src/android_avdtptest-log.o `test -f 'src/log.c' || echo '$(srcdir)/'`src/log.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/android_avdtptest-log.Tpo src/$(DEPDIR)/android_avdtptest-log.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/log.c' object='src/android_avdtptest-log.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -c -o src/android_avdtptest-log.o `test -f 'src/log.c' || echo '$(srcdir)/'`src/log.c + +src/android_avdtptest-log.obj: src/log.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -MT src/android_avdtptest-log.obj -MD -MP -MF src/$(DEPDIR)/android_avdtptest-log.Tpo -c -o src/android_avdtptest-log.obj `if test -f 'src/log.c'; then $(CYGPATH_W) 'src/log.c'; else $(CYGPATH_W) '$(srcdir)/src/log.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/android_avdtptest-log.Tpo src/$(DEPDIR)/android_avdtptest-log.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/log.c' object='src/android_avdtptest-log.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -c -o src/android_avdtptest-log.obj `if test -f 'src/log.c'; then $(CYGPATH_W) 'src/log.c'; else $(CYGPATH_W) '$(srcdir)/src/log.c'; fi` + +btio/android_avdtptest-btio.o: btio/btio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -MT btio/android_avdtptest-btio.o -MD -MP -MF btio/$(DEPDIR)/android_avdtptest-btio.Tpo -c -o btio/android_avdtptest-btio.o `test -f 'btio/btio.c' || echo '$(srcdir)/'`btio/btio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btio/$(DEPDIR)/android_avdtptest-btio.Tpo btio/$(DEPDIR)/android_avdtptest-btio.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btio/btio.c' object='btio/android_avdtptest-btio.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -c -o btio/android_avdtptest-btio.o `test -f 'btio/btio.c' || echo '$(srcdir)/'`btio/btio.c + +btio/android_avdtptest-btio.obj: btio/btio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -MT btio/android_avdtptest-btio.obj -MD -MP -MF btio/$(DEPDIR)/android_avdtptest-btio.Tpo -c -o btio/android_avdtptest-btio.obj `if test -f 'btio/btio.c'; then $(CYGPATH_W) 'btio/btio.c'; else $(CYGPATH_W) '$(srcdir)/btio/btio.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btio/$(DEPDIR)/android_avdtptest-btio.Tpo btio/$(DEPDIR)/android_avdtptest-btio.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btio/btio.c' object='btio/android_avdtptest-btio.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -c -o btio/android_avdtptest-btio.obj `if test -f 'btio/btio.c'; then $(CYGPATH_W) 'btio/btio.c'; else $(CYGPATH_W) '$(srcdir)/btio/btio.c'; fi` + +src/shared/android_avdtptest-util.o: src/shared/util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -MT src/shared/android_avdtptest-util.o -MD -MP -MF src/shared/$(DEPDIR)/android_avdtptest-util.Tpo -c -o src/shared/android_avdtptest-util.o `test -f 'src/shared/util.c' || echo '$(srcdir)/'`src/shared/util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/android_avdtptest-util.Tpo src/shared/$(DEPDIR)/android_avdtptest-util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/util.c' object='src/shared/android_avdtptest-util.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -c -o src/shared/android_avdtptest-util.o `test -f 'src/shared/util.c' || echo '$(srcdir)/'`src/shared/util.c + +src/shared/android_avdtptest-util.obj: src/shared/util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -MT src/shared/android_avdtptest-util.obj -MD -MP -MF src/shared/$(DEPDIR)/android_avdtptest-util.Tpo -c -o src/shared/android_avdtptest-util.obj `if test -f 'src/shared/util.c'; then $(CYGPATH_W) 'src/shared/util.c'; else $(CYGPATH_W) '$(srcdir)/src/shared/util.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/android_avdtptest-util.Tpo src/shared/$(DEPDIR)/android_avdtptest-util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/util.c' object='src/shared/android_avdtptest-util.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -c -o src/shared/android_avdtptest-util.obj `if test -f 'src/shared/util.c'; then $(CYGPATH_W) 'src/shared/util.c'; else $(CYGPATH_W) '$(srcdir)/src/shared/util.c'; fi` + +src/shared/android_avdtptest-queue.o: src/shared/queue.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -MT src/shared/android_avdtptest-queue.o -MD -MP -MF src/shared/$(DEPDIR)/android_avdtptest-queue.Tpo -c -o src/shared/android_avdtptest-queue.o `test -f 'src/shared/queue.c' || echo '$(srcdir)/'`src/shared/queue.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/android_avdtptest-queue.Tpo src/shared/$(DEPDIR)/android_avdtptest-queue.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/queue.c' object='src/shared/android_avdtptest-queue.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -c -o src/shared/android_avdtptest-queue.o `test -f 'src/shared/queue.c' || echo '$(srcdir)/'`src/shared/queue.c + +src/shared/android_avdtptest-queue.obj: src/shared/queue.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -MT src/shared/android_avdtptest-queue.obj -MD -MP -MF src/shared/$(DEPDIR)/android_avdtptest-queue.Tpo -c -o src/shared/android_avdtptest-queue.obj `if test -f 'src/shared/queue.c'; then $(CYGPATH_W) 'src/shared/queue.c'; else $(CYGPATH_W) '$(srcdir)/src/shared/queue.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/android_avdtptest-queue.Tpo src/shared/$(DEPDIR)/android_avdtptest-queue.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/queue.c' object='src/shared/android_avdtptest-queue.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -c -o src/shared/android_avdtptest-queue.obj `if test -f 'src/shared/queue.c'; then $(CYGPATH_W) 'src/shared/queue.c'; else $(CYGPATH_W) '$(srcdir)/src/shared/queue.c'; fi` + +src/shared/android_avdtptest-log.o: src/shared/log.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -MT src/shared/android_avdtptest-log.o -MD -MP -MF src/shared/$(DEPDIR)/android_avdtptest-log.Tpo -c -o src/shared/android_avdtptest-log.o `test -f 'src/shared/log.c' || echo '$(srcdir)/'`src/shared/log.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/android_avdtptest-log.Tpo src/shared/$(DEPDIR)/android_avdtptest-log.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/log.c' object='src/shared/android_avdtptest-log.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -c -o src/shared/android_avdtptest-log.o `test -f 'src/shared/log.c' || echo '$(srcdir)/'`src/shared/log.c + +src/shared/android_avdtptest-log.obj: src/shared/log.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -MT src/shared/android_avdtptest-log.obj -MD -MP -MF src/shared/$(DEPDIR)/android_avdtptest-log.Tpo -c -o src/shared/android_avdtptest-log.obj `if test -f 'src/shared/log.c'; then $(CYGPATH_W) 'src/shared/log.c'; else $(CYGPATH_W) '$(srcdir)/src/shared/log.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/android_avdtptest-log.Tpo src/shared/$(DEPDIR)/android_avdtptest-log.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/shared/log.c' object='src/shared/android_avdtptest-log.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -c -o src/shared/android_avdtptest-log.obj `if test -f 'src/shared/log.c'; then $(CYGPATH_W) 'src/shared/log.c'; else $(CYGPATH_W) '$(srcdir)/src/shared/log.c'; fi` + +android/avdtptest-avdtp.o: android/avdtp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -MT android/avdtptest-avdtp.o -MD -MP -MF android/$(DEPDIR)/avdtptest-avdtp.Tpo -c -o android/avdtptest-avdtp.o `test -f 'android/avdtp.c' || echo '$(srcdir)/'`android/avdtp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/avdtptest-avdtp.Tpo android/$(DEPDIR)/avdtptest-avdtp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/avdtp.c' object='android/avdtptest-avdtp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -c -o android/avdtptest-avdtp.o `test -f 'android/avdtp.c' || echo '$(srcdir)/'`android/avdtp.c + +android/avdtptest-avdtp.obj: android/avdtp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -MT android/avdtptest-avdtp.obj -MD -MP -MF android/$(DEPDIR)/avdtptest-avdtp.Tpo -c -o android/avdtptest-avdtp.obj `if test -f 'android/avdtp.c'; then $(CYGPATH_W) 'android/avdtp.c'; else $(CYGPATH_W) '$(srcdir)/android/avdtp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/avdtptest-avdtp.Tpo android/$(DEPDIR)/avdtptest-avdtp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/avdtp.c' object='android/avdtptest-avdtp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(android_avdtptest_CFLAGS) $(CFLAGS) -c -o android/avdtptest-avdtp.obj `if test -f 'android/avdtp.c'; then $(CYGPATH_W) 'android/avdtp.c'; else $(CYGPATH_W) '$(srcdir)/android/avdtp.c'; fi` + +android/client/haltest-haltest.o: android/client/haltest.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-haltest.o -MD -MP -MF android/client/$(DEPDIR)/haltest-haltest.Tpo -c -o android/client/haltest-haltest.o `test -f 'android/client/haltest.c' || echo '$(srcdir)/'`android/client/haltest.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-haltest.Tpo android/client/$(DEPDIR)/haltest-haltest.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/haltest.c' object='android/client/haltest-haltest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-haltest.o `test -f 'android/client/haltest.c' || echo '$(srcdir)/'`android/client/haltest.c + +android/client/haltest-haltest.obj: android/client/haltest.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-haltest.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-haltest.Tpo -c -o android/client/haltest-haltest.obj `if test -f 'android/client/haltest.c'; then $(CYGPATH_W) 'android/client/haltest.c'; else $(CYGPATH_W) '$(srcdir)/android/client/haltest.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-haltest.Tpo android/client/$(DEPDIR)/haltest-haltest.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/haltest.c' object='android/client/haltest-haltest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-haltest.obj `if test -f 'android/client/haltest.c'; then $(CYGPATH_W) 'android/client/haltest.c'; else $(CYGPATH_W) '$(srcdir)/android/client/haltest.c'; fi` + +android/client/haltest-pollhandler.o: android/client/pollhandler.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-pollhandler.o -MD -MP -MF android/client/$(DEPDIR)/haltest-pollhandler.Tpo -c -o android/client/haltest-pollhandler.o `test -f 'android/client/pollhandler.c' || echo '$(srcdir)/'`android/client/pollhandler.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-pollhandler.Tpo android/client/$(DEPDIR)/haltest-pollhandler.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/pollhandler.c' object='android/client/haltest-pollhandler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-pollhandler.o `test -f 'android/client/pollhandler.c' || echo '$(srcdir)/'`android/client/pollhandler.c + +android/client/haltest-pollhandler.obj: android/client/pollhandler.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-pollhandler.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-pollhandler.Tpo -c -o android/client/haltest-pollhandler.obj `if test -f 'android/client/pollhandler.c'; then $(CYGPATH_W) 'android/client/pollhandler.c'; else $(CYGPATH_W) '$(srcdir)/android/client/pollhandler.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-pollhandler.Tpo android/client/$(DEPDIR)/haltest-pollhandler.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/pollhandler.c' object='android/client/haltest-pollhandler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-pollhandler.obj `if test -f 'android/client/pollhandler.c'; then $(CYGPATH_W) 'android/client/pollhandler.c'; else $(CYGPATH_W) '$(srcdir)/android/client/pollhandler.c'; fi` + +android/client/haltest-terminal.o: android/client/terminal.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-terminal.o -MD -MP -MF android/client/$(DEPDIR)/haltest-terminal.Tpo -c -o android/client/haltest-terminal.o `test -f 'android/client/terminal.c' || echo '$(srcdir)/'`android/client/terminal.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-terminal.Tpo android/client/$(DEPDIR)/haltest-terminal.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/terminal.c' object='android/client/haltest-terminal.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-terminal.o `test -f 'android/client/terminal.c' || echo '$(srcdir)/'`android/client/terminal.c + +android/client/haltest-terminal.obj: android/client/terminal.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-terminal.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-terminal.Tpo -c -o android/client/haltest-terminal.obj `if test -f 'android/client/terminal.c'; then $(CYGPATH_W) 'android/client/terminal.c'; else $(CYGPATH_W) '$(srcdir)/android/client/terminal.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-terminal.Tpo android/client/$(DEPDIR)/haltest-terminal.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/terminal.c' object='android/client/haltest-terminal.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-terminal.obj `if test -f 'android/client/terminal.c'; then $(CYGPATH_W) 'android/client/terminal.c'; else $(CYGPATH_W) '$(srcdir)/android/client/terminal.c'; fi` + +android/client/haltest-history.o: android/client/history.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-history.o -MD -MP -MF android/client/$(DEPDIR)/haltest-history.Tpo -c -o android/client/haltest-history.o `test -f 'android/client/history.c' || echo '$(srcdir)/'`android/client/history.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-history.Tpo android/client/$(DEPDIR)/haltest-history.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/history.c' object='android/client/haltest-history.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-history.o `test -f 'android/client/history.c' || echo '$(srcdir)/'`android/client/history.c + +android/client/haltest-history.obj: android/client/history.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-history.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-history.Tpo -c -o android/client/haltest-history.obj `if test -f 'android/client/history.c'; then $(CYGPATH_W) 'android/client/history.c'; else $(CYGPATH_W) '$(srcdir)/android/client/history.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-history.Tpo android/client/$(DEPDIR)/haltest-history.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/history.c' object='android/client/haltest-history.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-history.obj `if test -f 'android/client/history.c'; then $(CYGPATH_W) 'android/client/history.c'; else $(CYGPATH_W) '$(srcdir)/android/client/history.c'; fi` + +android/client/haltest-tabcompletion.o: android/client/tabcompletion.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-tabcompletion.o -MD -MP -MF android/client/$(DEPDIR)/haltest-tabcompletion.Tpo -c -o android/client/haltest-tabcompletion.o `test -f 'android/client/tabcompletion.c' || echo '$(srcdir)/'`android/client/tabcompletion.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-tabcompletion.Tpo android/client/$(DEPDIR)/haltest-tabcompletion.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/tabcompletion.c' object='android/client/haltest-tabcompletion.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-tabcompletion.o `test -f 'android/client/tabcompletion.c' || echo '$(srcdir)/'`android/client/tabcompletion.c + +android/client/haltest-tabcompletion.obj: android/client/tabcompletion.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-tabcompletion.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-tabcompletion.Tpo -c -o android/client/haltest-tabcompletion.obj `if test -f 'android/client/tabcompletion.c'; then $(CYGPATH_W) 'android/client/tabcompletion.c'; else $(CYGPATH_W) '$(srcdir)/android/client/tabcompletion.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-tabcompletion.Tpo android/client/$(DEPDIR)/haltest-tabcompletion.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/tabcompletion.c' object='android/client/haltest-tabcompletion.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-tabcompletion.obj `if test -f 'android/client/tabcompletion.c'; then $(CYGPATH_W) 'android/client/tabcompletion.c'; else $(CYGPATH_W) '$(srcdir)/android/client/tabcompletion.c'; fi` + +android/client/haltest-if-av.o: android/client/if-av.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-av.o -MD -MP -MF android/client/$(DEPDIR)/haltest-if-av.Tpo -c -o android/client/haltest-if-av.o `test -f 'android/client/if-av.c' || echo '$(srcdir)/'`android/client/if-av.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-av.Tpo android/client/$(DEPDIR)/haltest-if-av.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-av.c' object='android/client/haltest-if-av.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-av.o `test -f 'android/client/if-av.c' || echo '$(srcdir)/'`android/client/if-av.c + +android/client/haltest-if-av.obj: android/client/if-av.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-av.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-if-av.Tpo -c -o android/client/haltest-if-av.obj `if test -f 'android/client/if-av.c'; then $(CYGPATH_W) 'android/client/if-av.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-av.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-av.Tpo android/client/$(DEPDIR)/haltest-if-av.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-av.c' object='android/client/haltest-if-av.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-av.obj `if test -f 'android/client/if-av.c'; then $(CYGPATH_W) 'android/client/if-av.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-av.c'; fi` + +android/client/haltest-if-av-sink.o: android/client/if-av-sink.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-av-sink.o -MD -MP -MF android/client/$(DEPDIR)/haltest-if-av-sink.Tpo -c -o android/client/haltest-if-av-sink.o `test -f 'android/client/if-av-sink.c' || echo '$(srcdir)/'`android/client/if-av-sink.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-av-sink.Tpo android/client/$(DEPDIR)/haltest-if-av-sink.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-av-sink.c' object='android/client/haltest-if-av-sink.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-av-sink.o `test -f 'android/client/if-av-sink.c' || echo '$(srcdir)/'`android/client/if-av-sink.c + +android/client/haltest-if-av-sink.obj: android/client/if-av-sink.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-av-sink.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-if-av-sink.Tpo -c -o android/client/haltest-if-av-sink.obj `if test -f 'android/client/if-av-sink.c'; then $(CYGPATH_W) 'android/client/if-av-sink.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-av-sink.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-av-sink.Tpo android/client/$(DEPDIR)/haltest-if-av-sink.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-av-sink.c' object='android/client/haltest-if-av-sink.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-av-sink.obj `if test -f 'android/client/if-av-sink.c'; then $(CYGPATH_W) 'android/client/if-av-sink.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-av-sink.c'; fi` + +android/client/haltest-if-rc.o: android/client/if-rc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-rc.o -MD -MP -MF android/client/$(DEPDIR)/haltest-if-rc.Tpo -c -o android/client/haltest-if-rc.o `test -f 'android/client/if-rc.c' || echo '$(srcdir)/'`android/client/if-rc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-rc.Tpo android/client/$(DEPDIR)/haltest-if-rc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-rc.c' object='android/client/haltest-if-rc.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-rc.o `test -f 'android/client/if-rc.c' || echo '$(srcdir)/'`android/client/if-rc.c + +android/client/haltest-if-rc.obj: android/client/if-rc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-rc.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-if-rc.Tpo -c -o android/client/haltest-if-rc.obj `if test -f 'android/client/if-rc.c'; then $(CYGPATH_W) 'android/client/if-rc.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-rc.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-rc.Tpo android/client/$(DEPDIR)/haltest-if-rc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-rc.c' object='android/client/haltest-if-rc.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-rc.obj `if test -f 'android/client/if-rc.c'; then $(CYGPATH_W) 'android/client/if-rc.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-rc.c'; fi` + +android/client/haltest-if-rc-ctrl.o: android/client/if-rc-ctrl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-rc-ctrl.o -MD -MP -MF android/client/$(DEPDIR)/haltest-if-rc-ctrl.Tpo -c -o android/client/haltest-if-rc-ctrl.o `test -f 'android/client/if-rc-ctrl.c' || echo '$(srcdir)/'`android/client/if-rc-ctrl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-rc-ctrl.Tpo android/client/$(DEPDIR)/haltest-if-rc-ctrl.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-rc-ctrl.c' object='android/client/haltest-if-rc-ctrl.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-rc-ctrl.o `test -f 'android/client/if-rc-ctrl.c' || echo '$(srcdir)/'`android/client/if-rc-ctrl.c + +android/client/haltest-if-rc-ctrl.obj: android/client/if-rc-ctrl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-rc-ctrl.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-if-rc-ctrl.Tpo -c -o android/client/haltest-if-rc-ctrl.obj `if test -f 'android/client/if-rc-ctrl.c'; then $(CYGPATH_W) 'android/client/if-rc-ctrl.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-rc-ctrl.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-rc-ctrl.Tpo android/client/$(DEPDIR)/haltest-if-rc-ctrl.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-rc-ctrl.c' object='android/client/haltest-if-rc-ctrl.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-rc-ctrl.obj `if test -f 'android/client/if-rc-ctrl.c'; then $(CYGPATH_W) 'android/client/if-rc-ctrl.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-rc-ctrl.c'; fi` + +android/client/haltest-if-bt.o: android/client/if-bt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-bt.o -MD -MP -MF android/client/$(DEPDIR)/haltest-if-bt.Tpo -c -o android/client/haltest-if-bt.o `test -f 'android/client/if-bt.c' || echo '$(srcdir)/'`android/client/if-bt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-bt.Tpo android/client/$(DEPDIR)/haltest-if-bt.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-bt.c' object='android/client/haltest-if-bt.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-bt.o `test -f 'android/client/if-bt.c' || echo '$(srcdir)/'`android/client/if-bt.c + +android/client/haltest-if-bt.obj: android/client/if-bt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-bt.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-if-bt.Tpo -c -o android/client/haltest-if-bt.obj `if test -f 'android/client/if-bt.c'; then $(CYGPATH_W) 'android/client/if-bt.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-bt.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-bt.Tpo android/client/$(DEPDIR)/haltest-if-bt.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-bt.c' object='android/client/haltest-if-bt.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-bt.obj `if test -f 'android/client/if-bt.c'; then $(CYGPATH_W) 'android/client/if-bt.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-bt.c'; fi` + +android/client/haltest-if-gatt.o: android/client/if-gatt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-gatt.o -MD -MP -MF android/client/$(DEPDIR)/haltest-if-gatt.Tpo -c -o android/client/haltest-if-gatt.o `test -f 'android/client/if-gatt.c' || echo '$(srcdir)/'`android/client/if-gatt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-gatt.Tpo android/client/$(DEPDIR)/haltest-if-gatt.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-gatt.c' object='android/client/haltest-if-gatt.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-gatt.o `test -f 'android/client/if-gatt.c' || echo '$(srcdir)/'`android/client/if-gatt.c + +android/client/haltest-if-gatt.obj: android/client/if-gatt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-gatt.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-if-gatt.Tpo -c -o android/client/haltest-if-gatt.obj `if test -f 'android/client/if-gatt.c'; then $(CYGPATH_W) 'android/client/if-gatt.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-gatt.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-gatt.Tpo android/client/$(DEPDIR)/haltest-if-gatt.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-gatt.c' object='android/client/haltest-if-gatt.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-gatt.obj `if test -f 'android/client/if-gatt.c'; then $(CYGPATH_W) 'android/client/if-gatt.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-gatt.c'; fi` + +android/client/haltest-if-hf.o: android/client/if-hf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-hf.o -MD -MP -MF android/client/$(DEPDIR)/haltest-if-hf.Tpo -c -o android/client/haltest-if-hf.o `test -f 'android/client/if-hf.c' || echo '$(srcdir)/'`android/client/if-hf.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-hf.Tpo android/client/$(DEPDIR)/haltest-if-hf.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-hf.c' object='android/client/haltest-if-hf.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-hf.o `test -f 'android/client/if-hf.c' || echo '$(srcdir)/'`android/client/if-hf.c + +android/client/haltest-if-hf.obj: android/client/if-hf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-hf.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-if-hf.Tpo -c -o android/client/haltest-if-hf.obj `if test -f 'android/client/if-hf.c'; then $(CYGPATH_W) 'android/client/if-hf.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-hf.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-hf.Tpo android/client/$(DEPDIR)/haltest-if-hf.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-hf.c' object='android/client/haltest-if-hf.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-hf.obj `if test -f 'android/client/if-hf.c'; then $(CYGPATH_W) 'android/client/if-hf.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-hf.c'; fi` + +android/client/haltest-if-hf-client.o: android/client/if-hf-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-hf-client.o -MD -MP -MF android/client/$(DEPDIR)/haltest-if-hf-client.Tpo -c -o android/client/haltest-if-hf-client.o `test -f 'android/client/if-hf-client.c' || echo '$(srcdir)/'`android/client/if-hf-client.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-hf-client.Tpo android/client/$(DEPDIR)/haltest-if-hf-client.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-hf-client.c' object='android/client/haltest-if-hf-client.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-hf-client.o `test -f 'android/client/if-hf-client.c' || echo '$(srcdir)/'`android/client/if-hf-client.c + +android/client/haltest-if-hf-client.obj: android/client/if-hf-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-hf-client.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-if-hf-client.Tpo -c -o android/client/haltest-if-hf-client.obj `if test -f 'android/client/if-hf-client.c'; then $(CYGPATH_W) 'android/client/if-hf-client.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-hf-client.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-hf-client.Tpo android/client/$(DEPDIR)/haltest-if-hf-client.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-hf-client.c' object='android/client/haltest-if-hf-client.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-hf-client.obj `if test -f 'android/client/if-hf-client.c'; then $(CYGPATH_W) 'android/client/if-hf-client.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-hf-client.c'; fi` + +android/client/haltest-if-hh.o: android/client/if-hh.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-hh.o -MD -MP -MF android/client/$(DEPDIR)/haltest-if-hh.Tpo -c -o android/client/haltest-if-hh.o `test -f 'android/client/if-hh.c' || echo '$(srcdir)/'`android/client/if-hh.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-hh.Tpo android/client/$(DEPDIR)/haltest-if-hh.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-hh.c' object='android/client/haltest-if-hh.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-hh.o `test -f 'android/client/if-hh.c' || echo '$(srcdir)/'`android/client/if-hh.c + +android/client/haltest-if-hh.obj: android/client/if-hh.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-hh.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-if-hh.Tpo -c -o android/client/haltest-if-hh.obj `if test -f 'android/client/if-hh.c'; then $(CYGPATH_W) 'android/client/if-hh.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-hh.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-hh.Tpo android/client/$(DEPDIR)/haltest-if-hh.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-hh.c' object='android/client/haltest-if-hh.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-hh.obj `if test -f 'android/client/if-hh.c'; then $(CYGPATH_W) 'android/client/if-hh.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-hh.c'; fi` + +android/client/haltest-if-pan.o: android/client/if-pan.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-pan.o -MD -MP -MF android/client/$(DEPDIR)/haltest-if-pan.Tpo -c -o android/client/haltest-if-pan.o `test -f 'android/client/if-pan.c' || echo '$(srcdir)/'`android/client/if-pan.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-pan.Tpo android/client/$(DEPDIR)/haltest-if-pan.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-pan.c' object='android/client/haltest-if-pan.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-pan.o `test -f 'android/client/if-pan.c' || echo '$(srcdir)/'`android/client/if-pan.c + +android/client/haltest-if-pan.obj: android/client/if-pan.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-pan.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-if-pan.Tpo -c -o android/client/haltest-if-pan.obj `if test -f 'android/client/if-pan.c'; then $(CYGPATH_W) 'android/client/if-pan.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-pan.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-pan.Tpo android/client/$(DEPDIR)/haltest-if-pan.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-pan.c' object='android/client/haltest-if-pan.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-pan.obj `if test -f 'android/client/if-pan.c'; then $(CYGPATH_W) 'android/client/if-pan.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-pan.c'; fi` + +android/client/haltest-if-hl.o: android/client/if-hl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-hl.o -MD -MP -MF android/client/$(DEPDIR)/haltest-if-hl.Tpo -c -o android/client/haltest-if-hl.o `test -f 'android/client/if-hl.c' || echo '$(srcdir)/'`android/client/if-hl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-hl.Tpo android/client/$(DEPDIR)/haltest-if-hl.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-hl.c' object='android/client/haltest-if-hl.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-hl.o `test -f 'android/client/if-hl.c' || echo '$(srcdir)/'`android/client/if-hl.c + +android/client/haltest-if-hl.obj: android/client/if-hl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-hl.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-if-hl.Tpo -c -o android/client/haltest-if-hl.obj `if test -f 'android/client/if-hl.c'; then $(CYGPATH_W) 'android/client/if-hl.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-hl.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-hl.Tpo android/client/$(DEPDIR)/haltest-if-hl.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-hl.c' object='android/client/haltest-if-hl.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-hl.obj `if test -f 'android/client/if-hl.c'; then $(CYGPATH_W) 'android/client/if-hl.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-hl.c'; fi` + +android/client/haltest-if-sock.o: android/client/if-sock.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-sock.o -MD -MP -MF android/client/$(DEPDIR)/haltest-if-sock.Tpo -c -o android/client/haltest-if-sock.o `test -f 'android/client/if-sock.c' || echo '$(srcdir)/'`android/client/if-sock.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-sock.Tpo android/client/$(DEPDIR)/haltest-if-sock.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-sock.c' object='android/client/haltest-if-sock.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-sock.o `test -f 'android/client/if-sock.c' || echo '$(srcdir)/'`android/client/if-sock.c + +android/client/haltest-if-sock.obj: android/client/if-sock.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-sock.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-if-sock.Tpo -c -o android/client/haltest-if-sock.obj `if test -f 'android/client/if-sock.c'; then $(CYGPATH_W) 'android/client/if-sock.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-sock.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-sock.Tpo android/client/$(DEPDIR)/haltest-if-sock.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-sock.c' object='android/client/haltest-if-sock.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-sock.obj `if test -f 'android/client/if-sock.c'; then $(CYGPATH_W) 'android/client/if-sock.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-sock.c'; fi` + +android/client/haltest-if-audio.o: android/client/if-audio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-audio.o -MD -MP -MF android/client/$(DEPDIR)/haltest-if-audio.Tpo -c -o android/client/haltest-if-audio.o `test -f 'android/client/if-audio.c' || echo '$(srcdir)/'`android/client/if-audio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-audio.Tpo android/client/$(DEPDIR)/haltest-if-audio.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-audio.c' object='android/client/haltest-if-audio.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-audio.o `test -f 'android/client/if-audio.c' || echo '$(srcdir)/'`android/client/if-audio.c + +android/client/haltest-if-audio.obj: android/client/if-audio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-audio.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-if-audio.Tpo -c -o android/client/haltest-if-audio.obj `if test -f 'android/client/if-audio.c'; then $(CYGPATH_W) 'android/client/if-audio.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-audio.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-audio.Tpo android/client/$(DEPDIR)/haltest-if-audio.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-audio.c' object='android/client/haltest-if-audio.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-audio.obj `if test -f 'android/client/if-audio.c'; then $(CYGPATH_W) 'android/client/if-audio.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-audio.c'; fi` + +android/client/haltest-if-sco.o: android/client/if-sco.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-sco.o -MD -MP -MF android/client/$(DEPDIR)/haltest-if-sco.Tpo -c -o android/client/haltest-if-sco.o `test -f 'android/client/if-sco.c' || echo '$(srcdir)/'`android/client/if-sco.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-sco.Tpo android/client/$(DEPDIR)/haltest-if-sco.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-sco.c' object='android/client/haltest-if-sco.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-sco.o `test -f 'android/client/if-sco.c' || echo '$(srcdir)/'`android/client/if-sco.c + +android/client/haltest-if-sco.obj: android/client/if-sco.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-sco.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-if-sco.Tpo -c -o android/client/haltest-if-sco.obj `if test -f 'android/client/if-sco.c'; then $(CYGPATH_W) 'android/client/if-sco.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-sco.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-sco.Tpo android/client/$(DEPDIR)/haltest-if-sco.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-sco.c' object='android/client/haltest-if-sco.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-sco.obj `if test -f 'android/client/if-sco.c'; then $(CYGPATH_W) 'android/client/if-sco.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-sco.c'; fi` + +android/client/haltest-if-mce.o: android/client/if-mce.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-mce.o -MD -MP -MF android/client/$(DEPDIR)/haltest-if-mce.Tpo -c -o android/client/haltest-if-mce.o `test -f 'android/client/if-mce.c' || echo '$(srcdir)/'`android/client/if-mce.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-mce.Tpo android/client/$(DEPDIR)/haltest-if-mce.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-mce.c' object='android/client/haltest-if-mce.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-mce.o `test -f 'android/client/if-mce.c' || echo '$(srcdir)/'`android/client/if-mce.c + +android/client/haltest-if-mce.obj: android/client/if-mce.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/client/haltest-if-mce.obj -MD -MP -MF android/client/$(DEPDIR)/haltest-if-mce.Tpo -c -o android/client/haltest-if-mce.obj `if test -f 'android/client/if-mce.c'; then $(CYGPATH_W) 'android/client/if-mce.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-mce.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/client/$(DEPDIR)/haltest-if-mce.Tpo android/client/$(DEPDIR)/haltest-if-mce.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/client/if-mce.c' object='android/client/haltest-if-mce.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/client/haltest-if-mce.obj `if test -f 'android/client/if-mce.c'; then $(CYGPATH_W) 'android/client/if-mce.c'; else $(CYGPATH_W) '$(srcdir)/android/client/if-mce.c'; fi` + +android/hardware/haltest-hardware.o: android/hardware/hardware.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/hardware/haltest-hardware.o -MD -MP -MF android/hardware/$(DEPDIR)/haltest-hardware.Tpo -c -o android/hardware/haltest-hardware.o `test -f 'android/hardware/hardware.c' || echo '$(srcdir)/'`android/hardware/hardware.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/hardware/$(DEPDIR)/haltest-hardware.Tpo android/hardware/$(DEPDIR)/haltest-hardware.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hardware/hardware.c' object='android/hardware/haltest-hardware.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/hardware/haltest-hardware.o `test -f 'android/hardware/hardware.c' || echo '$(srcdir)/'`android/hardware/hardware.c + +android/hardware/haltest-hardware.obj: android/hardware/hardware.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/hardware/haltest-hardware.obj -MD -MP -MF android/hardware/$(DEPDIR)/haltest-hardware.Tpo -c -o android/hardware/haltest-hardware.obj `if test -f 'android/hardware/hardware.c'; then $(CYGPATH_W) 'android/hardware/hardware.c'; else $(CYGPATH_W) '$(srcdir)/android/hardware/hardware.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/hardware/$(DEPDIR)/haltest-hardware.Tpo android/hardware/$(DEPDIR)/haltest-hardware.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hardware/hardware.c' object='android/hardware/haltest-hardware.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/hardware/haltest-hardware.obj `if test -f 'android/hardware/hardware.c'; then $(CYGPATH_W) 'android/hardware/hardware.c'; else $(CYGPATH_W) '$(srcdir)/android/hardware/hardware.c'; fi` + +android/haltest-hal-utils.o: android/hal-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/haltest-hal-utils.o -MD -MP -MF android/$(DEPDIR)/haltest-hal-utils.Tpo -c -o android/haltest-hal-utils.o `test -f 'android/hal-utils.c' || echo '$(srcdir)/'`android/hal-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/haltest-hal-utils.Tpo android/$(DEPDIR)/haltest-hal-utils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-utils.c' object='android/haltest-hal-utils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/haltest-hal-utils.o `test -f 'android/hal-utils.c' || echo '$(srcdir)/'`android/hal-utils.c + +android/haltest-hal-utils.obj: android/hal-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/haltest-hal-utils.obj -MD -MP -MF android/$(DEPDIR)/haltest-hal-utils.Tpo -c -o android/haltest-hal-utils.obj `if test -f 'android/hal-utils.c'; then $(CYGPATH_W) 'android/hal-utils.c'; else $(CYGPATH_W) '$(srcdir)/android/hal-utils.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/haltest-hal-utils.Tpo android/$(DEPDIR)/haltest-hal-utils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-utils.c' object='android/haltest-hal-utils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_haltest_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/haltest-hal-utils.obj `if test -f 'android/hal-utils.c'; then $(CYGPATH_W) 'android/hal-utils.c'; else $(CYGPATH_W) '$(srcdir)/android/hal-utils.c'; fi` + +emulator/android_ipc_tester-hciemu.o: emulator/hciemu.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_ipc_tester-hciemu.o -MD -MP -MF emulator/$(DEPDIR)/android_ipc_tester-hciemu.Tpo -c -o emulator/android_ipc_tester-hciemu.o `test -f 'emulator/hciemu.c' || echo '$(srcdir)/'`emulator/hciemu.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_ipc_tester-hciemu.Tpo emulator/$(DEPDIR)/android_ipc_tester-hciemu.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/hciemu.c' object='emulator/android_ipc_tester-hciemu.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_ipc_tester-hciemu.o `test -f 'emulator/hciemu.c' || echo '$(srcdir)/'`emulator/hciemu.c + +emulator/android_ipc_tester-hciemu.obj: emulator/hciemu.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_ipc_tester-hciemu.obj -MD -MP -MF emulator/$(DEPDIR)/android_ipc_tester-hciemu.Tpo -c -o emulator/android_ipc_tester-hciemu.obj `if test -f 'emulator/hciemu.c'; then $(CYGPATH_W) 'emulator/hciemu.c'; else $(CYGPATH_W) '$(srcdir)/emulator/hciemu.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_ipc_tester-hciemu.Tpo emulator/$(DEPDIR)/android_ipc_tester-hciemu.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/hciemu.c' object='emulator/android_ipc_tester-hciemu.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_ipc_tester-hciemu.obj `if test -f 'emulator/hciemu.c'; then $(CYGPATH_W) 'emulator/hciemu.c'; else $(CYGPATH_W) '$(srcdir)/emulator/hciemu.c'; fi` + +emulator/android_ipc_tester-vhci.o: emulator/vhci.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_ipc_tester-vhci.o -MD -MP -MF emulator/$(DEPDIR)/android_ipc_tester-vhci.Tpo -c -o emulator/android_ipc_tester-vhci.o `test -f 'emulator/vhci.c' || echo '$(srcdir)/'`emulator/vhci.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_ipc_tester-vhci.Tpo emulator/$(DEPDIR)/android_ipc_tester-vhci.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/vhci.c' object='emulator/android_ipc_tester-vhci.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_ipc_tester-vhci.o `test -f 'emulator/vhci.c' || echo '$(srcdir)/'`emulator/vhci.c + +emulator/android_ipc_tester-vhci.obj: emulator/vhci.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_ipc_tester-vhci.obj -MD -MP -MF emulator/$(DEPDIR)/android_ipc_tester-vhci.Tpo -c -o emulator/android_ipc_tester-vhci.obj `if test -f 'emulator/vhci.c'; then $(CYGPATH_W) 'emulator/vhci.c'; else $(CYGPATH_W) '$(srcdir)/emulator/vhci.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_ipc_tester-vhci.Tpo emulator/$(DEPDIR)/android_ipc_tester-vhci.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/vhci.c' object='emulator/android_ipc_tester-vhci.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_ipc_tester-vhci.obj `if test -f 'emulator/vhci.c'; then $(CYGPATH_W) 'emulator/vhci.c'; else $(CYGPATH_W) '$(srcdir)/emulator/vhci.c'; fi` + +emulator/android_ipc_tester-btdev.o: emulator/btdev.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_ipc_tester-btdev.o -MD -MP -MF emulator/$(DEPDIR)/android_ipc_tester-btdev.Tpo -c -o emulator/android_ipc_tester-btdev.o `test -f 'emulator/btdev.c' || echo '$(srcdir)/'`emulator/btdev.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_ipc_tester-btdev.Tpo emulator/$(DEPDIR)/android_ipc_tester-btdev.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/btdev.c' object='emulator/android_ipc_tester-btdev.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_ipc_tester-btdev.o `test -f 'emulator/btdev.c' || echo '$(srcdir)/'`emulator/btdev.c + +emulator/android_ipc_tester-btdev.obj: emulator/btdev.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_ipc_tester-btdev.obj -MD -MP -MF emulator/$(DEPDIR)/android_ipc_tester-btdev.Tpo -c -o emulator/android_ipc_tester-btdev.obj `if test -f 'emulator/btdev.c'; then $(CYGPATH_W) 'emulator/btdev.c'; else $(CYGPATH_W) '$(srcdir)/emulator/btdev.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_ipc_tester-btdev.Tpo emulator/$(DEPDIR)/android_ipc_tester-btdev.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/btdev.c' object='emulator/android_ipc_tester-btdev.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_ipc_tester-btdev.obj `if test -f 'emulator/btdev.c'; then $(CYGPATH_W) 'emulator/btdev.c'; else $(CYGPATH_W) '$(srcdir)/emulator/btdev.c'; fi` + +emulator/android_ipc_tester-bthost.o: emulator/bthost.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_ipc_tester-bthost.o -MD -MP -MF emulator/$(DEPDIR)/android_ipc_tester-bthost.Tpo -c -o emulator/android_ipc_tester-bthost.o `test -f 'emulator/bthost.c' || echo '$(srcdir)/'`emulator/bthost.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_ipc_tester-bthost.Tpo emulator/$(DEPDIR)/android_ipc_tester-bthost.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/bthost.c' object='emulator/android_ipc_tester-bthost.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_ipc_tester-bthost.o `test -f 'emulator/bthost.c' || echo '$(srcdir)/'`emulator/bthost.c + +emulator/android_ipc_tester-bthost.obj: emulator/bthost.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_ipc_tester-bthost.obj -MD -MP -MF emulator/$(DEPDIR)/android_ipc_tester-bthost.Tpo -c -o emulator/android_ipc_tester-bthost.obj `if test -f 'emulator/bthost.c'; then $(CYGPATH_W) 'emulator/bthost.c'; else $(CYGPATH_W) '$(srcdir)/emulator/bthost.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_ipc_tester-bthost.Tpo emulator/$(DEPDIR)/android_ipc_tester-bthost.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/bthost.c' object='emulator/android_ipc_tester-bthost.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_ipc_tester-bthost.obj `if test -f 'emulator/bthost.c'; then $(CYGPATH_W) 'emulator/bthost.c'; else $(CYGPATH_W) '$(srcdir)/emulator/bthost.c'; fi` + +emulator/android_ipc_tester-smp.o: emulator/smp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_ipc_tester-smp.o -MD -MP -MF emulator/$(DEPDIR)/android_ipc_tester-smp.Tpo -c -o emulator/android_ipc_tester-smp.o `test -f 'emulator/smp.c' || echo '$(srcdir)/'`emulator/smp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_ipc_tester-smp.Tpo emulator/$(DEPDIR)/android_ipc_tester-smp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/smp.c' object='emulator/android_ipc_tester-smp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_ipc_tester-smp.o `test -f 'emulator/smp.c' || echo '$(srcdir)/'`emulator/smp.c + +emulator/android_ipc_tester-smp.obj: emulator/smp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT emulator/android_ipc_tester-smp.obj -MD -MP -MF emulator/$(DEPDIR)/android_ipc_tester-smp.Tpo -c -o emulator/android_ipc_tester-smp.obj `if test -f 'emulator/smp.c'; then $(CYGPATH_W) 'emulator/smp.c'; else $(CYGPATH_W) '$(srcdir)/emulator/smp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) emulator/$(DEPDIR)/android_ipc_tester-smp.Tpo emulator/$(DEPDIR)/android_ipc_tester-smp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='emulator/smp.c' object='emulator/android_ipc_tester-smp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o emulator/android_ipc_tester-smp.obj `if test -f 'emulator/smp.c'; then $(CYGPATH_W) 'emulator/smp.c'; else $(CYGPATH_W) '$(srcdir)/emulator/smp.c'; fi` + +android/ipc_tester-hal-utils.o: android/hal-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/ipc_tester-hal-utils.o -MD -MP -MF android/$(DEPDIR)/ipc_tester-hal-utils.Tpo -c -o android/ipc_tester-hal-utils.o `test -f 'android/hal-utils.c' || echo '$(srcdir)/'`android/hal-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/ipc_tester-hal-utils.Tpo android/$(DEPDIR)/ipc_tester-hal-utils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-utils.c' object='android/ipc_tester-hal-utils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/ipc_tester-hal-utils.o `test -f 'android/hal-utils.c' || echo '$(srcdir)/'`android/hal-utils.c + +android/ipc_tester-hal-utils.obj: android/hal-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/ipc_tester-hal-utils.obj -MD -MP -MF android/$(DEPDIR)/ipc_tester-hal-utils.Tpo -c -o android/ipc_tester-hal-utils.obj `if test -f 'android/hal-utils.c'; then $(CYGPATH_W) 'android/hal-utils.c'; else $(CYGPATH_W) '$(srcdir)/android/hal-utils.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/ipc_tester-hal-utils.Tpo android/$(DEPDIR)/ipc_tester-hal-utils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/hal-utils.c' object='android/ipc_tester-hal-utils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/ipc_tester-hal-utils.obj `if test -f 'android/hal-utils.c'; then $(CYGPATH_W) 'android/hal-utils.c'; else $(CYGPATH_W) '$(srcdir)/android/hal-utils.c'; fi` + +android/ipc_tester-ipc-tester.o: android/ipc-tester.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/ipc_tester-ipc-tester.o -MD -MP -MF android/$(DEPDIR)/ipc_tester-ipc-tester.Tpo -c -o android/ipc_tester-ipc-tester.o `test -f 'android/ipc-tester.c' || echo '$(srcdir)/'`android/ipc-tester.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/ipc_tester-ipc-tester.Tpo android/$(DEPDIR)/ipc_tester-ipc-tester.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/ipc-tester.c' object='android/ipc_tester-ipc-tester.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/ipc_tester-ipc-tester.o `test -f 'android/ipc-tester.c' || echo '$(srcdir)/'`android/ipc-tester.c + +android/ipc_tester-ipc-tester.obj: android/ipc-tester.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT android/ipc_tester-ipc-tester.obj -MD -MP -MF android/$(DEPDIR)/ipc_tester-ipc-tester.Tpo -c -o android/ipc_tester-ipc-tester.obj `if test -f 'android/ipc-tester.c'; then $(CYGPATH_W) 'android/ipc-tester.c'; else $(CYGPATH_W) '$(srcdir)/android/ipc-tester.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) android/$(DEPDIR)/ipc_tester-ipc-tester.Tpo android/$(DEPDIR)/ipc_tester-ipc-tester.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='android/ipc-tester.c' object='android/ipc_tester-ipc-tester.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(android_ipc_tester_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o android/ipc_tester-ipc-tester.obj `if test -f 'android/ipc-tester.c'; then $(CYGPATH_W) 'android/ipc-tester.c'; else $(CYGPATH_W) '$(srcdir)/android/ipc-tester.c'; fi` + +btio/obexd-btio.o: btio/btio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT btio/obexd-btio.o -MD -MP -MF btio/$(DEPDIR)/obexd-btio.Tpo -c -o btio/obexd-btio.o `test -f 'btio/btio.c' || echo '$(srcdir)/'`btio/btio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btio/$(DEPDIR)/obexd-btio.Tpo btio/$(DEPDIR)/obexd-btio.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btio/btio.c' object='btio/obexd-btio.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o btio/obexd-btio.o `test -f 'btio/btio.c' || echo '$(srcdir)/'`btio/btio.c + +btio/obexd-btio.obj: btio/btio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT btio/obexd-btio.obj -MD -MP -MF btio/$(DEPDIR)/obexd-btio.Tpo -c -o btio/obexd-btio.obj `if test -f 'btio/btio.c'; then $(CYGPATH_W) 'btio/btio.c'; else $(CYGPATH_W) '$(srcdir)/btio/btio.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btio/$(DEPDIR)/obexd-btio.Tpo btio/$(DEPDIR)/obexd-btio.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btio/btio.c' object='btio/obexd-btio.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o btio/obexd-btio.obj `if test -f 'btio/btio.c'; then $(CYGPATH_W) 'btio/btio.c'; else $(CYGPATH_W) '$(srcdir)/btio/btio.c'; fi` + +gobex/obexd-gobex.o: gobex/gobex.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex.o -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex.Tpo -c -o gobex/obexd-gobex.o `test -f 'gobex/gobex.c' || echo '$(srcdir)/'`gobex/gobex.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex.Tpo gobex/$(DEPDIR)/obexd-gobex.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gobex/gobex.c' object='gobex/obexd-gobex.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex.o `test -f 'gobex/gobex.c' || echo '$(srcdir)/'`gobex/gobex.c + +gobex/obexd-gobex.obj: gobex/gobex.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex.obj -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex.Tpo -c -o gobex/obexd-gobex.obj `if test -f 'gobex/gobex.c'; then $(CYGPATH_W) 'gobex/gobex.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex.Tpo gobex/$(DEPDIR)/obexd-gobex.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gobex/gobex.c' object='gobex/obexd-gobex.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex.obj `if test -f 'gobex/gobex.c'; then $(CYGPATH_W) 'gobex/gobex.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex.c'; fi` + +gobex/obexd-gobex-defs.o: gobex/gobex-defs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-defs.o -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-defs.Tpo -c -o gobex/obexd-gobex-defs.o `test -f 'gobex/gobex-defs.c' || echo '$(srcdir)/'`gobex/gobex-defs.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-defs.Tpo gobex/$(DEPDIR)/obexd-gobex-defs.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gobex/gobex-defs.c' object='gobex/obexd-gobex-defs.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-defs.o `test -f 'gobex/gobex-defs.c' || echo '$(srcdir)/'`gobex/gobex-defs.c + +gobex/obexd-gobex-defs.obj: gobex/gobex-defs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-defs.obj -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-defs.Tpo -c -o gobex/obexd-gobex-defs.obj `if test -f 'gobex/gobex-defs.c'; then $(CYGPATH_W) 'gobex/gobex-defs.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-defs.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-defs.Tpo gobex/$(DEPDIR)/obexd-gobex-defs.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gobex/gobex-defs.c' object='gobex/obexd-gobex-defs.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-defs.obj `if test -f 'gobex/gobex-defs.c'; then $(CYGPATH_W) 'gobex/gobex-defs.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-defs.c'; fi` + +gobex/obexd-gobex-packet.o: gobex/gobex-packet.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-packet.o -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-packet.Tpo -c -o gobex/obexd-gobex-packet.o `test -f 'gobex/gobex-packet.c' || echo '$(srcdir)/'`gobex/gobex-packet.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-packet.Tpo gobex/$(DEPDIR)/obexd-gobex-packet.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gobex/gobex-packet.c' object='gobex/obexd-gobex-packet.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-packet.o `test -f 'gobex/gobex-packet.c' || echo '$(srcdir)/'`gobex/gobex-packet.c + +gobex/obexd-gobex-packet.obj: gobex/gobex-packet.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-packet.obj -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-packet.Tpo -c -o gobex/obexd-gobex-packet.obj `if test -f 'gobex/gobex-packet.c'; then $(CYGPATH_W) 'gobex/gobex-packet.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-packet.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-packet.Tpo gobex/$(DEPDIR)/obexd-gobex-packet.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gobex/gobex-packet.c' object='gobex/obexd-gobex-packet.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-packet.obj `if test -f 'gobex/gobex-packet.c'; then $(CYGPATH_W) 'gobex/gobex-packet.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-packet.c'; fi` + +gobex/obexd-gobex-header.o: gobex/gobex-header.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-header.o -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-header.Tpo -c -o gobex/obexd-gobex-header.o `test -f 'gobex/gobex-header.c' || echo '$(srcdir)/'`gobex/gobex-header.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-header.Tpo gobex/$(DEPDIR)/obexd-gobex-header.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gobex/gobex-header.c' object='gobex/obexd-gobex-header.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-header.o `test -f 'gobex/gobex-header.c' || echo '$(srcdir)/'`gobex/gobex-header.c + +gobex/obexd-gobex-header.obj: gobex/gobex-header.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-header.obj -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-header.Tpo -c -o gobex/obexd-gobex-header.obj `if test -f 'gobex/gobex-header.c'; then $(CYGPATH_W) 'gobex/gobex-header.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-header.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-header.Tpo gobex/$(DEPDIR)/obexd-gobex-header.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gobex/gobex-header.c' object='gobex/obexd-gobex-header.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-header.obj `if test -f 'gobex/gobex-header.c'; then $(CYGPATH_W) 'gobex/gobex-header.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-header.c'; fi` + +gobex/obexd-gobex-transfer.o: gobex/gobex-transfer.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-transfer.o -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-transfer.Tpo -c -o gobex/obexd-gobex-transfer.o `test -f 'gobex/gobex-transfer.c' || echo '$(srcdir)/'`gobex/gobex-transfer.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-transfer.Tpo gobex/$(DEPDIR)/obexd-gobex-transfer.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gobex/gobex-transfer.c' object='gobex/obexd-gobex-transfer.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-transfer.o `test -f 'gobex/gobex-transfer.c' || echo '$(srcdir)/'`gobex/gobex-transfer.c + +gobex/obexd-gobex-transfer.obj: gobex/gobex-transfer.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-transfer.obj -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-transfer.Tpo -c -o gobex/obexd-gobex-transfer.obj `if test -f 'gobex/gobex-transfer.c'; then $(CYGPATH_W) 'gobex/gobex-transfer.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-transfer.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-transfer.Tpo gobex/$(DEPDIR)/obexd-gobex-transfer.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gobex/gobex-transfer.c' object='gobex/obexd-gobex-transfer.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-transfer.obj `if test -f 'gobex/gobex-transfer.c'; then $(CYGPATH_W) 'gobex/gobex-transfer.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-transfer.c'; fi` + +gobex/obexd-gobex-apparam.o: gobex/gobex-apparam.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-apparam.o -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-apparam.Tpo -c -o gobex/obexd-gobex-apparam.o `test -f 'gobex/gobex-apparam.c' || echo '$(srcdir)/'`gobex/gobex-apparam.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-apparam.Tpo gobex/$(DEPDIR)/obexd-gobex-apparam.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gobex/gobex-apparam.c' object='gobex/obexd-gobex-apparam.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-apparam.o `test -f 'gobex/gobex-apparam.c' || echo '$(srcdir)/'`gobex/gobex-apparam.c + +gobex/obexd-gobex-apparam.obj: gobex/gobex-apparam.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-apparam.obj -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-apparam.Tpo -c -o gobex/obexd-gobex-apparam.obj `if test -f 'gobex/gobex-apparam.c'; then $(CYGPATH_W) 'gobex/gobex-apparam.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-apparam.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-apparam.Tpo gobex/$(DEPDIR)/obexd-gobex-apparam.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gobex/gobex-apparam.c' object='gobex/obexd-gobex-apparam.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-apparam.obj `if test -f 'gobex/gobex-apparam.c'; then $(CYGPATH_W) 'gobex/gobex-apparam.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-apparam.c'; fi` + +obexd/plugins/obexd-filesystem.o: obexd/plugins/filesystem.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-filesystem.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-filesystem.Tpo -c -o obexd/plugins/obexd-filesystem.o `test -f 'obexd/plugins/filesystem.c' || echo '$(srcdir)/'`obexd/plugins/filesystem.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-filesystem.Tpo obexd/plugins/$(DEPDIR)/obexd-filesystem.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/filesystem.c' object='obexd/plugins/obexd-filesystem.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-filesystem.o `test -f 'obexd/plugins/filesystem.c' || echo '$(srcdir)/'`obexd/plugins/filesystem.c + +obexd/plugins/obexd-filesystem.obj: obexd/plugins/filesystem.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-filesystem.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-filesystem.Tpo -c -o obexd/plugins/obexd-filesystem.obj `if test -f 'obexd/plugins/filesystem.c'; then $(CYGPATH_W) 'obexd/plugins/filesystem.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/filesystem.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-filesystem.Tpo obexd/plugins/$(DEPDIR)/obexd-filesystem.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/filesystem.c' object='obexd/plugins/obexd-filesystem.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-filesystem.obj `if test -f 'obexd/plugins/filesystem.c'; then $(CYGPATH_W) 'obexd/plugins/filesystem.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/filesystem.c'; fi` + +obexd/plugins/obexd-bluetooth.o: obexd/plugins/bluetooth.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-bluetooth.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-bluetooth.Tpo -c -o obexd/plugins/obexd-bluetooth.o `test -f 'obexd/plugins/bluetooth.c' || echo '$(srcdir)/'`obexd/plugins/bluetooth.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-bluetooth.Tpo obexd/plugins/$(DEPDIR)/obexd-bluetooth.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/bluetooth.c' object='obexd/plugins/obexd-bluetooth.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-bluetooth.o `test -f 'obexd/plugins/bluetooth.c' || echo '$(srcdir)/'`obexd/plugins/bluetooth.c + +obexd/plugins/obexd-bluetooth.obj: obexd/plugins/bluetooth.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-bluetooth.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-bluetooth.Tpo -c -o obexd/plugins/obexd-bluetooth.obj `if test -f 'obexd/plugins/bluetooth.c'; then $(CYGPATH_W) 'obexd/plugins/bluetooth.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/bluetooth.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-bluetooth.Tpo obexd/plugins/$(DEPDIR)/obexd-bluetooth.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/bluetooth.c' object='obexd/plugins/obexd-bluetooth.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-bluetooth.obj `if test -f 'obexd/plugins/bluetooth.c'; then $(CYGPATH_W) 'obexd/plugins/bluetooth.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/bluetooth.c'; fi` + +obexd/plugins/obexd-pcsuite.o: obexd/plugins/pcsuite.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-pcsuite.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-pcsuite.Tpo -c -o obexd/plugins/obexd-pcsuite.o `test -f 'obexd/plugins/pcsuite.c' || echo '$(srcdir)/'`obexd/plugins/pcsuite.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-pcsuite.Tpo obexd/plugins/$(DEPDIR)/obexd-pcsuite.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/pcsuite.c' object='obexd/plugins/obexd-pcsuite.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-pcsuite.o `test -f 'obexd/plugins/pcsuite.c' || echo '$(srcdir)/'`obexd/plugins/pcsuite.c + +obexd/plugins/obexd-pcsuite.obj: obexd/plugins/pcsuite.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-pcsuite.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-pcsuite.Tpo -c -o obexd/plugins/obexd-pcsuite.obj `if test -f 'obexd/plugins/pcsuite.c'; then $(CYGPATH_W) 'obexd/plugins/pcsuite.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/pcsuite.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-pcsuite.Tpo obexd/plugins/$(DEPDIR)/obexd-pcsuite.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/pcsuite.c' object='obexd/plugins/obexd-pcsuite.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-pcsuite.obj `if test -f 'obexd/plugins/pcsuite.c'; then $(CYGPATH_W) 'obexd/plugins/pcsuite.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/pcsuite.c'; fi` + +obexd/plugins/obexd-opp.o: obexd/plugins/opp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-opp.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-opp.Tpo -c -o obexd/plugins/obexd-opp.o `test -f 'obexd/plugins/opp.c' || echo '$(srcdir)/'`obexd/plugins/opp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-opp.Tpo obexd/plugins/$(DEPDIR)/obexd-opp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/opp.c' object='obexd/plugins/obexd-opp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-opp.o `test -f 'obexd/plugins/opp.c' || echo '$(srcdir)/'`obexd/plugins/opp.c + +obexd/plugins/obexd-opp.obj: obexd/plugins/opp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-opp.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-opp.Tpo -c -o obexd/plugins/obexd-opp.obj `if test -f 'obexd/plugins/opp.c'; then $(CYGPATH_W) 'obexd/plugins/opp.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/opp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-opp.Tpo obexd/plugins/$(DEPDIR)/obexd-opp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/opp.c' object='obexd/plugins/obexd-opp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-opp.obj `if test -f 'obexd/plugins/opp.c'; then $(CYGPATH_W) 'obexd/plugins/opp.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/opp.c'; fi` + +obexd/plugins/obexd-ftp.o: obexd/plugins/ftp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-ftp.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-ftp.Tpo -c -o obexd/plugins/obexd-ftp.o `test -f 'obexd/plugins/ftp.c' || echo '$(srcdir)/'`obexd/plugins/ftp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-ftp.Tpo obexd/plugins/$(DEPDIR)/obexd-ftp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/ftp.c' object='obexd/plugins/obexd-ftp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-ftp.o `test -f 'obexd/plugins/ftp.c' || echo '$(srcdir)/'`obexd/plugins/ftp.c + +obexd/plugins/obexd-ftp.obj: obexd/plugins/ftp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-ftp.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-ftp.Tpo -c -o obexd/plugins/obexd-ftp.obj `if test -f 'obexd/plugins/ftp.c'; then $(CYGPATH_W) 'obexd/plugins/ftp.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/ftp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-ftp.Tpo obexd/plugins/$(DEPDIR)/obexd-ftp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/ftp.c' object='obexd/plugins/obexd-ftp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-ftp.obj `if test -f 'obexd/plugins/ftp.c'; then $(CYGPATH_W) 'obexd/plugins/ftp.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/ftp.c'; fi` + +obexd/plugins/obexd-irmc.o: obexd/plugins/irmc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-irmc.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-irmc.Tpo -c -o obexd/plugins/obexd-irmc.o `test -f 'obexd/plugins/irmc.c' || echo '$(srcdir)/'`obexd/plugins/irmc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-irmc.Tpo obexd/plugins/$(DEPDIR)/obexd-irmc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/irmc.c' object='obexd/plugins/obexd-irmc.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-irmc.o `test -f 'obexd/plugins/irmc.c' || echo '$(srcdir)/'`obexd/plugins/irmc.c + +obexd/plugins/obexd-irmc.obj: obexd/plugins/irmc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-irmc.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-irmc.Tpo -c -o obexd/plugins/obexd-irmc.obj `if test -f 'obexd/plugins/irmc.c'; then $(CYGPATH_W) 'obexd/plugins/irmc.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/irmc.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-irmc.Tpo obexd/plugins/$(DEPDIR)/obexd-irmc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/irmc.c' object='obexd/plugins/obexd-irmc.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-irmc.obj `if test -f 'obexd/plugins/irmc.c'; then $(CYGPATH_W) 'obexd/plugins/irmc.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/irmc.c'; fi` + +obexd/plugins/obexd-pbap.o: obexd/plugins/pbap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-pbap.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-pbap.Tpo -c -o obexd/plugins/obexd-pbap.o `test -f 'obexd/plugins/pbap.c' || echo '$(srcdir)/'`obexd/plugins/pbap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-pbap.Tpo obexd/plugins/$(DEPDIR)/obexd-pbap.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/pbap.c' object='obexd/plugins/obexd-pbap.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-pbap.o `test -f 'obexd/plugins/pbap.c' || echo '$(srcdir)/'`obexd/plugins/pbap.c + +obexd/plugins/obexd-pbap.obj: obexd/plugins/pbap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-pbap.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-pbap.Tpo -c -o obexd/plugins/obexd-pbap.obj `if test -f 'obexd/plugins/pbap.c'; then $(CYGPATH_W) 'obexd/plugins/pbap.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/pbap.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-pbap.Tpo obexd/plugins/$(DEPDIR)/obexd-pbap.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/pbap.c' object='obexd/plugins/obexd-pbap.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-pbap.obj `if test -f 'obexd/plugins/pbap.c'; then $(CYGPATH_W) 'obexd/plugins/pbap.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/pbap.c'; fi` + +obexd/plugins/obexd-vcard.o: obexd/plugins/vcard.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-vcard.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-vcard.Tpo -c -o obexd/plugins/obexd-vcard.o `test -f 'obexd/plugins/vcard.c' || echo '$(srcdir)/'`obexd/plugins/vcard.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-vcard.Tpo obexd/plugins/$(DEPDIR)/obexd-vcard.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/vcard.c' object='obexd/plugins/obexd-vcard.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-vcard.o `test -f 'obexd/plugins/vcard.c' || echo '$(srcdir)/'`obexd/plugins/vcard.c + +obexd/plugins/obexd-vcard.obj: obexd/plugins/vcard.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-vcard.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-vcard.Tpo -c -o obexd/plugins/obexd-vcard.obj `if test -f 'obexd/plugins/vcard.c'; then $(CYGPATH_W) 'obexd/plugins/vcard.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/vcard.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-vcard.Tpo obexd/plugins/$(DEPDIR)/obexd-vcard.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/vcard.c' object='obexd/plugins/obexd-vcard.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-vcard.obj `if test -f 'obexd/plugins/vcard.c'; then $(CYGPATH_W) 'obexd/plugins/vcard.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/vcard.c'; fi` + +obexd/plugins/obexd-phonebook-@PLUGIN_PHONEBOOK@.o: obexd/plugins/phonebook-@PLUGIN_PHONEBOOK@.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-phonebook-@PLUGIN_PHONEBOOK@.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-phonebook-@PLUGIN_PHONEBOOK@.Tpo -c -o obexd/plugins/obexd-phonebook-@PLUGIN_PHONEBOOK@.o `test -f 'obexd/plugins/phonebook-@PLUGIN_PHONEBOOK@.c' || echo '$(srcdir)/'`obexd/plugins/phonebook-@PLUGIN_PHONEBOOK@.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-phonebook-@PLUGIN_PHONEBOOK@.Tpo obexd/plugins/$(DEPDIR)/obexd-phonebook-@PLUGIN_PHONEBOOK@.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/phonebook-@PLUGIN_PHONEBOOK@.c' object='obexd/plugins/obexd-phonebook-@PLUGIN_PHONEBOOK@.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-phonebook-@PLUGIN_PHONEBOOK@.o `test -f 'obexd/plugins/phonebook-@PLUGIN_PHONEBOOK@.c' || echo '$(srcdir)/'`obexd/plugins/phonebook-@PLUGIN_PHONEBOOK@.c + +obexd/plugins/obexd-phonebook-@PLUGIN_PHONEBOOK@.obj: obexd/plugins/phonebook-@PLUGIN_PHONEBOOK@.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-phonebook-@PLUGIN_PHONEBOOK@.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-phonebook-@PLUGIN_PHONEBOOK@.Tpo -c -o obexd/plugins/obexd-phonebook-@PLUGIN_PHONEBOOK@.obj `if test -f 'obexd/plugins/phonebook-@PLUGIN_PHONEBOOK@.c'; then $(CYGPATH_W) 'obexd/plugins/phonebook-@PLUGIN_PHONEBOOK@.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/phonebook-@PLUGIN_PHONEBOOK@.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-phonebook-@PLUGIN_PHONEBOOK@.Tpo obexd/plugins/$(DEPDIR)/obexd-phonebook-@PLUGIN_PHONEBOOK@.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/phonebook-@PLUGIN_PHONEBOOK@.c' object='obexd/plugins/obexd-phonebook-@PLUGIN_PHONEBOOK@.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-phonebook-@PLUGIN_PHONEBOOK@.obj `if test -f 'obexd/plugins/phonebook-@PLUGIN_PHONEBOOK@.c'; then $(CYGPATH_W) 'obexd/plugins/phonebook-@PLUGIN_PHONEBOOK@.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/phonebook-@PLUGIN_PHONEBOOK@.c'; fi` + +obexd/plugins/obexd-mas.o: obexd/plugins/mas.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-mas.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-mas.Tpo -c -o obexd/plugins/obexd-mas.o `test -f 'obexd/plugins/mas.c' || echo '$(srcdir)/'`obexd/plugins/mas.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-mas.Tpo obexd/plugins/$(DEPDIR)/obexd-mas.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/mas.c' object='obexd/plugins/obexd-mas.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-mas.o `test -f 'obexd/plugins/mas.c' || echo '$(srcdir)/'`obexd/plugins/mas.c + +obexd/plugins/obexd-mas.obj: obexd/plugins/mas.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-mas.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-mas.Tpo -c -o obexd/plugins/obexd-mas.obj `if test -f 'obexd/plugins/mas.c'; then $(CYGPATH_W) 'obexd/plugins/mas.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/mas.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-mas.Tpo obexd/plugins/$(DEPDIR)/obexd-mas.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/mas.c' object='obexd/plugins/obexd-mas.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-mas.obj `if test -f 'obexd/plugins/mas.c'; then $(CYGPATH_W) 'obexd/plugins/mas.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/mas.c'; fi` + +obexd/plugins/obexd-messages-dummy.o: obexd/plugins/messages-dummy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-messages-dummy.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-messages-dummy.Tpo -c -o obexd/plugins/obexd-messages-dummy.o `test -f 'obexd/plugins/messages-dummy.c' || echo '$(srcdir)/'`obexd/plugins/messages-dummy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-messages-dummy.Tpo obexd/plugins/$(DEPDIR)/obexd-messages-dummy.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/messages-dummy.c' object='obexd/plugins/obexd-messages-dummy.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-messages-dummy.o `test -f 'obexd/plugins/messages-dummy.c' || echo '$(srcdir)/'`obexd/plugins/messages-dummy.c + +obexd/plugins/obexd-messages-dummy.obj: obexd/plugins/messages-dummy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-messages-dummy.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-messages-dummy.Tpo -c -o obexd/plugins/obexd-messages-dummy.obj `if test -f 'obexd/plugins/messages-dummy.c'; then $(CYGPATH_W) 'obexd/plugins/messages-dummy.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/messages-dummy.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-messages-dummy.Tpo obexd/plugins/$(DEPDIR)/obexd-messages-dummy.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/plugins/messages-dummy.c' object='obexd/plugins/obexd-messages-dummy.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-messages-dummy.obj `if test -f 'obexd/plugins/messages-dummy.c'; then $(CYGPATH_W) 'obexd/plugins/messages-dummy.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/messages-dummy.c'; fi` + +obexd/client/obexd-mns.o: obexd/client/mns.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-mns.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-mns.Tpo -c -o obexd/client/obexd-mns.o `test -f 'obexd/client/mns.c' || echo '$(srcdir)/'`obexd/client/mns.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-mns.Tpo obexd/client/$(DEPDIR)/obexd-mns.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/mns.c' object='obexd/client/obexd-mns.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-mns.o `test -f 'obexd/client/mns.c' || echo '$(srcdir)/'`obexd/client/mns.c + +obexd/client/obexd-mns.obj: obexd/client/mns.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-mns.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-mns.Tpo -c -o obexd/client/obexd-mns.obj `if test -f 'obexd/client/mns.c'; then $(CYGPATH_W) 'obexd/client/mns.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/mns.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-mns.Tpo obexd/client/$(DEPDIR)/obexd-mns.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/mns.c' object='obexd/client/obexd-mns.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-mns.obj `if test -f 'obexd/client/mns.c'; then $(CYGPATH_W) 'obexd/client/mns.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/mns.c'; fi` + +obexd/src/obexd-main.o: obexd/src/main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-main.o -MD -MP -MF obexd/src/$(DEPDIR)/obexd-main.Tpo -c -o obexd/src/obexd-main.o `test -f 'obexd/src/main.c' || echo '$(srcdir)/'`obexd/src/main.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-main.Tpo obexd/src/$(DEPDIR)/obexd-main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/src/main.c' object='obexd/src/obexd-main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-main.o `test -f 'obexd/src/main.c' || echo '$(srcdir)/'`obexd/src/main.c + +obexd/src/obexd-main.obj: obexd/src/main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-main.obj -MD -MP -MF obexd/src/$(DEPDIR)/obexd-main.Tpo -c -o obexd/src/obexd-main.obj `if test -f 'obexd/src/main.c'; then $(CYGPATH_W) 'obexd/src/main.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/main.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-main.Tpo obexd/src/$(DEPDIR)/obexd-main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/src/main.c' object='obexd/src/obexd-main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-main.obj `if test -f 'obexd/src/main.c'; then $(CYGPATH_W) 'obexd/src/main.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/main.c'; fi` + +obexd/src/obexd-plugin.o: obexd/src/plugin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-plugin.o -MD -MP -MF obexd/src/$(DEPDIR)/obexd-plugin.Tpo -c -o obexd/src/obexd-plugin.o `test -f 'obexd/src/plugin.c' || echo '$(srcdir)/'`obexd/src/plugin.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-plugin.Tpo obexd/src/$(DEPDIR)/obexd-plugin.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/src/plugin.c' object='obexd/src/obexd-plugin.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-plugin.o `test -f 'obexd/src/plugin.c' || echo '$(srcdir)/'`obexd/src/plugin.c + +obexd/src/obexd-plugin.obj: obexd/src/plugin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-plugin.obj -MD -MP -MF obexd/src/$(DEPDIR)/obexd-plugin.Tpo -c -o obexd/src/obexd-plugin.obj `if test -f 'obexd/src/plugin.c'; then $(CYGPATH_W) 'obexd/src/plugin.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/plugin.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-plugin.Tpo obexd/src/$(DEPDIR)/obexd-plugin.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/src/plugin.c' object='obexd/src/obexd-plugin.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-plugin.obj `if test -f 'obexd/src/plugin.c'; then $(CYGPATH_W) 'obexd/src/plugin.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/plugin.c'; fi` + +obexd/src/obexd-log.o: obexd/src/log.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-log.o -MD -MP -MF obexd/src/$(DEPDIR)/obexd-log.Tpo -c -o obexd/src/obexd-log.o `test -f 'obexd/src/log.c' || echo '$(srcdir)/'`obexd/src/log.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-log.Tpo obexd/src/$(DEPDIR)/obexd-log.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/src/log.c' object='obexd/src/obexd-log.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-log.o `test -f 'obexd/src/log.c' || echo '$(srcdir)/'`obexd/src/log.c + +obexd/src/obexd-log.obj: obexd/src/log.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-log.obj -MD -MP -MF obexd/src/$(DEPDIR)/obexd-log.Tpo -c -o obexd/src/obexd-log.obj `if test -f 'obexd/src/log.c'; then $(CYGPATH_W) 'obexd/src/log.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/log.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-log.Tpo obexd/src/$(DEPDIR)/obexd-log.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/src/log.c' object='obexd/src/obexd-log.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-log.obj `if test -f 'obexd/src/log.c'; then $(CYGPATH_W) 'obexd/src/log.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/log.c'; fi` + +obexd/src/obexd-manager.o: obexd/src/manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-manager.o -MD -MP -MF obexd/src/$(DEPDIR)/obexd-manager.Tpo -c -o obexd/src/obexd-manager.o `test -f 'obexd/src/manager.c' || echo '$(srcdir)/'`obexd/src/manager.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-manager.Tpo obexd/src/$(DEPDIR)/obexd-manager.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/src/manager.c' object='obexd/src/obexd-manager.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-manager.o `test -f 'obexd/src/manager.c' || echo '$(srcdir)/'`obexd/src/manager.c + +obexd/src/obexd-manager.obj: obexd/src/manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-manager.obj -MD -MP -MF obexd/src/$(DEPDIR)/obexd-manager.Tpo -c -o obexd/src/obexd-manager.obj `if test -f 'obexd/src/manager.c'; then $(CYGPATH_W) 'obexd/src/manager.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/manager.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-manager.Tpo obexd/src/$(DEPDIR)/obexd-manager.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/src/manager.c' object='obexd/src/obexd-manager.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-manager.obj `if test -f 'obexd/src/manager.c'; then $(CYGPATH_W) 'obexd/src/manager.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/manager.c'; fi` + +obexd/src/obexd-obex.o: obexd/src/obex.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-obex.o -MD -MP -MF obexd/src/$(DEPDIR)/obexd-obex.Tpo -c -o obexd/src/obexd-obex.o `test -f 'obexd/src/obex.c' || echo '$(srcdir)/'`obexd/src/obex.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-obex.Tpo obexd/src/$(DEPDIR)/obexd-obex.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/src/obex.c' object='obexd/src/obexd-obex.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-obex.o `test -f 'obexd/src/obex.c' || echo '$(srcdir)/'`obexd/src/obex.c + +obexd/src/obexd-obex.obj: obexd/src/obex.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-obex.obj -MD -MP -MF obexd/src/$(DEPDIR)/obexd-obex.Tpo -c -o obexd/src/obexd-obex.obj `if test -f 'obexd/src/obex.c'; then $(CYGPATH_W) 'obexd/src/obex.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/obex.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-obex.Tpo obexd/src/$(DEPDIR)/obexd-obex.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/src/obex.c' object='obexd/src/obexd-obex.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-obex.obj `if test -f 'obexd/src/obex.c'; then $(CYGPATH_W) 'obexd/src/obex.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/obex.c'; fi` + +obexd/src/obexd-mimetype.o: obexd/src/mimetype.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-mimetype.o -MD -MP -MF obexd/src/$(DEPDIR)/obexd-mimetype.Tpo -c -o obexd/src/obexd-mimetype.o `test -f 'obexd/src/mimetype.c' || echo '$(srcdir)/'`obexd/src/mimetype.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-mimetype.Tpo obexd/src/$(DEPDIR)/obexd-mimetype.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/src/mimetype.c' object='obexd/src/obexd-mimetype.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-mimetype.o `test -f 'obexd/src/mimetype.c' || echo '$(srcdir)/'`obexd/src/mimetype.c + +obexd/src/obexd-mimetype.obj: obexd/src/mimetype.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-mimetype.obj -MD -MP -MF obexd/src/$(DEPDIR)/obexd-mimetype.Tpo -c -o obexd/src/obexd-mimetype.obj `if test -f 'obexd/src/mimetype.c'; then $(CYGPATH_W) 'obexd/src/mimetype.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/mimetype.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-mimetype.Tpo obexd/src/$(DEPDIR)/obexd-mimetype.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/src/mimetype.c' object='obexd/src/obexd-mimetype.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-mimetype.obj `if test -f 'obexd/src/mimetype.c'; then $(CYGPATH_W) 'obexd/src/mimetype.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/mimetype.c'; fi` + +obexd/src/obexd-service.o: obexd/src/service.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-service.o -MD -MP -MF obexd/src/$(DEPDIR)/obexd-service.Tpo -c -o obexd/src/obexd-service.o `test -f 'obexd/src/service.c' || echo '$(srcdir)/'`obexd/src/service.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-service.Tpo obexd/src/$(DEPDIR)/obexd-service.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/src/service.c' object='obexd/src/obexd-service.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-service.o `test -f 'obexd/src/service.c' || echo '$(srcdir)/'`obexd/src/service.c + +obexd/src/obexd-service.obj: obexd/src/service.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-service.obj -MD -MP -MF obexd/src/$(DEPDIR)/obexd-service.Tpo -c -o obexd/src/obexd-service.obj `if test -f 'obexd/src/service.c'; then $(CYGPATH_W) 'obexd/src/service.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/service.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-service.Tpo obexd/src/$(DEPDIR)/obexd-service.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/src/service.c' object='obexd/src/obexd-service.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-service.obj `if test -f 'obexd/src/service.c'; then $(CYGPATH_W) 'obexd/src/service.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/service.c'; fi` + +obexd/src/obexd-transport.o: obexd/src/transport.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-transport.o -MD -MP -MF obexd/src/$(DEPDIR)/obexd-transport.Tpo -c -o obexd/src/obexd-transport.o `test -f 'obexd/src/transport.c' || echo '$(srcdir)/'`obexd/src/transport.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-transport.Tpo obexd/src/$(DEPDIR)/obexd-transport.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/src/transport.c' object='obexd/src/obexd-transport.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-transport.o `test -f 'obexd/src/transport.c' || echo '$(srcdir)/'`obexd/src/transport.c + +obexd/src/obexd-transport.obj: obexd/src/transport.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-transport.obj -MD -MP -MF obexd/src/$(DEPDIR)/obexd-transport.Tpo -c -o obexd/src/obexd-transport.obj `if test -f 'obexd/src/transport.c'; then $(CYGPATH_W) 'obexd/src/transport.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/transport.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-transport.Tpo obexd/src/$(DEPDIR)/obexd-transport.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/src/transport.c' object='obexd/src/obexd-transport.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-transport.obj `if test -f 'obexd/src/transport.c'; then $(CYGPATH_W) 'obexd/src/transport.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/transport.c'; fi` + +obexd/src/obexd-server.o: obexd/src/server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-server.o -MD -MP -MF obexd/src/$(DEPDIR)/obexd-server.Tpo -c -o obexd/src/obexd-server.o `test -f 'obexd/src/server.c' || echo '$(srcdir)/'`obexd/src/server.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-server.Tpo obexd/src/$(DEPDIR)/obexd-server.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/src/server.c' object='obexd/src/obexd-server.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-server.o `test -f 'obexd/src/server.c' || echo '$(srcdir)/'`obexd/src/server.c + +obexd/src/obexd-server.obj: obexd/src/server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-server.obj -MD -MP -MF obexd/src/$(DEPDIR)/obexd-server.Tpo -c -o obexd/src/obexd-server.obj `if test -f 'obexd/src/server.c'; then $(CYGPATH_W) 'obexd/src/server.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/server.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-server.Tpo obexd/src/$(DEPDIR)/obexd-server.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/src/server.c' object='obexd/src/obexd-server.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-server.obj `if test -f 'obexd/src/server.c'; then $(CYGPATH_W) 'obexd/src/server.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/server.c'; fi` + +obexd/client/obexd-manager.o: obexd/client/manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-manager.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-manager.Tpo -c -o obexd/client/obexd-manager.o `test -f 'obexd/client/manager.c' || echo '$(srcdir)/'`obexd/client/manager.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-manager.Tpo obexd/client/$(DEPDIR)/obexd-manager.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/manager.c' object='obexd/client/obexd-manager.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-manager.o `test -f 'obexd/client/manager.c' || echo '$(srcdir)/'`obexd/client/manager.c + +obexd/client/obexd-manager.obj: obexd/client/manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-manager.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-manager.Tpo -c -o obexd/client/obexd-manager.obj `if test -f 'obexd/client/manager.c'; then $(CYGPATH_W) 'obexd/client/manager.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/manager.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-manager.Tpo obexd/client/$(DEPDIR)/obexd-manager.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/manager.c' object='obexd/client/obexd-manager.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-manager.obj `if test -f 'obexd/client/manager.c'; then $(CYGPATH_W) 'obexd/client/manager.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/manager.c'; fi` + +obexd/client/obexd-session.o: obexd/client/session.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-session.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-session.Tpo -c -o obexd/client/obexd-session.o `test -f 'obexd/client/session.c' || echo '$(srcdir)/'`obexd/client/session.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-session.Tpo obexd/client/$(DEPDIR)/obexd-session.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/session.c' object='obexd/client/obexd-session.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-session.o `test -f 'obexd/client/session.c' || echo '$(srcdir)/'`obexd/client/session.c + +obexd/client/obexd-session.obj: obexd/client/session.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-session.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-session.Tpo -c -o obexd/client/obexd-session.obj `if test -f 'obexd/client/session.c'; then $(CYGPATH_W) 'obexd/client/session.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/session.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-session.Tpo obexd/client/$(DEPDIR)/obexd-session.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/session.c' object='obexd/client/obexd-session.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-session.obj `if test -f 'obexd/client/session.c'; then $(CYGPATH_W) 'obexd/client/session.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/session.c'; fi` + +obexd/client/obexd-bluetooth.o: obexd/client/bluetooth.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-bluetooth.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-bluetooth.Tpo -c -o obexd/client/obexd-bluetooth.o `test -f 'obexd/client/bluetooth.c' || echo '$(srcdir)/'`obexd/client/bluetooth.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-bluetooth.Tpo obexd/client/$(DEPDIR)/obexd-bluetooth.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/bluetooth.c' object='obexd/client/obexd-bluetooth.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-bluetooth.o `test -f 'obexd/client/bluetooth.c' || echo '$(srcdir)/'`obexd/client/bluetooth.c + +obexd/client/obexd-bluetooth.obj: obexd/client/bluetooth.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-bluetooth.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-bluetooth.Tpo -c -o obexd/client/obexd-bluetooth.obj `if test -f 'obexd/client/bluetooth.c'; then $(CYGPATH_W) 'obexd/client/bluetooth.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/bluetooth.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-bluetooth.Tpo obexd/client/$(DEPDIR)/obexd-bluetooth.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/bluetooth.c' object='obexd/client/obexd-bluetooth.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-bluetooth.obj `if test -f 'obexd/client/bluetooth.c'; then $(CYGPATH_W) 'obexd/client/bluetooth.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/bluetooth.c'; fi` + +obexd/client/obexd-sync.o: obexd/client/sync.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-sync.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-sync.Tpo -c -o obexd/client/obexd-sync.o `test -f 'obexd/client/sync.c' || echo '$(srcdir)/'`obexd/client/sync.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-sync.Tpo obexd/client/$(DEPDIR)/obexd-sync.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/sync.c' object='obexd/client/obexd-sync.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-sync.o `test -f 'obexd/client/sync.c' || echo '$(srcdir)/'`obexd/client/sync.c + +obexd/client/obexd-sync.obj: obexd/client/sync.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-sync.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-sync.Tpo -c -o obexd/client/obexd-sync.obj `if test -f 'obexd/client/sync.c'; then $(CYGPATH_W) 'obexd/client/sync.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/sync.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-sync.Tpo obexd/client/$(DEPDIR)/obexd-sync.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/sync.c' object='obexd/client/obexd-sync.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-sync.obj `if test -f 'obexd/client/sync.c'; then $(CYGPATH_W) 'obexd/client/sync.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/sync.c'; fi` + +obexd/client/obexd-pbap.o: obexd/client/pbap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-pbap.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-pbap.Tpo -c -o obexd/client/obexd-pbap.o `test -f 'obexd/client/pbap.c' || echo '$(srcdir)/'`obexd/client/pbap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-pbap.Tpo obexd/client/$(DEPDIR)/obexd-pbap.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/pbap.c' object='obexd/client/obexd-pbap.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-pbap.o `test -f 'obexd/client/pbap.c' || echo '$(srcdir)/'`obexd/client/pbap.c + +obexd/client/obexd-pbap.obj: obexd/client/pbap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-pbap.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-pbap.Tpo -c -o obexd/client/obexd-pbap.obj `if test -f 'obexd/client/pbap.c'; then $(CYGPATH_W) 'obexd/client/pbap.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/pbap.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-pbap.Tpo obexd/client/$(DEPDIR)/obexd-pbap.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/pbap.c' object='obexd/client/obexd-pbap.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-pbap.obj `if test -f 'obexd/client/pbap.c'; then $(CYGPATH_W) 'obexd/client/pbap.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/pbap.c'; fi` + +obexd/client/obexd-ftp.o: obexd/client/ftp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-ftp.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-ftp.Tpo -c -o obexd/client/obexd-ftp.o `test -f 'obexd/client/ftp.c' || echo '$(srcdir)/'`obexd/client/ftp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-ftp.Tpo obexd/client/$(DEPDIR)/obexd-ftp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/ftp.c' object='obexd/client/obexd-ftp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-ftp.o `test -f 'obexd/client/ftp.c' || echo '$(srcdir)/'`obexd/client/ftp.c + +obexd/client/obexd-ftp.obj: obexd/client/ftp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-ftp.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-ftp.Tpo -c -o obexd/client/obexd-ftp.obj `if test -f 'obexd/client/ftp.c'; then $(CYGPATH_W) 'obexd/client/ftp.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/ftp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-ftp.Tpo obexd/client/$(DEPDIR)/obexd-ftp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/ftp.c' object='obexd/client/obexd-ftp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-ftp.obj `if test -f 'obexd/client/ftp.c'; then $(CYGPATH_W) 'obexd/client/ftp.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/ftp.c'; fi` + +obexd/client/obexd-opp.o: obexd/client/opp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-opp.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-opp.Tpo -c -o obexd/client/obexd-opp.o `test -f 'obexd/client/opp.c' || echo '$(srcdir)/'`obexd/client/opp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-opp.Tpo obexd/client/$(DEPDIR)/obexd-opp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/opp.c' object='obexd/client/obexd-opp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-opp.o `test -f 'obexd/client/opp.c' || echo '$(srcdir)/'`obexd/client/opp.c + +obexd/client/obexd-opp.obj: obexd/client/opp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-opp.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-opp.Tpo -c -o obexd/client/obexd-opp.obj `if test -f 'obexd/client/opp.c'; then $(CYGPATH_W) 'obexd/client/opp.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/opp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-opp.Tpo obexd/client/$(DEPDIR)/obexd-opp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/opp.c' object='obexd/client/obexd-opp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-opp.obj `if test -f 'obexd/client/opp.c'; then $(CYGPATH_W) 'obexd/client/opp.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/opp.c'; fi` + +obexd/client/obexd-map.o: obexd/client/map.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-map.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-map.Tpo -c -o obexd/client/obexd-map.o `test -f 'obexd/client/map.c' || echo '$(srcdir)/'`obexd/client/map.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-map.Tpo obexd/client/$(DEPDIR)/obexd-map.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/map.c' object='obexd/client/obexd-map.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-map.o `test -f 'obexd/client/map.c' || echo '$(srcdir)/'`obexd/client/map.c + +obexd/client/obexd-map.obj: obexd/client/map.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-map.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-map.Tpo -c -o obexd/client/obexd-map.obj `if test -f 'obexd/client/map.c'; then $(CYGPATH_W) 'obexd/client/map.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/map.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-map.Tpo obexd/client/$(DEPDIR)/obexd-map.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/map.c' object='obexd/client/obexd-map.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-map.obj `if test -f 'obexd/client/map.c'; then $(CYGPATH_W) 'obexd/client/map.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/map.c'; fi` + +obexd/client/obexd-bip.o: obexd/client/bip.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-bip.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-bip.Tpo -c -o obexd/client/obexd-bip.o `test -f 'obexd/client/bip.c' || echo '$(srcdir)/'`obexd/client/bip.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-bip.Tpo obexd/client/$(DEPDIR)/obexd-bip.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/bip.c' object='obexd/client/obexd-bip.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-bip.o `test -f 'obexd/client/bip.c' || echo '$(srcdir)/'`obexd/client/bip.c + +obexd/client/obexd-bip.obj: obexd/client/bip.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-bip.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-bip.Tpo -c -o obexd/client/obexd-bip.obj `if test -f 'obexd/client/bip.c'; then $(CYGPATH_W) 'obexd/client/bip.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/bip.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-bip.Tpo obexd/client/$(DEPDIR)/obexd-bip.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/bip.c' object='obexd/client/obexd-bip.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-bip.obj `if test -f 'obexd/client/bip.c'; then $(CYGPATH_W) 'obexd/client/bip.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/bip.c'; fi` + +obexd/client/obexd-bip-common.o: obexd/client/bip-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-bip-common.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-bip-common.Tpo -c -o obexd/client/obexd-bip-common.o `test -f 'obexd/client/bip-common.c' || echo '$(srcdir)/'`obexd/client/bip-common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-bip-common.Tpo obexd/client/$(DEPDIR)/obexd-bip-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/bip-common.c' object='obexd/client/obexd-bip-common.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-bip-common.o `test -f 'obexd/client/bip-common.c' || echo '$(srcdir)/'`obexd/client/bip-common.c + +obexd/client/obexd-bip-common.obj: obexd/client/bip-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-bip-common.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-bip-common.Tpo -c -o obexd/client/obexd-bip-common.obj `if test -f 'obexd/client/bip-common.c'; then $(CYGPATH_W) 'obexd/client/bip-common.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/bip-common.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-bip-common.Tpo obexd/client/$(DEPDIR)/obexd-bip-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/bip-common.c' object='obexd/client/obexd-bip-common.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-bip-common.obj `if test -f 'obexd/client/bip-common.c'; then $(CYGPATH_W) 'obexd/client/bip-common.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/bip-common.c'; fi` + +obexd/client/obexd-map-event.o: obexd/client/map-event.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-map-event.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-map-event.Tpo -c -o obexd/client/obexd-map-event.o `test -f 'obexd/client/map-event.c' || echo '$(srcdir)/'`obexd/client/map-event.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-map-event.Tpo obexd/client/$(DEPDIR)/obexd-map-event.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/map-event.c' object='obexd/client/obexd-map-event.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-map-event.o `test -f 'obexd/client/map-event.c' || echo '$(srcdir)/'`obexd/client/map-event.c + +obexd/client/obexd-map-event.obj: obexd/client/map-event.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-map-event.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-map-event.Tpo -c -o obexd/client/obexd-map-event.obj `if test -f 'obexd/client/map-event.c'; then $(CYGPATH_W) 'obexd/client/map-event.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/map-event.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-map-event.Tpo obexd/client/$(DEPDIR)/obexd-map-event.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/map-event.c' object='obexd/client/obexd-map-event.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-map-event.obj `if test -f 'obexd/client/map-event.c'; then $(CYGPATH_W) 'obexd/client/map-event.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/map-event.c'; fi` + +obexd/client/obexd-transfer.o: obexd/client/transfer.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-transfer.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-transfer.Tpo -c -o obexd/client/obexd-transfer.o `test -f 'obexd/client/transfer.c' || echo '$(srcdir)/'`obexd/client/transfer.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-transfer.Tpo obexd/client/$(DEPDIR)/obexd-transfer.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/transfer.c' object='obexd/client/obexd-transfer.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-transfer.o `test -f 'obexd/client/transfer.c' || echo '$(srcdir)/'`obexd/client/transfer.c + +obexd/client/obexd-transfer.obj: obexd/client/transfer.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-transfer.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-transfer.Tpo -c -o obexd/client/obexd-transfer.obj `if test -f 'obexd/client/transfer.c'; then $(CYGPATH_W) 'obexd/client/transfer.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/transfer.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-transfer.Tpo obexd/client/$(DEPDIR)/obexd-transfer.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/transfer.c' object='obexd/client/obexd-transfer.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-transfer.obj `if test -f 'obexd/client/transfer.c'; then $(CYGPATH_W) 'obexd/client/transfer.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/transfer.c'; fi` + +obexd/client/obexd-transport.o: obexd/client/transport.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-transport.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-transport.Tpo -c -o obexd/client/obexd-transport.o `test -f 'obexd/client/transport.c' || echo '$(srcdir)/'`obexd/client/transport.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-transport.Tpo obexd/client/$(DEPDIR)/obexd-transport.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/transport.c' object='obexd/client/obexd-transport.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-transport.o `test -f 'obexd/client/transport.c' || echo '$(srcdir)/'`obexd/client/transport.c + +obexd/client/obexd-transport.obj: obexd/client/transport.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-transport.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-transport.Tpo -c -o obexd/client/obexd-transport.obj `if test -f 'obexd/client/transport.c'; then $(CYGPATH_W) 'obexd/client/transport.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/transport.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-transport.Tpo obexd/client/$(DEPDIR)/obexd-transport.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/transport.c' object='obexd/client/obexd-transport.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-transport.obj `if test -f 'obexd/client/transport.c'; then $(CYGPATH_W) 'obexd/client/transport.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/transport.c'; fi` + +obexd/client/obexd-driver.o: obexd/client/driver.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-driver.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-driver.Tpo -c -o obexd/client/obexd-driver.o `test -f 'obexd/client/driver.c' || echo '$(srcdir)/'`obexd/client/driver.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-driver.Tpo obexd/client/$(DEPDIR)/obexd-driver.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/driver.c' object='obexd/client/obexd-driver.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-driver.o `test -f 'obexd/client/driver.c' || echo '$(srcdir)/'`obexd/client/driver.c + +obexd/client/obexd-driver.obj: obexd/client/driver.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-driver.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-driver.Tpo -c -o obexd/client/obexd-driver.obj `if test -f 'obexd/client/driver.c'; then $(CYGPATH_W) 'obexd/client/driver.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/driver.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-driver.Tpo obexd/client/$(DEPDIR)/obexd-driver.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='obexd/client/driver.c' object='obexd/client/obexd-driver.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-driver.obj `if test -f 'obexd/client/driver.c'; then $(CYGPATH_W) 'obexd/client/driver.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/driver.c'; fi` + +plugins/bluetoothd-hostname.o: plugins/hostname.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-hostname.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-hostname.Tpo -c -o plugins/bluetoothd-hostname.o `test -f 'plugins/hostname.c' || echo '$(srcdir)/'`plugins/hostname.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-hostname.Tpo plugins/$(DEPDIR)/bluetoothd-hostname.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/hostname.c' object='plugins/bluetoothd-hostname.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-hostname.o `test -f 'plugins/hostname.c' || echo '$(srcdir)/'`plugins/hostname.c + +plugins/bluetoothd-hostname.obj: plugins/hostname.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-hostname.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-hostname.Tpo -c -o plugins/bluetoothd-hostname.obj `if test -f 'plugins/hostname.c'; then $(CYGPATH_W) 'plugins/hostname.c'; else $(CYGPATH_W) '$(srcdir)/plugins/hostname.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-hostname.Tpo plugins/$(DEPDIR)/bluetoothd-hostname.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/hostname.c' object='plugins/bluetoothd-hostname.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-hostname.obj `if test -f 'plugins/hostname.c'; then $(CYGPATH_W) 'plugins/hostname.c'; else $(CYGPATH_W) '$(srcdir)/plugins/hostname.c'; fi` + +plugins/bluetoothd-wiimote.o: plugins/wiimote.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-wiimote.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-wiimote.Tpo -c -o plugins/bluetoothd-wiimote.o `test -f 'plugins/wiimote.c' || echo '$(srcdir)/'`plugins/wiimote.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-wiimote.Tpo plugins/$(DEPDIR)/bluetoothd-wiimote.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/wiimote.c' object='plugins/bluetoothd-wiimote.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-wiimote.o `test -f 'plugins/wiimote.c' || echo '$(srcdir)/'`plugins/wiimote.c + +plugins/bluetoothd-wiimote.obj: plugins/wiimote.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-wiimote.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-wiimote.Tpo -c -o plugins/bluetoothd-wiimote.obj `if test -f 'plugins/wiimote.c'; then $(CYGPATH_W) 'plugins/wiimote.c'; else $(CYGPATH_W) '$(srcdir)/plugins/wiimote.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-wiimote.Tpo plugins/$(DEPDIR)/bluetoothd-wiimote.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/wiimote.c' object='plugins/bluetoothd-wiimote.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-wiimote.obj `if test -f 'plugins/wiimote.c'; then $(CYGPATH_W) 'plugins/wiimote.c'; else $(CYGPATH_W) '$(srcdir)/plugins/wiimote.c'; fi` + +plugins/bluetoothd-autopair.o: plugins/autopair.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-autopair.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-autopair.Tpo -c -o plugins/bluetoothd-autopair.o `test -f 'plugins/autopair.c' || echo '$(srcdir)/'`plugins/autopair.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-autopair.Tpo plugins/$(DEPDIR)/bluetoothd-autopair.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/autopair.c' object='plugins/bluetoothd-autopair.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-autopair.o `test -f 'plugins/autopair.c' || echo '$(srcdir)/'`plugins/autopair.c + +plugins/bluetoothd-autopair.obj: plugins/autopair.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-autopair.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-autopair.Tpo -c -o plugins/bluetoothd-autopair.obj `if test -f 'plugins/autopair.c'; then $(CYGPATH_W) 'plugins/autopair.c'; else $(CYGPATH_W) '$(srcdir)/plugins/autopair.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-autopair.Tpo plugins/$(DEPDIR)/bluetoothd-autopair.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/autopair.c' object='plugins/bluetoothd-autopair.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-autopair.obj `if test -f 'plugins/autopair.c'; then $(CYGPATH_W) 'plugins/autopair.c'; else $(CYGPATH_W) '$(srcdir)/plugins/autopair.c'; fi` + +plugins/bluetoothd-policy.o: plugins/policy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-policy.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-policy.Tpo -c -o plugins/bluetoothd-policy.o `test -f 'plugins/policy.c' || echo '$(srcdir)/'`plugins/policy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-policy.Tpo plugins/$(DEPDIR)/bluetoothd-policy.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/policy.c' object='plugins/bluetoothd-policy.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-policy.o `test -f 'plugins/policy.c' || echo '$(srcdir)/'`plugins/policy.c + +plugins/bluetoothd-policy.obj: plugins/policy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-policy.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-policy.Tpo -c -o plugins/bluetoothd-policy.obj `if test -f 'plugins/policy.c'; then $(CYGPATH_W) 'plugins/policy.c'; else $(CYGPATH_W) '$(srcdir)/plugins/policy.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-policy.Tpo plugins/$(DEPDIR)/bluetoothd-policy.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/policy.c' object='plugins/bluetoothd-policy.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-policy.obj `if test -f 'plugins/policy.c'; then $(CYGPATH_W) 'plugins/policy.c'; else $(CYGPATH_W) '$(srcdir)/plugins/policy.c'; fi` + +plugins/bluetoothd-admin.o: plugins/admin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-admin.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-admin.Tpo -c -o plugins/bluetoothd-admin.o `test -f 'plugins/admin.c' || echo '$(srcdir)/'`plugins/admin.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-admin.Tpo plugins/$(DEPDIR)/bluetoothd-admin.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/admin.c' object='plugins/bluetoothd-admin.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-admin.o `test -f 'plugins/admin.c' || echo '$(srcdir)/'`plugins/admin.c + +plugins/bluetoothd-admin.obj: plugins/admin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-admin.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-admin.Tpo -c -o plugins/bluetoothd-admin.obj `if test -f 'plugins/admin.c'; then $(CYGPATH_W) 'plugins/admin.c'; else $(CYGPATH_W) '$(srcdir)/plugins/admin.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-admin.Tpo plugins/$(DEPDIR)/bluetoothd-admin.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/admin.c' object='plugins/bluetoothd-admin.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-admin.obj `if test -f 'plugins/admin.c'; then $(CYGPATH_W) 'plugins/admin.c'; else $(CYGPATH_W) '$(srcdir)/plugins/admin.c'; fi` + +plugins/bluetoothd-neard.o: plugins/neard.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-neard.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-neard.Tpo -c -o plugins/bluetoothd-neard.o `test -f 'plugins/neard.c' || echo '$(srcdir)/'`plugins/neard.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-neard.Tpo plugins/$(DEPDIR)/bluetoothd-neard.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/neard.c' object='plugins/bluetoothd-neard.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-neard.o `test -f 'plugins/neard.c' || echo '$(srcdir)/'`plugins/neard.c + +plugins/bluetoothd-neard.obj: plugins/neard.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-neard.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-neard.Tpo -c -o plugins/bluetoothd-neard.obj `if test -f 'plugins/neard.c'; then $(CYGPATH_W) 'plugins/neard.c'; else $(CYGPATH_W) '$(srcdir)/plugins/neard.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-neard.Tpo plugins/$(DEPDIR)/bluetoothd-neard.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/neard.c' object='plugins/bluetoothd-neard.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-neard.obj `if test -f 'plugins/neard.c'; then $(CYGPATH_W) 'plugins/neard.c'; else $(CYGPATH_W) '$(srcdir)/plugins/neard.c'; fi` + +profiles/sap/bluetoothd-main.o: profiles/sap/main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/sap/bluetoothd-main.o -MD -MP -MF profiles/sap/$(DEPDIR)/bluetoothd-main.Tpo -c -o profiles/sap/bluetoothd-main.o `test -f 'profiles/sap/main.c' || echo '$(srcdir)/'`profiles/sap/main.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/sap/$(DEPDIR)/bluetoothd-main.Tpo profiles/sap/$(DEPDIR)/bluetoothd-main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/sap/main.c' object='profiles/sap/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/sap/bluetoothd-main.o `test -f 'profiles/sap/main.c' || echo '$(srcdir)/'`profiles/sap/main.c + +profiles/sap/bluetoothd-main.obj: profiles/sap/main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/sap/bluetoothd-main.obj -MD -MP -MF profiles/sap/$(DEPDIR)/bluetoothd-main.Tpo -c -o profiles/sap/bluetoothd-main.obj `if test -f 'profiles/sap/main.c'; then $(CYGPATH_W) 'profiles/sap/main.c'; else $(CYGPATH_W) '$(srcdir)/profiles/sap/main.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/sap/$(DEPDIR)/bluetoothd-main.Tpo profiles/sap/$(DEPDIR)/bluetoothd-main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/sap/main.c' object='profiles/sap/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/sap/bluetoothd-main.obj `if test -f 'profiles/sap/main.c'; then $(CYGPATH_W) 'profiles/sap/main.c'; else $(CYGPATH_W) '$(srcdir)/profiles/sap/main.c'; fi` + +profiles/sap/bluetoothd-manager.o: profiles/sap/manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/sap/bluetoothd-manager.o -MD -MP -MF profiles/sap/$(DEPDIR)/bluetoothd-manager.Tpo -c -o profiles/sap/bluetoothd-manager.o `test -f 'profiles/sap/manager.c' || echo '$(srcdir)/'`profiles/sap/manager.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/sap/$(DEPDIR)/bluetoothd-manager.Tpo profiles/sap/$(DEPDIR)/bluetoothd-manager.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/sap/manager.c' object='profiles/sap/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/sap/bluetoothd-manager.o `test -f 'profiles/sap/manager.c' || echo '$(srcdir)/'`profiles/sap/manager.c + +profiles/sap/bluetoothd-manager.obj: profiles/sap/manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/sap/bluetoothd-manager.obj -MD -MP -MF profiles/sap/$(DEPDIR)/bluetoothd-manager.Tpo -c -o profiles/sap/bluetoothd-manager.obj `if test -f 'profiles/sap/manager.c'; then $(CYGPATH_W) 'profiles/sap/manager.c'; else $(CYGPATH_W) '$(srcdir)/profiles/sap/manager.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/sap/$(DEPDIR)/bluetoothd-manager.Tpo profiles/sap/$(DEPDIR)/bluetoothd-manager.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/sap/manager.c' object='profiles/sap/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/sap/bluetoothd-manager.obj `if test -f 'profiles/sap/manager.c'; then $(CYGPATH_W) 'profiles/sap/manager.c'; else $(CYGPATH_W) '$(srcdir)/profiles/sap/manager.c'; fi` + +profiles/sap/bluetoothd-server.o: profiles/sap/server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/sap/bluetoothd-server.o -MD -MP -MF profiles/sap/$(DEPDIR)/bluetoothd-server.Tpo -c -o profiles/sap/bluetoothd-server.o `test -f 'profiles/sap/server.c' || echo '$(srcdir)/'`profiles/sap/server.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/sap/$(DEPDIR)/bluetoothd-server.Tpo profiles/sap/$(DEPDIR)/bluetoothd-server.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/sap/server.c' object='profiles/sap/bluetoothd-server.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/sap/bluetoothd-server.o `test -f 'profiles/sap/server.c' || echo '$(srcdir)/'`profiles/sap/server.c + +profiles/sap/bluetoothd-server.obj: profiles/sap/server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/sap/bluetoothd-server.obj -MD -MP -MF profiles/sap/$(DEPDIR)/bluetoothd-server.Tpo -c -o profiles/sap/bluetoothd-server.obj `if test -f 'profiles/sap/server.c'; then $(CYGPATH_W) 'profiles/sap/server.c'; else $(CYGPATH_W) '$(srcdir)/profiles/sap/server.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/sap/$(DEPDIR)/bluetoothd-server.Tpo profiles/sap/$(DEPDIR)/bluetoothd-server.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/sap/server.c' object='profiles/sap/bluetoothd-server.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/sap/bluetoothd-server.obj `if test -f 'profiles/sap/server.c'; then $(CYGPATH_W) 'profiles/sap/server.c'; else $(CYGPATH_W) '$(srcdir)/profiles/sap/server.c'; fi` + +profiles/sap/bluetoothd-sap-dummy.o: profiles/sap/sap-dummy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/sap/bluetoothd-sap-dummy.o -MD -MP -MF profiles/sap/$(DEPDIR)/bluetoothd-sap-dummy.Tpo -c -o profiles/sap/bluetoothd-sap-dummy.o `test -f 'profiles/sap/sap-dummy.c' || echo '$(srcdir)/'`profiles/sap/sap-dummy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/sap/$(DEPDIR)/bluetoothd-sap-dummy.Tpo profiles/sap/$(DEPDIR)/bluetoothd-sap-dummy.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/sap/sap-dummy.c' object='profiles/sap/bluetoothd-sap-dummy.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/sap/bluetoothd-sap-dummy.o `test -f 'profiles/sap/sap-dummy.c' || echo '$(srcdir)/'`profiles/sap/sap-dummy.c + +profiles/sap/bluetoothd-sap-dummy.obj: profiles/sap/sap-dummy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/sap/bluetoothd-sap-dummy.obj -MD -MP -MF profiles/sap/$(DEPDIR)/bluetoothd-sap-dummy.Tpo -c -o profiles/sap/bluetoothd-sap-dummy.obj `if test -f 'profiles/sap/sap-dummy.c'; then $(CYGPATH_W) 'profiles/sap/sap-dummy.c'; else $(CYGPATH_W) '$(srcdir)/profiles/sap/sap-dummy.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/sap/$(DEPDIR)/bluetoothd-sap-dummy.Tpo profiles/sap/$(DEPDIR)/bluetoothd-sap-dummy.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/sap/sap-dummy.c' object='profiles/sap/bluetoothd-sap-dummy.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/sap/bluetoothd-sap-dummy.obj `if test -f 'profiles/sap/sap-dummy.c'; then $(CYGPATH_W) 'profiles/sap/sap-dummy.c'; else $(CYGPATH_W) '$(srcdir)/profiles/sap/sap-dummy.c'; fi` + +profiles/audio/bluetoothd-source.o: profiles/audio/source.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-source.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-source.Tpo -c -o profiles/audio/bluetoothd-source.o `test -f 'profiles/audio/source.c' || echo '$(srcdir)/'`profiles/audio/source.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-source.Tpo profiles/audio/$(DEPDIR)/bluetoothd-source.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/source.c' object='profiles/audio/bluetoothd-source.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-source.o `test -f 'profiles/audio/source.c' || echo '$(srcdir)/'`profiles/audio/source.c + +profiles/audio/bluetoothd-source.obj: profiles/audio/source.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-source.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-source.Tpo -c -o profiles/audio/bluetoothd-source.obj `if test -f 'profiles/audio/source.c'; then $(CYGPATH_W) 'profiles/audio/source.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/source.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-source.Tpo profiles/audio/$(DEPDIR)/bluetoothd-source.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/source.c' object='profiles/audio/bluetoothd-source.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-source.obj `if test -f 'profiles/audio/source.c'; then $(CYGPATH_W) 'profiles/audio/source.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/source.c'; fi` + +profiles/audio/bluetoothd-sink.o: profiles/audio/sink.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-sink.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-sink.Tpo -c -o profiles/audio/bluetoothd-sink.o `test -f 'profiles/audio/sink.c' || echo '$(srcdir)/'`profiles/audio/sink.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-sink.Tpo profiles/audio/$(DEPDIR)/bluetoothd-sink.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/sink.c' object='profiles/audio/bluetoothd-sink.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-sink.o `test -f 'profiles/audio/sink.c' || echo '$(srcdir)/'`profiles/audio/sink.c + +profiles/audio/bluetoothd-sink.obj: profiles/audio/sink.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-sink.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-sink.Tpo -c -o profiles/audio/bluetoothd-sink.obj `if test -f 'profiles/audio/sink.c'; then $(CYGPATH_W) 'profiles/audio/sink.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/sink.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-sink.Tpo profiles/audio/$(DEPDIR)/bluetoothd-sink.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/sink.c' object='profiles/audio/bluetoothd-sink.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-sink.obj `if test -f 'profiles/audio/sink.c'; then $(CYGPATH_W) 'profiles/audio/sink.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/sink.c'; fi` + +profiles/audio/bluetoothd-a2dp.o: profiles/audio/a2dp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-a2dp.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-a2dp.Tpo -c -o profiles/audio/bluetoothd-a2dp.o `test -f 'profiles/audio/a2dp.c' || echo '$(srcdir)/'`profiles/audio/a2dp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-a2dp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-a2dp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/a2dp.c' object='profiles/audio/bluetoothd-a2dp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-a2dp.o `test -f 'profiles/audio/a2dp.c' || echo '$(srcdir)/'`profiles/audio/a2dp.c + +profiles/audio/bluetoothd-a2dp.obj: profiles/audio/a2dp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-a2dp.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-a2dp.Tpo -c -o profiles/audio/bluetoothd-a2dp.obj `if test -f 'profiles/audio/a2dp.c'; then $(CYGPATH_W) 'profiles/audio/a2dp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/a2dp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-a2dp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-a2dp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/a2dp.c' object='profiles/audio/bluetoothd-a2dp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-a2dp.obj `if test -f 'profiles/audio/a2dp.c'; then $(CYGPATH_W) 'profiles/audio/a2dp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/a2dp.c'; fi` + +profiles/audio/bluetoothd-avdtp.o: profiles/audio/avdtp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-avdtp.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-avdtp.Tpo -c -o profiles/audio/bluetoothd-avdtp.o `test -f 'profiles/audio/avdtp.c' || echo '$(srcdir)/'`profiles/audio/avdtp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-avdtp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-avdtp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/avdtp.c' object='profiles/audio/bluetoothd-avdtp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-avdtp.o `test -f 'profiles/audio/avdtp.c' || echo '$(srcdir)/'`profiles/audio/avdtp.c + +profiles/audio/bluetoothd-avdtp.obj: profiles/audio/avdtp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-avdtp.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-avdtp.Tpo -c -o profiles/audio/bluetoothd-avdtp.obj `if test -f 'profiles/audio/avdtp.c'; then $(CYGPATH_W) 'profiles/audio/avdtp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/avdtp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-avdtp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-avdtp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/avdtp.c' object='profiles/audio/bluetoothd-avdtp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-avdtp.obj `if test -f 'profiles/audio/avdtp.c'; then $(CYGPATH_W) 'profiles/audio/avdtp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/avdtp.c'; fi` + +profiles/audio/bluetoothd-media.o: profiles/audio/media.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-media.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-media.Tpo -c -o profiles/audio/bluetoothd-media.o `test -f 'profiles/audio/media.c' || echo '$(srcdir)/'`profiles/audio/media.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-media.Tpo profiles/audio/$(DEPDIR)/bluetoothd-media.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/media.c' object='profiles/audio/bluetoothd-media.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-media.o `test -f 'profiles/audio/media.c' || echo '$(srcdir)/'`profiles/audio/media.c + +profiles/audio/bluetoothd-media.obj: profiles/audio/media.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-media.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-media.Tpo -c -o profiles/audio/bluetoothd-media.obj `if test -f 'profiles/audio/media.c'; then $(CYGPATH_W) 'profiles/audio/media.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/media.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-media.Tpo profiles/audio/$(DEPDIR)/bluetoothd-media.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/media.c' object='profiles/audio/bluetoothd-media.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-media.obj `if test -f 'profiles/audio/media.c'; then $(CYGPATH_W) 'profiles/audio/media.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/media.c'; fi` + +profiles/audio/bluetoothd-transport.o: profiles/audio/transport.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-transport.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-transport.Tpo -c -o profiles/audio/bluetoothd-transport.o `test -f 'profiles/audio/transport.c' || echo '$(srcdir)/'`profiles/audio/transport.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-transport.Tpo profiles/audio/$(DEPDIR)/bluetoothd-transport.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/transport.c' object='profiles/audio/bluetoothd-transport.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-transport.o `test -f 'profiles/audio/transport.c' || echo '$(srcdir)/'`profiles/audio/transport.c + +profiles/audio/bluetoothd-transport.obj: profiles/audio/transport.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-transport.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-transport.Tpo -c -o profiles/audio/bluetoothd-transport.obj `if test -f 'profiles/audio/transport.c'; then $(CYGPATH_W) 'profiles/audio/transport.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/transport.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-transport.Tpo profiles/audio/$(DEPDIR)/bluetoothd-transport.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/transport.c' object='profiles/audio/bluetoothd-transport.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-transport.obj `if test -f 'profiles/audio/transport.c'; then $(CYGPATH_W) 'profiles/audio/transport.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/transport.c'; fi` + +profiles/audio/bluetoothd-control.o: profiles/audio/control.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-control.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-control.Tpo -c -o profiles/audio/bluetoothd-control.o `test -f 'profiles/audio/control.c' || echo '$(srcdir)/'`profiles/audio/control.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-control.Tpo profiles/audio/$(DEPDIR)/bluetoothd-control.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/control.c' object='profiles/audio/bluetoothd-control.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-control.o `test -f 'profiles/audio/control.c' || echo '$(srcdir)/'`profiles/audio/control.c + +profiles/audio/bluetoothd-control.obj: profiles/audio/control.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-control.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-control.Tpo -c -o profiles/audio/bluetoothd-control.obj `if test -f 'profiles/audio/control.c'; then $(CYGPATH_W) 'profiles/audio/control.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/control.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-control.Tpo profiles/audio/$(DEPDIR)/bluetoothd-control.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/control.c' object='profiles/audio/bluetoothd-control.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-control.obj `if test -f 'profiles/audio/control.c'; then $(CYGPATH_W) 'profiles/audio/control.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/control.c'; fi` + +profiles/audio/bluetoothd-avctp.o: profiles/audio/avctp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-avctp.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-avctp.Tpo -c -o profiles/audio/bluetoothd-avctp.o `test -f 'profiles/audio/avctp.c' || echo '$(srcdir)/'`profiles/audio/avctp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-avctp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-avctp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/avctp.c' object='profiles/audio/bluetoothd-avctp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-avctp.o `test -f 'profiles/audio/avctp.c' || echo '$(srcdir)/'`profiles/audio/avctp.c + +profiles/audio/bluetoothd-avctp.obj: profiles/audio/avctp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-avctp.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-avctp.Tpo -c -o profiles/audio/bluetoothd-avctp.obj `if test -f 'profiles/audio/avctp.c'; then $(CYGPATH_W) 'profiles/audio/avctp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/avctp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-avctp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-avctp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/avctp.c' object='profiles/audio/bluetoothd-avctp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-avctp.obj `if test -f 'profiles/audio/avctp.c'; then $(CYGPATH_W) 'profiles/audio/avctp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/avctp.c'; fi` + +profiles/audio/bluetoothd-avrcp.o: profiles/audio/avrcp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-avrcp.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-avrcp.Tpo -c -o profiles/audio/bluetoothd-avrcp.o `test -f 'profiles/audio/avrcp.c' || echo '$(srcdir)/'`profiles/audio/avrcp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-avrcp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-avrcp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/avrcp.c' object='profiles/audio/bluetoothd-avrcp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-avrcp.o `test -f 'profiles/audio/avrcp.c' || echo '$(srcdir)/'`profiles/audio/avrcp.c + +profiles/audio/bluetoothd-avrcp.obj: profiles/audio/avrcp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-avrcp.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-avrcp.Tpo -c -o profiles/audio/bluetoothd-avrcp.obj `if test -f 'profiles/audio/avrcp.c'; then $(CYGPATH_W) 'profiles/audio/avrcp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/avrcp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-avrcp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-avrcp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/avrcp.c' object='profiles/audio/bluetoothd-avrcp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-avrcp.obj `if test -f 'profiles/audio/avrcp.c'; then $(CYGPATH_W) 'profiles/audio/avrcp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/avrcp.c'; fi` + +profiles/audio/bluetoothd-player.o: profiles/audio/player.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-player.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-player.Tpo -c -o profiles/audio/bluetoothd-player.o `test -f 'profiles/audio/player.c' || echo '$(srcdir)/'`profiles/audio/player.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-player.Tpo profiles/audio/$(DEPDIR)/bluetoothd-player.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/player.c' object='profiles/audio/bluetoothd-player.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-player.o `test -f 'profiles/audio/player.c' || echo '$(srcdir)/'`profiles/audio/player.c + +profiles/audio/bluetoothd-player.obj: profiles/audio/player.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-player.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-player.Tpo -c -o profiles/audio/bluetoothd-player.obj `if test -f 'profiles/audio/player.c'; then $(CYGPATH_W) 'profiles/audio/player.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/player.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-player.Tpo profiles/audio/$(DEPDIR)/bluetoothd-player.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/player.c' object='profiles/audio/bluetoothd-player.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-player.obj `if test -f 'profiles/audio/player.c'; then $(CYGPATH_W) 'profiles/audio/player.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/player.c'; fi` + +profiles/network/bluetoothd-manager.o: profiles/network/manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/network/bluetoothd-manager.o -MD -MP -MF profiles/network/$(DEPDIR)/bluetoothd-manager.Tpo -c -o profiles/network/bluetoothd-manager.o `test -f 'profiles/network/manager.c' || echo '$(srcdir)/'`profiles/network/manager.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/network/$(DEPDIR)/bluetoothd-manager.Tpo profiles/network/$(DEPDIR)/bluetoothd-manager.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/network/manager.c' object='profiles/network/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/network/bluetoothd-manager.o `test -f 'profiles/network/manager.c' || echo '$(srcdir)/'`profiles/network/manager.c + +profiles/network/bluetoothd-manager.obj: profiles/network/manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/network/bluetoothd-manager.obj -MD -MP -MF profiles/network/$(DEPDIR)/bluetoothd-manager.Tpo -c -o profiles/network/bluetoothd-manager.obj `if test -f 'profiles/network/manager.c'; then $(CYGPATH_W) 'profiles/network/manager.c'; else $(CYGPATH_W) '$(srcdir)/profiles/network/manager.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/network/$(DEPDIR)/bluetoothd-manager.Tpo profiles/network/$(DEPDIR)/bluetoothd-manager.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/network/manager.c' object='profiles/network/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/network/bluetoothd-manager.obj `if test -f 'profiles/network/manager.c'; then $(CYGPATH_W) 'profiles/network/manager.c'; else $(CYGPATH_W) '$(srcdir)/profiles/network/manager.c'; fi` + +profiles/network/bluetoothd-bnep.o: profiles/network/bnep.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/network/bluetoothd-bnep.o -MD -MP -MF profiles/network/$(DEPDIR)/bluetoothd-bnep.Tpo -c -o profiles/network/bluetoothd-bnep.o `test -f 'profiles/network/bnep.c' || echo '$(srcdir)/'`profiles/network/bnep.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/network/$(DEPDIR)/bluetoothd-bnep.Tpo profiles/network/$(DEPDIR)/bluetoothd-bnep.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/network/bnep.c' object='profiles/network/bluetoothd-bnep.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/network/bluetoothd-bnep.o `test -f 'profiles/network/bnep.c' || echo '$(srcdir)/'`profiles/network/bnep.c + +profiles/network/bluetoothd-bnep.obj: profiles/network/bnep.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/network/bluetoothd-bnep.obj -MD -MP -MF profiles/network/$(DEPDIR)/bluetoothd-bnep.Tpo -c -o profiles/network/bluetoothd-bnep.obj `if test -f 'profiles/network/bnep.c'; then $(CYGPATH_W) 'profiles/network/bnep.c'; else $(CYGPATH_W) '$(srcdir)/profiles/network/bnep.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/network/$(DEPDIR)/bluetoothd-bnep.Tpo profiles/network/$(DEPDIR)/bluetoothd-bnep.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/network/bnep.c' object='profiles/network/bluetoothd-bnep.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/network/bluetoothd-bnep.obj `if test -f 'profiles/network/bnep.c'; then $(CYGPATH_W) 'profiles/network/bnep.c'; else $(CYGPATH_W) '$(srcdir)/profiles/network/bnep.c'; fi` + +profiles/network/bluetoothd-server.o: profiles/network/server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/network/bluetoothd-server.o -MD -MP -MF profiles/network/$(DEPDIR)/bluetoothd-server.Tpo -c -o profiles/network/bluetoothd-server.o `test -f 'profiles/network/server.c' || echo '$(srcdir)/'`profiles/network/server.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/network/$(DEPDIR)/bluetoothd-server.Tpo profiles/network/$(DEPDIR)/bluetoothd-server.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/network/server.c' object='profiles/network/bluetoothd-server.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/network/bluetoothd-server.o `test -f 'profiles/network/server.c' || echo '$(srcdir)/'`profiles/network/server.c + +profiles/network/bluetoothd-server.obj: profiles/network/server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/network/bluetoothd-server.obj -MD -MP -MF profiles/network/$(DEPDIR)/bluetoothd-server.Tpo -c -o profiles/network/bluetoothd-server.obj `if test -f 'profiles/network/server.c'; then $(CYGPATH_W) 'profiles/network/server.c'; else $(CYGPATH_W) '$(srcdir)/profiles/network/server.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/network/$(DEPDIR)/bluetoothd-server.Tpo profiles/network/$(DEPDIR)/bluetoothd-server.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/network/server.c' object='profiles/network/bluetoothd-server.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/network/bluetoothd-server.obj `if test -f 'profiles/network/server.c'; then $(CYGPATH_W) 'profiles/network/server.c'; else $(CYGPATH_W) '$(srcdir)/profiles/network/server.c'; fi` + +profiles/network/bluetoothd-connection.o: profiles/network/connection.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/network/bluetoothd-connection.o -MD -MP -MF profiles/network/$(DEPDIR)/bluetoothd-connection.Tpo -c -o profiles/network/bluetoothd-connection.o `test -f 'profiles/network/connection.c' || echo '$(srcdir)/'`profiles/network/connection.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/network/$(DEPDIR)/bluetoothd-connection.Tpo profiles/network/$(DEPDIR)/bluetoothd-connection.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/network/connection.c' object='profiles/network/bluetoothd-connection.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/network/bluetoothd-connection.o `test -f 'profiles/network/connection.c' || echo '$(srcdir)/'`profiles/network/connection.c + +profiles/network/bluetoothd-connection.obj: profiles/network/connection.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/network/bluetoothd-connection.obj -MD -MP -MF profiles/network/$(DEPDIR)/bluetoothd-connection.Tpo -c -o profiles/network/bluetoothd-connection.obj `if test -f 'profiles/network/connection.c'; then $(CYGPATH_W) 'profiles/network/connection.c'; else $(CYGPATH_W) '$(srcdir)/profiles/network/connection.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/network/$(DEPDIR)/bluetoothd-connection.Tpo profiles/network/$(DEPDIR)/bluetoothd-connection.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/network/connection.c' object='profiles/network/bluetoothd-connection.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/network/bluetoothd-connection.obj `if test -f 'profiles/network/connection.c'; then $(CYGPATH_W) 'profiles/network/connection.c'; else $(CYGPATH_W) '$(srcdir)/profiles/network/connection.c'; fi` + +profiles/input/bluetoothd-manager.o: profiles/input/manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-manager.o -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-manager.Tpo -c -o profiles/input/bluetoothd-manager.o `test -f 'profiles/input/manager.c' || echo '$(srcdir)/'`profiles/input/manager.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-manager.Tpo profiles/input/$(DEPDIR)/bluetoothd-manager.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/input/manager.c' object='profiles/input/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-manager.o `test -f 'profiles/input/manager.c' || echo '$(srcdir)/'`profiles/input/manager.c + +profiles/input/bluetoothd-manager.obj: profiles/input/manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-manager.obj -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-manager.Tpo -c -o profiles/input/bluetoothd-manager.obj `if test -f 'profiles/input/manager.c'; then $(CYGPATH_W) 'profiles/input/manager.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/manager.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-manager.Tpo profiles/input/$(DEPDIR)/bluetoothd-manager.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/input/manager.c' object='profiles/input/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-manager.obj `if test -f 'profiles/input/manager.c'; then $(CYGPATH_W) 'profiles/input/manager.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/manager.c'; fi` + +profiles/input/bluetoothd-server.o: profiles/input/server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-server.o -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-server.Tpo -c -o profiles/input/bluetoothd-server.o `test -f 'profiles/input/server.c' || echo '$(srcdir)/'`profiles/input/server.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-server.Tpo profiles/input/$(DEPDIR)/bluetoothd-server.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/input/server.c' object='profiles/input/bluetoothd-server.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-server.o `test -f 'profiles/input/server.c' || echo '$(srcdir)/'`profiles/input/server.c + +profiles/input/bluetoothd-server.obj: profiles/input/server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-server.obj -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-server.Tpo -c -o profiles/input/bluetoothd-server.obj `if test -f 'profiles/input/server.c'; then $(CYGPATH_W) 'profiles/input/server.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/server.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-server.Tpo profiles/input/$(DEPDIR)/bluetoothd-server.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/input/server.c' object='profiles/input/bluetoothd-server.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-server.obj `if test -f 'profiles/input/server.c'; then $(CYGPATH_W) 'profiles/input/server.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/server.c'; fi` + +profiles/input/bluetoothd-device.o: profiles/input/device.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-device.o -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-device.Tpo -c -o profiles/input/bluetoothd-device.o `test -f 'profiles/input/device.c' || echo '$(srcdir)/'`profiles/input/device.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-device.Tpo profiles/input/$(DEPDIR)/bluetoothd-device.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/input/device.c' object='profiles/input/bluetoothd-device.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-device.o `test -f 'profiles/input/device.c' || echo '$(srcdir)/'`profiles/input/device.c + +profiles/input/bluetoothd-device.obj: profiles/input/device.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-device.obj -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-device.Tpo -c -o profiles/input/bluetoothd-device.obj `if test -f 'profiles/input/device.c'; then $(CYGPATH_W) 'profiles/input/device.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/device.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-device.Tpo profiles/input/$(DEPDIR)/bluetoothd-device.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/input/device.c' object='profiles/input/bluetoothd-device.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-device.obj `if test -f 'profiles/input/device.c'; then $(CYGPATH_W) 'profiles/input/device.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/device.c'; fi` + +profiles/input/bluetoothd-hog.o: profiles/input/hog.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-hog.o -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-hog.Tpo -c -o profiles/input/bluetoothd-hog.o `test -f 'profiles/input/hog.c' || echo '$(srcdir)/'`profiles/input/hog.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-hog.Tpo profiles/input/$(DEPDIR)/bluetoothd-hog.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/input/hog.c' object='profiles/input/bluetoothd-hog.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-hog.o `test -f 'profiles/input/hog.c' || echo '$(srcdir)/'`profiles/input/hog.c + +profiles/input/bluetoothd-hog.obj: profiles/input/hog.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-hog.obj -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-hog.Tpo -c -o profiles/input/bluetoothd-hog.obj `if test -f 'profiles/input/hog.c'; then $(CYGPATH_W) 'profiles/input/hog.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/hog.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-hog.Tpo profiles/input/$(DEPDIR)/bluetoothd-hog.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/input/hog.c' object='profiles/input/bluetoothd-hog.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-hog.obj `if test -f 'profiles/input/hog.c'; then $(CYGPATH_W) 'profiles/input/hog.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/hog.c'; fi` + +profiles/input/bluetoothd-hog-lib.o: profiles/input/hog-lib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-hog-lib.o -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-hog-lib.Tpo -c -o profiles/input/bluetoothd-hog-lib.o `test -f 'profiles/input/hog-lib.c' || echo '$(srcdir)/'`profiles/input/hog-lib.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-hog-lib.Tpo profiles/input/$(DEPDIR)/bluetoothd-hog-lib.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/input/hog-lib.c' object='profiles/input/bluetoothd-hog-lib.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-hog-lib.o `test -f 'profiles/input/hog-lib.c' || echo '$(srcdir)/'`profiles/input/hog-lib.c + +profiles/input/bluetoothd-hog-lib.obj: profiles/input/hog-lib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-hog-lib.obj -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-hog-lib.Tpo -c -o profiles/input/bluetoothd-hog-lib.obj `if test -f 'profiles/input/hog-lib.c'; then $(CYGPATH_W) 'profiles/input/hog-lib.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/hog-lib.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-hog-lib.Tpo profiles/input/$(DEPDIR)/bluetoothd-hog-lib.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/input/hog-lib.c' object='profiles/input/bluetoothd-hog-lib.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-hog-lib.obj `if test -f 'profiles/input/hog-lib.c'; then $(CYGPATH_W) 'profiles/input/hog-lib.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/hog-lib.c'; fi` + +profiles/deviceinfo/bluetoothd-dis.o: profiles/deviceinfo/dis.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/deviceinfo/bluetoothd-dis.o -MD -MP -MF profiles/deviceinfo/$(DEPDIR)/bluetoothd-dis.Tpo -c -o profiles/deviceinfo/bluetoothd-dis.o `test -f 'profiles/deviceinfo/dis.c' || echo '$(srcdir)/'`profiles/deviceinfo/dis.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/deviceinfo/$(DEPDIR)/bluetoothd-dis.Tpo profiles/deviceinfo/$(DEPDIR)/bluetoothd-dis.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/deviceinfo/dis.c' object='profiles/deviceinfo/bluetoothd-dis.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/deviceinfo/bluetoothd-dis.o `test -f 'profiles/deviceinfo/dis.c' || echo '$(srcdir)/'`profiles/deviceinfo/dis.c + +profiles/deviceinfo/bluetoothd-dis.obj: profiles/deviceinfo/dis.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/deviceinfo/bluetoothd-dis.obj -MD -MP -MF profiles/deviceinfo/$(DEPDIR)/bluetoothd-dis.Tpo -c -o profiles/deviceinfo/bluetoothd-dis.obj `if test -f 'profiles/deviceinfo/dis.c'; then $(CYGPATH_W) 'profiles/deviceinfo/dis.c'; else $(CYGPATH_W) '$(srcdir)/profiles/deviceinfo/dis.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/deviceinfo/$(DEPDIR)/bluetoothd-dis.Tpo profiles/deviceinfo/$(DEPDIR)/bluetoothd-dis.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/deviceinfo/dis.c' object='profiles/deviceinfo/bluetoothd-dis.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/deviceinfo/bluetoothd-dis.obj `if test -f 'profiles/deviceinfo/dis.c'; then $(CYGPATH_W) 'profiles/deviceinfo/dis.c'; else $(CYGPATH_W) '$(srcdir)/profiles/deviceinfo/dis.c'; fi` + +profiles/battery/bluetoothd-bas.o: profiles/battery/bas.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/battery/bluetoothd-bas.o -MD -MP -MF profiles/battery/$(DEPDIR)/bluetoothd-bas.Tpo -c -o profiles/battery/bluetoothd-bas.o `test -f 'profiles/battery/bas.c' || echo '$(srcdir)/'`profiles/battery/bas.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/battery/$(DEPDIR)/bluetoothd-bas.Tpo profiles/battery/$(DEPDIR)/bluetoothd-bas.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/battery/bas.c' object='profiles/battery/bluetoothd-bas.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/battery/bluetoothd-bas.o `test -f 'profiles/battery/bas.c' || echo '$(srcdir)/'`profiles/battery/bas.c + +profiles/battery/bluetoothd-bas.obj: profiles/battery/bas.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/battery/bluetoothd-bas.obj -MD -MP -MF profiles/battery/$(DEPDIR)/bluetoothd-bas.Tpo -c -o profiles/battery/bluetoothd-bas.obj `if test -f 'profiles/battery/bas.c'; then $(CYGPATH_W) 'profiles/battery/bas.c'; else $(CYGPATH_W) '$(srcdir)/profiles/battery/bas.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/battery/$(DEPDIR)/bluetoothd-bas.Tpo profiles/battery/$(DEPDIR)/bluetoothd-bas.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/battery/bas.c' object='profiles/battery/bluetoothd-bas.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/battery/bluetoothd-bas.obj `if test -f 'profiles/battery/bas.c'; then $(CYGPATH_W) 'profiles/battery/bas.c'; else $(CYGPATH_W) '$(srcdir)/profiles/battery/bas.c'; fi` + +profiles/scanparam/bluetoothd-scpp.o: profiles/scanparam/scpp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/scanparam/bluetoothd-scpp.o -MD -MP -MF profiles/scanparam/$(DEPDIR)/bluetoothd-scpp.Tpo -c -o profiles/scanparam/bluetoothd-scpp.o `test -f 'profiles/scanparam/scpp.c' || echo '$(srcdir)/'`profiles/scanparam/scpp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/scanparam/$(DEPDIR)/bluetoothd-scpp.Tpo profiles/scanparam/$(DEPDIR)/bluetoothd-scpp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/scanparam/scpp.c' object='profiles/scanparam/bluetoothd-scpp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/scanparam/bluetoothd-scpp.o `test -f 'profiles/scanparam/scpp.c' || echo '$(srcdir)/'`profiles/scanparam/scpp.c + +profiles/scanparam/bluetoothd-scpp.obj: profiles/scanparam/scpp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/scanparam/bluetoothd-scpp.obj -MD -MP -MF profiles/scanparam/$(DEPDIR)/bluetoothd-scpp.Tpo -c -o profiles/scanparam/bluetoothd-scpp.obj `if test -f 'profiles/scanparam/scpp.c'; then $(CYGPATH_W) 'profiles/scanparam/scpp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/scanparam/scpp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/scanparam/$(DEPDIR)/bluetoothd-scpp.Tpo profiles/scanparam/$(DEPDIR)/bluetoothd-scpp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/scanparam/scpp.c' object='profiles/scanparam/bluetoothd-scpp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/scanparam/bluetoothd-scpp.obj `if test -f 'profiles/scanparam/scpp.c'; then $(CYGPATH_W) 'profiles/scanparam/scpp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/scanparam/scpp.c'; fi` + +profiles/input/bluetoothd-suspend-none.o: profiles/input/suspend-none.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-suspend-none.o -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-suspend-none.Tpo -c -o profiles/input/bluetoothd-suspend-none.o `test -f 'profiles/input/suspend-none.c' || echo '$(srcdir)/'`profiles/input/suspend-none.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-suspend-none.Tpo profiles/input/$(DEPDIR)/bluetoothd-suspend-none.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/input/suspend-none.c' object='profiles/input/bluetoothd-suspend-none.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-suspend-none.o `test -f 'profiles/input/suspend-none.c' || echo '$(srcdir)/'`profiles/input/suspend-none.c + +profiles/input/bluetoothd-suspend-none.obj: profiles/input/suspend-none.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-suspend-none.obj -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-suspend-none.Tpo -c -o profiles/input/bluetoothd-suspend-none.obj `if test -f 'profiles/input/suspend-none.c'; then $(CYGPATH_W) 'profiles/input/suspend-none.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/suspend-none.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-suspend-none.Tpo profiles/input/$(DEPDIR)/bluetoothd-suspend-none.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/input/suspend-none.c' object='profiles/input/bluetoothd-suspend-none.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-suspend-none.obj `if test -f 'profiles/input/suspend-none.c'; then $(CYGPATH_W) 'profiles/input/suspend-none.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/suspend-none.c'; fi` + +profiles/health/bluetoothd-mcap.o: profiles/health/mcap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-mcap.o -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-mcap.Tpo -c -o profiles/health/bluetoothd-mcap.o `test -f 'profiles/health/mcap.c' || echo '$(srcdir)/'`profiles/health/mcap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-mcap.Tpo profiles/health/$(DEPDIR)/bluetoothd-mcap.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/health/mcap.c' object='profiles/health/bluetoothd-mcap.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-mcap.o `test -f 'profiles/health/mcap.c' || echo '$(srcdir)/'`profiles/health/mcap.c + +profiles/health/bluetoothd-mcap.obj: profiles/health/mcap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-mcap.obj -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-mcap.Tpo -c -o profiles/health/bluetoothd-mcap.obj `if test -f 'profiles/health/mcap.c'; then $(CYGPATH_W) 'profiles/health/mcap.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/mcap.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-mcap.Tpo profiles/health/$(DEPDIR)/bluetoothd-mcap.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/health/mcap.c' object='profiles/health/bluetoothd-mcap.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-mcap.obj `if test -f 'profiles/health/mcap.c'; then $(CYGPATH_W) 'profiles/health/mcap.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/mcap.c'; fi` + +profiles/health/bluetoothd-hdp_main.o: profiles/health/hdp_main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-hdp_main.o -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-hdp_main.Tpo -c -o profiles/health/bluetoothd-hdp_main.o `test -f 'profiles/health/hdp_main.c' || echo '$(srcdir)/'`profiles/health/hdp_main.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-hdp_main.Tpo profiles/health/$(DEPDIR)/bluetoothd-hdp_main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/health/hdp_main.c' object='profiles/health/bluetoothd-hdp_main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-hdp_main.o `test -f 'profiles/health/hdp_main.c' || echo '$(srcdir)/'`profiles/health/hdp_main.c + +profiles/health/bluetoothd-hdp_main.obj: profiles/health/hdp_main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-hdp_main.obj -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-hdp_main.Tpo -c -o profiles/health/bluetoothd-hdp_main.obj `if test -f 'profiles/health/hdp_main.c'; then $(CYGPATH_W) 'profiles/health/hdp_main.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/hdp_main.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-hdp_main.Tpo profiles/health/$(DEPDIR)/bluetoothd-hdp_main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/health/hdp_main.c' object='profiles/health/bluetoothd-hdp_main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-hdp_main.obj `if test -f 'profiles/health/hdp_main.c'; then $(CYGPATH_W) 'profiles/health/hdp_main.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/hdp_main.c'; fi` + +profiles/health/bluetoothd-hdp_manager.o: profiles/health/hdp_manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-hdp_manager.o -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-hdp_manager.Tpo -c -o profiles/health/bluetoothd-hdp_manager.o `test -f 'profiles/health/hdp_manager.c' || echo '$(srcdir)/'`profiles/health/hdp_manager.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-hdp_manager.Tpo profiles/health/$(DEPDIR)/bluetoothd-hdp_manager.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/health/hdp_manager.c' object='profiles/health/bluetoothd-hdp_manager.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-hdp_manager.o `test -f 'profiles/health/hdp_manager.c' || echo '$(srcdir)/'`profiles/health/hdp_manager.c + +profiles/health/bluetoothd-hdp_manager.obj: profiles/health/hdp_manager.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-hdp_manager.obj -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-hdp_manager.Tpo -c -o profiles/health/bluetoothd-hdp_manager.obj `if test -f 'profiles/health/hdp_manager.c'; then $(CYGPATH_W) 'profiles/health/hdp_manager.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/hdp_manager.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-hdp_manager.Tpo profiles/health/$(DEPDIR)/bluetoothd-hdp_manager.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/health/hdp_manager.c' object='profiles/health/bluetoothd-hdp_manager.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-hdp_manager.obj `if test -f 'profiles/health/hdp_manager.c'; then $(CYGPATH_W) 'profiles/health/hdp_manager.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/hdp_manager.c'; fi` + +profiles/health/bluetoothd-hdp.o: profiles/health/hdp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-hdp.o -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-hdp.Tpo -c -o profiles/health/bluetoothd-hdp.o `test -f 'profiles/health/hdp.c' || echo '$(srcdir)/'`profiles/health/hdp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-hdp.Tpo profiles/health/$(DEPDIR)/bluetoothd-hdp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/health/hdp.c' object='profiles/health/bluetoothd-hdp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-hdp.o `test -f 'profiles/health/hdp.c' || echo '$(srcdir)/'`profiles/health/hdp.c + +profiles/health/bluetoothd-hdp.obj: profiles/health/hdp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-hdp.obj -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-hdp.Tpo -c -o profiles/health/bluetoothd-hdp.obj `if test -f 'profiles/health/hdp.c'; then $(CYGPATH_W) 'profiles/health/hdp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/hdp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-hdp.Tpo profiles/health/$(DEPDIR)/bluetoothd-hdp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/health/hdp.c' object='profiles/health/bluetoothd-hdp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-hdp.obj `if test -f 'profiles/health/hdp.c'; then $(CYGPATH_W) 'profiles/health/hdp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/hdp.c'; fi` + +profiles/health/bluetoothd-hdp_util.o: profiles/health/hdp_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-hdp_util.o -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-hdp_util.Tpo -c -o profiles/health/bluetoothd-hdp_util.o `test -f 'profiles/health/hdp_util.c' || echo '$(srcdir)/'`profiles/health/hdp_util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-hdp_util.Tpo profiles/health/$(DEPDIR)/bluetoothd-hdp_util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/health/hdp_util.c' object='profiles/health/bluetoothd-hdp_util.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-hdp_util.o `test -f 'profiles/health/hdp_util.c' || echo '$(srcdir)/'`profiles/health/hdp_util.c + +profiles/health/bluetoothd-hdp_util.obj: profiles/health/hdp_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-hdp_util.obj -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-hdp_util.Tpo -c -o profiles/health/bluetoothd-hdp_util.obj `if test -f 'profiles/health/hdp_util.c'; then $(CYGPATH_W) 'profiles/health/hdp_util.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/hdp_util.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-hdp_util.Tpo profiles/health/$(DEPDIR)/bluetoothd-hdp_util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/health/hdp_util.c' object='profiles/health/bluetoothd-hdp_util.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-hdp_util.obj `if test -f 'profiles/health/hdp_util.c'; then $(CYGPATH_W) 'profiles/health/hdp_util.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/hdp_util.c'; fi` + +profiles/gap/bluetoothd-gas.o: profiles/gap/gas.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/gap/bluetoothd-gas.o -MD -MP -MF profiles/gap/$(DEPDIR)/bluetoothd-gas.Tpo -c -o profiles/gap/bluetoothd-gas.o `test -f 'profiles/gap/gas.c' || echo '$(srcdir)/'`profiles/gap/gas.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/gap/$(DEPDIR)/bluetoothd-gas.Tpo profiles/gap/$(DEPDIR)/bluetoothd-gas.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/gap/gas.c' object='profiles/gap/bluetoothd-gas.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/gap/bluetoothd-gas.o `test -f 'profiles/gap/gas.c' || echo '$(srcdir)/'`profiles/gap/gas.c + +profiles/gap/bluetoothd-gas.obj: profiles/gap/gas.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/gap/bluetoothd-gas.obj -MD -MP -MF profiles/gap/$(DEPDIR)/bluetoothd-gas.Tpo -c -o profiles/gap/bluetoothd-gas.obj `if test -f 'profiles/gap/gas.c'; then $(CYGPATH_W) 'profiles/gap/gas.c'; else $(CYGPATH_W) '$(srcdir)/profiles/gap/gas.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/gap/$(DEPDIR)/bluetoothd-gas.Tpo profiles/gap/$(DEPDIR)/bluetoothd-gas.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/gap/gas.c' object='profiles/gap/bluetoothd-gas.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/gap/bluetoothd-gas.obj `if test -f 'profiles/gap/gas.c'; then $(CYGPATH_W) 'profiles/gap/gas.c'; else $(CYGPATH_W) '$(srcdir)/profiles/gap/gas.c'; fi` + +profiles/scanparam/bluetoothd-scan.o: profiles/scanparam/scan.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/scanparam/bluetoothd-scan.o -MD -MP -MF profiles/scanparam/$(DEPDIR)/bluetoothd-scan.Tpo -c -o profiles/scanparam/bluetoothd-scan.o `test -f 'profiles/scanparam/scan.c' || echo '$(srcdir)/'`profiles/scanparam/scan.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/scanparam/$(DEPDIR)/bluetoothd-scan.Tpo profiles/scanparam/$(DEPDIR)/bluetoothd-scan.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/scanparam/scan.c' object='profiles/scanparam/bluetoothd-scan.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/scanparam/bluetoothd-scan.o `test -f 'profiles/scanparam/scan.c' || echo '$(srcdir)/'`profiles/scanparam/scan.c + +profiles/scanparam/bluetoothd-scan.obj: profiles/scanparam/scan.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/scanparam/bluetoothd-scan.obj -MD -MP -MF profiles/scanparam/$(DEPDIR)/bluetoothd-scan.Tpo -c -o profiles/scanparam/bluetoothd-scan.obj `if test -f 'profiles/scanparam/scan.c'; then $(CYGPATH_W) 'profiles/scanparam/scan.c'; else $(CYGPATH_W) '$(srcdir)/profiles/scanparam/scan.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/scanparam/$(DEPDIR)/bluetoothd-scan.Tpo profiles/scanparam/$(DEPDIR)/bluetoothd-scan.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/scanparam/scan.c' object='profiles/scanparam/bluetoothd-scan.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/scanparam/bluetoothd-scan.obj `if test -f 'profiles/scanparam/scan.c'; then $(CYGPATH_W) 'profiles/scanparam/scan.c'; else $(CYGPATH_W) '$(srcdir)/profiles/scanparam/scan.c'; fi` + +profiles/deviceinfo/bluetoothd-deviceinfo.o: profiles/deviceinfo/deviceinfo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/deviceinfo/bluetoothd-deviceinfo.o -MD -MP -MF profiles/deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Tpo -c -o profiles/deviceinfo/bluetoothd-deviceinfo.o `test -f 'profiles/deviceinfo/deviceinfo.c' || echo '$(srcdir)/'`profiles/deviceinfo/deviceinfo.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Tpo profiles/deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/deviceinfo/deviceinfo.c' object='profiles/deviceinfo/bluetoothd-deviceinfo.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/deviceinfo/bluetoothd-deviceinfo.o `test -f 'profiles/deviceinfo/deviceinfo.c' || echo '$(srcdir)/'`profiles/deviceinfo/deviceinfo.c + +profiles/deviceinfo/bluetoothd-deviceinfo.obj: profiles/deviceinfo/deviceinfo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/deviceinfo/bluetoothd-deviceinfo.obj -MD -MP -MF profiles/deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Tpo -c -o profiles/deviceinfo/bluetoothd-deviceinfo.obj `if test -f 'profiles/deviceinfo/deviceinfo.c'; then $(CYGPATH_W) 'profiles/deviceinfo/deviceinfo.c'; else $(CYGPATH_W) '$(srcdir)/profiles/deviceinfo/deviceinfo.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Tpo profiles/deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/deviceinfo/deviceinfo.c' object='profiles/deviceinfo/bluetoothd-deviceinfo.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/deviceinfo/bluetoothd-deviceinfo.obj `if test -f 'profiles/deviceinfo/deviceinfo.c'; then $(CYGPATH_W) 'profiles/deviceinfo/deviceinfo.c'; else $(CYGPATH_W) '$(srcdir)/profiles/deviceinfo/deviceinfo.c'; fi` + +profiles/midi/bluetoothd-midi.o: profiles/midi/midi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/midi/bluetoothd-midi.o -MD -MP -MF profiles/midi/$(DEPDIR)/bluetoothd-midi.Tpo -c -o profiles/midi/bluetoothd-midi.o `test -f 'profiles/midi/midi.c' || echo '$(srcdir)/'`profiles/midi/midi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/midi/$(DEPDIR)/bluetoothd-midi.Tpo profiles/midi/$(DEPDIR)/bluetoothd-midi.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/midi/midi.c' object='profiles/midi/bluetoothd-midi.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/midi/bluetoothd-midi.o `test -f 'profiles/midi/midi.c' || echo '$(srcdir)/'`profiles/midi/midi.c + +profiles/midi/bluetoothd-midi.obj: profiles/midi/midi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/midi/bluetoothd-midi.obj -MD -MP -MF profiles/midi/$(DEPDIR)/bluetoothd-midi.Tpo -c -o profiles/midi/bluetoothd-midi.obj `if test -f 'profiles/midi/midi.c'; then $(CYGPATH_W) 'profiles/midi/midi.c'; else $(CYGPATH_W) '$(srcdir)/profiles/midi/midi.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/midi/$(DEPDIR)/bluetoothd-midi.Tpo profiles/midi/$(DEPDIR)/bluetoothd-midi.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/midi/midi.c' object='profiles/midi/bluetoothd-midi.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/midi/bluetoothd-midi.obj `if test -f 'profiles/midi/midi.c'; then $(CYGPATH_W) 'profiles/midi/midi.c'; else $(CYGPATH_W) '$(srcdir)/profiles/midi/midi.c'; fi` + +profiles/midi/bluetoothd-libmidi.o: profiles/midi/libmidi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/midi/bluetoothd-libmidi.o -MD -MP -MF profiles/midi/$(DEPDIR)/bluetoothd-libmidi.Tpo -c -o profiles/midi/bluetoothd-libmidi.o `test -f 'profiles/midi/libmidi.c' || echo '$(srcdir)/'`profiles/midi/libmidi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/midi/$(DEPDIR)/bluetoothd-libmidi.Tpo profiles/midi/$(DEPDIR)/bluetoothd-libmidi.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/midi/libmidi.c' object='profiles/midi/bluetoothd-libmidi.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/midi/bluetoothd-libmidi.o `test -f 'profiles/midi/libmidi.c' || echo '$(srcdir)/'`profiles/midi/libmidi.c + +profiles/midi/bluetoothd-libmidi.obj: profiles/midi/libmidi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/midi/bluetoothd-libmidi.obj -MD -MP -MF profiles/midi/$(DEPDIR)/bluetoothd-libmidi.Tpo -c -o profiles/midi/bluetoothd-libmidi.obj `if test -f 'profiles/midi/libmidi.c'; then $(CYGPATH_W) 'profiles/midi/libmidi.c'; else $(CYGPATH_W) '$(srcdir)/profiles/midi/libmidi.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/midi/$(DEPDIR)/bluetoothd-libmidi.Tpo profiles/midi/$(DEPDIR)/bluetoothd-libmidi.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/midi/libmidi.c' object='profiles/midi/bluetoothd-libmidi.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/midi/bluetoothd-libmidi.obj `if test -f 'profiles/midi/libmidi.c'; then $(CYGPATH_W) 'profiles/midi/libmidi.c'; else $(CYGPATH_W) '$(srcdir)/profiles/midi/libmidi.c'; fi` + +profiles/battery/bluetoothd-battery.o: profiles/battery/battery.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/battery/bluetoothd-battery.o -MD -MP -MF profiles/battery/$(DEPDIR)/bluetoothd-battery.Tpo -c -o profiles/battery/bluetoothd-battery.o `test -f 'profiles/battery/battery.c' || echo '$(srcdir)/'`profiles/battery/battery.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/battery/$(DEPDIR)/bluetoothd-battery.Tpo profiles/battery/$(DEPDIR)/bluetoothd-battery.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/battery/battery.c' object='profiles/battery/bluetoothd-battery.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/battery/bluetoothd-battery.o `test -f 'profiles/battery/battery.c' || echo '$(srcdir)/'`profiles/battery/battery.c + +profiles/battery/bluetoothd-battery.obj: profiles/battery/battery.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/battery/bluetoothd-battery.obj -MD -MP -MF profiles/battery/$(DEPDIR)/bluetoothd-battery.Tpo -c -o profiles/battery/bluetoothd-battery.obj `if test -f 'profiles/battery/battery.c'; then $(CYGPATH_W) 'profiles/battery/battery.c'; else $(CYGPATH_W) '$(srcdir)/profiles/battery/battery.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/battery/$(DEPDIR)/bluetoothd-battery.Tpo profiles/battery/$(DEPDIR)/bluetoothd-battery.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/battery/battery.c' object='profiles/battery/bluetoothd-battery.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/battery/bluetoothd-battery.obj `if test -f 'profiles/battery/battery.c'; then $(CYGPATH_W) 'profiles/battery/battery.c'; else $(CYGPATH_W) '$(srcdir)/profiles/battery/battery.c'; fi` + +plugins/bluetoothd-sixaxis.o: plugins/sixaxis.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-sixaxis.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-sixaxis.Tpo -c -o plugins/bluetoothd-sixaxis.o `test -f 'plugins/sixaxis.c' || echo '$(srcdir)/'`plugins/sixaxis.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-sixaxis.Tpo plugins/$(DEPDIR)/bluetoothd-sixaxis.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/sixaxis.c' object='plugins/bluetoothd-sixaxis.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-sixaxis.o `test -f 'plugins/sixaxis.c' || echo '$(srcdir)/'`plugins/sixaxis.c + +plugins/bluetoothd-sixaxis.obj: plugins/sixaxis.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-sixaxis.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-sixaxis.Tpo -c -o plugins/bluetoothd-sixaxis.obj `if test -f 'plugins/sixaxis.c'; then $(CYGPATH_W) 'plugins/sixaxis.c'; else $(CYGPATH_W) '$(srcdir)/plugins/sixaxis.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-sixaxis.Tpo plugins/$(DEPDIR)/bluetoothd-sixaxis.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/sixaxis.c' object='plugins/bluetoothd-sixaxis.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-sixaxis.obj `if test -f 'plugins/sixaxis.c'; then $(CYGPATH_W) 'plugins/sixaxis.c'; else $(CYGPATH_W) '$(srcdir)/plugins/sixaxis.c'; fi` + +profiles/audio/bluetoothd-bap.o: profiles/audio/bap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-bap.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-bap.Tpo -c -o profiles/audio/bluetoothd-bap.o `test -f 'profiles/audio/bap.c' || echo '$(srcdir)/'`profiles/audio/bap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-bap.Tpo profiles/audio/$(DEPDIR)/bluetoothd-bap.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/bap.c' object='profiles/audio/bluetoothd-bap.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-bap.o `test -f 'profiles/audio/bap.c' || echo '$(srcdir)/'`profiles/audio/bap.c + +profiles/audio/bluetoothd-bap.obj: profiles/audio/bap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-bap.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-bap.Tpo -c -o profiles/audio/bluetoothd-bap.obj `if test -f 'profiles/audio/bap.c'; then $(CYGPATH_W) 'profiles/audio/bap.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/bap.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-bap.Tpo profiles/audio/$(DEPDIR)/bluetoothd-bap.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/bap.c' object='profiles/audio/bluetoothd-bap.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-bap.obj `if test -f 'profiles/audio/bap.c'; then $(CYGPATH_W) 'profiles/audio/bap.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/bap.c'; fi` + +profiles/audio/bluetoothd-bass.o: profiles/audio/bass.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-bass.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-bass.Tpo -c -o profiles/audio/bluetoothd-bass.o `test -f 'profiles/audio/bass.c' || echo '$(srcdir)/'`profiles/audio/bass.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-bass.Tpo profiles/audio/$(DEPDIR)/bluetoothd-bass.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/bass.c' object='profiles/audio/bluetoothd-bass.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-bass.o `test -f 'profiles/audio/bass.c' || echo '$(srcdir)/'`profiles/audio/bass.c + +profiles/audio/bluetoothd-bass.obj: profiles/audio/bass.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-bass.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-bass.Tpo -c -o profiles/audio/bluetoothd-bass.obj `if test -f 'profiles/audio/bass.c'; then $(CYGPATH_W) 'profiles/audio/bass.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/bass.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-bass.Tpo profiles/audio/$(DEPDIR)/bluetoothd-bass.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/bass.c' object='profiles/audio/bluetoothd-bass.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-bass.obj `if test -f 'profiles/audio/bass.c'; then $(CYGPATH_W) 'profiles/audio/bass.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/bass.c'; fi` + +profiles/audio/bluetoothd-mcp.o: profiles/audio/mcp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-mcp.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-mcp.Tpo -c -o profiles/audio/bluetoothd-mcp.o `test -f 'profiles/audio/mcp.c' || echo '$(srcdir)/'`profiles/audio/mcp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-mcp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-mcp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/mcp.c' object='profiles/audio/bluetoothd-mcp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-mcp.o `test -f 'profiles/audio/mcp.c' || echo '$(srcdir)/'`profiles/audio/mcp.c + +profiles/audio/bluetoothd-mcp.obj: profiles/audio/mcp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-mcp.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-mcp.Tpo -c -o profiles/audio/bluetoothd-mcp.obj `if test -f 'profiles/audio/mcp.c'; then $(CYGPATH_W) 'profiles/audio/mcp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/mcp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-mcp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-mcp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/mcp.c' object='profiles/audio/bluetoothd-mcp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-mcp.obj `if test -f 'profiles/audio/mcp.c'; then $(CYGPATH_W) 'profiles/audio/mcp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/mcp.c'; fi` + +profiles/audio/bluetoothd-vcp.o: profiles/audio/vcp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-vcp.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-vcp.Tpo -c -o profiles/audio/bluetoothd-vcp.o `test -f 'profiles/audio/vcp.c' || echo '$(srcdir)/'`profiles/audio/vcp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-vcp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-vcp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/vcp.c' object='profiles/audio/bluetoothd-vcp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-vcp.o `test -f 'profiles/audio/vcp.c' || echo '$(srcdir)/'`profiles/audio/vcp.c + +profiles/audio/bluetoothd-vcp.obj: profiles/audio/vcp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-vcp.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-vcp.Tpo -c -o profiles/audio/bluetoothd-vcp.obj `if test -f 'profiles/audio/vcp.c'; then $(CYGPATH_W) 'profiles/audio/vcp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/vcp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-vcp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-vcp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/vcp.c' object='profiles/audio/bluetoothd-vcp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-vcp.obj `if test -f 'profiles/audio/vcp.c'; then $(CYGPATH_W) 'profiles/audio/vcp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/vcp.c'; fi` + +profiles/audio/bluetoothd-micp.o: profiles/audio/micp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-micp.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-micp.Tpo -c -o profiles/audio/bluetoothd-micp.o `test -f 'profiles/audio/micp.c' || echo '$(srcdir)/'`profiles/audio/micp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-micp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-micp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/micp.c' object='profiles/audio/bluetoothd-micp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-micp.o `test -f 'profiles/audio/micp.c' || echo '$(srcdir)/'`profiles/audio/micp.c + +profiles/audio/bluetoothd-micp.obj: profiles/audio/micp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-micp.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-micp.Tpo -c -o profiles/audio/bluetoothd-micp.obj `if test -f 'profiles/audio/micp.c'; then $(CYGPATH_W) 'profiles/audio/micp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/micp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-micp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-micp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/micp.c' object='profiles/audio/bluetoothd-micp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-micp.obj `if test -f 'profiles/audio/micp.c'; then $(CYGPATH_W) 'profiles/audio/micp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/micp.c'; fi` + +profiles/audio/bluetoothd-ccp.o: profiles/audio/ccp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-ccp.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-ccp.Tpo -c -o profiles/audio/bluetoothd-ccp.o `test -f 'profiles/audio/ccp.c' || echo '$(srcdir)/'`profiles/audio/ccp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-ccp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-ccp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/ccp.c' object='profiles/audio/bluetoothd-ccp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-ccp.o `test -f 'profiles/audio/ccp.c' || echo '$(srcdir)/'`profiles/audio/ccp.c + +profiles/audio/bluetoothd-ccp.obj: profiles/audio/ccp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-ccp.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-ccp.Tpo -c -o profiles/audio/bluetoothd-ccp.obj `if test -f 'profiles/audio/ccp.c'; then $(CYGPATH_W) 'profiles/audio/ccp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/ccp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-ccp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-ccp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/ccp.c' object='profiles/audio/bluetoothd-ccp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-ccp.obj `if test -f 'profiles/audio/ccp.c'; then $(CYGPATH_W) 'profiles/audio/ccp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/ccp.c'; fi` + +profiles/audio/bluetoothd-csip.o: profiles/audio/csip.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-csip.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-csip.Tpo -c -o profiles/audio/bluetoothd-csip.o `test -f 'profiles/audio/csip.c' || echo '$(srcdir)/'`profiles/audio/csip.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-csip.Tpo profiles/audio/$(DEPDIR)/bluetoothd-csip.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/csip.c' object='profiles/audio/bluetoothd-csip.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-csip.o `test -f 'profiles/audio/csip.c' || echo '$(srcdir)/'`profiles/audio/csip.c + +profiles/audio/bluetoothd-csip.obj: profiles/audio/csip.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-csip.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-csip.Tpo -c -o profiles/audio/bluetoothd-csip.obj `if test -f 'profiles/audio/csip.c'; then $(CYGPATH_W) 'profiles/audio/csip.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/csip.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-csip.Tpo profiles/audio/$(DEPDIR)/bluetoothd-csip.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/csip.c' object='profiles/audio/bluetoothd-csip.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-csip.obj `if test -f 'profiles/audio/csip.c'; then $(CYGPATH_W) 'profiles/audio/csip.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/csip.c'; fi` + +profiles/audio/bluetoothd-asha.o: profiles/audio/asha.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-asha.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-asha.Tpo -c -o profiles/audio/bluetoothd-asha.o `test -f 'profiles/audio/asha.c' || echo '$(srcdir)/'`profiles/audio/asha.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-asha.Tpo profiles/audio/$(DEPDIR)/bluetoothd-asha.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/asha.c' object='profiles/audio/bluetoothd-asha.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-asha.o `test -f 'profiles/audio/asha.c' || echo '$(srcdir)/'`profiles/audio/asha.c + +profiles/audio/bluetoothd-asha.obj: profiles/audio/asha.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-asha.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-asha.Tpo -c -o profiles/audio/bluetoothd-asha.obj `if test -f 'profiles/audio/asha.c'; then $(CYGPATH_W) 'profiles/audio/asha.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/asha.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-asha.Tpo profiles/audio/$(DEPDIR)/bluetoothd-asha.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/audio/asha.c' object='profiles/audio/bluetoothd-asha.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-asha.obj `if test -f 'profiles/audio/asha.c'; then $(CYGPATH_W) 'profiles/audio/asha.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/asha.c'; fi` + +attrib/bluetoothd-att.o: attrib/att.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-att.o -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-att.Tpo -c -o attrib/bluetoothd-att.o `test -f 'attrib/att.c' || echo '$(srcdir)/'`attrib/att.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-att.Tpo attrib/$(DEPDIR)/bluetoothd-att.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrib/att.c' object='attrib/bluetoothd-att.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-att.o `test -f 'attrib/att.c' || echo '$(srcdir)/'`attrib/att.c + +attrib/bluetoothd-att.obj: attrib/att.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-att.obj -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-att.Tpo -c -o attrib/bluetoothd-att.obj `if test -f 'attrib/att.c'; then $(CYGPATH_W) 'attrib/att.c'; else $(CYGPATH_W) '$(srcdir)/attrib/att.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-att.Tpo attrib/$(DEPDIR)/bluetoothd-att.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrib/att.c' object='attrib/bluetoothd-att.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-att.obj `if test -f 'attrib/att.c'; then $(CYGPATH_W) 'attrib/att.c'; else $(CYGPATH_W) '$(srcdir)/attrib/att.c'; fi` + +attrib/bluetoothd-gatt.o: attrib/gatt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-gatt.o -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-gatt.Tpo -c -o attrib/bluetoothd-gatt.o `test -f 'attrib/gatt.c' || echo '$(srcdir)/'`attrib/gatt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-gatt.Tpo attrib/$(DEPDIR)/bluetoothd-gatt.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrib/gatt.c' object='attrib/bluetoothd-gatt.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-gatt.o `test -f 'attrib/gatt.c' || echo '$(srcdir)/'`attrib/gatt.c + +attrib/bluetoothd-gatt.obj: attrib/gatt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-gatt.obj -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-gatt.Tpo -c -o attrib/bluetoothd-gatt.obj `if test -f 'attrib/gatt.c'; then $(CYGPATH_W) 'attrib/gatt.c'; else $(CYGPATH_W) '$(srcdir)/attrib/gatt.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-gatt.Tpo attrib/$(DEPDIR)/bluetoothd-gatt.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrib/gatt.c' object='attrib/bluetoothd-gatt.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-gatt.obj `if test -f 'attrib/gatt.c'; then $(CYGPATH_W) 'attrib/gatt.c'; else $(CYGPATH_W) '$(srcdir)/attrib/gatt.c'; fi` + +attrib/bluetoothd-gattrib.o: attrib/gattrib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-gattrib.o -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-gattrib.Tpo -c -o attrib/bluetoothd-gattrib.o `test -f 'attrib/gattrib.c' || echo '$(srcdir)/'`attrib/gattrib.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-gattrib.Tpo attrib/$(DEPDIR)/bluetoothd-gattrib.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrib/gattrib.c' object='attrib/bluetoothd-gattrib.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-gattrib.o `test -f 'attrib/gattrib.c' || echo '$(srcdir)/'`attrib/gattrib.c + +attrib/bluetoothd-gattrib.obj: attrib/gattrib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-gattrib.obj -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-gattrib.Tpo -c -o attrib/bluetoothd-gattrib.obj `if test -f 'attrib/gattrib.c'; then $(CYGPATH_W) 'attrib/gattrib.c'; else $(CYGPATH_W) '$(srcdir)/attrib/gattrib.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-gattrib.Tpo attrib/$(DEPDIR)/bluetoothd-gattrib.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrib/gattrib.c' object='attrib/bluetoothd-gattrib.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-gattrib.obj `if test -f 'attrib/gattrib.c'; then $(CYGPATH_W) 'attrib/gattrib.c'; else $(CYGPATH_W) '$(srcdir)/attrib/gattrib.c'; fi` + +btio/bluetoothd-btio.o: btio/btio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT btio/bluetoothd-btio.o -MD -MP -MF btio/$(DEPDIR)/bluetoothd-btio.Tpo -c -o btio/bluetoothd-btio.o `test -f 'btio/btio.c' || echo '$(srcdir)/'`btio/btio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btio/$(DEPDIR)/bluetoothd-btio.Tpo btio/$(DEPDIR)/bluetoothd-btio.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btio/btio.c' object='btio/bluetoothd-btio.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o btio/bluetoothd-btio.o `test -f 'btio/btio.c' || echo '$(srcdir)/'`btio/btio.c + +btio/bluetoothd-btio.obj: btio/btio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT btio/bluetoothd-btio.obj -MD -MP -MF btio/$(DEPDIR)/bluetoothd-btio.Tpo -c -o btio/bluetoothd-btio.obj `if test -f 'btio/btio.c'; then $(CYGPATH_W) 'btio/btio.c'; else $(CYGPATH_W) '$(srcdir)/btio/btio.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btio/$(DEPDIR)/bluetoothd-btio.Tpo btio/$(DEPDIR)/bluetoothd-btio.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btio/btio.c' object='btio/bluetoothd-btio.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o btio/bluetoothd-btio.obj `if test -f 'btio/btio.c'; then $(CYGPATH_W) 'btio/btio.c'; else $(CYGPATH_W) '$(srcdir)/btio/btio.c'; fi` + +src/bluetoothd-main.o: src/main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-main.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-main.Tpo -c -o src/bluetoothd-main.o `test -f 'src/main.c' || echo '$(srcdir)/'`src/main.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-main.Tpo src/$(DEPDIR)/bluetoothd-main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/main.c' object='src/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-main.o `test -f 'src/main.c' || echo '$(srcdir)/'`src/main.c + +src/bluetoothd-main.obj: src/main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-main.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-main.Tpo -c -o src/bluetoothd-main.obj `if test -f 'src/main.c'; then $(CYGPATH_W) 'src/main.c'; else $(CYGPATH_W) '$(srcdir)/src/main.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-main.Tpo src/$(DEPDIR)/bluetoothd-main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/main.c' object='src/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-main.obj `if test -f 'src/main.c'; then $(CYGPATH_W) 'src/main.c'; else $(CYGPATH_W) '$(srcdir)/src/main.c'; fi` + +src/bluetoothd-log.o: src/log.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-log.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-log.Tpo -c -o src/bluetoothd-log.o `test -f 'src/log.c' || echo '$(srcdir)/'`src/log.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-log.Tpo src/$(DEPDIR)/bluetoothd-log.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/log.c' object='src/bluetoothd-log.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-log.o `test -f 'src/log.c' || echo '$(srcdir)/'`src/log.c + +src/bluetoothd-log.obj: src/log.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-log.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-log.Tpo -c -o src/bluetoothd-log.obj `if test -f 'src/log.c'; then $(CYGPATH_W) 'src/log.c'; else $(CYGPATH_W) '$(srcdir)/src/log.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-log.Tpo src/$(DEPDIR)/bluetoothd-log.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/log.c' object='src/bluetoothd-log.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-log.obj `if test -f 'src/log.c'; then $(CYGPATH_W) 'src/log.c'; else $(CYGPATH_W) '$(srcdir)/src/log.c'; fi` + +src/bluetoothd-backtrace.o: src/backtrace.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-backtrace.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-backtrace.Tpo -c -o src/bluetoothd-backtrace.o `test -f 'src/backtrace.c' || echo '$(srcdir)/'`src/backtrace.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-backtrace.Tpo src/$(DEPDIR)/bluetoothd-backtrace.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/backtrace.c' object='src/bluetoothd-backtrace.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-backtrace.o `test -f 'src/backtrace.c' || echo '$(srcdir)/'`src/backtrace.c + +src/bluetoothd-backtrace.obj: src/backtrace.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-backtrace.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-backtrace.Tpo -c -o src/bluetoothd-backtrace.obj `if test -f 'src/backtrace.c'; then $(CYGPATH_W) 'src/backtrace.c'; else $(CYGPATH_W) '$(srcdir)/src/backtrace.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-backtrace.Tpo src/$(DEPDIR)/bluetoothd-backtrace.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/backtrace.c' object='src/bluetoothd-backtrace.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-backtrace.obj `if test -f 'src/backtrace.c'; then $(CYGPATH_W) 'src/backtrace.c'; else $(CYGPATH_W) '$(srcdir)/src/backtrace.c'; fi` + +src/bluetoothd-rfkill.o: src/rfkill.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-rfkill.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-rfkill.Tpo -c -o src/bluetoothd-rfkill.o `test -f 'src/rfkill.c' || echo '$(srcdir)/'`src/rfkill.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-rfkill.Tpo src/$(DEPDIR)/bluetoothd-rfkill.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/rfkill.c' object='src/bluetoothd-rfkill.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-rfkill.o `test -f 'src/rfkill.c' || echo '$(srcdir)/'`src/rfkill.c + +src/bluetoothd-rfkill.obj: src/rfkill.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-rfkill.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-rfkill.Tpo -c -o src/bluetoothd-rfkill.obj `if test -f 'src/rfkill.c'; then $(CYGPATH_W) 'src/rfkill.c'; else $(CYGPATH_W) '$(srcdir)/src/rfkill.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-rfkill.Tpo src/$(DEPDIR)/bluetoothd-rfkill.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/rfkill.c' object='src/bluetoothd-rfkill.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-rfkill.obj `if test -f 'src/rfkill.c'; then $(CYGPATH_W) 'src/rfkill.c'; else $(CYGPATH_W) '$(srcdir)/src/rfkill.c'; fi` + +src/bluetoothd-sdpd-server.o: src/sdpd-server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdpd-server.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdpd-server.Tpo -c -o src/bluetoothd-sdpd-server.o `test -f 'src/sdpd-server.c' || echo '$(srcdir)/'`src/sdpd-server.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdpd-server.Tpo src/$(DEPDIR)/bluetoothd-sdpd-server.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdpd-server.c' object='src/bluetoothd-sdpd-server.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdpd-server.o `test -f 'src/sdpd-server.c' || echo '$(srcdir)/'`src/sdpd-server.c + +src/bluetoothd-sdpd-server.obj: src/sdpd-server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdpd-server.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdpd-server.Tpo -c -o src/bluetoothd-sdpd-server.obj `if test -f 'src/sdpd-server.c'; then $(CYGPATH_W) 'src/sdpd-server.c'; else $(CYGPATH_W) '$(srcdir)/src/sdpd-server.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdpd-server.Tpo src/$(DEPDIR)/bluetoothd-sdpd-server.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdpd-server.c' object='src/bluetoothd-sdpd-server.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdpd-server.obj `if test -f 'src/sdpd-server.c'; then $(CYGPATH_W) 'src/sdpd-server.c'; else $(CYGPATH_W) '$(srcdir)/src/sdpd-server.c'; fi` + +src/bluetoothd-sdpd-request.o: src/sdpd-request.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdpd-request.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdpd-request.Tpo -c -o src/bluetoothd-sdpd-request.o `test -f 'src/sdpd-request.c' || echo '$(srcdir)/'`src/sdpd-request.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdpd-request.Tpo src/$(DEPDIR)/bluetoothd-sdpd-request.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdpd-request.c' object='src/bluetoothd-sdpd-request.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdpd-request.o `test -f 'src/sdpd-request.c' || echo '$(srcdir)/'`src/sdpd-request.c + +src/bluetoothd-sdpd-request.obj: src/sdpd-request.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdpd-request.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdpd-request.Tpo -c -o src/bluetoothd-sdpd-request.obj `if test -f 'src/sdpd-request.c'; then $(CYGPATH_W) 'src/sdpd-request.c'; else $(CYGPATH_W) '$(srcdir)/src/sdpd-request.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdpd-request.Tpo src/$(DEPDIR)/bluetoothd-sdpd-request.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdpd-request.c' object='src/bluetoothd-sdpd-request.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdpd-request.obj `if test -f 'src/sdpd-request.c'; then $(CYGPATH_W) 'src/sdpd-request.c'; else $(CYGPATH_W) '$(srcdir)/src/sdpd-request.c'; fi` + +src/bluetoothd-sdpd-service.o: src/sdpd-service.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdpd-service.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdpd-service.Tpo -c -o src/bluetoothd-sdpd-service.o `test -f 'src/sdpd-service.c' || echo '$(srcdir)/'`src/sdpd-service.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdpd-service.Tpo src/$(DEPDIR)/bluetoothd-sdpd-service.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdpd-service.c' object='src/bluetoothd-sdpd-service.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdpd-service.o `test -f 'src/sdpd-service.c' || echo '$(srcdir)/'`src/sdpd-service.c + +src/bluetoothd-sdpd-service.obj: src/sdpd-service.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdpd-service.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdpd-service.Tpo -c -o src/bluetoothd-sdpd-service.obj `if test -f 'src/sdpd-service.c'; then $(CYGPATH_W) 'src/sdpd-service.c'; else $(CYGPATH_W) '$(srcdir)/src/sdpd-service.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdpd-service.Tpo src/$(DEPDIR)/bluetoothd-sdpd-service.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdpd-service.c' object='src/bluetoothd-sdpd-service.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdpd-service.obj `if test -f 'src/sdpd-service.c'; then $(CYGPATH_W) 'src/sdpd-service.c'; else $(CYGPATH_W) '$(srcdir)/src/sdpd-service.c'; fi` + +src/bluetoothd-sdpd-database.o: src/sdpd-database.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdpd-database.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdpd-database.Tpo -c -o src/bluetoothd-sdpd-database.o `test -f 'src/sdpd-database.c' || echo '$(srcdir)/'`src/sdpd-database.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdpd-database.Tpo src/$(DEPDIR)/bluetoothd-sdpd-database.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdpd-database.c' object='src/bluetoothd-sdpd-database.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdpd-database.o `test -f 'src/sdpd-database.c' || echo '$(srcdir)/'`src/sdpd-database.c + +src/bluetoothd-sdpd-database.obj: src/sdpd-database.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdpd-database.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdpd-database.Tpo -c -o src/bluetoothd-sdpd-database.obj `if test -f 'src/sdpd-database.c'; then $(CYGPATH_W) 'src/sdpd-database.c'; else $(CYGPATH_W) '$(srcdir)/src/sdpd-database.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdpd-database.Tpo src/$(DEPDIR)/bluetoothd-sdpd-database.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdpd-database.c' object='src/bluetoothd-sdpd-database.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdpd-database.obj `if test -f 'src/sdpd-database.c'; then $(CYGPATH_W) 'src/sdpd-database.c'; else $(CYGPATH_W) '$(srcdir)/src/sdpd-database.c'; fi` + +src/bluetoothd-gatt-database.o: src/gatt-database.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-gatt-database.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-gatt-database.Tpo -c -o src/bluetoothd-gatt-database.o `test -f 'src/gatt-database.c' || echo '$(srcdir)/'`src/gatt-database.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-gatt-database.Tpo src/$(DEPDIR)/bluetoothd-gatt-database.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/gatt-database.c' object='src/bluetoothd-gatt-database.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-gatt-database.o `test -f 'src/gatt-database.c' || echo '$(srcdir)/'`src/gatt-database.c + +src/bluetoothd-gatt-database.obj: src/gatt-database.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-gatt-database.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-gatt-database.Tpo -c -o src/bluetoothd-gatt-database.obj `if test -f 'src/gatt-database.c'; then $(CYGPATH_W) 'src/gatt-database.c'; else $(CYGPATH_W) '$(srcdir)/src/gatt-database.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-gatt-database.Tpo src/$(DEPDIR)/bluetoothd-gatt-database.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/gatt-database.c' object='src/bluetoothd-gatt-database.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-gatt-database.obj `if test -f 'src/gatt-database.c'; then $(CYGPATH_W) 'src/gatt-database.c'; else $(CYGPATH_W) '$(srcdir)/src/gatt-database.c'; fi` + +src/bluetoothd-sdp-xml.o: src/sdp-xml.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdp-xml.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdp-xml.Tpo -c -o src/bluetoothd-sdp-xml.o `test -f 'src/sdp-xml.c' || echo '$(srcdir)/'`src/sdp-xml.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdp-xml.Tpo src/$(DEPDIR)/bluetoothd-sdp-xml.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdp-xml.c' object='src/bluetoothd-sdp-xml.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdp-xml.o `test -f 'src/sdp-xml.c' || echo '$(srcdir)/'`src/sdp-xml.c + +src/bluetoothd-sdp-xml.obj: src/sdp-xml.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdp-xml.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdp-xml.Tpo -c -o src/bluetoothd-sdp-xml.obj `if test -f 'src/sdp-xml.c'; then $(CYGPATH_W) 'src/sdp-xml.c'; else $(CYGPATH_W) '$(srcdir)/src/sdp-xml.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdp-xml.Tpo src/$(DEPDIR)/bluetoothd-sdp-xml.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdp-xml.c' object='src/bluetoothd-sdp-xml.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdp-xml.obj `if test -f 'src/sdp-xml.c'; then $(CYGPATH_W) 'src/sdp-xml.c'; else $(CYGPATH_W) '$(srcdir)/src/sdp-xml.c'; fi` + +src/bluetoothd-sdp-client.o: src/sdp-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdp-client.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdp-client.Tpo -c -o src/bluetoothd-sdp-client.o `test -f 'src/sdp-client.c' || echo '$(srcdir)/'`src/sdp-client.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdp-client.Tpo src/$(DEPDIR)/bluetoothd-sdp-client.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdp-client.c' object='src/bluetoothd-sdp-client.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdp-client.o `test -f 'src/sdp-client.c' || echo '$(srcdir)/'`src/sdp-client.c + +src/bluetoothd-sdp-client.obj: src/sdp-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdp-client.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdp-client.Tpo -c -o src/bluetoothd-sdp-client.obj `if test -f 'src/sdp-client.c'; then $(CYGPATH_W) 'src/sdp-client.c'; else $(CYGPATH_W) '$(srcdir)/src/sdp-client.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdp-client.Tpo src/$(DEPDIR)/bluetoothd-sdp-client.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdp-client.c' object='src/bluetoothd-sdp-client.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdp-client.obj `if test -f 'src/sdp-client.c'; then $(CYGPATH_W) 'src/sdp-client.c'; else $(CYGPATH_W) '$(srcdir)/src/sdp-client.c'; fi` + +src/bluetoothd-textfile.o: src/textfile.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-textfile.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-textfile.Tpo -c -o src/bluetoothd-textfile.o `test -f 'src/textfile.c' || echo '$(srcdir)/'`src/textfile.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-textfile.Tpo src/$(DEPDIR)/bluetoothd-textfile.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/textfile.c' object='src/bluetoothd-textfile.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-textfile.o `test -f 'src/textfile.c' || echo '$(srcdir)/'`src/textfile.c + +src/bluetoothd-textfile.obj: src/textfile.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-textfile.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-textfile.Tpo -c -o src/bluetoothd-textfile.obj `if test -f 'src/textfile.c'; then $(CYGPATH_W) 'src/textfile.c'; else $(CYGPATH_W) '$(srcdir)/src/textfile.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-textfile.Tpo src/$(DEPDIR)/bluetoothd-textfile.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/textfile.c' object='src/bluetoothd-textfile.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-textfile.obj `if test -f 'src/textfile.c'; then $(CYGPATH_W) 'src/textfile.c'; else $(CYGPATH_W) '$(srcdir)/src/textfile.c'; fi` + +src/bluetoothd-uuid-helper.o: src/uuid-helper.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-uuid-helper.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-uuid-helper.Tpo -c -o src/bluetoothd-uuid-helper.o `test -f 'src/uuid-helper.c' || echo '$(srcdir)/'`src/uuid-helper.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-uuid-helper.Tpo src/$(DEPDIR)/bluetoothd-uuid-helper.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/uuid-helper.c' object='src/bluetoothd-uuid-helper.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-uuid-helper.o `test -f 'src/uuid-helper.c' || echo '$(srcdir)/'`src/uuid-helper.c + +src/bluetoothd-uuid-helper.obj: src/uuid-helper.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-uuid-helper.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-uuid-helper.Tpo -c -o src/bluetoothd-uuid-helper.obj `if test -f 'src/uuid-helper.c'; then $(CYGPATH_W) 'src/uuid-helper.c'; else $(CYGPATH_W) '$(srcdir)/src/uuid-helper.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-uuid-helper.Tpo src/$(DEPDIR)/bluetoothd-uuid-helper.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/uuid-helper.c' object='src/bluetoothd-uuid-helper.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-uuid-helper.obj `if test -f 'src/uuid-helper.c'; then $(CYGPATH_W) 'src/uuid-helper.c'; else $(CYGPATH_W) '$(srcdir)/src/uuid-helper.c'; fi` + +src/bluetoothd-plugin.o: src/plugin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-plugin.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-plugin.Tpo -c -o src/bluetoothd-plugin.o `test -f 'src/plugin.c' || echo '$(srcdir)/'`src/plugin.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-plugin.Tpo src/$(DEPDIR)/bluetoothd-plugin.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/plugin.c' object='src/bluetoothd-plugin.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-plugin.o `test -f 'src/plugin.c' || echo '$(srcdir)/'`src/plugin.c + +src/bluetoothd-plugin.obj: src/plugin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-plugin.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-plugin.Tpo -c -o src/bluetoothd-plugin.obj `if test -f 'src/plugin.c'; then $(CYGPATH_W) 'src/plugin.c'; else $(CYGPATH_W) '$(srcdir)/src/plugin.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-plugin.Tpo src/$(DEPDIR)/bluetoothd-plugin.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/plugin.c' object='src/bluetoothd-plugin.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-plugin.obj `if test -f 'src/plugin.c'; then $(CYGPATH_W) 'src/plugin.c'; else $(CYGPATH_W) '$(srcdir)/src/plugin.c'; fi` + +src/bluetoothd-storage.o: src/storage.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-storage.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-storage.Tpo -c -o src/bluetoothd-storage.o `test -f 'src/storage.c' || echo '$(srcdir)/'`src/storage.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-storage.Tpo src/$(DEPDIR)/bluetoothd-storage.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/storage.c' object='src/bluetoothd-storage.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-storage.o `test -f 'src/storage.c' || echo '$(srcdir)/'`src/storage.c + +src/bluetoothd-storage.obj: src/storage.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-storage.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-storage.Tpo -c -o src/bluetoothd-storage.obj `if test -f 'src/storage.c'; then $(CYGPATH_W) 'src/storage.c'; else $(CYGPATH_W) '$(srcdir)/src/storage.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-storage.Tpo src/$(DEPDIR)/bluetoothd-storage.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/storage.c' object='src/bluetoothd-storage.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-storage.obj `if test -f 'src/storage.c'; then $(CYGPATH_W) 'src/storage.c'; else $(CYGPATH_W) '$(srcdir)/src/storage.c'; fi` + +src/bluetoothd-advertising.o: src/advertising.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-advertising.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-advertising.Tpo -c -o src/bluetoothd-advertising.o `test -f 'src/advertising.c' || echo '$(srcdir)/'`src/advertising.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-advertising.Tpo src/$(DEPDIR)/bluetoothd-advertising.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/advertising.c' object='src/bluetoothd-advertising.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-advertising.o `test -f 'src/advertising.c' || echo '$(srcdir)/'`src/advertising.c + +src/bluetoothd-advertising.obj: src/advertising.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-advertising.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-advertising.Tpo -c -o src/bluetoothd-advertising.obj `if test -f 'src/advertising.c'; then $(CYGPATH_W) 'src/advertising.c'; else $(CYGPATH_W) '$(srcdir)/src/advertising.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-advertising.Tpo src/$(DEPDIR)/bluetoothd-advertising.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/advertising.c' object='src/bluetoothd-advertising.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-advertising.obj `if test -f 'src/advertising.c'; then $(CYGPATH_W) 'src/advertising.c'; else $(CYGPATH_W) '$(srcdir)/src/advertising.c'; fi` + +src/bluetoothd-agent.o: src/agent.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-agent.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-agent.Tpo -c -o src/bluetoothd-agent.o `test -f 'src/agent.c' || echo '$(srcdir)/'`src/agent.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-agent.Tpo src/$(DEPDIR)/bluetoothd-agent.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/agent.c' object='src/bluetoothd-agent.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-agent.o `test -f 'src/agent.c' || echo '$(srcdir)/'`src/agent.c + +src/bluetoothd-agent.obj: src/agent.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-agent.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-agent.Tpo -c -o src/bluetoothd-agent.obj `if test -f 'src/agent.c'; then $(CYGPATH_W) 'src/agent.c'; else $(CYGPATH_W) '$(srcdir)/src/agent.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-agent.Tpo src/$(DEPDIR)/bluetoothd-agent.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/agent.c' object='src/bluetoothd-agent.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-agent.obj `if test -f 'src/agent.c'; then $(CYGPATH_W) 'src/agent.c'; else $(CYGPATH_W) '$(srcdir)/src/agent.c'; fi` + +src/bluetoothd-error.o: src/error.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-error.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-error.Tpo -c -o src/bluetoothd-error.o `test -f 'src/error.c' || echo '$(srcdir)/'`src/error.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-error.Tpo src/$(DEPDIR)/bluetoothd-error.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/error.c' object='src/bluetoothd-error.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-error.o `test -f 'src/error.c' || echo '$(srcdir)/'`src/error.c + +src/bluetoothd-error.obj: src/error.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-error.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-error.Tpo -c -o src/bluetoothd-error.obj `if test -f 'src/error.c'; then $(CYGPATH_W) 'src/error.c'; else $(CYGPATH_W) '$(srcdir)/src/error.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-error.Tpo src/$(DEPDIR)/bluetoothd-error.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/error.c' object='src/bluetoothd-error.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-error.obj `if test -f 'src/error.c'; then $(CYGPATH_W) 'src/error.c'; else $(CYGPATH_W) '$(srcdir)/src/error.c'; fi` + +src/bluetoothd-adapter.o: src/adapter.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-adapter.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-adapter.Tpo -c -o src/bluetoothd-adapter.o `test -f 'src/adapter.c' || echo '$(srcdir)/'`src/adapter.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-adapter.Tpo src/$(DEPDIR)/bluetoothd-adapter.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/adapter.c' object='src/bluetoothd-adapter.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-adapter.o `test -f 'src/adapter.c' || echo '$(srcdir)/'`src/adapter.c + +src/bluetoothd-adapter.obj: src/adapter.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-adapter.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-adapter.Tpo -c -o src/bluetoothd-adapter.obj `if test -f 'src/adapter.c'; then $(CYGPATH_W) 'src/adapter.c'; else $(CYGPATH_W) '$(srcdir)/src/adapter.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-adapter.Tpo src/$(DEPDIR)/bluetoothd-adapter.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/adapter.c' object='src/bluetoothd-adapter.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-adapter.obj `if test -f 'src/adapter.c'; then $(CYGPATH_W) 'src/adapter.c'; else $(CYGPATH_W) '$(srcdir)/src/adapter.c'; fi` + +src/bluetoothd-profile.o: src/profile.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-profile.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-profile.Tpo -c -o src/bluetoothd-profile.o `test -f 'src/profile.c' || echo '$(srcdir)/'`src/profile.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-profile.Tpo src/$(DEPDIR)/bluetoothd-profile.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/profile.c' object='src/bluetoothd-profile.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-profile.o `test -f 'src/profile.c' || echo '$(srcdir)/'`src/profile.c + +src/bluetoothd-profile.obj: src/profile.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-profile.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-profile.Tpo -c -o src/bluetoothd-profile.obj `if test -f 'src/profile.c'; then $(CYGPATH_W) 'src/profile.c'; else $(CYGPATH_W) '$(srcdir)/src/profile.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-profile.Tpo src/$(DEPDIR)/bluetoothd-profile.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/profile.c' object='src/bluetoothd-profile.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-profile.obj `if test -f 'src/profile.c'; then $(CYGPATH_W) 'src/profile.c'; else $(CYGPATH_W) '$(srcdir)/src/profile.c'; fi` + +src/bluetoothd-service.o: src/service.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-service.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-service.Tpo -c -o src/bluetoothd-service.o `test -f 'src/service.c' || echo '$(srcdir)/'`src/service.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-service.Tpo src/$(DEPDIR)/bluetoothd-service.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/service.c' object='src/bluetoothd-service.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-service.o `test -f 'src/service.c' || echo '$(srcdir)/'`src/service.c + +src/bluetoothd-service.obj: src/service.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-service.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-service.Tpo -c -o src/bluetoothd-service.obj `if test -f 'src/service.c'; then $(CYGPATH_W) 'src/service.c'; else $(CYGPATH_W) '$(srcdir)/src/service.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-service.Tpo src/$(DEPDIR)/bluetoothd-service.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/service.c' object='src/bluetoothd-service.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-service.obj `if test -f 'src/service.c'; then $(CYGPATH_W) 'src/service.c'; else $(CYGPATH_W) '$(srcdir)/src/service.c'; fi` + +src/bluetoothd-gatt-client.o: src/gatt-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-gatt-client.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-gatt-client.Tpo -c -o src/bluetoothd-gatt-client.o `test -f 'src/gatt-client.c' || echo '$(srcdir)/'`src/gatt-client.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-gatt-client.Tpo src/$(DEPDIR)/bluetoothd-gatt-client.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/gatt-client.c' object='src/bluetoothd-gatt-client.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-gatt-client.o `test -f 'src/gatt-client.c' || echo '$(srcdir)/'`src/gatt-client.c + +src/bluetoothd-gatt-client.obj: src/gatt-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-gatt-client.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-gatt-client.Tpo -c -o src/bluetoothd-gatt-client.obj `if test -f 'src/gatt-client.c'; then $(CYGPATH_W) 'src/gatt-client.c'; else $(CYGPATH_W) '$(srcdir)/src/gatt-client.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-gatt-client.Tpo src/$(DEPDIR)/bluetoothd-gatt-client.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/gatt-client.c' object='src/bluetoothd-gatt-client.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-gatt-client.obj `if test -f 'src/gatt-client.c'; then $(CYGPATH_W) 'src/gatt-client.c'; else $(CYGPATH_W) '$(srcdir)/src/gatt-client.c'; fi` + +src/bluetoothd-device.o: src/device.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-device.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-device.Tpo -c -o src/bluetoothd-device.o `test -f 'src/device.c' || echo '$(srcdir)/'`src/device.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-device.Tpo src/$(DEPDIR)/bluetoothd-device.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/device.c' object='src/bluetoothd-device.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-device.o `test -f 'src/device.c' || echo '$(srcdir)/'`src/device.c + +src/bluetoothd-device.obj: src/device.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-device.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-device.Tpo -c -o src/bluetoothd-device.obj `if test -f 'src/device.c'; then $(CYGPATH_W) 'src/device.c'; else $(CYGPATH_W) '$(srcdir)/src/device.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-device.Tpo src/$(DEPDIR)/bluetoothd-device.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/device.c' object='src/bluetoothd-device.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-device.obj `if test -f 'src/device.c'; then $(CYGPATH_W) 'src/device.c'; else $(CYGPATH_W) '$(srcdir)/src/device.c'; fi` + +src/bluetoothd-dbus-common.o: src/dbus-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-dbus-common.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-dbus-common.Tpo -c -o src/bluetoothd-dbus-common.o `test -f 'src/dbus-common.c' || echo '$(srcdir)/'`src/dbus-common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-dbus-common.Tpo src/$(DEPDIR)/bluetoothd-dbus-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/dbus-common.c' object='src/bluetoothd-dbus-common.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-dbus-common.o `test -f 'src/dbus-common.c' || echo '$(srcdir)/'`src/dbus-common.c + +src/bluetoothd-dbus-common.obj: src/dbus-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-dbus-common.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-dbus-common.Tpo -c -o src/bluetoothd-dbus-common.obj `if test -f 'src/dbus-common.c'; then $(CYGPATH_W) 'src/dbus-common.c'; else $(CYGPATH_W) '$(srcdir)/src/dbus-common.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-dbus-common.Tpo src/$(DEPDIR)/bluetoothd-dbus-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/dbus-common.c' object='src/bluetoothd-dbus-common.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-dbus-common.obj `if test -f 'src/dbus-common.c'; then $(CYGPATH_W) 'src/dbus-common.c'; else $(CYGPATH_W) '$(srcdir)/src/dbus-common.c'; fi` + +src/bluetoothd-eir.o: src/eir.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-eir.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-eir.Tpo -c -o src/bluetoothd-eir.o `test -f 'src/eir.c' || echo '$(srcdir)/'`src/eir.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-eir.Tpo src/$(DEPDIR)/bluetoothd-eir.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/eir.c' object='src/bluetoothd-eir.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-eir.o `test -f 'src/eir.c' || echo '$(srcdir)/'`src/eir.c + +src/bluetoothd-eir.obj: src/eir.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-eir.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-eir.Tpo -c -o src/bluetoothd-eir.obj `if test -f 'src/eir.c'; then $(CYGPATH_W) 'src/eir.c'; else $(CYGPATH_W) '$(srcdir)/src/eir.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-eir.Tpo src/$(DEPDIR)/bluetoothd-eir.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/eir.c' object='src/bluetoothd-eir.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-eir.obj `if test -f 'src/eir.c'; then $(CYGPATH_W) 'src/eir.c'; else $(CYGPATH_W) '$(srcdir)/src/eir.c'; fi` + +src/bluetoothd-adv_monitor.o: src/adv_monitor.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-adv_monitor.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-adv_monitor.Tpo -c -o src/bluetoothd-adv_monitor.o `test -f 'src/adv_monitor.c' || echo '$(srcdir)/'`src/adv_monitor.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-adv_monitor.Tpo src/$(DEPDIR)/bluetoothd-adv_monitor.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/adv_monitor.c' object='src/bluetoothd-adv_monitor.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-adv_monitor.o `test -f 'src/adv_monitor.c' || echo '$(srcdir)/'`src/adv_monitor.c + +src/bluetoothd-adv_monitor.obj: src/adv_monitor.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-adv_monitor.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-adv_monitor.Tpo -c -o src/bluetoothd-adv_monitor.obj `if test -f 'src/adv_monitor.c'; then $(CYGPATH_W) 'src/adv_monitor.c'; else $(CYGPATH_W) '$(srcdir)/src/adv_monitor.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-adv_monitor.Tpo src/$(DEPDIR)/bluetoothd-adv_monitor.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/adv_monitor.c' object='src/bluetoothd-adv_monitor.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-adv_monitor.obj `if test -f 'src/adv_monitor.c'; then $(CYGPATH_W) 'src/adv_monitor.c'; else $(CYGPATH_W) '$(srcdir)/src/adv_monitor.c'; fi` + +src/bluetoothd-battery.o: src/battery.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-battery.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-battery.Tpo -c -o src/bluetoothd-battery.o `test -f 'src/battery.c' || echo '$(srcdir)/'`src/battery.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-battery.Tpo src/$(DEPDIR)/bluetoothd-battery.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/battery.c' object='src/bluetoothd-battery.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-battery.o `test -f 'src/battery.c' || echo '$(srcdir)/'`src/battery.c + +src/bluetoothd-battery.obj: src/battery.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-battery.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-battery.Tpo -c -o src/bluetoothd-battery.obj `if test -f 'src/battery.c'; then $(CYGPATH_W) 'src/battery.c'; else $(CYGPATH_W) '$(srcdir)/src/battery.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-battery.Tpo src/$(DEPDIR)/bluetoothd-battery.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/battery.c' object='src/bluetoothd-battery.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-battery.obj `if test -f 'src/battery.c'; then $(CYGPATH_W) 'src/battery.c'; else $(CYGPATH_W) '$(srcdir)/src/battery.c'; fi` + +src/bluetoothd-settings.o: src/settings.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-settings.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-settings.Tpo -c -o src/bluetoothd-settings.o `test -f 'src/settings.c' || echo '$(srcdir)/'`src/settings.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-settings.Tpo src/$(DEPDIR)/bluetoothd-settings.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/settings.c' object='src/bluetoothd-settings.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-settings.o `test -f 'src/settings.c' || echo '$(srcdir)/'`src/settings.c + +src/bluetoothd-settings.obj: src/settings.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-settings.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-settings.Tpo -c -o src/bluetoothd-settings.obj `if test -f 'src/settings.c'; then $(CYGPATH_W) 'src/settings.c'; else $(CYGPATH_W) '$(srcdir)/src/settings.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-settings.Tpo src/$(DEPDIR)/bluetoothd-settings.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/settings.c' object='src/bluetoothd-settings.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-settings.obj `if test -f 'src/settings.c'; then $(CYGPATH_W) 'src/settings.c'; else $(CYGPATH_W) '$(srcdir)/src/settings.c'; fi` + +src/bluetoothd-set.o: src/set.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-set.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-set.Tpo -c -o src/bluetoothd-set.o `test -f 'src/set.c' || echo '$(srcdir)/'`src/set.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-set.Tpo src/$(DEPDIR)/bluetoothd-set.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/set.c' object='src/bluetoothd-set.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-set.o `test -f 'src/set.c' || echo '$(srcdir)/'`src/set.c + +src/bluetoothd-set.obj: src/set.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/bluetoothd-set.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-set.Tpo -c -o src/bluetoothd-set.obj `if test -f 'src/set.c'; then $(CYGPATH_W) 'src/set.c'; else $(CYGPATH_W) '$(srcdir)/src/set.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-set.Tpo src/$(DEPDIR)/bluetoothd-set.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/set.c' object='src/bluetoothd-set.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_bluetoothd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-set.obj `if test -f 'src/set.c'; then $(CYGPATH_W) 'src/set.c'; else $(CYGPATH_W) '$(srcdir)/src/set.c'; fi` + +unit/test_mesh_crypto-test-mesh-crypto.o: unit/test-mesh-crypto.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit_test_mesh_crypto_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unit/test_mesh_crypto-test-mesh-crypto.o -MD -MP -MF unit/$(DEPDIR)/test_mesh_crypto-test-mesh-crypto.Tpo -c -o unit/test_mesh_crypto-test-mesh-crypto.o `test -f 'unit/test-mesh-crypto.c' || echo '$(srcdir)/'`unit/test-mesh-crypto.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) unit/$(DEPDIR)/test_mesh_crypto-test-mesh-crypto.Tpo unit/$(DEPDIR)/test_mesh_crypto-test-mesh-crypto.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='unit/test-mesh-crypto.c' object='unit/test_mesh_crypto-test-mesh-crypto.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit_test_mesh_crypto_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unit/test_mesh_crypto-test-mesh-crypto.o `test -f 'unit/test-mesh-crypto.c' || echo '$(srcdir)/'`unit/test-mesh-crypto.c + +unit/test_mesh_crypto-test-mesh-crypto.obj: unit/test-mesh-crypto.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit_test_mesh_crypto_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unit/test_mesh_crypto-test-mesh-crypto.obj -MD -MP -MF unit/$(DEPDIR)/test_mesh_crypto-test-mesh-crypto.Tpo -c -o unit/test_mesh_crypto-test-mesh-crypto.obj `if test -f 'unit/test-mesh-crypto.c'; then $(CYGPATH_W) 'unit/test-mesh-crypto.c'; else $(CYGPATH_W) '$(srcdir)/unit/test-mesh-crypto.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) unit/$(DEPDIR)/test_mesh_crypto-test-mesh-crypto.Tpo unit/$(DEPDIR)/test_mesh_crypto-test-mesh-crypto.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='unit/test-mesh-crypto.c' object='unit/test_mesh_crypto-test-mesh-crypto.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit_test_mesh_crypto_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unit/test_mesh_crypto-test-mesh-crypto.obj `if test -f 'unit/test-mesh-crypto.c'; then $(CYGPATH_W) 'unit/test-mesh-crypto.c'; else $(CYGPATH_W) '$(srcdir)/unit/test-mesh-crypto.c'; fi` + +unit/test_midi-test-midi.o: unit/test-midi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit_test_midi_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unit/test_midi-test-midi.o -MD -MP -MF unit/$(DEPDIR)/test_midi-test-midi.Tpo -c -o unit/test_midi-test-midi.o `test -f 'unit/test-midi.c' || echo '$(srcdir)/'`unit/test-midi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) unit/$(DEPDIR)/test_midi-test-midi.Tpo unit/$(DEPDIR)/test_midi-test-midi.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='unit/test-midi.c' object='unit/test_midi-test-midi.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit_test_midi_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unit/test_midi-test-midi.o `test -f 'unit/test-midi.c' || echo '$(srcdir)/'`unit/test-midi.c + +unit/test_midi-test-midi.obj: unit/test-midi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit_test_midi_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unit/test_midi-test-midi.obj -MD -MP -MF unit/$(DEPDIR)/test_midi-test-midi.Tpo -c -o unit/test_midi-test-midi.obj `if test -f 'unit/test-midi.c'; then $(CYGPATH_W) 'unit/test-midi.c'; else $(CYGPATH_W) '$(srcdir)/unit/test-midi.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) unit/$(DEPDIR)/test_midi-test-midi.Tpo unit/$(DEPDIR)/test_midi-test-midi.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='unit/test-midi.c' object='unit/test_midi-test-midi.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit_test_midi_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unit/test_midi-test-midi.obj `if test -f 'unit/test-midi.c'; then $(CYGPATH_W) 'unit/test-midi.c'; else $(CYGPATH_W) '$(srcdir)/unit/test-midi.c'; fi` + +profiles/midi/unit_test_midi-libmidi.o: profiles/midi/libmidi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit_test_midi_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/midi/unit_test_midi-libmidi.o -MD -MP -MF profiles/midi/$(DEPDIR)/unit_test_midi-libmidi.Tpo -c -o profiles/midi/unit_test_midi-libmidi.o `test -f 'profiles/midi/libmidi.c' || echo '$(srcdir)/'`profiles/midi/libmidi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/midi/$(DEPDIR)/unit_test_midi-libmidi.Tpo profiles/midi/$(DEPDIR)/unit_test_midi-libmidi.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/midi/libmidi.c' object='profiles/midi/unit_test_midi-libmidi.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit_test_midi_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/midi/unit_test_midi-libmidi.o `test -f 'profiles/midi/libmidi.c' || echo '$(srcdir)/'`profiles/midi/libmidi.c + +profiles/midi/unit_test_midi-libmidi.obj: profiles/midi/libmidi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit_test_midi_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT profiles/midi/unit_test_midi-libmidi.obj -MD -MP -MF profiles/midi/$(DEPDIR)/unit_test_midi-libmidi.Tpo -c -o profiles/midi/unit_test_midi-libmidi.obj `if test -f 'profiles/midi/libmidi.c'; then $(CYGPATH_W) 'profiles/midi/libmidi.c'; else $(CYGPATH_W) '$(srcdir)/profiles/midi/libmidi.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) profiles/midi/$(DEPDIR)/unit_test_midi-libmidi.Tpo profiles/midi/$(DEPDIR)/unit_test_midi-libmidi.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profiles/midi/libmidi.c' object='profiles/midi/unit_test_midi-libmidi.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(unit_test_midi_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o profiles/midi/unit_test_midi-libmidi.obj `if test -f 'profiles/midi/libmidi.c'; then $(CYGPATH_W) 'profiles/midi/libmidi.c'; else $(CYGPATH_W) '$(srcdir)/profiles/midi/libmidi.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf android/.libs android/_libs + -rm -rf android/audio_utils/.libs android/audio_utils/_libs + -rm -rf attrib/.libs attrib/_libs + -rm -rf client/.libs client/_libs + -rm -rf ell/.libs ell/_libs + -rm -rf emulator/.libs emulator/_libs + -rm -rf gdbus/.libs gdbus/_libs + -rm -rf lib/.libs lib/_libs + -rm -rf mesh/.libs mesh/_libs + -rm -rf monitor/.libs monitor/_libs + -rm -rf obexd/src/.libs obexd/src/_libs + -rm -rf peripheral/.libs peripheral/_libs + -rm -rf profiles/cups/.libs profiles/cups/_libs + -rm -rf profiles/iap/.libs profiles/iap/_libs + -rm -rf src/.libs src/_libs + -rm -rf src/shared/.libs src/shared/_libs + -rm -rf tools/.libs tools/_libs + -rm -rf unit/.libs unit/_libs + +distclean-libtool: + -rm -f libtool config.lt +install-man1: $(man_MANS) + @$(NORMAL_INSTALL) + @list1=''; \ + list2='$(man_MANS)'; \ + test -n "$(man1dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.1[a-z]*$$/p'; \ + fi; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ + done; } + +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list=''; test -n "$(man1dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.1[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) +install-man5: $(man_MANS) + @$(NORMAL_INSTALL) + @list1=''; \ + list2='$(man_MANS)'; \ + test -n "$(man5dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man5dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man5dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.5[a-z]*$$/p'; \ + fi; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \ + done; } + +uninstall-man5: + @$(NORMAL_UNINSTALL) + @list=''; test -n "$(man5dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.5[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir) +install-man7: $(man_MANS) + @$(NORMAL_INSTALL) + @list1=''; \ + list2='$(man_MANS)'; \ + test -n "$(man7dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man7dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man7dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.7[a-z]*$$/p'; \ + fi; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^7][0-9a-z]*$$,7,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man7dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man7dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man7dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man7dir)" || exit $$?; }; \ + done; } + +uninstall-man7: + @$(NORMAL_UNINSTALL) + @list=''; test -n "$(man7dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.7[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^7][0-9a-z]*$$,7,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man7dir)'; $(am__uninstall_files_from_dir) +install-man8: $(man_MANS) + @$(NORMAL_INSTALL) + @list1=''; \ + list2='$(man_MANS)'; \ + test -n "$(man8dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.8[a-z]*$$/p'; \ + fi; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ + done; } + +uninstall-man8: + @$(NORMAL_UNINSTALL) + @list=''; test -n "$(man8dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.8[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir) +install-confDATA: $(conf_DATA) + @$(NORMAL_INSTALL) + @list='$(conf_DATA)'; test -n "$(confdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(confdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(confdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(confdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(confdir)" || exit $$?; \ + done + +uninstall-confDATA: + @$(NORMAL_UNINSTALL) + @list='$(conf_DATA)'; test -n "$(confdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(confdir)'; $(am__uninstall_files_from_dir) +install-dbusDATA: $(dbus_DATA) + @$(NORMAL_INSTALL) + @list='$(dbus_DATA)'; test -n "$(dbusdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(dbusdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(dbusdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dbusdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(dbusdir)" || exit $$?; \ + done + +uninstall-dbusDATA: + @$(NORMAL_UNINSTALL) + @list='$(dbus_DATA)'; test -n "$(dbusdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(dbusdir)'; $(am__uninstall_files_from_dir) +install-dbussessionbusDATA: $(dbussessionbus_DATA) + @$(NORMAL_INSTALL) + @list='$(dbussessionbus_DATA)'; test -n "$(dbussessionbusdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(dbussessionbusdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(dbussessionbusdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dbussessionbusdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(dbussessionbusdir)" || exit $$?; \ + done + +uninstall-dbussessionbusDATA: + @$(NORMAL_UNINSTALL) + @list='$(dbussessionbus_DATA)'; test -n "$(dbussessionbusdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(dbussessionbusdir)'; $(am__uninstall_files_from_dir) +install-dbussystembusDATA: $(dbussystembus_DATA) + @$(NORMAL_INSTALL) + @list='$(dbussystembus_DATA)'; test -n "$(dbussystembusdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(dbussystembusdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(dbussystembusdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dbussystembusdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(dbussystembusdir)" || exit $$?; \ + done + +uninstall-dbussystembusDATA: + @$(NORMAL_UNINSTALL) + @list='$(dbussystembus_DATA)'; test -n "$(dbussystembusdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(dbussystembusdir)'; $(am__uninstall_files_from_dir) +install-dist_zshcompletionDATA: $(dist_zshcompletion_DATA) + @$(NORMAL_INSTALL) + @list='$(dist_zshcompletion_DATA)'; test -n "$(zshcompletiondir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(zshcompletiondir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(zshcompletiondir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(zshcompletiondir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(zshcompletiondir)" || exit $$?; \ + done + +uninstall-dist_zshcompletionDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_zshcompletion_DATA)'; test -n "$(zshcompletiondir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(zshcompletiondir)'; $(am__uninstall_files_from_dir) +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ + done + +uninstall-pkgconfigDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) +install-rulesDATA: $(rules_DATA) + @$(NORMAL_INSTALL) + @list='$(rules_DATA)'; test -n "$(rulesdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(rulesdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(rulesdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(rulesdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(rulesdir)" || exit $$?; \ + done + +uninstall-rulesDATA: + @$(NORMAL_UNINSTALL) + @list='$(rules_DATA)'; test -n "$(rulesdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(rulesdir)'; $(am__uninstall_files_from_dir) +install-stateDATA: $(state_DATA) + @$(NORMAL_INSTALL) + @list='$(state_DATA)'; test -n "$(statedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(statedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(statedir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(statedir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(statedir)" || exit $$?; \ + done + +uninstall-stateDATA: + @$(NORMAL_UNINSTALL) + @list='$(state_DATA)'; test -n "$(statedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(statedir)'; $(am__uninstall_files_from_dir) +install-systemdsystemunitDATA: $(systemdsystemunit_DATA) + @$(NORMAL_INSTALL) + @list='$(systemdsystemunit_DATA)'; test -n "$(systemdsystemunitdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(systemdsystemunitdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(systemdsystemunitdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemdsystemunitdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(systemdsystemunitdir)" || exit $$?; \ + done + +uninstall-systemdsystemunitDATA: + @$(NORMAL_UNINSTALL) + @list='$(systemdsystemunit_DATA)'; test -n "$(systemdsystemunitdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(systemdsystemunitdir)'; $(am__uninstall_files_from_dir) +install-systemduserunitDATA: $(systemduserunit_DATA) + @$(NORMAL_INSTALL) + @list='$(systemduserunit_DATA)'; test -n "$(systemduserunitdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(systemduserunitdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(systemduserunitdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemduserunitdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(systemduserunitdir)" || exit $$?; \ + done + +uninstall-systemduserunitDATA: + @$(NORMAL_UNINSTALL) + @list='$(systemduserunit_DATA)'; test -n "$(systemduserunitdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(systemduserunitdir)'; $(am__uninstall_files_from_dir) +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkgincludedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkgincludedir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludedir)" || exit $$?; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(pkgincludedir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscope: cscope.files + test ! -s cscope.files \ + || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) +clean-cscope: + -rm -f cscope.files +cscope.files: clean-cscope cscopelist +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + -rm -f cscope.out cscope.in.out cscope.po.out cscope.files + +# Recover from deleted '.trs' file; this should ensure that +# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create +# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells +# to avoid problems with "make -n". +.log.trs: + rm -f $< $@ + $(MAKE) $(AM_MAKEFLAGS) $< + +# Leading 'am--fnord' is there to ensure the list of targets does not +# expand to empty, as could happen e.g. with make check TESTS=''. +am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) +am--force-recheck: + @: + +$(TEST_SUITE_LOG): $(TEST_LOGS) + @$(am__set_TESTS_bases); \ + am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ + redo_bases=`for i in $$bases; do \ + am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ + done`; \ + if test -n "$$redo_bases"; then \ + redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ + redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ + if $(am__make_dryrun); then :; else \ + rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ + fi; \ + fi; \ + if test -n "$$am__remaking_logs"; then \ + echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ + "recursion detected" >&2; \ + elif test -n "$$redo_logs"; then \ + am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ + fi; \ + if $(am__make_dryrun); then :; else \ + st=0; \ + errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ + for i in $$redo_bases; do \ + test -f $$i.trs && test -r $$i.trs \ + || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ + test -f $$i.log && test -r $$i.log \ + || { echo "$$errmsg $$i.log" >&2; st=1; }; \ + done; \ + test $$st -eq 0 || exit 1; \ + fi + @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ + ws='[ ]'; \ + results=`for b in $$bases; do echo $$b.trs; done`; \ + test -n "$$results" || results=/dev/null; \ + all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ + pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ + fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ + skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ + xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ + xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ + error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ + if test `expr $$fail + $$xpass + $$error` -eq 0; then \ + success=true; \ + else \ + success=false; \ + fi; \ + br='==================='; br=$$br$$br$$br$$br; \ + result_count () \ + { \ + if test x"$$1" = x"--maybe-color"; then \ + maybe_colorize=yes; \ + elif test x"$$1" = x"--no-color"; then \ + maybe_colorize=no; \ + else \ + echo "$@: invalid 'result_count' usage" >&2; exit 4; \ + fi; \ + shift; \ + desc=$$1 count=$$2; \ + if test $$maybe_colorize = yes && test $$count -gt 0; then \ + color_start=$$3 color_end=$$std; \ + else \ + color_start= color_end=; \ + fi; \ + echo "$${color_start}# $$desc $$count$${color_end}"; \ + }; \ + create_testsuite_report () \ + { \ + result_count $$1 "TOTAL:" $$all "$$brg"; \ + result_count $$1 "PASS: " $$pass "$$grn"; \ + result_count $$1 "SKIP: " $$skip "$$blu"; \ + result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ + result_count $$1 "FAIL: " $$fail "$$red"; \ + result_count $$1 "XPASS:" $$xpass "$$red"; \ + result_count $$1 "ERROR:" $$error "$$mgn"; \ + }; \ + { \ + echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ + $(am__rst_title); \ + create_testsuite_report --no-color; \ + echo; \ + echo ".. contents:: :depth: 2"; \ + echo; \ + for b in $$bases; do echo $$b; done \ + | $(am__create_global_log); \ + } >$(TEST_SUITE_LOG).tmp || exit 1; \ + mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ + if $$success; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ + fi; \ + echo "$${col}$$br$${std}"; \ + echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \ + echo "$${col}$$br$${std}"; \ + create_testsuite_report --maybe-color; \ + echo "$$col$$br$$std"; \ + if $$success; then :; else \ + echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ + if test -n "$(PACKAGE_BUGREPORT)"; then \ + echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ + fi; \ + echo "$$col$$br$$std"; \ + fi; \ + $$success || exit 1 + +check-TESTS: + @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list + @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + trs_list=`for i in $$bases; do echo $$i.trs; done`; \ + log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ + exit $$?; +recheck: all + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + bases=`for i in $$bases; do echo $$i; done \ + | $(am__list_recheck_tests)` || exit 1; \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + log_list=`echo $$log_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ + am__force_recheck=am--force-recheck \ + TEST_LOGS="$$log_list"; \ + exit $$? +android/test-ipc.log: android/test-ipc$(EXEEXT) + @p='android/test-ipc$(EXEEXT)'; \ + b='android/test-ipc'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-tester.log: unit/test-tester$(EXEEXT) + @p='unit/test-tester$(EXEEXT)'; \ + b='unit/test-tester'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-eir.log: unit/test-eir$(EXEEXT) + @p='unit/test-eir$(EXEEXT)'; \ + b='unit/test-eir'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-uuid.log: unit/test-uuid$(EXEEXT) + @p='unit/test-uuid$(EXEEXT)'; \ + b='unit/test-uuid'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-textfile.log: unit/test-textfile$(EXEEXT) + @p='unit/test-textfile$(EXEEXT)'; \ + b='unit/test-textfile'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-crc.log: unit/test-crc$(EXEEXT) + @p='unit/test-crc$(EXEEXT)'; \ + b='unit/test-crc'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-crypto.log: unit/test-crypto$(EXEEXT) + @p='unit/test-crypto$(EXEEXT)'; \ + b='unit/test-crypto'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-ecc.log: unit/test-ecc$(EXEEXT) + @p='unit/test-ecc$(EXEEXT)'; \ + b='unit/test-ecc'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-ringbuf.log: unit/test-ringbuf$(EXEEXT) + @p='unit/test-ringbuf$(EXEEXT)'; \ + b='unit/test-ringbuf'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-queue.log: unit/test-queue$(EXEEXT) + @p='unit/test-queue$(EXEEXT)'; \ + b='unit/test-queue'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-mgmt.log: unit/test-mgmt$(EXEEXT) + @p='unit/test-mgmt$(EXEEXT)'; \ + b='unit/test-mgmt'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-uhid.log: unit/test-uhid$(EXEEXT) + @p='unit/test-uhid$(EXEEXT)'; \ + b='unit/test-uhid'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-sdp.log: unit/test-sdp$(EXEEXT) + @p='unit/test-sdp$(EXEEXT)'; \ + b='unit/test-sdp'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-avdtp.log: unit/test-avdtp$(EXEEXT) + @p='unit/test-avdtp$(EXEEXT)'; \ + b='unit/test-avdtp'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-avctp.log: unit/test-avctp$(EXEEXT) + @p='unit/test-avctp$(EXEEXT)'; \ + b='unit/test-avctp'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-avrcp.log: unit/test-avrcp$(EXEEXT) + @p='unit/test-avrcp$(EXEEXT)'; \ + b='unit/test-avrcp'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-hfp.log: unit/test-hfp$(EXEEXT) + @p='unit/test-hfp$(EXEEXT)'; \ + b='unit/test-hfp'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-gdbus-client.log: unit/test-gdbus-client$(EXEEXT) + @p='unit/test-gdbus-client$(EXEEXT)'; \ + b='unit/test-gdbus-client'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-gobex-header.log: unit/test-gobex-header$(EXEEXT) + @p='unit/test-gobex-header$(EXEEXT)'; \ + b='unit/test-gobex-header'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-gobex-packet.log: unit/test-gobex-packet$(EXEEXT) + @p='unit/test-gobex-packet$(EXEEXT)'; \ + b='unit/test-gobex-packet'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-gobex.log: unit/test-gobex$(EXEEXT) + @p='unit/test-gobex$(EXEEXT)'; \ + b='unit/test-gobex'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-gobex-transfer.log: unit/test-gobex-transfer$(EXEEXT) + @p='unit/test-gobex-transfer$(EXEEXT)'; \ + b='unit/test-gobex-transfer'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-gobex-apparam.log: unit/test-gobex-apparam$(EXEEXT) + @p='unit/test-gobex-apparam$(EXEEXT)'; \ + b='unit/test-gobex-apparam'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-lib.log: unit/test-lib$(EXEEXT) + @p='unit/test-lib$(EXEEXT)'; \ + b='unit/test-lib'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-gatt.log: unit/test-gatt$(EXEEXT) + @p='unit/test-gatt$(EXEEXT)'; \ + b='unit/test-gatt'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-hog.log: unit/test-hog$(EXEEXT) + @p='unit/test-hog$(EXEEXT)'; \ + b='unit/test-hog'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-gattrib.log: unit/test-gattrib$(EXEEXT) + @p='unit/test-gattrib$(EXEEXT)'; \ + b='unit/test-gattrib'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-bap.log: unit/test-bap$(EXEEXT) + @p='unit/test-bap$(EXEEXT)'; \ + b='unit/test-bap'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-micp.log: unit/test-micp$(EXEEXT) + @p='unit/test-micp$(EXEEXT)'; \ + b='unit/test-micp'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-bass.log: unit/test-bass$(EXEEXT) + @p='unit/test-bass$(EXEEXT)'; \ + b='unit/test-bass'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-vcp.log: unit/test-vcp$(EXEEXT) + @p='unit/test-vcp$(EXEEXT)'; \ + b='unit/test-vcp'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-midi.log: unit/test-midi$(EXEEXT) + @p='unit/test-midi$(EXEEXT)'; \ + b='unit/test-midi'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +unit/test-mesh-crypto.log: unit/test-mesh-crypto$(EXEEXT) + @p='unit/test-mesh-crypto$(EXEEXT)'; \ + b='unit/test-mesh-crypto'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +.test.log: + @p='$<'; \ + $(am__set_b); \ + $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +@am__EXEEXT_TRUE@.test$(EXEEXT).log: +@am__EXEEXT_TRUE@ @p='$<'; \ +@am__EXEEXT_TRUE@ $(am__set_b); \ +@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ +@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ +@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ +@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(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 "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -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) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz + $(am__post_remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 + $(am__post_remove_distdir) + +dist-lzip: distdir + tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz + $(am__post_remove_distdir) +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz + $(am__post_remove_distdir) + +dist-zstd: distdir + tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst + $(am__post_remove_distdir) + +dist-tarZ: distdir + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__post_remove_distdir) + +dist-shar: distdir + @echo WARNING: "Support for shar distribution archives is" \ + "deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz + $(am__post_remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__post_remove_distdir) + +dist dist-all: + $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' + $(am__post_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*) \ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lz*) \ + lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + *.tar.zst*) \ + zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ + esac + chmod -R a-w $(distdir) + chmod u+w $(distdir) + mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build/sub \ + && ../../configure \ + $(AM_DISTCHECK_CONFIGURE_FLAGS) \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + --srcdir=../.. --prefix="$$dc_install_base" \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ + && $(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 \ + && cd "$$am__cwd" \ + || exit 1 + $(am__post_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: + @test -n '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: trying to run $@ with an empty' \ + '$$(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + $(am__cd) '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ + || { 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 + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(PROGRAMS) $(LIBRARIES) $(LTLIBRARIES) $(SCRIPTS) \ + $(MANS) $(DATA) $(HEADERS) config.h +install-binPROGRAMS: install-libLTLIBRARIES + +install-cupsPROGRAMS: install-libLTLIBRARIES + +install-pkglibexecPROGRAMS: install-libLTLIBRARIES + +install-udevPROGRAMS: install-libLTLIBRARIES + +install-pluginLTLIBRARIES: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(cupsdir)" "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(udevdir)" "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(testdir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man7dir)" "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(confdir)" "$(DESTDIR)$(dbusdir)" "$(DESTDIR)$(dbussessionbusdir)" "$(DESTDIR)$(dbussystembusdir)" "$(DESTDIR)$(zshcompletiondir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(rulesdir)" "$(DESTDIR)$(statedir)" "$(DESTDIR)$(systemdsystemunitdir)" "$(DESTDIR)$(systemduserunitdir)" "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) 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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) + -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) + -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f android/$(DEPDIR)/$(am__dirstamp) + -rm -f android/$(am__dirstamp) + -rm -f android/audio_utils/$(DEPDIR)/$(am__dirstamp) + -rm -f android/audio_utils/$(am__dirstamp) + -rm -f android/client/$(DEPDIR)/$(am__dirstamp) + -rm -f android/client/$(am__dirstamp) + -rm -f android/hardware/$(DEPDIR)/$(am__dirstamp) + -rm -f android/hardware/$(am__dirstamp) + -rm -f attrib/$(DEPDIR)/$(am__dirstamp) + -rm -f attrib/$(am__dirstamp) + -rm -f btio/$(DEPDIR)/$(am__dirstamp) + -rm -f btio/$(am__dirstamp) + -rm -f client/$(DEPDIR)/$(am__dirstamp) + -rm -f client/$(am__dirstamp) + -rm -f ell/$(DEPDIR)/$(am__dirstamp) + -rm -f ell/$(am__dirstamp) + -rm -f emulator/$(DEPDIR)/$(am__dirstamp) + -rm -f emulator/$(am__dirstamp) + -rm -f gdbus/$(DEPDIR)/$(am__dirstamp) + -rm -f gdbus/$(am__dirstamp) + -rm -f gobex/$(DEPDIR)/$(am__dirstamp) + -rm -f gobex/$(am__dirstamp) + -rm -f lib/$(DEPDIR)/$(am__dirstamp) + -rm -f lib/$(am__dirstamp) + -rm -f mesh/$(DEPDIR)/$(am__dirstamp) + -rm -f mesh/$(am__dirstamp) + -rm -f monitor/$(DEPDIR)/$(am__dirstamp) + -rm -f monitor/$(am__dirstamp) + -rm -f obexd/client/$(DEPDIR)/$(am__dirstamp) + -rm -f obexd/client/$(am__dirstamp) + -rm -f obexd/plugins/$(DEPDIR)/$(am__dirstamp) + -rm -f obexd/plugins/$(am__dirstamp) + -rm -f obexd/src/$(DEPDIR)/$(am__dirstamp) + -rm -f obexd/src/$(am__dirstamp) + -rm -f peripheral/$(DEPDIR)/$(am__dirstamp) + -rm -f peripheral/$(am__dirstamp) + -rm -f plugins/$(DEPDIR)/$(am__dirstamp) + -rm -f plugins/$(am__dirstamp) + -rm -f profiles/audio/$(DEPDIR)/$(am__dirstamp) + -rm -f profiles/audio/$(am__dirstamp) + -rm -f profiles/battery/$(DEPDIR)/$(am__dirstamp) + -rm -f profiles/battery/$(am__dirstamp) + -rm -f profiles/cups/$(DEPDIR)/$(am__dirstamp) + -rm -f profiles/cups/$(am__dirstamp) + -rm -f profiles/deviceinfo/$(DEPDIR)/$(am__dirstamp) + -rm -f profiles/deviceinfo/$(am__dirstamp) + -rm -f profiles/gap/$(DEPDIR)/$(am__dirstamp) + -rm -f profiles/gap/$(am__dirstamp) + -rm -f profiles/health/$(DEPDIR)/$(am__dirstamp) + -rm -f profiles/health/$(am__dirstamp) + -rm -f profiles/iap/$(DEPDIR)/$(am__dirstamp) + -rm -f profiles/iap/$(am__dirstamp) + -rm -f profiles/input/$(DEPDIR)/$(am__dirstamp) + -rm -f profiles/input/$(am__dirstamp) + -rm -f profiles/midi/$(DEPDIR)/$(am__dirstamp) + -rm -f profiles/midi/$(am__dirstamp) + -rm -f profiles/network/$(DEPDIR)/$(am__dirstamp) + -rm -f profiles/network/$(am__dirstamp) + -rm -f profiles/sap/$(DEPDIR)/$(am__dirstamp) + -rm -f profiles/sap/$(am__dirstamp) + -rm -f profiles/scanparam/$(DEPDIR)/$(am__dirstamp) + -rm -f profiles/scanparam/$(am__dirstamp) + -rm -f src/$(DEPDIR)/$(am__dirstamp) + -rm -f src/$(am__dirstamp) + -rm -f src/shared/$(DEPDIR)/$(am__dirstamp) + -rm -f src/shared/$(am__dirstamp) + -rm -f tools/$(DEPDIR)/$(am__dirstamp) + -rm -f tools/$(am__dirstamp) + -rm -f tools/mesh-gatt/$(DEPDIR)/$(am__dirstamp) + -rm -f tools/mesh-gatt/$(am__dirstamp) + -rm -f tools/mesh/$(DEPDIR)/$(am__dirstamp) + -rm -f tools/mesh/$(am__dirstamp) + -rm -f tools/parser/$(DEPDIR)/$(am__dirstamp) + -rm -f tools/parser/$(am__dirstamp) + -rm -f unit/$(DEPDIR)/$(am__dirstamp) + -rm -f unit/$(am__dirstamp) + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +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 "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-binPROGRAMS clean-cupsPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-local \ + clean-noinstLIBRARIES clean-noinstLTLIBRARIES \ + clean-noinstPROGRAMS clean-pkglibexecPROGRAMS \ + clean-pluginLTLIBRARIES clean-udevPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f android/$(DEPDIR)/a2dp-sink.Po + -rm -f android/$(DEPDIR)/a2dp.Po + -rm -f android/$(DEPDIR)/android_tester-tester-a2dp.Po + -rm -f android/$(DEPDIR)/android_tester-tester-avrcp.Po + -rm -f android/$(DEPDIR)/android_tester-tester-bluetooth.Po + -rm -f android/$(DEPDIR)/android_tester-tester-gatt.Po + -rm -f android/$(DEPDIR)/android_tester-tester-hdp.Po + -rm -f android/$(DEPDIR)/android_tester-tester-hidhost.Po + -rm -f android/$(DEPDIR)/android_tester-tester-main.Po + -rm -f android/$(DEPDIR)/android_tester-tester-map-client.Po + -rm -f android/$(DEPDIR)/android_tester-tester-pan.Po + -rm -f android/$(DEPDIR)/android_tester-tester-socket.Po + -rm -f android/$(DEPDIR)/audio_a2dp_default_la-hal-audio-aptx.Plo + -rm -f android/$(DEPDIR)/audio_a2dp_default_la-hal-audio-sbc.Plo + -rm -f android/$(DEPDIR)/audio_a2dp_default_la-hal-audio.Plo + -rm -f android/$(DEPDIR)/audio_sco_default_la-hal-sco.Plo + -rm -f android/$(DEPDIR)/avctp.Po + -rm -f android/$(DEPDIR)/avdtp.Po + -rm -f android/$(DEPDIR)/avdtptest-avdtp.Po + -rm -f android/$(DEPDIR)/avdtptest-avdtptest.Po + -rm -f android/$(DEPDIR)/avrcp-lib.Po + -rm -f android/$(DEPDIR)/avrcp.Po + -rm -f android/$(DEPDIR)/bluetooth.Po + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-a2dp-sink.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-a2dp.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-avrcp-ctrl.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-avrcp.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-bluetooth.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-gatt.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-handsfree-client.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-handsfree.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-health.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-hidhost.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-ipc.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-map-client.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-pan.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-socket.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-utils.Plo + -rm -f android/$(DEPDIR)/bluetoothd-snoop.Po + -rm -f android/$(DEPDIR)/gatt.Po + -rm -f android/$(DEPDIR)/haltest-hal-utils.Po + -rm -f android/$(DEPDIR)/handsfree-client.Po + -rm -f android/$(DEPDIR)/handsfree.Po + -rm -f android/$(DEPDIR)/health.Po + -rm -f android/$(DEPDIR)/hidhost.Po + -rm -f android/$(DEPDIR)/ipc.Po + -rm -f android/$(DEPDIR)/ipc_tester-hal-utils.Po + -rm -f android/$(DEPDIR)/ipc_tester-ipc-tester.Po + -rm -f android/$(DEPDIR)/main.Po + -rm -f android/$(DEPDIR)/map-client.Po + -rm -f android/$(DEPDIR)/pan.Po + -rm -f android/$(DEPDIR)/sco.Po + -rm -f android/$(DEPDIR)/socket.Po + -rm -f android/$(DEPDIR)/system-emulator.Po + -rm -f android/$(DEPDIR)/test-ipc.Po + -rm -f android/audio_utils/$(DEPDIR)/audio_sco_default_la-resampler.Plo + -rm -f android/client/$(DEPDIR)/haltest-haltest.Po + -rm -f android/client/$(DEPDIR)/haltest-history.Po + -rm -f android/client/$(DEPDIR)/haltest-if-audio.Po + -rm -f android/client/$(DEPDIR)/haltest-if-av-sink.Po + -rm -f android/client/$(DEPDIR)/haltest-if-av.Po + -rm -f android/client/$(DEPDIR)/haltest-if-bt.Po + -rm -f android/client/$(DEPDIR)/haltest-if-gatt.Po + -rm -f android/client/$(DEPDIR)/haltest-if-hf-client.Po + -rm -f android/client/$(DEPDIR)/haltest-if-hf.Po + -rm -f android/client/$(DEPDIR)/haltest-if-hh.Po + -rm -f android/client/$(DEPDIR)/haltest-if-hl.Po + -rm -f android/client/$(DEPDIR)/haltest-if-mce.Po + -rm -f android/client/$(DEPDIR)/haltest-if-pan.Po + -rm -f android/client/$(DEPDIR)/haltest-if-rc-ctrl.Po + -rm -f android/client/$(DEPDIR)/haltest-if-rc.Po + -rm -f android/client/$(DEPDIR)/haltest-if-sco.Po + -rm -f android/client/$(DEPDIR)/haltest-if-sock.Po + -rm -f android/client/$(DEPDIR)/haltest-pollhandler.Po + -rm -f android/client/$(DEPDIR)/haltest-tabcompletion.Po + -rm -f android/client/$(DEPDIR)/haltest-terminal.Po + -rm -f android/hardware/$(DEPDIR)/android_tester-hardware.Po + -rm -f android/hardware/$(DEPDIR)/haltest-hardware.Po + -rm -f attrib/$(DEPDIR)/att.Po + -rm -f attrib/$(DEPDIR)/bluetoothd-att.Po + -rm -f attrib/$(DEPDIR)/bluetoothd-gatt.Po + -rm -f attrib/$(DEPDIR)/bluetoothd-gattrib.Po + -rm -f attrib/$(DEPDIR)/gatt.Po + -rm -f attrib/$(DEPDIR)/gattrib.Po + -rm -f attrib/$(DEPDIR)/gatttool.Po + -rm -f attrib/$(DEPDIR)/interactive.Po + -rm -f attrib/$(DEPDIR)/utils.Po + -rm -f btio/$(DEPDIR)/android_avdtptest-btio.Po + -rm -f btio/$(DEPDIR)/bluetoothd-btio.Po + -rm -f btio/$(DEPDIR)/btio.Po + -rm -f btio/$(DEPDIR)/obexd-btio.Po + -rm -f client/$(DEPDIR)/admin.Po + -rm -f client/$(DEPDIR)/adv_monitor.Po + -rm -f client/$(DEPDIR)/advertising.Po + -rm -f client/$(DEPDIR)/agent.Po + -rm -f client/$(DEPDIR)/assistant.Po + -rm -f client/$(DEPDIR)/display.Po + -rm -f client/$(DEPDIR)/gatt.Po + -rm -f client/$(DEPDIR)/main.Po + -rm -f client/$(DEPDIR)/mgmt.Po + -rm -f client/$(DEPDIR)/player.Po + -rm -f client/$(DEPDIR)/print.Po + -rm -f ell/$(DEPDIR)/base64.Plo + -rm -f ell/$(DEPDIR)/cert-crypto.Plo + -rm -f ell/$(DEPDIR)/cert.Plo + -rm -f ell/$(DEPDIR)/checksum.Plo + -rm -f ell/$(DEPDIR)/cipher.Plo + -rm -f ell/$(DEPDIR)/dbus-client.Plo + -rm -f ell/$(DEPDIR)/dbus-filter.Plo + -rm -f ell/$(DEPDIR)/dbus-message.Plo + -rm -f ell/$(DEPDIR)/dbus-name-cache.Plo + -rm -f ell/$(DEPDIR)/dbus-service.Plo + -rm -f ell/$(DEPDIR)/dbus-util.Plo + -rm -f ell/$(DEPDIR)/dbus.Plo + -rm -f ell/$(DEPDIR)/ecc-external.Plo + -rm -f ell/$(DEPDIR)/ecc.Plo + -rm -f ell/$(DEPDIR)/ecdh.Plo + -rm -f ell/$(DEPDIR)/gvariant-util.Plo + -rm -f ell/$(DEPDIR)/hashmap.Plo + -rm -f ell/$(DEPDIR)/idle.Plo + -rm -f ell/$(DEPDIR)/io.Plo + -rm -f ell/$(DEPDIR)/key.Plo + -rm -f ell/$(DEPDIR)/log.Plo + -rm -f ell/$(DEPDIR)/main.Plo + -rm -f ell/$(DEPDIR)/pem.Plo + -rm -f ell/$(DEPDIR)/queue.Plo + -rm -f ell/$(DEPDIR)/random.Plo + -rm -f ell/$(DEPDIR)/settings.Plo + -rm -f ell/$(DEPDIR)/signal.Plo + -rm -f ell/$(DEPDIR)/siphash.Plo + -rm -f ell/$(DEPDIR)/string.Plo + -rm -f ell/$(DEPDIR)/strv.Plo + -rm -f ell/$(DEPDIR)/tester.Plo + -rm -f ell/$(DEPDIR)/time.Plo + -rm -f ell/$(DEPDIR)/timeout.Plo + -rm -f ell/$(DEPDIR)/tls-extensions.Plo + -rm -f ell/$(DEPDIR)/tls-record.Plo + -rm -f ell/$(DEPDIR)/tls-suites.Plo + -rm -f ell/$(DEPDIR)/tls.Plo + -rm -f ell/$(DEPDIR)/utf8.Plo + -rm -f ell/$(DEPDIR)/util.Plo + -rm -f ell/$(DEPDIR)/uuid.Plo + -rm -f emulator/$(DEPDIR)/amp.Po + -rm -f emulator/$(DEPDIR)/android_android_tester-btdev.Po + -rm -f emulator/$(DEPDIR)/android_android_tester-bthost.Po + -rm -f emulator/$(DEPDIR)/android_android_tester-hciemu.Po + -rm -f emulator/$(DEPDIR)/android_android_tester-smp.Po + -rm -f emulator/$(DEPDIR)/android_android_tester-vhci.Po + -rm -f emulator/$(DEPDIR)/android_ipc_tester-btdev.Po + -rm -f emulator/$(DEPDIR)/android_ipc_tester-bthost.Po + -rm -f emulator/$(DEPDIR)/android_ipc_tester-hciemu.Po + -rm -f emulator/$(DEPDIR)/android_ipc_tester-smp.Po + -rm -f emulator/$(DEPDIR)/android_ipc_tester-vhci.Po + -rm -f emulator/$(DEPDIR)/b1ee.Po + -rm -f emulator/$(DEPDIR)/btdev.Po + -rm -f emulator/$(DEPDIR)/bthost.Po + -rm -f emulator/$(DEPDIR)/hciemu.Po + -rm -f emulator/$(DEPDIR)/hfp.Po + -rm -f emulator/$(DEPDIR)/le.Po + -rm -f emulator/$(DEPDIR)/main.Po + -rm -f emulator/$(DEPDIR)/phy.Po + -rm -f emulator/$(DEPDIR)/serial.Po + -rm -f emulator/$(DEPDIR)/server.Po + -rm -f emulator/$(DEPDIR)/smp.Po + -rm -f emulator/$(DEPDIR)/vhci.Po + -rm -f gdbus/$(DEPDIR)/client.Plo + -rm -f gdbus/$(DEPDIR)/mainloop.Plo + -rm -f gdbus/$(DEPDIR)/object.Plo + -rm -f gdbus/$(DEPDIR)/polkit.Plo + -rm -f gdbus/$(DEPDIR)/watch.Plo + -rm -f gobex/$(DEPDIR)/gobex-apparam.Po + -rm -f gobex/$(DEPDIR)/gobex-defs.Po + -rm -f gobex/$(DEPDIR)/gobex-header.Po + -rm -f gobex/$(DEPDIR)/gobex-packet.Po + -rm -f gobex/$(DEPDIR)/gobex-transfer.Po + -rm -f gobex/$(DEPDIR)/gobex.Po + -rm -f gobex/$(DEPDIR)/obexd-gobex-apparam.Po + -rm -f gobex/$(DEPDIR)/obexd-gobex-defs.Po + -rm -f gobex/$(DEPDIR)/obexd-gobex-header.Po + -rm -f gobex/$(DEPDIR)/obexd-gobex-packet.Po + -rm -f gobex/$(DEPDIR)/obexd-gobex-transfer.Po + -rm -f gobex/$(DEPDIR)/obexd-gobex.Po + -rm -f lib/$(DEPDIR)/bluetooth.Plo + -rm -f lib/$(DEPDIR)/hci.Plo + -rm -f lib/$(DEPDIR)/sdp.Plo + -rm -f lib/$(DEPDIR)/uuid.Plo + -rm -f mesh/$(DEPDIR)/agent.Po + -rm -f mesh/$(DEPDIR)/appkey.Po + -rm -f mesh/$(DEPDIR)/cfgmod-server.Po + -rm -f mesh/$(DEPDIR)/crypto.Po + -rm -f mesh/$(DEPDIR)/dbus.Po + -rm -f mesh/$(DEPDIR)/friend.Po + -rm -f mesh/$(DEPDIR)/keyring.Po + -rm -f mesh/$(DEPDIR)/main.Po + -rm -f mesh/$(DEPDIR)/manager.Po + -rm -f mesh/$(DEPDIR)/mesh-config-json.Po + -rm -f mesh/$(DEPDIR)/mesh-io-generic.Po + -rm -f mesh/$(DEPDIR)/mesh-io-mgmt.Po + -rm -f mesh/$(DEPDIR)/mesh-io-unit.Po + -rm -f mesh/$(DEPDIR)/mesh-io.Po + -rm -f mesh/$(DEPDIR)/mesh-mgmt.Po + -rm -f mesh/$(DEPDIR)/mesh.Po + -rm -f mesh/$(DEPDIR)/model.Po + -rm -f mesh/$(DEPDIR)/net-keys.Po + -rm -f mesh/$(DEPDIR)/net.Po + -rm -f mesh/$(DEPDIR)/node.Po + -rm -f mesh/$(DEPDIR)/pb-adv.Po + -rm -f mesh/$(DEPDIR)/prov-acceptor.Po + -rm -f mesh/$(DEPDIR)/prov-initiator.Po + -rm -f mesh/$(DEPDIR)/prvbeac-server.Po + -rm -f mesh/$(DEPDIR)/remprv-server.Po + -rm -f mesh/$(DEPDIR)/rpl.Po + -rm -f mesh/$(DEPDIR)/util.Po + -rm -f monitor/$(DEPDIR)/a2dp.Po + -rm -f monitor/$(DEPDIR)/analyze.Po + -rm -f monitor/$(DEPDIR)/att.Po + -rm -f monitor/$(DEPDIR)/avctp.Po + -rm -f monitor/$(DEPDIR)/avdtp.Po + -rm -f monitor/$(DEPDIR)/bnep.Po + -rm -f monitor/$(DEPDIR)/broadcom.Po + -rm -f monitor/$(DEPDIR)/control.Po + -rm -f monitor/$(DEPDIR)/crc.Po + -rm -f monitor/$(DEPDIR)/display.Po + -rm -f monitor/$(DEPDIR)/ellisys.Po + -rm -f monitor/$(DEPDIR)/hcidump.Po + -rm -f monitor/$(DEPDIR)/hwdb.Po + -rm -f monitor/$(DEPDIR)/intel.Po + -rm -f monitor/$(DEPDIR)/jlink.Po + -rm -f monitor/$(DEPDIR)/keys.Po + -rm -f monitor/$(DEPDIR)/l2cap.Po + -rm -f monitor/$(DEPDIR)/ll.Po + -rm -f monitor/$(DEPDIR)/lmp.Po + -rm -f monitor/$(DEPDIR)/main.Po + -rm -f monitor/$(DEPDIR)/msft.Po + -rm -f monitor/$(DEPDIR)/packet.Po + -rm -f monitor/$(DEPDIR)/rfcomm.Po + -rm -f monitor/$(DEPDIR)/sdp.Po + -rm -f monitor/$(DEPDIR)/vendor.Po + -rm -f obexd/client/$(DEPDIR)/obexd-bip-common.Po + -rm -f obexd/client/$(DEPDIR)/obexd-bip.Po + -rm -f obexd/client/$(DEPDIR)/obexd-bluetooth.Po + -rm -f obexd/client/$(DEPDIR)/obexd-driver.Po + -rm -f obexd/client/$(DEPDIR)/obexd-ftp.Po + -rm -f obexd/client/$(DEPDIR)/obexd-manager.Po + -rm -f obexd/client/$(DEPDIR)/obexd-map-event.Po + -rm -f obexd/client/$(DEPDIR)/obexd-map.Po + -rm -f obexd/client/$(DEPDIR)/obexd-mns.Po + -rm -f obexd/client/$(DEPDIR)/obexd-opp.Po + -rm -f obexd/client/$(DEPDIR)/obexd-pbap.Po + -rm -f obexd/client/$(DEPDIR)/obexd-session.Po + -rm -f obexd/client/$(DEPDIR)/obexd-sync.Po + -rm -f obexd/client/$(DEPDIR)/obexd-transfer.Po + -rm -f obexd/client/$(DEPDIR)/obexd-transport.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-bluetooth.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-filesystem.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-ftp.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-irmc.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-mas.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-messages-dummy.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-opp.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-pbap.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-pcsuite.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-phonebook-@PLUGIN_PHONEBOOK@.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-vcard.Po + -rm -f obexd/src/$(DEPDIR)/obexd-log.Po + -rm -f obexd/src/$(DEPDIR)/obexd-main.Po + -rm -f obexd/src/$(DEPDIR)/obexd-manager.Po + -rm -f obexd/src/$(DEPDIR)/obexd-mimetype.Po + -rm -f obexd/src/$(DEPDIR)/obexd-obex.Po + -rm -f obexd/src/$(DEPDIR)/obexd-plugin.Po + -rm -f obexd/src/$(DEPDIR)/obexd-server.Po + -rm -f obexd/src/$(DEPDIR)/obexd-service.Po + -rm -f obexd/src/$(DEPDIR)/obexd-transport.Po + -rm -f peripheral/$(DEPDIR)/attach.Po + -rm -f peripheral/$(DEPDIR)/efivars.Po + -rm -f peripheral/$(DEPDIR)/gap.Po + -rm -f peripheral/$(DEPDIR)/gatt.Po + -rm -f peripheral/$(DEPDIR)/log.Po + -rm -f peripheral/$(DEPDIR)/main.Po + -rm -f plugins/$(DEPDIR)/bluetoothd-admin.Po + -rm -f plugins/$(DEPDIR)/bluetoothd-autopair.Po + -rm -f plugins/$(DEPDIR)/bluetoothd-hostname.Po + -rm -f plugins/$(DEPDIR)/bluetoothd-neard.Po + -rm -f plugins/$(DEPDIR)/bluetoothd-policy.Po + -rm -f plugins/$(DEPDIR)/bluetoothd-sixaxis.Po + -rm -f plugins/$(DEPDIR)/bluetoothd-wiimote.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-a2dp.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-asha.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-avctp.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-avdtp.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-avrcp.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-bap.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-bass.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-ccp.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-control.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-csip.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-mcp.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-media.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-micp.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-player.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-sink.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-source.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-transport.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-vcp.Po + -rm -f profiles/battery/$(DEPDIR)/bas.Po + -rm -f profiles/battery/$(DEPDIR)/bluetoothd-bas.Po + -rm -f profiles/battery/$(DEPDIR)/bluetoothd-battery.Po + -rm -f profiles/cups/$(DEPDIR)/hcrp.Po + -rm -f profiles/cups/$(DEPDIR)/main.Po + -rm -f profiles/cups/$(DEPDIR)/sdp.Po + -rm -f profiles/cups/$(DEPDIR)/spp.Po + -rm -f profiles/deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Po + -rm -f profiles/deviceinfo/$(DEPDIR)/bluetoothd-dis.Po + -rm -f profiles/deviceinfo/$(DEPDIR)/dis.Po + -rm -f profiles/gap/$(DEPDIR)/bluetoothd-gas.Po + -rm -f profiles/health/$(DEPDIR)/bluetoothd-hdp.Po + -rm -f profiles/health/$(DEPDIR)/bluetoothd-hdp_main.Po + -rm -f profiles/health/$(DEPDIR)/bluetoothd-hdp_manager.Po + -rm -f profiles/health/$(DEPDIR)/bluetoothd-hdp_util.Po + -rm -f profiles/health/$(DEPDIR)/bluetoothd-mcap.Po + -rm -f profiles/health/$(DEPDIR)/mcap.Po + -rm -f profiles/iap/$(DEPDIR)/main.Po + -rm -f profiles/input/$(DEPDIR)/bluetoothd-device.Po + -rm -f profiles/input/$(DEPDIR)/bluetoothd-hog-lib.Po + -rm -f profiles/input/$(DEPDIR)/bluetoothd-hog.Po + -rm -f profiles/input/$(DEPDIR)/bluetoothd-manager.Po + -rm -f profiles/input/$(DEPDIR)/bluetoothd-server.Po + -rm -f profiles/input/$(DEPDIR)/bluetoothd-suspend-none.Po + -rm -f profiles/input/$(DEPDIR)/hog-lib.Po + -rm -f profiles/midi/$(DEPDIR)/bluetoothd-libmidi.Po + -rm -f profiles/midi/$(DEPDIR)/bluetoothd-midi.Po + -rm -f profiles/midi/$(DEPDIR)/unit_test_midi-libmidi.Po + -rm -f profiles/network/$(DEPDIR)/bluetoothd-bnep.Po + -rm -f profiles/network/$(DEPDIR)/bluetoothd-connection.Po + -rm -f profiles/network/$(DEPDIR)/bluetoothd-manager.Po + -rm -f profiles/network/$(DEPDIR)/bluetoothd-server.Po + -rm -f profiles/network/$(DEPDIR)/bnep.Po + -rm -f profiles/sap/$(DEPDIR)/bluetoothd-main.Po + -rm -f profiles/sap/$(DEPDIR)/bluetoothd-manager.Po + -rm -f profiles/sap/$(DEPDIR)/bluetoothd-sap-dummy.Po + -rm -f profiles/sap/$(DEPDIR)/bluetoothd-server.Po + -rm -f profiles/scanparam/$(DEPDIR)/bluetoothd-scan.Po + -rm -f profiles/scanparam/$(DEPDIR)/bluetoothd-scpp.Po + -rm -f profiles/scanparam/$(DEPDIR)/scpp.Po + -rm -f src/$(DEPDIR)/android_avdtptest-log.Po + -rm -f src/$(DEPDIR)/bluetoothd-adapter.Po + -rm -f src/$(DEPDIR)/bluetoothd-adv_monitor.Po + -rm -f src/$(DEPDIR)/bluetoothd-advertising.Po + -rm -f src/$(DEPDIR)/bluetoothd-agent.Po + -rm -f src/$(DEPDIR)/bluetoothd-backtrace.Po + -rm -f src/$(DEPDIR)/bluetoothd-battery.Po + -rm -f src/$(DEPDIR)/bluetoothd-dbus-common.Po + -rm -f src/$(DEPDIR)/bluetoothd-device.Po + -rm -f src/$(DEPDIR)/bluetoothd-eir.Po + -rm -f src/$(DEPDIR)/bluetoothd-error.Po + -rm -f src/$(DEPDIR)/bluetoothd-gatt-client.Po + -rm -f src/$(DEPDIR)/bluetoothd-gatt-database.Po + -rm -f src/$(DEPDIR)/bluetoothd-log.Po + -rm -f src/$(DEPDIR)/bluetoothd-main.Po + -rm -f src/$(DEPDIR)/bluetoothd-plugin.Po + -rm -f src/$(DEPDIR)/bluetoothd-profile.Po + -rm -f src/$(DEPDIR)/bluetoothd-rfkill.Po + -rm -f src/$(DEPDIR)/bluetoothd-sdp-client.Po + -rm -f src/$(DEPDIR)/bluetoothd-sdp-xml.Po + -rm -f src/$(DEPDIR)/bluetoothd-sdpd-database.Po + -rm -f src/$(DEPDIR)/bluetoothd-sdpd-request.Po + -rm -f src/$(DEPDIR)/bluetoothd-sdpd-server.Po + -rm -f src/$(DEPDIR)/bluetoothd-sdpd-service.Po + -rm -f src/$(DEPDIR)/bluetoothd-service.Po + -rm -f src/$(DEPDIR)/bluetoothd-set.Po + -rm -f src/$(DEPDIR)/bluetoothd-settings.Po + -rm -f src/$(DEPDIR)/bluetoothd-storage.Po + -rm -f src/$(DEPDIR)/bluetoothd-textfile.Po + -rm -f src/$(DEPDIR)/bluetoothd-uuid-helper.Po + -rm -f src/$(DEPDIR)/eir.Po + -rm -f src/$(DEPDIR)/log.Po + -rm -f src/$(DEPDIR)/oui.Po + -rm -f src/$(DEPDIR)/sdp-client.Po + -rm -f src/$(DEPDIR)/sdp-xml.Po + -rm -f src/$(DEPDIR)/sdpd-database.Po + -rm -f src/$(DEPDIR)/sdpd-request.Po + -rm -f src/$(DEPDIR)/sdpd-server.Po + -rm -f src/$(DEPDIR)/sdpd-service.Po + -rm -f src/$(DEPDIR)/settings.Po + -rm -f src/$(DEPDIR)/textfile.Po + -rm -f src/$(DEPDIR)/uuid-helper.Po + -rm -f src/shared/$(DEPDIR)/android_avdtptest-log.Po + -rm -f src/shared/$(DEPDIR)/android_avdtptest-queue.Po + -rm -f src/shared/$(DEPDIR)/android_avdtptest-util.Po + -rm -f src/shared/$(DEPDIR)/btp.Po + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-ad.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-asha.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-att.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-bap-debug.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-bap.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-bass.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-btsnoop.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-ccp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-crypto.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-csip.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-ecc.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-gap.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-gatt-client.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-gatt-db.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-gatt-helpers.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-gatt-server.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-hci-crypto.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-hci.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-hfp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-io-ell.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-log.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-mainloop-ell.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-mcp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-mgmt.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-micp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-pcap.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-queue.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-ringbuf.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-shell.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-timeout-ell.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-uhid.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-util.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-vcp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-ad.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-asha.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-att.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-bap-debug.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-bap.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-bass.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-btsnoop.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-ccp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-crypto.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-csip.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-ecc.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-gap.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-gatt-client.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-gatt-db.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-gatt-helpers.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-gatt-server.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-hci-crypto.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-hci.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-hfp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-io-glib.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-log.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-mainloop-glib.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-mainloop-notify.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-mcp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-mgmt.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-micp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-pcap.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-queue.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-ringbuf.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-shell.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-tester.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-timeout-glib.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-uhid.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-util.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-vcp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-ad.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-asha.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-att.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-bap-debug.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-bap.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-bass.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-btsnoop.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-ccp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-crypto.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-csip.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-ecc.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-gap.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-client.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-db.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-helpers.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-server.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-hci-crypto.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-hci.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-hfp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-io-mainloop.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-log.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-mainloop-notify.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-mainloop.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-mcp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-mgmt.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-micp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-pcap.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-queue.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-ringbuf.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-shell.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-timeout-mainloop.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-uhid.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-util.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-vcp.Plo + -rm -f tools/$(DEPDIR)/3dsp.Po + -rm -f tools/$(DEPDIR)/advtest.Po + -rm -f tools/$(DEPDIR)/amptest.Po + -rm -f tools/$(DEPDIR)/avinfo.Po + -rm -f tools/$(DEPDIR)/avtest.Po + -rm -f tools/$(DEPDIR)/bcmfw.Po + -rm -f tools/$(DEPDIR)/bdaddr.Po + -rm -f tools/$(DEPDIR)/bluemoon.Po + -rm -f tools/$(DEPDIR)/bluetooth-player.Po + -rm -f tools/$(DEPDIR)/bnep-tester.Po + -rm -f tools/$(DEPDIR)/bneptest.Po + -rm -f tools/$(DEPDIR)/btattach.Po + -rm -f tools/$(DEPDIR)/btconfig.Po + -rm -f tools/$(DEPDIR)/btgatt-client.Po + -rm -f tools/$(DEPDIR)/btgatt-server.Po + -rm -f tools/$(DEPDIR)/btinfo.Po + -rm -f tools/$(DEPDIR)/btiotest.Po + -rm -f tools/$(DEPDIR)/btmgmt.Po + -rm -f tools/$(DEPDIR)/btmon-logger.Po + -rm -f tools/$(DEPDIR)/btpclient.Po + -rm -f tools/$(DEPDIR)/btpclientctl.Po + -rm -f tools/$(DEPDIR)/btproxy.Po + -rm -f tools/$(DEPDIR)/btsnoop.Po + -rm -f tools/$(DEPDIR)/check-selftest.Po + -rm -f tools/$(DEPDIR)/ciptool.Po + -rm -f tools/$(DEPDIR)/cltest.Po + -rm -f tools/$(DEPDIR)/create-image.Po + -rm -f tools/$(DEPDIR)/eddystone.Po + -rm -f tools/$(DEPDIR)/gap-tester.Po + -rm -f tools/$(DEPDIR)/gatt-service.Po + -rm -f tools/$(DEPDIR)/hci-tester.Po + -rm -f tools/$(DEPDIR)/hciattach.Po + -rm -f tools/$(DEPDIR)/hciattach_ath3k.Po + -rm -f tools/$(DEPDIR)/hciattach_bcm43xx.Po + -rm -f tools/$(DEPDIR)/hciattach_intel.Po + -rm -f tools/$(DEPDIR)/hciattach_qualcomm.Po + -rm -f tools/$(DEPDIR)/hciattach_st.Po + -rm -f tools/$(DEPDIR)/hciattach_ti.Po + -rm -f tools/$(DEPDIR)/hciattach_tialt.Po + -rm -f tools/$(DEPDIR)/hciconfig.Po + -rm -f tools/$(DEPDIR)/hcidump.Po + -rm -f tools/$(DEPDIR)/hcieventmask.Po + -rm -f tools/$(DEPDIR)/hcisecfilter.Po + -rm -f tools/$(DEPDIR)/hcitool.Po + -rm -f tools/$(DEPDIR)/hex2hcd.Po + -rm -f tools/$(DEPDIR)/hid2hci.Po + -rm -f tools/$(DEPDIR)/hwdb.Po + -rm -f tools/$(DEPDIR)/ibeacon.Po + -rm -f tools/$(DEPDIR)/ioctl-tester.Po + -rm -f tools/$(DEPDIR)/iso-tester.Po + -rm -f tools/$(DEPDIR)/isotest.Po + -rm -f tools/$(DEPDIR)/l2cap-tester.Po + -rm -f tools/$(DEPDIR)/l2ping.Po + -rm -f tools/$(DEPDIR)/l2test.Po + -rm -f tools/$(DEPDIR)/mcaptest.Po + -rm -f tools/$(DEPDIR)/mesh-cfgclient.Po + -rm -f tools/$(DEPDIR)/mesh-cfgtest.Po + -rm -f tools/$(DEPDIR)/mesh-tester.Po + -rm -f tools/$(DEPDIR)/meshctl.Po + -rm -f tools/$(DEPDIR)/mgmt-tester.Po + -rm -f tools/$(DEPDIR)/mpris-proxy.Po + -rm -f tools/$(DEPDIR)/nokfw.Po + -rm -f tools/$(DEPDIR)/obex-client-tool.Po + -rm -f tools/$(DEPDIR)/obex-server-tool.Po + -rm -f tools/$(DEPDIR)/obexctl.Po + -rm -f tools/$(DEPDIR)/oobtest.Po + -rm -f tools/$(DEPDIR)/rctest.Po + -rm -f tools/$(DEPDIR)/rfcomm-tester.Po + -rm -f tools/$(DEPDIR)/rfcomm.Po + -rm -f tools/$(DEPDIR)/rtlfw.Po + -rm -f tools/$(DEPDIR)/sco-tester.Po + -rm -f tools/$(DEPDIR)/scotest.Po + -rm -f tools/$(DEPDIR)/sdptool.Po + -rm -f tools/$(DEPDIR)/seq2bseq.Po + -rm -f tools/$(DEPDIR)/smp-tester.Po + -rm -f tools/$(DEPDIR)/test-runner.Po + -rm -f tools/$(DEPDIR)/userchan-tester.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/config-client.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/config-server.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/crypto.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/gatt.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/net.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/node.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/onoff-model.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/prov-db.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/prov.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/util.Po + -rm -f tools/mesh/$(DEPDIR)/agent.Po + -rm -f tools/mesh/$(DEPDIR)/cfgcli.Po + -rm -f tools/mesh/$(DEPDIR)/keys.Po + -rm -f tools/mesh/$(DEPDIR)/mesh-db.Po + -rm -f tools/mesh/$(DEPDIR)/remote.Po + -rm -f tools/mesh/$(DEPDIR)/util.Po + -rm -f tools/parser/$(DEPDIR)/amp.Po + -rm -f tools/parser/$(DEPDIR)/att.Po + -rm -f tools/parser/$(DEPDIR)/avctp.Po + -rm -f tools/parser/$(DEPDIR)/avdtp.Po + -rm -f tools/parser/$(DEPDIR)/avrcp.Po + -rm -f tools/parser/$(DEPDIR)/bnep.Po + -rm -f tools/parser/$(DEPDIR)/bpa.Po + -rm -f tools/parser/$(DEPDIR)/capi.Po + -rm -f tools/parser/$(DEPDIR)/cmtp.Po + -rm -f tools/parser/$(DEPDIR)/csr.Po + -rm -f tools/parser/$(DEPDIR)/ericsson.Po + -rm -f tools/parser/$(DEPDIR)/hci.Po + -rm -f tools/parser/$(DEPDIR)/hcrp.Po + -rm -f tools/parser/$(DEPDIR)/hidp.Po + -rm -f tools/parser/$(DEPDIR)/l2cap.Po + -rm -f tools/parser/$(DEPDIR)/lmp.Po + -rm -f tools/parser/$(DEPDIR)/obex.Po + -rm -f tools/parser/$(DEPDIR)/parser.Po + -rm -f tools/parser/$(DEPDIR)/ppp.Po + -rm -f tools/parser/$(DEPDIR)/rfcomm.Po + -rm -f tools/parser/$(DEPDIR)/sap.Po + -rm -f tools/parser/$(DEPDIR)/sdp.Po + -rm -f tools/parser/$(DEPDIR)/smp.Po + -rm -f tools/parser/$(DEPDIR)/tcpip.Po + -rm -f unit/$(DEPDIR)/test-avctp.Po + -rm -f unit/$(DEPDIR)/test-avdtp.Po + -rm -f unit/$(DEPDIR)/test-avrcp.Po + -rm -f unit/$(DEPDIR)/test-bap.Po + -rm -f unit/$(DEPDIR)/test-bass.Po + -rm -f unit/$(DEPDIR)/test-crc.Po + -rm -f unit/$(DEPDIR)/test-crypto.Po + -rm -f unit/$(DEPDIR)/test-ecc.Po + -rm -f unit/$(DEPDIR)/test-eir.Po + -rm -f unit/$(DEPDIR)/test-gatt.Po + -rm -f unit/$(DEPDIR)/test-gattrib.Po + -rm -f unit/$(DEPDIR)/test-gdbus-client.Po + -rm -f unit/$(DEPDIR)/test-gobex-apparam.Po + -rm -f unit/$(DEPDIR)/test-gobex-header.Po + -rm -f unit/$(DEPDIR)/test-gobex-packet.Po + -rm -f unit/$(DEPDIR)/test-gobex-transfer.Po + -rm -f unit/$(DEPDIR)/test-gobex.Po + -rm -f unit/$(DEPDIR)/test-hfp.Po + -rm -f unit/$(DEPDIR)/test-hog.Po + -rm -f unit/$(DEPDIR)/test-lib.Po + -rm -f unit/$(DEPDIR)/test-mgmt.Po + -rm -f unit/$(DEPDIR)/test-micp.Po + -rm -f unit/$(DEPDIR)/test-queue.Po + -rm -f unit/$(DEPDIR)/test-ringbuf.Po + -rm -f unit/$(DEPDIR)/test-sdp.Po + -rm -f unit/$(DEPDIR)/test-tester.Po + -rm -f unit/$(DEPDIR)/test-textfile.Po + -rm -f unit/$(DEPDIR)/test-uhid.Po + -rm -f unit/$(DEPDIR)/test-uuid.Po + -rm -f unit/$(DEPDIR)/test-vcp.Po + -rm -f unit/$(DEPDIR)/test_mesh_crypto-test-mesh-crypto.Po + -rm -f unit/$(DEPDIR)/test_midi-test-midi.Po + -rm -f unit/$(DEPDIR)/util.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-confDATA install-cupsPROGRAMS \ + install-dbusDATA install-dbussessionbusDATA \ + install-dbussystembusDATA install-dist_zshcompletionDATA \ + install-man install-pkgconfigDATA install-pkgincludeHEADERS \ + install-pluginLTLIBRARIES install-rulesDATA install-stateDATA \ + install-systemdsystemunitDATA install-systemduserunitDATA \ + install-testSCRIPTS install-udevPROGRAMS + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-data-hook +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES \ + install-pkglibexecPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: install-man1 install-man5 install-man7 install-man8 + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f android/$(DEPDIR)/a2dp-sink.Po + -rm -f android/$(DEPDIR)/a2dp.Po + -rm -f android/$(DEPDIR)/android_tester-tester-a2dp.Po + -rm -f android/$(DEPDIR)/android_tester-tester-avrcp.Po + -rm -f android/$(DEPDIR)/android_tester-tester-bluetooth.Po + -rm -f android/$(DEPDIR)/android_tester-tester-gatt.Po + -rm -f android/$(DEPDIR)/android_tester-tester-hdp.Po + -rm -f android/$(DEPDIR)/android_tester-tester-hidhost.Po + -rm -f android/$(DEPDIR)/android_tester-tester-main.Po + -rm -f android/$(DEPDIR)/android_tester-tester-map-client.Po + -rm -f android/$(DEPDIR)/android_tester-tester-pan.Po + -rm -f android/$(DEPDIR)/android_tester-tester-socket.Po + -rm -f android/$(DEPDIR)/audio_a2dp_default_la-hal-audio-aptx.Plo + -rm -f android/$(DEPDIR)/audio_a2dp_default_la-hal-audio-sbc.Plo + -rm -f android/$(DEPDIR)/audio_a2dp_default_la-hal-audio.Plo + -rm -f android/$(DEPDIR)/audio_sco_default_la-hal-sco.Plo + -rm -f android/$(DEPDIR)/avctp.Po + -rm -f android/$(DEPDIR)/avdtp.Po + -rm -f android/$(DEPDIR)/avdtptest-avdtp.Po + -rm -f android/$(DEPDIR)/avdtptest-avdtptest.Po + -rm -f android/$(DEPDIR)/avrcp-lib.Po + -rm -f android/$(DEPDIR)/avrcp.Po + -rm -f android/$(DEPDIR)/bluetooth.Po + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-a2dp-sink.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-a2dp.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-avrcp-ctrl.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-avrcp.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-bluetooth.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-gatt.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-handsfree-client.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-handsfree.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-health.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-hidhost.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-ipc.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-map-client.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-pan.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-socket.Plo + -rm -f android/$(DEPDIR)/bluetooth_default_la-hal-utils.Plo + -rm -f android/$(DEPDIR)/bluetoothd-snoop.Po + -rm -f android/$(DEPDIR)/gatt.Po + -rm -f android/$(DEPDIR)/haltest-hal-utils.Po + -rm -f android/$(DEPDIR)/handsfree-client.Po + -rm -f android/$(DEPDIR)/handsfree.Po + -rm -f android/$(DEPDIR)/health.Po + -rm -f android/$(DEPDIR)/hidhost.Po + -rm -f android/$(DEPDIR)/ipc.Po + -rm -f android/$(DEPDIR)/ipc_tester-hal-utils.Po + -rm -f android/$(DEPDIR)/ipc_tester-ipc-tester.Po + -rm -f android/$(DEPDIR)/main.Po + -rm -f android/$(DEPDIR)/map-client.Po + -rm -f android/$(DEPDIR)/pan.Po + -rm -f android/$(DEPDIR)/sco.Po + -rm -f android/$(DEPDIR)/socket.Po + -rm -f android/$(DEPDIR)/system-emulator.Po + -rm -f android/$(DEPDIR)/test-ipc.Po + -rm -f android/audio_utils/$(DEPDIR)/audio_sco_default_la-resampler.Plo + -rm -f android/client/$(DEPDIR)/haltest-haltest.Po + -rm -f android/client/$(DEPDIR)/haltest-history.Po + -rm -f android/client/$(DEPDIR)/haltest-if-audio.Po + -rm -f android/client/$(DEPDIR)/haltest-if-av-sink.Po + -rm -f android/client/$(DEPDIR)/haltest-if-av.Po + -rm -f android/client/$(DEPDIR)/haltest-if-bt.Po + -rm -f android/client/$(DEPDIR)/haltest-if-gatt.Po + -rm -f android/client/$(DEPDIR)/haltest-if-hf-client.Po + -rm -f android/client/$(DEPDIR)/haltest-if-hf.Po + -rm -f android/client/$(DEPDIR)/haltest-if-hh.Po + -rm -f android/client/$(DEPDIR)/haltest-if-hl.Po + -rm -f android/client/$(DEPDIR)/haltest-if-mce.Po + -rm -f android/client/$(DEPDIR)/haltest-if-pan.Po + -rm -f android/client/$(DEPDIR)/haltest-if-rc-ctrl.Po + -rm -f android/client/$(DEPDIR)/haltest-if-rc.Po + -rm -f android/client/$(DEPDIR)/haltest-if-sco.Po + -rm -f android/client/$(DEPDIR)/haltest-if-sock.Po + -rm -f android/client/$(DEPDIR)/haltest-pollhandler.Po + -rm -f android/client/$(DEPDIR)/haltest-tabcompletion.Po + -rm -f android/client/$(DEPDIR)/haltest-terminal.Po + -rm -f android/hardware/$(DEPDIR)/android_tester-hardware.Po + -rm -f android/hardware/$(DEPDIR)/haltest-hardware.Po + -rm -f attrib/$(DEPDIR)/att.Po + -rm -f attrib/$(DEPDIR)/bluetoothd-att.Po + -rm -f attrib/$(DEPDIR)/bluetoothd-gatt.Po + -rm -f attrib/$(DEPDIR)/bluetoothd-gattrib.Po + -rm -f attrib/$(DEPDIR)/gatt.Po + -rm -f attrib/$(DEPDIR)/gattrib.Po + -rm -f attrib/$(DEPDIR)/gatttool.Po + -rm -f attrib/$(DEPDIR)/interactive.Po + -rm -f attrib/$(DEPDIR)/utils.Po + -rm -f btio/$(DEPDIR)/android_avdtptest-btio.Po + -rm -f btio/$(DEPDIR)/bluetoothd-btio.Po + -rm -f btio/$(DEPDIR)/btio.Po + -rm -f btio/$(DEPDIR)/obexd-btio.Po + -rm -f client/$(DEPDIR)/admin.Po + -rm -f client/$(DEPDIR)/adv_monitor.Po + -rm -f client/$(DEPDIR)/advertising.Po + -rm -f client/$(DEPDIR)/agent.Po + -rm -f client/$(DEPDIR)/assistant.Po + -rm -f client/$(DEPDIR)/display.Po + -rm -f client/$(DEPDIR)/gatt.Po + -rm -f client/$(DEPDIR)/main.Po + -rm -f client/$(DEPDIR)/mgmt.Po + -rm -f client/$(DEPDIR)/player.Po + -rm -f client/$(DEPDIR)/print.Po + -rm -f ell/$(DEPDIR)/base64.Plo + -rm -f ell/$(DEPDIR)/cert-crypto.Plo + -rm -f ell/$(DEPDIR)/cert.Plo + -rm -f ell/$(DEPDIR)/checksum.Plo + -rm -f ell/$(DEPDIR)/cipher.Plo + -rm -f ell/$(DEPDIR)/dbus-client.Plo + -rm -f ell/$(DEPDIR)/dbus-filter.Plo + -rm -f ell/$(DEPDIR)/dbus-message.Plo + -rm -f ell/$(DEPDIR)/dbus-name-cache.Plo + -rm -f ell/$(DEPDIR)/dbus-service.Plo + -rm -f ell/$(DEPDIR)/dbus-util.Plo + -rm -f ell/$(DEPDIR)/dbus.Plo + -rm -f ell/$(DEPDIR)/ecc-external.Plo + -rm -f ell/$(DEPDIR)/ecc.Plo + -rm -f ell/$(DEPDIR)/ecdh.Plo + -rm -f ell/$(DEPDIR)/gvariant-util.Plo + -rm -f ell/$(DEPDIR)/hashmap.Plo + -rm -f ell/$(DEPDIR)/idle.Plo + -rm -f ell/$(DEPDIR)/io.Plo + -rm -f ell/$(DEPDIR)/key.Plo + -rm -f ell/$(DEPDIR)/log.Plo + -rm -f ell/$(DEPDIR)/main.Plo + -rm -f ell/$(DEPDIR)/pem.Plo + -rm -f ell/$(DEPDIR)/queue.Plo + -rm -f ell/$(DEPDIR)/random.Plo + -rm -f ell/$(DEPDIR)/settings.Plo + -rm -f ell/$(DEPDIR)/signal.Plo + -rm -f ell/$(DEPDIR)/siphash.Plo + -rm -f ell/$(DEPDIR)/string.Plo + -rm -f ell/$(DEPDIR)/strv.Plo + -rm -f ell/$(DEPDIR)/tester.Plo + -rm -f ell/$(DEPDIR)/time.Plo + -rm -f ell/$(DEPDIR)/timeout.Plo + -rm -f ell/$(DEPDIR)/tls-extensions.Plo + -rm -f ell/$(DEPDIR)/tls-record.Plo + -rm -f ell/$(DEPDIR)/tls-suites.Plo + -rm -f ell/$(DEPDIR)/tls.Plo + -rm -f ell/$(DEPDIR)/utf8.Plo + -rm -f ell/$(DEPDIR)/util.Plo + -rm -f ell/$(DEPDIR)/uuid.Plo + -rm -f emulator/$(DEPDIR)/amp.Po + -rm -f emulator/$(DEPDIR)/android_android_tester-btdev.Po + -rm -f emulator/$(DEPDIR)/android_android_tester-bthost.Po + -rm -f emulator/$(DEPDIR)/android_android_tester-hciemu.Po + -rm -f emulator/$(DEPDIR)/android_android_tester-smp.Po + -rm -f emulator/$(DEPDIR)/android_android_tester-vhci.Po + -rm -f emulator/$(DEPDIR)/android_ipc_tester-btdev.Po + -rm -f emulator/$(DEPDIR)/android_ipc_tester-bthost.Po + -rm -f emulator/$(DEPDIR)/android_ipc_tester-hciemu.Po + -rm -f emulator/$(DEPDIR)/android_ipc_tester-smp.Po + -rm -f emulator/$(DEPDIR)/android_ipc_tester-vhci.Po + -rm -f emulator/$(DEPDIR)/b1ee.Po + -rm -f emulator/$(DEPDIR)/btdev.Po + -rm -f emulator/$(DEPDIR)/bthost.Po + -rm -f emulator/$(DEPDIR)/hciemu.Po + -rm -f emulator/$(DEPDIR)/hfp.Po + -rm -f emulator/$(DEPDIR)/le.Po + -rm -f emulator/$(DEPDIR)/main.Po + -rm -f emulator/$(DEPDIR)/phy.Po + -rm -f emulator/$(DEPDIR)/serial.Po + -rm -f emulator/$(DEPDIR)/server.Po + -rm -f emulator/$(DEPDIR)/smp.Po + -rm -f emulator/$(DEPDIR)/vhci.Po + -rm -f gdbus/$(DEPDIR)/client.Plo + -rm -f gdbus/$(DEPDIR)/mainloop.Plo + -rm -f gdbus/$(DEPDIR)/object.Plo + -rm -f gdbus/$(DEPDIR)/polkit.Plo + -rm -f gdbus/$(DEPDIR)/watch.Plo + -rm -f gobex/$(DEPDIR)/gobex-apparam.Po + -rm -f gobex/$(DEPDIR)/gobex-defs.Po + -rm -f gobex/$(DEPDIR)/gobex-header.Po + -rm -f gobex/$(DEPDIR)/gobex-packet.Po + -rm -f gobex/$(DEPDIR)/gobex-transfer.Po + -rm -f gobex/$(DEPDIR)/gobex.Po + -rm -f gobex/$(DEPDIR)/obexd-gobex-apparam.Po + -rm -f gobex/$(DEPDIR)/obexd-gobex-defs.Po + -rm -f gobex/$(DEPDIR)/obexd-gobex-header.Po + -rm -f gobex/$(DEPDIR)/obexd-gobex-packet.Po + -rm -f gobex/$(DEPDIR)/obexd-gobex-transfer.Po + -rm -f gobex/$(DEPDIR)/obexd-gobex.Po + -rm -f lib/$(DEPDIR)/bluetooth.Plo + -rm -f lib/$(DEPDIR)/hci.Plo + -rm -f lib/$(DEPDIR)/sdp.Plo + -rm -f lib/$(DEPDIR)/uuid.Plo + -rm -f mesh/$(DEPDIR)/agent.Po + -rm -f mesh/$(DEPDIR)/appkey.Po + -rm -f mesh/$(DEPDIR)/cfgmod-server.Po + -rm -f mesh/$(DEPDIR)/crypto.Po + -rm -f mesh/$(DEPDIR)/dbus.Po + -rm -f mesh/$(DEPDIR)/friend.Po + -rm -f mesh/$(DEPDIR)/keyring.Po + -rm -f mesh/$(DEPDIR)/main.Po + -rm -f mesh/$(DEPDIR)/manager.Po + -rm -f mesh/$(DEPDIR)/mesh-config-json.Po + -rm -f mesh/$(DEPDIR)/mesh-io-generic.Po + -rm -f mesh/$(DEPDIR)/mesh-io-mgmt.Po + -rm -f mesh/$(DEPDIR)/mesh-io-unit.Po + -rm -f mesh/$(DEPDIR)/mesh-io.Po + -rm -f mesh/$(DEPDIR)/mesh-mgmt.Po + -rm -f mesh/$(DEPDIR)/mesh.Po + -rm -f mesh/$(DEPDIR)/model.Po + -rm -f mesh/$(DEPDIR)/net-keys.Po + -rm -f mesh/$(DEPDIR)/net.Po + -rm -f mesh/$(DEPDIR)/node.Po + -rm -f mesh/$(DEPDIR)/pb-adv.Po + -rm -f mesh/$(DEPDIR)/prov-acceptor.Po + -rm -f mesh/$(DEPDIR)/prov-initiator.Po + -rm -f mesh/$(DEPDIR)/prvbeac-server.Po + -rm -f mesh/$(DEPDIR)/remprv-server.Po + -rm -f mesh/$(DEPDIR)/rpl.Po + -rm -f mesh/$(DEPDIR)/util.Po + -rm -f monitor/$(DEPDIR)/a2dp.Po + -rm -f monitor/$(DEPDIR)/analyze.Po + -rm -f monitor/$(DEPDIR)/att.Po + -rm -f monitor/$(DEPDIR)/avctp.Po + -rm -f monitor/$(DEPDIR)/avdtp.Po + -rm -f monitor/$(DEPDIR)/bnep.Po + -rm -f monitor/$(DEPDIR)/broadcom.Po + -rm -f monitor/$(DEPDIR)/control.Po + -rm -f monitor/$(DEPDIR)/crc.Po + -rm -f monitor/$(DEPDIR)/display.Po + -rm -f monitor/$(DEPDIR)/ellisys.Po + -rm -f monitor/$(DEPDIR)/hcidump.Po + -rm -f monitor/$(DEPDIR)/hwdb.Po + -rm -f monitor/$(DEPDIR)/intel.Po + -rm -f monitor/$(DEPDIR)/jlink.Po + -rm -f monitor/$(DEPDIR)/keys.Po + -rm -f monitor/$(DEPDIR)/l2cap.Po + -rm -f monitor/$(DEPDIR)/ll.Po + -rm -f monitor/$(DEPDIR)/lmp.Po + -rm -f monitor/$(DEPDIR)/main.Po + -rm -f monitor/$(DEPDIR)/msft.Po + -rm -f monitor/$(DEPDIR)/packet.Po + -rm -f monitor/$(DEPDIR)/rfcomm.Po + -rm -f monitor/$(DEPDIR)/sdp.Po + -rm -f monitor/$(DEPDIR)/vendor.Po + -rm -f obexd/client/$(DEPDIR)/obexd-bip-common.Po + -rm -f obexd/client/$(DEPDIR)/obexd-bip.Po + -rm -f obexd/client/$(DEPDIR)/obexd-bluetooth.Po + -rm -f obexd/client/$(DEPDIR)/obexd-driver.Po + -rm -f obexd/client/$(DEPDIR)/obexd-ftp.Po + -rm -f obexd/client/$(DEPDIR)/obexd-manager.Po + -rm -f obexd/client/$(DEPDIR)/obexd-map-event.Po + -rm -f obexd/client/$(DEPDIR)/obexd-map.Po + -rm -f obexd/client/$(DEPDIR)/obexd-mns.Po + -rm -f obexd/client/$(DEPDIR)/obexd-opp.Po + -rm -f obexd/client/$(DEPDIR)/obexd-pbap.Po + -rm -f obexd/client/$(DEPDIR)/obexd-session.Po + -rm -f obexd/client/$(DEPDIR)/obexd-sync.Po + -rm -f obexd/client/$(DEPDIR)/obexd-transfer.Po + -rm -f obexd/client/$(DEPDIR)/obexd-transport.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-bluetooth.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-filesystem.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-ftp.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-irmc.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-mas.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-messages-dummy.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-opp.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-pbap.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-pcsuite.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-phonebook-@PLUGIN_PHONEBOOK@.Po + -rm -f obexd/plugins/$(DEPDIR)/obexd-vcard.Po + -rm -f obexd/src/$(DEPDIR)/obexd-log.Po + -rm -f obexd/src/$(DEPDIR)/obexd-main.Po + -rm -f obexd/src/$(DEPDIR)/obexd-manager.Po + -rm -f obexd/src/$(DEPDIR)/obexd-mimetype.Po + -rm -f obexd/src/$(DEPDIR)/obexd-obex.Po + -rm -f obexd/src/$(DEPDIR)/obexd-plugin.Po + -rm -f obexd/src/$(DEPDIR)/obexd-server.Po + -rm -f obexd/src/$(DEPDIR)/obexd-service.Po + -rm -f obexd/src/$(DEPDIR)/obexd-transport.Po + -rm -f peripheral/$(DEPDIR)/attach.Po + -rm -f peripheral/$(DEPDIR)/efivars.Po + -rm -f peripheral/$(DEPDIR)/gap.Po + -rm -f peripheral/$(DEPDIR)/gatt.Po + -rm -f peripheral/$(DEPDIR)/log.Po + -rm -f peripheral/$(DEPDIR)/main.Po + -rm -f plugins/$(DEPDIR)/bluetoothd-admin.Po + -rm -f plugins/$(DEPDIR)/bluetoothd-autopair.Po + -rm -f plugins/$(DEPDIR)/bluetoothd-hostname.Po + -rm -f plugins/$(DEPDIR)/bluetoothd-neard.Po + -rm -f plugins/$(DEPDIR)/bluetoothd-policy.Po + -rm -f plugins/$(DEPDIR)/bluetoothd-sixaxis.Po + -rm -f plugins/$(DEPDIR)/bluetoothd-wiimote.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-a2dp.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-asha.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-avctp.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-avdtp.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-avrcp.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-bap.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-bass.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-ccp.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-control.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-csip.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-mcp.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-media.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-micp.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-player.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-sink.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-source.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-transport.Po + -rm -f profiles/audio/$(DEPDIR)/bluetoothd-vcp.Po + -rm -f profiles/battery/$(DEPDIR)/bas.Po + -rm -f profiles/battery/$(DEPDIR)/bluetoothd-bas.Po + -rm -f profiles/battery/$(DEPDIR)/bluetoothd-battery.Po + -rm -f profiles/cups/$(DEPDIR)/hcrp.Po + -rm -f profiles/cups/$(DEPDIR)/main.Po + -rm -f profiles/cups/$(DEPDIR)/sdp.Po + -rm -f profiles/cups/$(DEPDIR)/spp.Po + -rm -f profiles/deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Po + -rm -f profiles/deviceinfo/$(DEPDIR)/bluetoothd-dis.Po + -rm -f profiles/deviceinfo/$(DEPDIR)/dis.Po + -rm -f profiles/gap/$(DEPDIR)/bluetoothd-gas.Po + -rm -f profiles/health/$(DEPDIR)/bluetoothd-hdp.Po + -rm -f profiles/health/$(DEPDIR)/bluetoothd-hdp_main.Po + -rm -f profiles/health/$(DEPDIR)/bluetoothd-hdp_manager.Po + -rm -f profiles/health/$(DEPDIR)/bluetoothd-hdp_util.Po + -rm -f profiles/health/$(DEPDIR)/bluetoothd-mcap.Po + -rm -f profiles/health/$(DEPDIR)/mcap.Po + -rm -f profiles/iap/$(DEPDIR)/main.Po + -rm -f profiles/input/$(DEPDIR)/bluetoothd-device.Po + -rm -f profiles/input/$(DEPDIR)/bluetoothd-hog-lib.Po + -rm -f profiles/input/$(DEPDIR)/bluetoothd-hog.Po + -rm -f profiles/input/$(DEPDIR)/bluetoothd-manager.Po + -rm -f profiles/input/$(DEPDIR)/bluetoothd-server.Po + -rm -f profiles/input/$(DEPDIR)/bluetoothd-suspend-none.Po + -rm -f profiles/input/$(DEPDIR)/hog-lib.Po + -rm -f profiles/midi/$(DEPDIR)/bluetoothd-libmidi.Po + -rm -f profiles/midi/$(DEPDIR)/bluetoothd-midi.Po + -rm -f profiles/midi/$(DEPDIR)/unit_test_midi-libmidi.Po + -rm -f profiles/network/$(DEPDIR)/bluetoothd-bnep.Po + -rm -f profiles/network/$(DEPDIR)/bluetoothd-connection.Po + -rm -f profiles/network/$(DEPDIR)/bluetoothd-manager.Po + -rm -f profiles/network/$(DEPDIR)/bluetoothd-server.Po + -rm -f profiles/network/$(DEPDIR)/bnep.Po + -rm -f profiles/sap/$(DEPDIR)/bluetoothd-main.Po + -rm -f profiles/sap/$(DEPDIR)/bluetoothd-manager.Po + -rm -f profiles/sap/$(DEPDIR)/bluetoothd-sap-dummy.Po + -rm -f profiles/sap/$(DEPDIR)/bluetoothd-server.Po + -rm -f profiles/scanparam/$(DEPDIR)/bluetoothd-scan.Po + -rm -f profiles/scanparam/$(DEPDIR)/bluetoothd-scpp.Po + -rm -f profiles/scanparam/$(DEPDIR)/scpp.Po + -rm -f src/$(DEPDIR)/android_avdtptest-log.Po + -rm -f src/$(DEPDIR)/bluetoothd-adapter.Po + -rm -f src/$(DEPDIR)/bluetoothd-adv_monitor.Po + -rm -f src/$(DEPDIR)/bluetoothd-advertising.Po + -rm -f src/$(DEPDIR)/bluetoothd-agent.Po + -rm -f src/$(DEPDIR)/bluetoothd-backtrace.Po + -rm -f src/$(DEPDIR)/bluetoothd-battery.Po + -rm -f src/$(DEPDIR)/bluetoothd-dbus-common.Po + -rm -f src/$(DEPDIR)/bluetoothd-device.Po + -rm -f src/$(DEPDIR)/bluetoothd-eir.Po + -rm -f src/$(DEPDIR)/bluetoothd-error.Po + -rm -f src/$(DEPDIR)/bluetoothd-gatt-client.Po + -rm -f src/$(DEPDIR)/bluetoothd-gatt-database.Po + -rm -f src/$(DEPDIR)/bluetoothd-log.Po + -rm -f src/$(DEPDIR)/bluetoothd-main.Po + -rm -f src/$(DEPDIR)/bluetoothd-plugin.Po + -rm -f src/$(DEPDIR)/bluetoothd-profile.Po + -rm -f src/$(DEPDIR)/bluetoothd-rfkill.Po + -rm -f src/$(DEPDIR)/bluetoothd-sdp-client.Po + -rm -f src/$(DEPDIR)/bluetoothd-sdp-xml.Po + -rm -f src/$(DEPDIR)/bluetoothd-sdpd-database.Po + -rm -f src/$(DEPDIR)/bluetoothd-sdpd-request.Po + -rm -f src/$(DEPDIR)/bluetoothd-sdpd-server.Po + -rm -f src/$(DEPDIR)/bluetoothd-sdpd-service.Po + -rm -f src/$(DEPDIR)/bluetoothd-service.Po + -rm -f src/$(DEPDIR)/bluetoothd-set.Po + -rm -f src/$(DEPDIR)/bluetoothd-settings.Po + -rm -f src/$(DEPDIR)/bluetoothd-storage.Po + -rm -f src/$(DEPDIR)/bluetoothd-textfile.Po + -rm -f src/$(DEPDIR)/bluetoothd-uuid-helper.Po + -rm -f src/$(DEPDIR)/eir.Po + -rm -f src/$(DEPDIR)/log.Po + -rm -f src/$(DEPDIR)/oui.Po + -rm -f src/$(DEPDIR)/sdp-client.Po + -rm -f src/$(DEPDIR)/sdp-xml.Po + -rm -f src/$(DEPDIR)/sdpd-database.Po + -rm -f src/$(DEPDIR)/sdpd-request.Po + -rm -f src/$(DEPDIR)/sdpd-server.Po + -rm -f src/$(DEPDIR)/sdpd-service.Po + -rm -f src/$(DEPDIR)/settings.Po + -rm -f src/$(DEPDIR)/textfile.Po + -rm -f src/$(DEPDIR)/uuid-helper.Po + -rm -f src/shared/$(DEPDIR)/android_avdtptest-log.Po + -rm -f src/shared/$(DEPDIR)/android_avdtptest-queue.Po + -rm -f src/shared/$(DEPDIR)/android_avdtptest-util.Po + -rm -f src/shared/$(DEPDIR)/btp.Po + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-ad.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-asha.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-att.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-bap-debug.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-bap.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-bass.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-btsnoop.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-ccp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-crypto.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-csip.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-ecc.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-gap.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-gatt-client.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-gatt-db.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-gatt-helpers.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-gatt-server.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-hci-crypto.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-hci.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-hfp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-io-ell.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-log.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-mainloop-ell.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-mcp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-mgmt.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-micp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-pcap.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-queue.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-ringbuf.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-shell.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-timeout-ell.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-uhid.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-util.Plo + -rm -f src/shared/$(DEPDIR)/libshared_ell_la-vcp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-ad.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-asha.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-att.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-bap-debug.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-bap.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-bass.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-btsnoop.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-ccp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-crypto.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-csip.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-ecc.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-gap.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-gatt-client.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-gatt-db.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-gatt-helpers.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-gatt-server.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-hci-crypto.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-hci.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-hfp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-io-glib.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-log.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-mainloop-glib.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-mainloop-notify.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-mcp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-mgmt.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-micp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-pcap.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-queue.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-ringbuf.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-shell.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-tester.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-timeout-glib.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-uhid.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-util.Plo + -rm -f src/shared/$(DEPDIR)/libshared_glib_la-vcp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-ad.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-asha.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-att.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-bap-debug.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-bap.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-bass.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-btsnoop.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-ccp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-crypto.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-csip.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-ecc.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-gap.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-client.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-db.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-helpers.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-gatt-server.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-hci-crypto.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-hci.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-hfp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-io-mainloop.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-log.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-mainloop-notify.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-mainloop.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-mcp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-mgmt.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-micp.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-pcap.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-queue.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-ringbuf.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-shell.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-timeout-mainloop.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-uhid.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-util.Plo + -rm -f src/shared/$(DEPDIR)/libshared_mainloop_la-vcp.Plo + -rm -f tools/$(DEPDIR)/3dsp.Po + -rm -f tools/$(DEPDIR)/advtest.Po + -rm -f tools/$(DEPDIR)/amptest.Po + -rm -f tools/$(DEPDIR)/avinfo.Po + -rm -f tools/$(DEPDIR)/avtest.Po + -rm -f tools/$(DEPDIR)/bcmfw.Po + -rm -f tools/$(DEPDIR)/bdaddr.Po + -rm -f tools/$(DEPDIR)/bluemoon.Po + -rm -f tools/$(DEPDIR)/bluetooth-player.Po + -rm -f tools/$(DEPDIR)/bnep-tester.Po + -rm -f tools/$(DEPDIR)/bneptest.Po + -rm -f tools/$(DEPDIR)/btattach.Po + -rm -f tools/$(DEPDIR)/btconfig.Po + -rm -f tools/$(DEPDIR)/btgatt-client.Po + -rm -f tools/$(DEPDIR)/btgatt-server.Po + -rm -f tools/$(DEPDIR)/btinfo.Po + -rm -f tools/$(DEPDIR)/btiotest.Po + -rm -f tools/$(DEPDIR)/btmgmt.Po + -rm -f tools/$(DEPDIR)/btmon-logger.Po + -rm -f tools/$(DEPDIR)/btpclient.Po + -rm -f tools/$(DEPDIR)/btpclientctl.Po + -rm -f tools/$(DEPDIR)/btproxy.Po + -rm -f tools/$(DEPDIR)/btsnoop.Po + -rm -f tools/$(DEPDIR)/check-selftest.Po + -rm -f tools/$(DEPDIR)/ciptool.Po + -rm -f tools/$(DEPDIR)/cltest.Po + -rm -f tools/$(DEPDIR)/create-image.Po + -rm -f tools/$(DEPDIR)/eddystone.Po + -rm -f tools/$(DEPDIR)/gap-tester.Po + -rm -f tools/$(DEPDIR)/gatt-service.Po + -rm -f tools/$(DEPDIR)/hci-tester.Po + -rm -f tools/$(DEPDIR)/hciattach.Po + -rm -f tools/$(DEPDIR)/hciattach_ath3k.Po + -rm -f tools/$(DEPDIR)/hciattach_bcm43xx.Po + -rm -f tools/$(DEPDIR)/hciattach_intel.Po + -rm -f tools/$(DEPDIR)/hciattach_qualcomm.Po + -rm -f tools/$(DEPDIR)/hciattach_st.Po + -rm -f tools/$(DEPDIR)/hciattach_ti.Po + -rm -f tools/$(DEPDIR)/hciattach_tialt.Po + -rm -f tools/$(DEPDIR)/hciconfig.Po + -rm -f tools/$(DEPDIR)/hcidump.Po + -rm -f tools/$(DEPDIR)/hcieventmask.Po + -rm -f tools/$(DEPDIR)/hcisecfilter.Po + -rm -f tools/$(DEPDIR)/hcitool.Po + -rm -f tools/$(DEPDIR)/hex2hcd.Po + -rm -f tools/$(DEPDIR)/hid2hci.Po + -rm -f tools/$(DEPDIR)/hwdb.Po + -rm -f tools/$(DEPDIR)/ibeacon.Po + -rm -f tools/$(DEPDIR)/ioctl-tester.Po + -rm -f tools/$(DEPDIR)/iso-tester.Po + -rm -f tools/$(DEPDIR)/isotest.Po + -rm -f tools/$(DEPDIR)/l2cap-tester.Po + -rm -f tools/$(DEPDIR)/l2ping.Po + -rm -f tools/$(DEPDIR)/l2test.Po + -rm -f tools/$(DEPDIR)/mcaptest.Po + -rm -f tools/$(DEPDIR)/mesh-cfgclient.Po + -rm -f tools/$(DEPDIR)/mesh-cfgtest.Po + -rm -f tools/$(DEPDIR)/mesh-tester.Po + -rm -f tools/$(DEPDIR)/meshctl.Po + -rm -f tools/$(DEPDIR)/mgmt-tester.Po + -rm -f tools/$(DEPDIR)/mpris-proxy.Po + -rm -f tools/$(DEPDIR)/nokfw.Po + -rm -f tools/$(DEPDIR)/obex-client-tool.Po + -rm -f tools/$(DEPDIR)/obex-server-tool.Po + -rm -f tools/$(DEPDIR)/obexctl.Po + -rm -f tools/$(DEPDIR)/oobtest.Po + -rm -f tools/$(DEPDIR)/rctest.Po + -rm -f tools/$(DEPDIR)/rfcomm-tester.Po + -rm -f tools/$(DEPDIR)/rfcomm.Po + -rm -f tools/$(DEPDIR)/rtlfw.Po + -rm -f tools/$(DEPDIR)/sco-tester.Po + -rm -f tools/$(DEPDIR)/scotest.Po + -rm -f tools/$(DEPDIR)/sdptool.Po + -rm -f tools/$(DEPDIR)/seq2bseq.Po + -rm -f tools/$(DEPDIR)/smp-tester.Po + -rm -f tools/$(DEPDIR)/test-runner.Po + -rm -f tools/$(DEPDIR)/userchan-tester.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/config-client.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/config-server.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/crypto.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/gatt.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/net.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/node.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/onoff-model.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/prov-db.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/prov.Po + -rm -f tools/mesh-gatt/$(DEPDIR)/util.Po + -rm -f tools/mesh/$(DEPDIR)/agent.Po + -rm -f tools/mesh/$(DEPDIR)/cfgcli.Po + -rm -f tools/mesh/$(DEPDIR)/keys.Po + -rm -f tools/mesh/$(DEPDIR)/mesh-db.Po + -rm -f tools/mesh/$(DEPDIR)/remote.Po + -rm -f tools/mesh/$(DEPDIR)/util.Po + -rm -f tools/parser/$(DEPDIR)/amp.Po + -rm -f tools/parser/$(DEPDIR)/att.Po + -rm -f tools/parser/$(DEPDIR)/avctp.Po + -rm -f tools/parser/$(DEPDIR)/avdtp.Po + -rm -f tools/parser/$(DEPDIR)/avrcp.Po + -rm -f tools/parser/$(DEPDIR)/bnep.Po + -rm -f tools/parser/$(DEPDIR)/bpa.Po + -rm -f tools/parser/$(DEPDIR)/capi.Po + -rm -f tools/parser/$(DEPDIR)/cmtp.Po + -rm -f tools/parser/$(DEPDIR)/csr.Po + -rm -f tools/parser/$(DEPDIR)/ericsson.Po + -rm -f tools/parser/$(DEPDIR)/hci.Po + -rm -f tools/parser/$(DEPDIR)/hcrp.Po + -rm -f tools/parser/$(DEPDIR)/hidp.Po + -rm -f tools/parser/$(DEPDIR)/l2cap.Po + -rm -f tools/parser/$(DEPDIR)/lmp.Po + -rm -f tools/parser/$(DEPDIR)/obex.Po + -rm -f tools/parser/$(DEPDIR)/parser.Po + -rm -f tools/parser/$(DEPDIR)/ppp.Po + -rm -f tools/parser/$(DEPDIR)/rfcomm.Po + -rm -f tools/parser/$(DEPDIR)/sap.Po + -rm -f tools/parser/$(DEPDIR)/sdp.Po + -rm -f tools/parser/$(DEPDIR)/smp.Po + -rm -f tools/parser/$(DEPDIR)/tcpip.Po + -rm -f unit/$(DEPDIR)/test-avctp.Po + -rm -f unit/$(DEPDIR)/test-avdtp.Po + -rm -f unit/$(DEPDIR)/test-avrcp.Po + -rm -f unit/$(DEPDIR)/test-bap.Po + -rm -f unit/$(DEPDIR)/test-bass.Po + -rm -f unit/$(DEPDIR)/test-crc.Po + -rm -f unit/$(DEPDIR)/test-crypto.Po + -rm -f unit/$(DEPDIR)/test-ecc.Po + -rm -f unit/$(DEPDIR)/test-eir.Po + -rm -f unit/$(DEPDIR)/test-gatt.Po + -rm -f unit/$(DEPDIR)/test-gattrib.Po + -rm -f unit/$(DEPDIR)/test-gdbus-client.Po + -rm -f unit/$(DEPDIR)/test-gobex-apparam.Po + -rm -f unit/$(DEPDIR)/test-gobex-header.Po + -rm -f unit/$(DEPDIR)/test-gobex-packet.Po + -rm -f unit/$(DEPDIR)/test-gobex-transfer.Po + -rm -f unit/$(DEPDIR)/test-gobex.Po + -rm -f unit/$(DEPDIR)/test-hfp.Po + -rm -f unit/$(DEPDIR)/test-hog.Po + -rm -f unit/$(DEPDIR)/test-lib.Po + -rm -f unit/$(DEPDIR)/test-mgmt.Po + -rm -f unit/$(DEPDIR)/test-micp.Po + -rm -f unit/$(DEPDIR)/test-queue.Po + -rm -f unit/$(DEPDIR)/test-ringbuf.Po + -rm -f unit/$(DEPDIR)/test-sdp.Po + -rm -f unit/$(DEPDIR)/test-tester.Po + -rm -f unit/$(DEPDIR)/test-textfile.Po + -rm -f unit/$(DEPDIR)/test-uhid.Po + -rm -f unit/$(DEPDIR)/test-uuid.Po + -rm -f unit/$(DEPDIR)/test-vcp.Po + -rm -f unit/$(DEPDIR)/test_mesh_crypto-test-mesh-crypto.Po + -rm -f unit/$(DEPDIR)/test_midi-test-midi.Po + -rm -f unit/$(DEPDIR)/util.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic \ + maintainer-clean-local + +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-cupsPROGRAMS uninstall-dbusDATA \ + uninstall-dbussessionbusDATA uninstall-dbussystembusDATA \ + uninstall-dist_zshcompletionDATA uninstall-libLTLIBRARIES \ + uninstall-man uninstall-pkgconfigDATA \ + uninstall-pkgincludeHEADERS uninstall-pkglibexecPROGRAMS \ + uninstall-pluginLTLIBRARIES uninstall-rulesDATA \ + uninstall-stateDATA uninstall-systemdsystemunitDATA \ + uninstall-systemduserunitDATA uninstall-testSCRIPTS \ + uninstall-udevPROGRAMS + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-hook +uninstall-man: uninstall-man1 uninstall-man5 uninstall-man7 \ + uninstall-man8 + +.MAKE: all check check-am install install-am install-data-am \ + install-exec install-strip uninstall-am + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles am--refresh check \ + check-TESTS check-am clean clean-binPROGRAMS clean-cscope \ + clean-cupsPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool clean-local clean-noinstLIBRARIES \ + clean-noinstLTLIBRARIES clean-noinstPROGRAMS \ + clean-pkglibexecPROGRAMS clean-pluginLTLIBRARIES \ + clean-udevPROGRAMS cscope cscopelist-am ctags ctags-am dist \ + dist-all dist-bzip2 dist-gzip dist-lzip dist-shar dist-tarZ \ + dist-xz dist-zip dist-zstd distcheck distclean \ + distclean-compile distclean-generic distclean-hdr \ + distclean-libtool distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-confDATA \ + install-cupsPROGRAMS install-data install-data-am \ + install-data-hook install-dbusDATA install-dbussessionbusDATA \ + install-dbussystembusDATA install-dist_zshcompletionDATA \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-man1 install-man5 \ + install-man7 install-man8 install-pdf install-pdf-am \ + install-pkgconfigDATA install-pkgincludeHEADERS \ + install-pkglibexecPROGRAMS install-pluginLTLIBRARIES \ + install-ps install-ps-am install-rulesDATA install-stateDATA \ + install-strip install-systemdsystemunitDATA \ + install-systemduserunitDATA install-testSCRIPTS \ + install-udevPROGRAMS installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic \ + maintainer-clean-local mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + recheck tags tags-am uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-confDATA \ + uninstall-cupsPROGRAMS uninstall-dbusDATA \ + uninstall-dbussessionbusDATA uninstall-dbussystembusDATA \ + uninstall-dist_zshcompletionDATA uninstall-hook \ + uninstall-libLTLIBRARIES uninstall-man uninstall-man1 \ + uninstall-man5 uninstall-man7 uninstall-man8 \ + uninstall-pkgconfigDATA uninstall-pkgincludeHEADERS \ + uninstall-pkglibexecPROGRAMS uninstall-pluginLTLIBRARIES \ + uninstall-rulesDATA uninstall-stateDATA \ + uninstall-systemdsystemunitDATA uninstall-systemduserunitDATA \ + uninstall-testSCRIPTS uninstall-udevPROGRAMS + +.PRECIOUS: Makefile + + +bluetoothd-fix-permissions: + install -dm555 $(DESTDIR)$(confdir) + install -dm700 $(DESTDIR)$(statedir) +@BTPCLIENT_TRUE@tools/btpclient.$(OBJEXT): src/libshared-ell.la ell/internal + +@OBEX_TRUE@@SYSTEMD_TRUE@obexd-add-service-symlink: +@OBEX_TRUE@@SYSTEMD_TRUE@ $(LN_S) -f obex.service $(DESTDIR)$(SYSTEMD_USERUNITDIR)/dbus-org.bluez.obex.service + +@OBEX_TRUE@@SYSTEMD_TRUE@obexd-remove-service-symlink: +@OBEX_TRUE@@SYSTEMD_TRUE@ rm -f $(DESTDIR)$(SYSTEMD_USERUNITDIR)/dbus-org.bluez.obex.service +@OBEX_TRUE@@SYSTEMD_FALSE@obexd-add-service-symlink: +@OBEX_TRUE@@SYSTEMD_FALSE@obexd-remove-service-symlink: + +@OBEX_FALSE@obexd-add-service-symlink: +@OBEX_FALSE@obexd-remove-service-symlink: + +obexd/src/plugin.$(OBJEXT): obexd/src/builtin.h + +obexd/src/builtin.h: obexd/src/genbuiltin $(obexd_builtin_sources) + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)$(srcdir)/obexd/src/genbuiltin $(obexd_builtin_modules) > $@ + +@MESH_TRUE@mesh/mesh.$(OBJEXT): ell/internal +@MESH_TRUE@mesh/main.$(OBJEXT): src/builtin.h lib/bluetooth/bluetooth.h + +@SYSTEMD_TRUE@install-data-hook: obexd-add-service-symlink +@SYSTEMD_FALSE@install-data-hook: bluetoothd-fix-permissions obexd-add-service-symlink + +uninstall-hook: obexd-remove-service-symlink + +%.1: %.rst Makefile + $(RST2MAN_PROCESS) + +%.5: %.rst Makefile + $(RST2MAN_PROCESS) + +%.7: %.rst Makefile + $(RST2MAN_PROCESS) + +%.8: %.rst Makefile + $(RST2MAN_PROCESS) + +src/builtin.h: src/genbuiltin $(builtin_sources) + $(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@ + +tools/%.rules: + $(AM_V_at)$(MKDIR_P) tools + $(AM_V_GEN)cp $(srcdir)/$(subst 97-,,$@) $@ + +$(lib_libbluetooth_la_OBJECTS): $(local_headers) + +lib/bluetooth/%.h: lib/%.h + $(AM_V_at)$(MKDIR_P) lib/bluetooth + $(AM_V_GEN)$(LN_S) -f $(abspath $<) $@ + +ell/shared: Makefile + $(AM_V_at)$(MKDIR_P) ell + $(AM_V_GEN)for f in $(ell_shared) ; do \ + if [ ! -f $$f ] ; then \ + $(LN_S) -t ell -f $(abs_srcdir)/../ell/$$f ; \ + fi \ + done > $@ + +ell/internal: Makefile + $(AM_V_at)$(MKDIR_P) ell + $(AM_V_GEN)for f in $(ell_headers) $(ell_sources) ; do \ + if [ ! -f $$f ] ; then \ + $(LN_S) -t ell -f $(abs_srcdir)/../ell/$$f ; \ + fi \ + done > $@ + +ell/ell.h: Makefile + $(AM_V_at)echo -n > $@ + $(AM_V_GEN)for f in $(ell_headers) ; do \ + echo "#include <$$f>" >> $@ ; \ + done + +maintainer-clean-local: + -rm -rf ell + +clean-coverage: +@COVERAGE_TRUE@ @lcov --directory $(top_builddir) --zerocounters +@COVERAGE_TRUE@ $(RM) -r coverage $(top_builddir)/coverage.info + +@COVERAGE_TRUE@coverage: check +@COVERAGE_TRUE@ @lcov --compat-libtool --directory $(top_builddir) --capture \ +@COVERAGE_TRUE@ --output-file $(top_builddir)/coverage.info +@COVERAGE_TRUE@ $(AM_V_at)$(MKDIR_P) coverage +@COVERAGE_TRUE@ @genhtml -o coverage/ $(top_builddir)/coverage.info + +clean-local: clean-coverage + -find $(top_builddir) -name "*.gcno" -delete + -find $(top_builddir) -name "*.gcda" -delete + $(RM) -r lib/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/Makefile.mesh b/Makefile.mesh index 3047f362b640102a4abdd7268507b6ad70fb1ca4..e4c9fa6a32e6c85333832e0b4e8f0a646f9c820e 100644 --- a/Makefile.mesh +++ b/Makefile.mesh @@ -3,6 +3,7 @@ if MESH if DATAFILES dbus_DATA += mesh/bluetooth-mesh.conf +conf_DATA += mesh/mesh-main.conf endif if SYSTEMD @@ -26,6 +27,7 @@ mesh_sources = mesh/mesh.h mesh/mesh.c \ mesh/provision.h mesh/prov.h \ mesh/model.h mesh/model.c \ mesh/cfgmod.h mesh/cfgmod-server.c \ + mesh/remprv.h mesh/remprv-server.c \ mesh/mesh-config.h mesh/mesh-config-json.c \ mesh/util.h mesh/util.c \ mesh/dbus.h mesh/dbus.c \ @@ -35,6 +37,7 @@ mesh_sources = mesh/mesh.h mesh/mesh.c \ mesh/pb-adv.h mesh/pb-adv.c \ mesh/keyring.h mesh/keyring.c \ mesh/rpl.h mesh/rpl.c \ + mesh/prv-beacon.h mesh/prvbeac-server.c \ mesh/mesh-defs.h pkglibexec_PROGRAMS += mesh/bluetooth-meshd @@ -43,17 +46,12 @@ mesh/main.$(OBJEXT): src/builtin.h lib/bluetooth/bluetooth.h mesh_bluetooth_meshd_SOURCES = $(mesh_sources) mesh/main.c mesh_bluetooth_meshd_LDADD = src/libshared-ell.la $(ell_ldadd) -ljson-c -mesh_bluetooth_meshd_DEPENDENCIES = $(ell_dependencies) src/libshared-ell.la \ - mesh/bluetooth-mesh.service if MANPAGES man_MANS += mesh/bluetooth-meshd.8 endif manual_pages += mesh/bluetooth-meshd.8 -CLEANFILES += mesh/bluetooth-mesh.service - endif -EXTRA_DIST += mesh/bluetooth-mesh.conf mesh/bluetooth-mesh.service.in \ - mesh/org.bluez.mesh.service mesh/mesh-main.conf +EXTRA_DIST += mesh/bluetooth-mesh.conf mesh/org.bluez.mesh.service mesh/mesh-main.conf diff --git a/Makefile.obexd b/Makefile.obexd index 5d1a4ff65245a92d0993babe201fa98c8b824909..74dd977a069277170805f2122277d92ce7304b74 100644 --- a/Makefile.obexd +++ b/Makefile.obexd @@ -1,15 +1,21 @@ # SPDX-License-Identifier: GPL-2.0 +if OBEX + if SYSTEMD -systemduserunitdir = $(SYSTEMD_USERUNITDIR) -systemduserunit_DATA = obexd/src/obex.service +systemduserunit_DATA += obexd/src/obex.service dbussessionbusdir = $(DBUS_SESSIONBUSDIR) dbussessionbus_DATA = obexd/src/org.bluez.obex.service -endif -EXTRA_DIST += obexd/src/obex.service.in obexd/src/org.bluez.obex.service +obexd-add-service-symlink: + $(LN_S) -f obex.service $(DESTDIR)$(SYSTEMD_USERUNITDIR)/dbus-org.bluez.obex.service -if OBEX +obexd-remove-service-symlink: + rm -f $(DESTDIR)$(SYSTEMD_USERUNITDIR)/dbus-org.bluez.obex.service +else +obexd-add-service-symlink: +obexd-remove-service-symlink: +endif obex_plugindir = $(libdir)/obex/plugins @@ -75,6 +81,8 @@ obexd_src_obexd_SOURCES = $(btio_sources) $(gobex_sources) \ obexd/client/ftp.h obexd/client/ftp.c \ obexd/client/opp.h obexd/client/opp.c \ obexd/client/map.h obexd/client/map.c \ + obexd/client/bip.h obexd/client/bip.c \ + obexd/client/bip-common.h obexd/client/bip-common.c \ obexd/client/map-event.h obexd/client/map-event.c \ obexd/client/transfer.h obexd/client/transfer.c \ obexd/client/transport.h obexd/client/transport.c \ @@ -86,16 +94,19 @@ obexd_src_obexd_LDADD = lib/libbluetooth-internal.la \ $(ICAL_LIBS) $(DBUS_LIBS) $(LIBEBOOK_LIBS) \ $(LIBEDATASERVER_LIBS) $(GLIB_LIBS) -ldl +if EXTERNAL_PLUGINS obexd_src_obexd_LDFLAGS = $(AM_LDFLAGS) -Wl,--export-dynamic +endif obexd_src_obexd_CPPFLAGS = $(AM_CPPFLAGS) $(GLIB_CFLAGS) $(DBUS_CFLAGS) \ $(ICAL_CFLAGS) -DOBEX_PLUGIN_BUILTIN \ -DPLUGINDIR=\""$(obex_plugindir)"\" \ -D_FILE_OFFSET_BITS=64 \ - -I$(builddir)/lib -I$(builddir)/obexd/src - -obexd_src_obexd_CFLAGS = $(AM_CFLAGS) -fPIC + -I$(builddir)/obexd/src +else +obexd-add-service-symlink: +obexd-remove-service-symlink: endif obexd_src_obexd_SHORTNAME = obexd @@ -112,6 +123,6 @@ obexd/src/builtin.h: obexd/src/genbuiltin $(obexd_builtin_sources) $(AM_V_at)$(MKDIR_P) $(dir $@) $(AM_V_GEN)$(srcdir)/obexd/src/genbuiltin $(obexd_builtin_modules) > $@ -CLEANFILES += obexd/src/builtin.h $(builtin_files) obexd/src/obex.service +CLEANFILES += obexd/src/builtin.h EXTRA_DIST += obexd/src/genbuiltin diff --git a/Makefile.plugins b/Makefile.plugins index 20cac384ef44dd08cd1676ea8134abdfb82b34f8..9da29a3ce43a4d067d22444c2aa3cd967a95f56b 100644 --- a/Makefile.plugins +++ b/Makefile.plugins @@ -74,8 +74,6 @@ builtin_sources += profiles/input/hog.c \ profiles/battery/bas.c profiles/battery/bas.h \ profiles/scanparam/scpp.c profiles/scanparam/scpp.h \ profiles/input/suspend.h profiles/input/suspend-none.c - -EXTRA_DIST += profiles/input/suspend-dummy.c endif if HEALTH @@ -110,16 +108,19 @@ builtin_modules += battery builtin_sources += profiles/battery/battery.c if SIXAXIS -plugin_LTLIBRARIES += plugins/sixaxis.la -plugins_sixaxis_la_SOURCES = plugins/sixaxis.c -plugins_sixaxis_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version -plugins_sixaxis_la_LIBADD = $(UDEV_LIBS) -plugins_sixaxis_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden +builtin_modules += sixaxis +builtin_sources += plugins/sixaxis.c +builtin_ldadd += $(UDEV_LIBS) endif if BAP builtin_modules += bap -builtin_sources += profiles/audio/bap.c +builtin_sources += profiles/audio/bap.h profiles/audio/bap.c +endif + +if BASS +builtin_modules += bass +builtin_sources += profiles/audio/bass.h profiles/audio/bass.c endif if MCP @@ -131,3 +132,23 @@ if VCP builtin_modules += vcp builtin_sources += profiles/audio/vcp.c endif + +if MICP +builtin_modules += micp +builtin_sources += profiles/audio/micp.c +endif + +if CCP +builtin_modules += ccp +builtin_sources += profiles/audio/ccp.c +endif + +if CSIP +builtin_modules += csip +builtin_sources += profiles/audio/csip.c +endif + +if ASHA +builtin_modules += asha +builtin_sources += profiles/audio/asha.h profiles/audio/asha.c +endif diff --git a/Makefile.tools b/Makefile.tools index 4bc355c34b9ab803405b951fcde1173af9c64141..71033d6388cf984bb601ecb97eeb7cefac20a378 100644 --- a/Makefile.tools +++ b/Makefile.tools @@ -3,6 +3,7 @@ if CLIENT bin_PROGRAMS += client/bluetoothctl client_bluetoothctl_SOURCES = client/main.c \ + client/print.h client/print.c \ client/display.h client/display.c \ client/agent.h client/agent.c \ client/advertising.h \ @@ -11,9 +12,12 @@ client_bluetoothctl_SOURCES = client/main.c \ client/adv_monitor.c \ client/gatt.h client/gatt.c \ client/admin.h client/admin.c \ - client/player.h client/player.c -client_bluetoothctl_LDADD = gdbus/libgdbus-internal.la src/libshared-glib.la \ - $(GLIB_LIBS) $(DBUS_LIBS) -lreadline + client/player.h client/player.c \ + client/mgmt.h client/mgmt.c \ + client/assistant.h client/assistant.c +client_bluetoothctl_LDADD = lib/libbluetooth-internal.la \ + gdbus/libgdbus-internal.la src/libshared-glib.la \ + $(GLIB_LIBS) $(DBUS_LIBS) -lreadline endif if ZSH_COMPLETIONS @@ -68,17 +72,12 @@ pkglibexec_PROGRAMS += tools/btmon-logger tools_btmon_logger_SOURCES = tools/btmon-logger.c tools_btmon_logger_LDADD = src/libshared-mainloop.la -tools_btmon_logger_DEPENDENCIES = src/libshared-mainloop.la \ - tools/bluetooth-logger.service if SYSTEMD systemdsystemunit_DATA += tools/bluetooth-logger.service endif endif -CLEANFILES += tools/bluetooth-logger.service -EXTRA_DIST += tools/bluetooth-logger.service.in - if TESTING noinst_PROGRAMS += emulator/btvirt emulator/b1ee emulator/hfp \ peripheral/btsensor tools/3dsp \ @@ -137,7 +136,7 @@ tools_mesh_tester_SOURCES = tools/mesh-tester.c monitor/bt.h \ tools_mesh_tester_LDADD = lib/libbluetooth-internal.la \ src/libshared-glib.la $(GLIB_LIBS) -tools_l2cap_tester_SOURCES = tools/l2cap-tester.c monitor/bt.h \ +tools_l2cap_tester_SOURCES = tools/l2cap-tester.c tools/tester.h monitor/bt.h \ emulator/hciemu.h emulator/hciemu.c \ emulator/vhci.h emulator/vhci.c \ emulator/btdev.h emulator/btdev.c \ @@ -184,7 +183,7 @@ tools_gap_tester_LDADD = lib/libbluetooth-internal.la \ src/libshared-glib.la \ $(GLIB_LIBS) $(DBUS_LIBS) -tools_sco_tester_SOURCES = tools/sco-tester.c monitor/bt.h \ +tools_sco_tester_SOURCES = tools/sco-tester.c tools/tester.h monitor/bt.h \ emulator/hciemu.h emulator/hciemu.c \ emulator/vhci.h emulator/vhci.c \ emulator/btdev.h emulator/btdev.c \ @@ -205,7 +204,7 @@ tools_userchan_tester_SOURCES = tools/userchan-tester.c monitor/bt.h \ tools_userchan_tester_LDADD = lib/libbluetooth-internal.la \ src/libshared-glib.la $(GLIB_LIBS) -tools_iso_tester_SOURCES = tools/iso-tester.c monitor/bt.h \ +tools_iso_tester_SOURCES = tools/iso-tester.c tools/tester.h monitor/bt.h \ emulator/hciemu.h emulator/hciemu.c \ emulator/vhci.h emulator/vhci.c \ emulator/btdev.h emulator/btdev.c \ @@ -329,10 +328,13 @@ tools_l2ping_LDADD = lib/libbluetooth-internal.la tools_bluemoon_SOURCES = tools/bluemoon.c monitor/bt.h tools_bluemoon_LDADD = src/libshared-mainloop.la -tools_hex2hcd_SOURCES = tools/hex2hcd.c +tools_hex2hcd_SOURCES = tools/hex2hcd.c tools/missing.h tools_mpris_proxy_SOURCES = tools/mpris-proxy.c tools_mpris_proxy_LDADD = gdbus/libgdbus-internal.la $(GLIB_LIBS) $(DBUS_LIBS) +if SYSTEMD +systemduserunit_DATA += tools/mpris-proxy.service +endif tools_gatt_service_SOURCES = tools/gatt-service.c tools_gatt_service_LDADD = gdbus/libgdbus-internal.la \ @@ -344,7 +346,15 @@ profiles_iap_iapd_SOURCES = profiles/iap/main.c profiles_iap_iapd_LDADD = gdbus/libgdbus-internal.la $(GLIB_LIBS) $(DBUS_LIBS) if MANPAGES -man_MANS += tools/rctest.1 tools/l2ping.1 tools/btattach.1 tools/isotest.1 +man_MANS += tools/rctest.1 tools/l2ping.1 tools/btattach.1 tools/isotest.1 \ + tools/btmgmt.1 client/bluetoothctl.1 \ + client/bluetoothctl-mgmt.1 \ + client/bluetoothctl-monitor.1 client/bluetoothctl-admin.1 \ + client/bluetoothctl-advertise.1 client/bluetoothctl-endpoint.1 \ + client/bluetoothctl-gatt.1 client/bluetoothctl-player.1 \ + client/bluetoothctl-scan.1 client/bluetoothctl-transport.1 \ + client/bluetoothctl-assistant.1 + endif if MESH @@ -465,7 +475,18 @@ manual_pages += tools/hciattach.1 tools/hciconfig.1 \ tools/hcitool.1 tools/hcidump.1 \ tools/rfcomm.1 tools/sdptool.1 tools/ciptool.1 \ tools/rctest.1 tools/l2ping.1 tools/btattach.1 \ - tools/bdaddr.1 tools/isotest.1 + tools/bdaddr.1 tools/isotest.1 tools/btmgmt.1 \ + client/bluetoothctl.1 \ + client/bluetoothctl-mgmt.1 \ + client/bluetoothctl-monitor.1 \ + client/bluetoothctl-admin.1 \ + client/bluetoothctl-advertise.1 \ + client/bluetoothctl-endpoint.1 \ + client/bluetoothctl-gatt.1 \ + client/bluetoothctl-player.1 \ + client/bluetoothctl-scan.1 \ + client/bluetoothctl-transport.1 \ + client/bluetoothctl-assistant.1 if HID2HCI udevdir = $(UDEV_DIR) @@ -494,7 +515,8 @@ tools_obex_server_tool_SOURCES = $(gobex_sources) $(btio_sources) \ tools_obex_server_tool_LDADD = lib/libbluetooth-internal.la \ src/libshared-glib.la $(GLIB_LIBS) -tools_bluetooth_player_SOURCES = tools/bluetooth-player.c client/player.c +tools_bluetooth_player_SOURCES = tools/bluetooth-player.c client/print.c \ + client/player.c tools_bluetooth_player_LDADD = gdbus/libgdbus-internal.la \ src/libshared-glib.la \ $(GLIB_LIBS) $(DBUS_LIBS) -lreadline @@ -503,7 +525,8 @@ tools_obexctl_SOURCES = tools/obexctl.c tools_obexctl_LDADD = gdbus/libgdbus-internal.la src/libshared-glib.la \ $(GLIB_LIBS) $(DBUS_LIBS) -lreadline -tools_btmgmt_SOURCES = tools/btmgmt.c src/uuid-helper.c client/display.c +tools_btmgmt_SOURCES = tools/btmgmt.c src/uuid-helper.c client/display.c \ + client/mgmt.c tools_btmgmt_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la \ -lreadline if DEPRECATED @@ -521,7 +544,12 @@ endif endif if CUPS + +if CUPS_SERVERBIN +cupsdir = $(CUPS_SERVERBIN)/backend +else cupsdir = $(libdir)/cups/backend +endif cups_PROGRAMS = profiles/cups/bluetooth @@ -556,7 +584,6 @@ noinst_PROGRAMS += tools/btpclient tools/btpclientctl tools_btpclient_SOURCES = tools/btpclient.c src/shared/btp.c src/shared/btp.h tools_btpclient_LDADD = lib/libbluetooth-internal.la \ src/libshared-ell.la $(ell_ldadd) -tools_btpclient_DEPENDENCIES = lib/libbluetooth-internal.la $(ell_dependencies) tools/btpclient.$(OBJEXT): src/libshared-ell.la ell/internal tools_btpclientctl_SOURCES = tools/btpclientctl.c client/display.c diff --git a/README b/README index 7de7045a8b67586387c712eab2ac3a4c811a2fbe..6c07770465459165b72ca131e19481325c3d16dc 100644 --- a/README +++ b/README @@ -249,6 +249,19 @@ For a working system, certain configuration options need to be enabled: systems. The behavior of the deprecated tools may be unstable or simply don't work anymore. + --enable-external-plugins + + Enable support for external plugins + + By default external plugins for bluetoothd and obexd are not + supported and thus disabled. + + External plugins require access to internal, undocumented and + unversioned API in said daemons. As such they can break at any + time. If you have such plugins, enable this option and work + actively with the community to make said plugin part of the + upstream bluez project. + --enable-nfc This option enable NFC pairing support. diff --git a/acinclude.m4 b/acinclude.m4 index c5d6de7b35ba044e0c0d73d0eed796fa858a57fb..4b73a5bfc38fe5a628644fa96c0749abe1dc396b 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -134,6 +134,8 @@ AC_DEFUN([MISC_FLAGS], [ misc_cflags="$misc_cflags --coverage" misc_ldflags="$misc_ldflags --coverage" fi + misc_cflags="$misc_cflags -ffunction-sections -fdata-sections" + misc_ldflags="$misc_ldflags -Wl,--gc-sections" AC_SUBST([MISC_CFLAGS], $misc_cflags) AC_SUBST([MISC_LDFLAGS], $misc_ldflags) ]) diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000000000000000000000000000000000000..cfb9291f092000d4886bcc3bfcd178de39a7ff59 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,10619 @@ +# generated automatically by aclocal 1.16.5 -*- Autoconf -*- + +# Copyright (C) 1996-2021 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_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.72],, +[m4_warning([this file was generated for autoconf 2.72. +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-*- +# +# Copyright (C) 1996-2001, 2003-2019, 2021-2022 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# 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. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 2014 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. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program or library that is built +# using GNU Libtool, you may include this file under the same +# distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +]) + +# serial 59 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK +AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS=$ltmain + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_PREPARE_CC_BASENAME +# ----------------------- +m4_defun([_LT_PREPARE_CC_BASENAME], [ +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in @S|@*""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} +])# _LT_PREPARE_CC_BASENAME + + +# _LT_CC_BASENAME(CC) +# ------------------- +# It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME, +# but that macro is also expanded into generated libtool script, which +# arranges for $SED and $ECHO to be set by different means. +m4_defun([_LT_CC_BASENAME], +[m4_require([_LT_PREPARE_CC_BASENAME])dnl +AC_REQUIRE([_LT_DECL_SED])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl +func_cc_basename $1 +cc_basename=$func_cc_basename_result +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl + +_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl +dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_DECL_FILECMD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_WITH_SYSROOT])dnl +m4_require([_LT_CMD_TRUNCATE])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options that allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl + +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 set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a '.a' archive for static linking (except MSVC and +# ICC, which need '.lib'). +libext=a + +with_gnu_ld=$lt_cv_prog_gnu_ld + +old_CC=$CC +old_CFLAGS=$CFLAGS + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PREPARE_SED_QUOTE_VARS +# -------------------------- +# Define a few sed substitution that help us do robust quoting. +m4_defun([_LT_PREPARE_SED_QUOTE_VARS], +[# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' +]) + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from 'configure', and 'config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# 'config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain=$ac_aux_dir/ltmain.sh +])# _LT_PROG_LTMAIN + + + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the 'libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to 'config.status' so that its +# declaration there will have the same value as in 'configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags='_LT_TAGS'dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the 'libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into 'config.status', and then the shell code to quote escape them in +# for loops in 'config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# 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 + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$[]1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +_LT_OUTPUT_LIBTOOL_INIT +]) + +# _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) +# ------------------------------------ +# Generate a child script FILE with all initialization necessary to +# reuse the environment learned by the parent script, and make the +# file executable. If COMMENT is supplied, it is inserted after the +# '#!' sequence but before initialization text begins. After this +# macro, additional text can be appended to FILE to form the body of +# the child script. The macro ends with non-zero status if the +# file could not be fully written (such as if the disk is full). +m4_ifdef([AS_INIT_GENERATED], +[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], +[m4_defun([_LT_GENERATED_FILE_INIT], +[m4_require([AS_PREPARE])]dnl +[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl +[lt_write_fail=0 +cat >$1 <<_ASEOF || lt_write_fail=1 +#! $SHELL +# Generated by $as_me. +$2 +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$1 <<\_ASEOF || lt_write_fail=1 +AS_SHELL_SANITIZE +_AS_PREPARE +exec AS_MESSAGE_FD>&1 +_ASEOF +test 0 = "$lt_write_fail" && chmod +x $1[]dnl +m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +_LT_GENERATED_FILE_INIT(["$CONFIG_LT"], +[# Run this file to recreate a libtool stub with the current configuration.]) + +cat >>"$CONFIG_LT" <<\_LTEOF +lt_cl_silent=false +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +'$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to <bug-libtool@gnu.org>." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2011 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test 0 != $[#] +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try '$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try '$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +lt_cl_success=: +test yes = "$silent" && + lt_config_lt_args="$lt_config_lt_args --quiet" +exec AS_MESSAGE_LOG_FD>/dev/null +$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false +exec AS_MESSAGE_LOG_FD>>config.log +$lt_cl_success || AS_EXIT(1) +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, 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 TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options that allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST + fi + + cfgfile=${ofile}T + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL +# Generated automatically by $as_me ($PACKAGE) $VERSION +# NOTE: Changes made to this file will be lost: look at ltmain.sh. + +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit, 1996 + +_LT_COPYING +_LT_LIBTOOL_TAGS + +# Configured defaults for sys_lib_dlsearch_path munging. +: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + cat <<'_LT_EOF' >> "$cfgfile" + +# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE + +_LT_PREPARE_MUNGE_PATH_LIST +_LT_PREPARE_CC_BASENAME + +# ### END FUNCTIONS SHARED WITH CONFIGURE + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_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 set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # 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" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Go], [_LT_LANG(GO)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +m4_ifndef([AC_PROG_GO], [ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_GO. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +m4_defun([AC_PROG_GO], +[AC_LANG_PUSH(Go)dnl +AC_ARG_VAR([GOC], [Go compiler command])dnl +AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl +_AC_ARG_VAR_LDFLAGS()dnl +AC_CHECK_TOOL(GOC, gccgo) +if test -z "$GOC"; then + if test -n "$ac_tool_prefix"; then + AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) + fi +fi +if test -z "$GOC"; then + AC_CHECK_PROG(GOC, gccgo, gccgo, false) +fi +])#m4_defun +])#m4_ifndef + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([AC_PROG_GO], + [LT_LANG(GO)], + [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) +dnl AC_DEFUN([AC_LIBTOOL_RC], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])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_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_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. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_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 -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "$LT_MULTI_MODULE"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test 0 = "$_lt_result"; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS=$save_LDFLAGS + ]) + + AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], + [lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD + echo "$AR $AR_FLAGS libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD + $AR $AR_FLAGS libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD + echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD + $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + darwin*) + case $MACOSX_DEPLOYMENT_TARGET,$host in + 10.[[012]],*|,*powerpc*-darwin[[5-8]]*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + *) + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test yes = "$lt_cv_apple_cc_single_mod"; then + _lt_dar_single_mod='$single_module' + fi + if test yes = "$lt_cv_ld_exported_symbols_list"; then + _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' + fi + if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES([TAG]) +# --------------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + if test yes = "$lt_cv_ld_force_load"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], + [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined + case $cc_basename in + ifort*|nagfor*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test yes = "$_lt_dar_can_shared"; then + output_verbose_link_cmd=func_echo_all + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" + _LT_TAGVAR(archive_expsym_cmds, $1)="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" + _LT_TAGVAR(module_expsym_cmds, $1)="$SED -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" + m4_if([$1], [CXX], +[ if test yes != "$lt_cv_apple_cc_single_mod"; then + _LT_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$_lt_dsymutil" + _LT_TAGVAR(archive_expsym_cmds, $1)="$SED '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$_lt_dar_export_syms$_lt_dsymutil" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX([TAGNAME]) +# ---------------------------------- +# 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. +# Store the results from the different compilers for each TAGNAME. +# Allow to override them for all tags through lt_cv_aix_libpath. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], + [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ + lt_aix_libpath_sed='[ + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }]' + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`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 "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi],[]) + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib + fi + ]) + aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) +fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[m4_divert_text([M4SH-INIT], [$1 +])])# _LT_SHELL_INIT + + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Find how we can fake an echo command that does not interpret backslash. +# In particular, with Autoconf 2.60 or later we add some code to the start +# of the generated configure script that will find a shell with a builtin +# printf (that we can use as an echo command). +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +AC_MSG_CHECKING([how to print strings]) +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$[]1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +case $ECHO in + printf*) AC_MSG_RESULT([printf]) ;; + print*) AC_MSG_RESULT([print -r]) ;; + *) AC_MSG_RESULT([cat]) ;; +esac + +m4_ifdef([_AS_DETECT_SUGGESTED], +[_AS_DETECT_SUGGESTED([ + test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test "X`printf %s $ECHO`" = "X$ECHO" \ + || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) + +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_WITH_SYSROOT +# ---------------- +AC_DEFUN([_LT_WITH_SYSROOT], +[m4_require([_LT_DECL_SED])dnl +AC_MSG_CHECKING([for sysroot]) +AC_ARG_WITH([sysroot], +[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], + [Search for dependent libraries within DIR (or the compiler's sysroot + if not specified).])], +[], [with_sysroot=no]) + +dnl lt_sysroot will always be passed unquoted. We quote it here +dnl in case the user passed a directory name. +lt_sysroot= +case $with_sysroot in #( + yes) + if test yes = "$GCC"; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + AC_MSG_RESULT([$with_sysroot]) + AC_MSG_ERROR([The sysroot must be an absolute path.]) + ;; +esac + + AC_MSG_RESULT([${lt_sysroot:-no}]) +_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl +[dependent libraries, and where our libraries should be installed.])]) + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test no = "$enable_libtool_lock" || 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 what ABI is being produced by ac_compile, and set mode + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `$FILECMD conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE=32 + ;; + *ELF-64*) + HPUX_IA64_MODE=64 + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test yes = "$lt_cv_prog_gnu_ld"; then + case `$FILECMD conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `$FILECMD 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* + ;; + +mips64*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + emul=elf + case `$FILECMD conftest.$ac_objext` in + *32-bit*) + emul="${emul}32" + ;; + *64-bit*) + emul="${emul}64" + ;; + esac + case `$FILECMD conftest.$ac_objext` in + *MSB*) + emul="${emul}btsmip" + ;; + *LSB*) + emul="${emul}ltsmip" + ;; + esac + case `$FILECMD conftest.$ac_objext` in + *N32*) + emul="${emul}n32" + ;; + esac + LD="${LD-ld} -m $emul" + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. Note that the listed cases only cover the + # situations where additional linker options are needed (such as when + # doing 32-bit compilation for a host where ld defaults to 64-bit, or + # vice versa); the common cases where no linker options are needed do + # not appear in the list. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `$FILECMD conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + case `$FILECMD conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*linux*) + LD="${LD-ld} -m elf32lppclinux" + ;; + 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*) + 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" + ;; + powerpcle-*linux*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + 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_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test yes != "$lt_cv_cc_needs_belf"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS=$SAVE_CFLAGS + fi + ;; +*-*solaris*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `$FILECMD conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*|x86_64-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD=${LD-ld}_sol2 + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks=$enable_libtool_lock +])# _LT_ENABLE_LOCK + + +# _LT_PROG_AR +# ----------- +m4_defun([_LT_PROG_AR], +[AC_CHECK_TOOLS(AR, [ar], false) +: ${AR=ar} +_LT_DECL([], [AR], [1], [The archiver]) + +# Use ARFLAGS variable as AR's operation code to sync the variable naming with +# Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have +# higher priority because thats what people were doing historically (setting +# ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS +# variable obsoleted/removed. + +test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr} +lt_ar_flags=$AR_FLAGS +_LT_DECL([], [lt_ar_flags], [0], [Flags to create an archive (by configure)]) + +# Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override +# by AR_FLAGS because that was never working and AR_FLAGS is about to die. +_LT_DECL([], [AR_FLAGS], [\@S|@{ARFLAGS-"\@S|@lt_ar_flags"}], + [Flags to create an archive]) + +AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], + [lt_cv_ar_at_file=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([lt_ar_try]) + if test 0 -eq "$ac_status"; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + AC_TRY_EVAL([lt_ar_try]) + if test 0 -ne "$ac_status"; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + ]) + ]) + +if test no = "$lt_cv_ar_at_file"; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi +_LT_DECL([], [archiver_list_spec], [1], + [How to feed a file listing to the archiver]) +])# _LT_PROG_AR + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[_LT_PROG_AR + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# 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 + bitrig* | openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +_LT_DECL([], [lock_old_archive_extraction], [0], + [Whether to use a lock for old archive extraction]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment + # 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:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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 yes = "[$]$2"; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_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 "$_lt_linker_boilerplate" | $SED '/^$/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 -r conftest* + LDFLAGS=$save_LDFLAGS +]) + +if test yes = "[$]$2"; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# 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* | cegcc*) + # 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; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + 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; + ;; + + bitrig* | darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) + # 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 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + 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" && \ + test undefined != "$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 + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test X`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test 17 != "$i" # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + 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 +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test yes = "$cross_compiling"; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line $LINENO "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 + +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 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; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_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_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test yes != "$enable_dlopen"; 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* | cegcc*) + 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 + ]) + ;; + + tpf*) + # Don't try to run any link tests for TPF. We know it's impossible + # because TPF is a cross-compiler, and we know how we open DSOs. + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + lt_cv_dlopen_self=no + ;; + + *) + 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=-ldld], + [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=-ldld]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test no = "$lt_cv_dlopen"; then + enable_dlopen=no + else + enable_dlopen=yes + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS=$CPPFLAGS + test yes = "$ac_cv_header_dlfcn_h" && 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_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 yes = "$lt_cv_dlopen_self"; 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_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 +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_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:$LINENO: $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:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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_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 .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links=nottested +if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; 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 no = "$hard_links"; 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 +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_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 +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/", + [Define to the sub-directory where libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then + + # We can hardcode non-existent directories. + if test no != "$_LT_TAGVAR(hardcode_direct, $1)" && + # 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 no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" && + test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test relink = "$_LT_TAGVAR(hardcode_action, $1)" || + test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then + # Fast installation is not supported + enable_fast_install=no +elif test yes = "$shlibpath_overrides_runpath" || + test no = "$enable_shared"; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -z "$STRIP"; then + AC_MSG_RESULT([no]) +else + if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + old_striplib="$STRIP --strip-debug" + striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) + else + case $host_os in + darwin*) + # FIXME - insert some real tests, host_os isn't really good enough + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + ;; + freebsd*) + if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then + old_striplib="$STRIP --strip-debug" + striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac + fi +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_PREPARE_MUNGE_PATH_LIST +# --------------------------- +# Make sure func_munge_path_list() is defined correctly. +m4_defun([_LT_PREPARE_MUNGE_PATH_LIST], +[[# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x@S|@2 in + x) + ;; + *:) + eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" + ;; + x:*) + eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" + ;; + *) + eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" + ;; + esac +} +]])# _LT_PREPARE_PATH_LIST + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test yes = "$GCC"; then + case $host_os in + darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; + *) lt_awk_arg='/^libraries:/' ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; + *) lt_sed_strip_eq='s|=/|/|g' ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # 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 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # 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` + # ...but if some path component already ends with the multilib dir we assume + # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). + case "$lt_multi_os_dir; $lt_search_path_spec " in + "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) + lt_multi_os_dir= + ;; + esac + 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" + elif test -n "$lt_multi_os_dir"; then + 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; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +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" +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 + +AC_ARG_VAR([LT_SYS_LIBRARY_PATH], +[User-defined run-time library search path.]) + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + 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' + ;; + +aix[[4-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test ia64 = "$host_cpu"; 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 + # Using Import Files as archive members, it is possible to support + # filename-based versioning of shared library archives on AIX. While + # this would work for both with and without runtime linking, it will + # prevent static linking of such archives. So we do filename-based + # shared library versioning with .so extension only, which is used + # when both runtime linking and shared linking is enabled. + # Unfortunately, runtime linking may impact performance, so we do + # not want this to be the default eventually. Also, we use the + # versioned .so libs for executables only if there is the -brtl + # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. + # To allow for filename-based versioning support, we need to create + # libNAME.so.V as an archive file, containing: + # *) an Import File, referring to the versioned filename of the + # archive as well as the shared archive member, telling the + # bitwidth (32 or 64) of that shared object, and providing the + # list of exported symbols of that shared object, eventually + # decorated with the 'weak' keyword + # *) the shared object with the F_LOADONLY flag set, to really avoid + # it being seen by the linker. + # At run time we better use the real file rather than another symlink, + # but for link time we create the symlink libNAME.so -> libNAME.so.V + + case $with_aix_soname,$aix_use_runtimelinking in + # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + aix,yes) # traditional libtool + dynamic_linker='AIX unversionable lib.so' + # 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' + ;; + aix,no) # traditional AIX only + dynamic_linker='AIX lib.a[(]lib.so.V[)]' + # 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' + ;; + svr4,*) # full svr4 only + dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,yes) # both, prefer svr4 + dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # unpreferred sharedlib libNAME.a needs extra handling + postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' + postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,no) # both, prefer aix + dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]" + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling + postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' + postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' + ;; + esac + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + m68k) + 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=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $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' + ;; + esac + ;; + +beos*) + library_names_spec='$libname$shared_ext' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux # correct to gnu/linux during the next big refactor + 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* | cegcc*) + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + 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~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + 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' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' + ;; + 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 + dynamic_linker='Win32 ld.exe' + ;; + + *,cl* | *,icl*) + # Native MSVC or ICC + libname_spec='$name' + soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' + library_names_spec='$libname.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec=$LIB + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH. + 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 + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # 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' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC and ICC wrapper + library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # 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$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 # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly* | midnightbsd*) + # 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[[23]].*) 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$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + 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 + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + 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=LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + 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 32 = "$HPUX_IA64_MODE"; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + sys_lib_dlsearch_path_spec=/usr/lib/hpux32 + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + sys_lib_dlsearch_path_spec=/usr/lib/hpux64 + fi + ;; + 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' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[[3-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + 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 yes = "$lt_cv_prog_gnu_ld"; then + version_type=linux # correct to gnu/linux during the next big refactor + 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 + ;; + +linux*android*) + version_type=none # Android doesn't support versioned libraries. + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext' + soname_spec='$libname$release$shared_ext' + finish_cmds= + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + + # 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 + + dynamic_linker='Android linker' + # Don't embed -rpath directories since the linker doesn't support them. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + 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 + + # Some binutils ld are patched to set DT_RUNPATH + AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], + [lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [lt_cv_shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + ]) + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # 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 + + # Ideally, we could use ldconfig to report *all* directores which are + # searched for libraries, however this is still not possible. Aside from not + # being certain /sbin/ldconfig is available, command + # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, + # even though it is searched at run-time. Try to do the best guess by + # appending ld.so.conf contents (and includes) 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;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $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' + ;; + +netbsdelf*-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 + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_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 # correct to gnu/linux during the next big refactor + 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=qnx + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd* | bitrig*) + version_type=sunos + sys_lib_dlsearch_path_spec=/usr/lib + need_lib_prefix=no + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + need_version=no + else + need_version=yes + fi + 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 + shlibpath_overrides_runpath=yes + ;; + +os2*) + libname_spec='$name' + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + # OS/2 can only load a DLL with a base name of 8 characters or less. + soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; + v=$($ECHO $release$versuffix | tr -d .-); + n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); + $ECHO $n$v`$shared_ext' + library_names_spec='${libname}_dll.$libext' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=BEGINLIBPATH + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + 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~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + ;; + +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 # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=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 yes = "$with_gnu_ld"; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + 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 + 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 # correct to gnu/linux during the next big refactor + 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=sco + 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 + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test yes = "$with_gnu_ld"; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + 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' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + 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 no = "$dynamic_linker" && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test yes = "$GCC"; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then + sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec +fi + +if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then + sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec +fi + +# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... +configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec + +# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code +func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" + +# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool +configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[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]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [install_override_mode], [1], + [Permission mode override for installation of shared libraries]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2], + [Detected run-time system search path for libraries]) +_LT_DECL([], [configure_time_lt_sys_library_path], [2], + [Explicit LT_SYS_LIBRARY_PATH set during ./configure time]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program that can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_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="m4_if([$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 <<_LT_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 + +_LT_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 +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program that can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_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 + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PROG_ECHO_BACKSLASH])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test no = "$withval" || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test yes = "$GCC"; 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 yes = "$with_gnu_ld"; 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 no != "$with_gnu_ld" && break + ;; + *) + test yes != "$with_gnu_ld" && 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]) +_LT_PATH_LD_GNU +AC_SUBST([LD]) + +_LT_TAGDECL([], [LD], [1], [The linker used to build libraries]) +])# LT_PATH_LD + +# Old names: +AU_ALIAS([AM_PROG_LD], [LT_PATH_LD]) +AU_ALIAS([AC_PROG_LD], [LT_PATH_LD]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_LD], []) +dnl AC_DEFUN([AC_PROG_LD], []) + + +# _LT_PATH_LD_GNU +#- -------------- +m4_defun([_LT_PATH_LD_GNU], +[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 +])# _LT_PATH_LD_GNU + + +# _LT_CMD_RELOAD +# -------------- +# find reload flag for linker +# -- PORTME Some linkers may need a different reload flag. +m4_defun([_LT_CMD_RELOAD], +[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 + cygwin* | mingw* | pw32* | cegcc*) + if test yes != "$GCC"; then + reload_cmds=false + fi + ;; + darwin*) + if test yes = "$GCC"; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac +_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl +_LT_TAGDECL([], [reload_cmds], [2])dnl +])# _LT_CMD_RELOAD + + +# _LT_PATH_DD +# ----------- +# find a working dd +m4_defun([_LT_PATH_DD], +[AC_CACHE_CHECK([for a working dd], [ac_cv_path_lt_DD], +[printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +: ${lt_DD:=$DD} +AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd], +[if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: +fi]) +rm -f conftest.i conftest2.i conftest.out]) +])# _LT_PATH_DD + + +# _LT_CMD_TRUNCATE +# ---------------- +# find command to truncate a binary pipe +m4_defun([_LT_CMD_TRUNCATE], +[m4_require([_LT_PATH_DD]) +AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin], +[printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +lt_cv_truncate_bin= +if "$ac_cv_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" +fi +rm -f conftest.i conftest2.i conftest.out +test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"]) +_LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1], + [Command to truncate a binary pipe]) +])# _LT_CMD_TRUNCATE + + +# _LT_CHECK_MAGIC_METHOD +# ---------------------- +# how to check for library dependencies +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_MAGIC_METHOD], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +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 +# that 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 +aix[[4-9]]*) + 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='$FILECMD -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 + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly* | midnightbsd*) + 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=$FILECMD + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=$FILECMD + 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])(-bit)?( [LM]SB)? 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 glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + 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=$FILECMD + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd* | bitrig*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; 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 + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + 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 + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +os2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` + fi + ;; + esac +fi + +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 + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method = "file_magic"]) +_LT_DECL([], [file_magic_glob], [1], + [How to find potential files when deplibs_check_method = "file_magic"]) +_LT_DECL([], [want_nocaseglob], [1], + [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (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 + # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty + case $build_os in + mingw*) lt_bad_file=conftest.nm/nofile ;; + *) lt_bad_file=/dev/null ;; + esac + case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in + *$lt_bad_file* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break 2 + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break 2 + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS=$lt_save_ifs + done + : ${lt_cv_path_NM=no} +fi]) +if test no != "$lt_cv_path_NM"; then + NM=$lt_cv_path_NM +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) + case `$DUMPBIN -symbols -headers /dev/null 2>&1 | $SED '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols -headers" + ;; + *) + DUMPBIN=: + ;; + esac + fi + AC_SUBST([DUMPBIN]) + if test : != "$DUMPBIN"; then + NM=$DUMPBIN + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + +# _LT_CHECK_SHAREDLIB_FROM_LINKLIB +# -------------------------------- +# how to determine the name of the shared library +# associated with a specific link library. +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +m4_require([_LT_DECL_DLLTOOL]) +AC_CACHE_CHECK([how to associate runtime and link libraries], +lt_cv_sharedlib_from_linklib_cmd, +[lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh; + # decide which one to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd=$ECHO + ;; +esac +]) +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + +_LT_DECL([], [sharedlib_from_linklib_cmd], [1], + [Command to associate shared and link libraries]) +])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB + + +# _LT_PATH_MANIFEST_TOOL +# ---------------------- +# locate the manifest tool +m4_defun([_LT_PATH_MANIFEST_TOOL], +[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], + [lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&AS_MESSAGE_LOG_FD + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest*]) +if test yes != "$lt_cv_path_mainfest_tool"; then + MANIFEST_TOOL=: +fi +_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl +])# _LT_PATH_MANIFEST_TOOL + + +# _LT_DLL_DEF_P([FILE]) +# --------------------- +# True iff FILE is a Windows DLL '.def' file. +# Keep in sync with func_dll_def_p in the libtool script +AC_DEFUN([_LT_DLL_DEF_P], +[dnl + test DEF = "`$SED -n dnl + -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace + -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments + -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl + -e q dnl Only consider the first "real" line + $1`" dnl +])# _LT_DLL_DEF_P + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-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_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test yes = "$GCC"; then + case $cc_basename in + nvcc*) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; + *) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; + esac + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# 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]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test ia64 = "$host_cpu"; then + symcode='[[ABCDEGRST]]' + 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 + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Gets list of data symbols to import. + lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'" + # Adjust the below global symbol transforms to fixup imported variables. + lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" + lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" + lt_c_name_lib_hook="\ + -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ + -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" +else + # Disable hooks by default. + lt_cv_sys_global_symbol_to_import= + lt_cdecl_hook= + lt_c_name_hook= + lt_c_name_lib_hook= +fi + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="$SED -n"\ +$lt_cdecl_hook\ +" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="$SED -n"\ +$lt_c_name_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" + +# Transform an extracted symbol line into symbol name with lib prefix and +# symbol address. +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\ +$lt_c_name_lib_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" + +# 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 + +# Try without a prefix underscore, 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. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function, + # D for any global variable and I for any imported variable. + # Also find C++ and __fastcall symbols from MSVC++ or ICC, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ +" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ +" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ +" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ +" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="$SED -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | $SED '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&AS_MESSAGE_LOG_FD + if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&AS_MESSAGE_LOG_FD && 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 <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT@&t@_DLSYM_CONST +#elif defined __osf__ +/* This system does not cope well with relocations in const data. */ +# define LT@&t@_DLSYM_CONST +#else +# define LT@&t@_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT@&t@_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS=conftstm.$ac_objext + CFLAGS="$CFLAGS$_LT_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_globsym_save_LIBS + CFLAGS=$lt_globsym_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 -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test yes = "$pipe_works"; 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 + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1], + [Transform the output of nm into a list of symbols to manually relocate]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +_LT_DECL([nm_interface], [lt_cv_nm_interface], [1], + [The name lister interface]) +_LT_DECL([], [nm_file_list_spec], [1], + [Specify filename containing input files for $NM]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test yes = "$GXX"; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # 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_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # 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 + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + case $host_os in + os2*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' + ;; + esac + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $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_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_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 + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # 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). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly* | midnightbsd*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' + if test ia64 != "$host_cpu"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_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_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64, which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_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_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | $SED 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_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_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test yes = "$GCC"; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # 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_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # 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 + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + case $host_os in + os2*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' + ;; + esac + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + 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_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' + if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + case $cc_basename in + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # 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). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + case $host_os in + os2*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' + ;; + esac + ;; + + hpux9* | hpux10* | hpux11*) + _LT_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_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + # old Intel for x86_64, which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # flang / f18. f95 an alias for gfortran or flang on Debian + flang* | f18* | f95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | $SED 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + *Sun\ F* | *Sun*Fortran*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Intel*\ [[CF]]*Compiler*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + *Portland\ Group*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms that do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +AC_CACHE_CHECK([for $compiler option to produce PIC], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX nm. + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl* | icl*) + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + ;; + esac + ;; + linux* | k*bsd*-gnu | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_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_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # 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. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++ or Intel C++ Compiler. + if test yes != "$GCC"; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) + with_gnu_ld=yes + ;; + openbsd* | bitrig*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test yes = "$with_gnu_ld"; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; + *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test yes = "$lt_use_gnu_ld_interface"; 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_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_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_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v | $SED -e 's/([[^)]]\+)\s\+//' 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [[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 + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test ia64 != "$host_cpu"; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, 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 install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_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_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach <jrb3@best.com> says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_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, use it as + # is; otherwise, prepend EXPORTS... + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); 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_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + shrext_cmds=.dll + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_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_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_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* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test linux-dietlibc = "$host_os"; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test no = "$tmp_diet" + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$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' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + nagfor*) # NAGFOR 5.3 + tmp_sharedflag='-Wl,-shared' ;; + xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + ;; + esac + case `$CC -V 2>&1 | $SED 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_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; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + + if test yes = "$supports_anon_versioning"; then + _LT_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 + + case $cc_basename in + tcc*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic' + ;; + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test yes = "$supports_anon_versioning"; then + _LT_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~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $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_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_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. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_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_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot +*** 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 + ;; + *) + # 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. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_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_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_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_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_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_TAGVAR(hardcode_minus_L, $1)=yes + if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test ia64 = "$host_cpu"; 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 GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX nm. + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | 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 + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then + aix_use_runtimelinking=yes + break + fi + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + 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_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='$wl-f,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # traditional, no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + ;; + esac + + if test yes = "$GCC"; 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_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_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test yes = "$aix_use_runtimelinking"; then + shared_flag="$shared_flag "'$wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; 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 yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_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_SYS_MODULE_PATH_AIX([$1]) + _LT_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_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_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_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++ or Intel C++ Compiler. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl* | icl*) + # Native MSVC or ICC + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # 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_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC and ICC wrapper + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_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_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + esac + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $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_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly* | midnightbsd*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + ;; + + hpux10*) + if test yes,no = "$GCC,$with_gnu_ld"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_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_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test yes,no = "$GCC,$with_gnu_ld"; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + m4_if($1, [], [ + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + _LT_LINKER_OPTION([if $CC understands -b], + _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], + [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], + [_LT_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 no = "$with_gnu_ld"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_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_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], + [lt_cv_irix_exported_symbol], + [save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" + AC_LINK_IFELSE( + [AC_LANG_SOURCE( + [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], + [C++], [[int foo (void) { return 0; }]], + [Fortran 77], [[ + subroutine foo + end]], + [Fortran], [[ + subroutine foo + end]])])], + [lt_cv_irix_exported_symbol=yes], + [lt_cv_irix_exported_symbol=no]) + LDFLAGS=$save_LDFLAGS]) + if test yes = "$lt_cv_irix_exported_symbol"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' + fi + _LT_TAGVAR(link_all_deplibs, $1)=no + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + linux*) + case $cc_basename in + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + _LT_TAGVAR(ld_shlibs, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + ;; + esac + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd* | bitrig*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + shrext_cmds=.dll + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + ;; + + osf3*) + if test yes = "$GCC"; then + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test yes = "$GCC"; then + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_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_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test yes = "$GCC"; then + wlarc='$wl' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_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' + ;; + *) + wlarc='$wl' + _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_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 -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_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 yes = "$GCC"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test sequent = "$host_vendor"; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_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 CANNOT 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_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test sni = "$host_vendor"; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test yes,yes = "$GCC,$enable_shared"; then + case $_LT_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_CACHE_CHECK([whether -lc should be explicitly linked in], + [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), + [$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_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + ]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting $shlibpath_var if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [postlink_cmds], [2], + [Commands necessary for finishing linking programs]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +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_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_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report what 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 no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + 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 yes = "$enable_shared" || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC=$lt_save_CC +])# _LT_LANG_C_CONFIG + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +if test -n "$CXX" && ( test no != "$CXX" && + ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || + (test g++ != "$CXX"))); then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test yes != "$_lt_caught_CXX_error"; then + # 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_TAG_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_CFLAGS=$CFLAGS + 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++"} + CFLAGS=$CXXFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test yes = "$GXX"; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test yes = "$GXX"; then + # Set up default GNU C++ configuration + + LT_PATH_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 yes = "$with_gnu_ld"; then + _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_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_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + else + _LT_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_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 -v "^Configured with:" | $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_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test ia64 = "$host_cpu"; 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 + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + 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_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='$wl-f,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + ;; + esac + + if test yes = "$GXX"; 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_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_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test yes = "$aix_use_runtimelinking"; then + shared_flag=$shared_flag' $wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; 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 yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + # The "-G" linker flag allows undefined symbols. + _LT_TAGVAR(no_undefined_flag, $1)='-bernotok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_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_SYS_MODULE_PATH_AIX([$1]) + _LT_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_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared + # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach <jrb3@best.com> says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl* | ,icl* | no,icl*) + # Native MSVC or ICC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # 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_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_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, use it as + # is; otherwise, prepend EXPORTS... + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); 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_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + shrext_cmds=.dll + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly* | midnightbsd*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_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_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_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 "x$output_objdir/$soname" = "x$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) | $EGREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes = "$GXX"; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_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_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_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; func_echo_all "$list"' + ;; + *) + if test yes = "$GXX"; then + if test no = "$with_gnu_ld"; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $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_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_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_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_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_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-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_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test yes = "$GXX"; then + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | 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_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_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; func_echo_all "$list"' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_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_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # 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_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_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_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_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_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_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' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_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_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_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=`func_echo_all "$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; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + if test yes = "$supports_anon_versioning"; then + _LT_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 -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | $SED 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_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_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_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; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # 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_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_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::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd* | bitrig*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then + _LT_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_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | 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_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_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_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_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_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=`func_echo_all "$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; func_echo_all "$list"' + ;; + *) + if test yes,no = "$GXX,$with_gnu_ld"; then + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + case $host in + osf3*) + _LT_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" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_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 -v "^Configured with:" | $GREP " \-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_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_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_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_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='func_echo_all' + + # 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_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_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_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test yes,no = "$GXX,$with_gnu_ld"; then + _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -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 -v "^Configured with:" | $GREP " \-L"' + else + # g++ 2.7 appears to require '-G' NOT '-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + _LT_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 $wl-h $wl$soname -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 -v "^Configured with:" | $GREP " \-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_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_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_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 CANNOT 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_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ + '"$_LT_TAGVAR(old_archive_cmds, $1)" + _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ + '"$_LT_TAGVAR(reload_cmds, $1)" + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$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_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no + + _LT_TAGVAR(GCC, $1)=$GXX + _LT_TAGVAR(LD, $1)=$LD + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + 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 +fi # test yes != "$_lt_caught_CXX_error" + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_FUNC_STRIPNAME_CNF +# ---------------------- +# func_stripname_cnf prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# +# This function is identical to the (non-XSI) version of func_stripname, +# except this one can be used by m4 code that may be executed by configure, +# rather than the libtool script. +m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl +AC_REQUIRE([_LT_DECL_SED]) +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) +func_stripname_cnf () +{ + case @S|@2 in + .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;; + *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;; + esac +} # func_stripname_cnf +])# _LT_FUNC_STRIPNAME_CNF + + +# _LT_SYS_HIDDEN_LIBDEPS([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. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +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... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF +package foo +func foo() { +} +_LT_EOF +]) + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +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 + + for p in `eval "$output_verbose_link_cmd"`; do + case $prev$p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test x-L = "$p" || + test x-R = "$p"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test no = "$pre_test_object_deps_done"; then + case $prev 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_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_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_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)=$prev$p + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$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 no = "$pre_test_object_deps_done"; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)=$p + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)=$p + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_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 +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +m4_if([$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_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_LANG_PUSH(Fortran 77) +if test -z "$F77" || test no = "$F77"; then + _lt_disable_F77=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_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_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test yes != "$_lt_disable_F77"; then + # 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_TAG_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_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${F77-"f77"} + CFLAGS=$FFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + 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 yes = "$enable_shared" || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)=$G77 + _LT_TAGVAR(LD, $1)=$LD + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS +fi # test yes != "$_lt_disable_F77" + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_LANG_PUSH(Fortran) + +if test -z "$FC" || test no = "$FC"; then + _lt_disable_FC=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test yes != "$_lt_disable_FC"; then + # 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_TAG_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_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${FC-"f95"} + CFLAGS=$FCFLAGS + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + 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 yes = "$enable_shared" || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu + _LT_TAGVAR(LD, $1)=$LD + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS +fi # test yes != "$_lt_disable_FC" + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_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_TAG_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_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +CFLAGS=$GCJFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)=$LD +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_GO_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Go compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_GO_CONFIG], +[AC_REQUIRE([LT_PROG_GO])dnl +AC_LANG_SAVE + +# Source file extension for Go test sources. +ac_ext=go + +# Object file extension for compiled Go test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="package main; func main() { }" + +# Code to be used in simple link tests +lt_simple_link_test_code='package main; func main() { }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_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_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GOC-"gccgo"} +CFLAGS=$GOFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)=$LD +_LT_CC_BASENAME([$compiler]) + +# Go did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GO_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_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_TAG_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_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +CFLAGS= +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_GO +# ---------- +AC_DEFUN([LT_PROG_GO], +[AC_CHECK_TOOL(GOC, gccgo,) +]) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + +# _LT_DECL_DLLTOOL +# ---------------- +# Ensure DLLTOOL variable is set. +m4_defun([_LT_DECL_DLLTOOL], +[AC_CHECK_TOOL(DLLTOOL, dlltool, false) +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program]) +AC_SUBST([DLLTOOL]) +]) + +# _LT_DECL_FILECMD +# ---------------- +# Check for a file(cmd) program that can be used to detect file type and magic +m4_defun([_LT_DECL_FILECMD], +[AC_CHECK_TOOL([FILECMD], [file], [:]) +_LT_DECL([], [FILECMD], [1], [A file(cmd) program that detects file types]) +])# _LD_DECL_FILECMD + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +# 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. # + +m4_defun([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 10 -lt "$lt_ac_count" && 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]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# 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 + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PATH_CONVERSION_FUNCTIONS +# ----------------------------- +# Determine what file name conversion functions should be used by +# func_to_host_file (and, implicitly, by func_to_host_path). These are needed +# for certain cross-compile configurations and native mingw. +m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_MSG_CHECKING([how to convert $build file names to $host format]) +AC_CACHE_VAL(lt_cv_to_host_file_cmd, +[case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac +]) +to_host_file_cmd=$lt_cv_to_host_file_cmd +AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) +_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], + [0], [convert $build file names to $host format])dnl + +AC_MSG_CHECKING([how to convert $build file names to toolchain format]) +AC_CACHE_VAL(lt_cv_to_tool_file_cmd, +[#assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac +]) +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) +_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], + [0], [convert $build files to toolchain format])dnl +])# _LT_PATH_CONVERSION_FUNCTIONS + +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004-2005, 2007-2009, 2011-2019, 2021-2022 Free +# Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# 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 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option '$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl 'shared' nor 'disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4], + [_LT_WITH_AIX_SONAME([aix])]) + ]) +])# _LT_SET_OPTIONS + + + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the 'dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [1], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the 'win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the 'shared' and +# 'disable-shared' LT_INIT options. +# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_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=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the 'static' and +# 'disable-static' LT_INIT options. +# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_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=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the 'fast-install' +# and 'disable-fast-install' LT_INIT options. +# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_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=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the 'fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the 'disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_AIX_SONAME([DEFAULT]) +# ---------------------------------- +# implement the --with-aix-soname flag, and support the `aix-soname=aix' +# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT +# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'. +m4_define([_LT_WITH_AIX_SONAME], +[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl +shared_archive_member_spec= +case $host,$enable_shared in +power*-*-aix[[5-9]]*,yes) + AC_MSG_CHECKING([which variant of shared library versioning to provide]) + AC_ARG_WITH([aix-soname], + [AS_HELP_STRING([--with-aix-soname=aix|svr4|both], + [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])], + [case $withval in + aix|svr4|both) + ;; + *) + AC_MSG_ERROR([Unknown argument to --with-aix-soname]) + ;; + esac + lt_cv_with_aix_soname=$with_aix_soname], + [AC_CACHE_VAL([lt_cv_with_aix_soname], + [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT) + with_aix_soname=$lt_cv_with_aix_soname]) + AC_MSG_RESULT([$with_aix_soname]) + if test aix != "$with_aix_soname"; then + # For the AIX way of multilib, we name the shared archive member + # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', + # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. + # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, + # the AIX toolchain works better with OBJECT_MODE set (default 32). + if test 64 = "${OBJECT_MODE-32}"; then + shared_archive_member_spec=shr_64 + else + shared_archive_member_spec=shr + fi + fi + ;; +*) + with_aix_soname=aix + ;; +esac + +_LT_DECL([], [shared_archive_member_spec], [0], + [Shared archive member basename, for filename based shared library versioning on AIX])dnl +])# _LT_WITH_AIX_SONAME + +LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])]) +LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])]) +LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])]) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the 'pic-only' and 'no-pic' +# LT_INIT options. +# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for lt_pkg in $withval; do + IFS=$lt_save_ifs + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [pic_mode=m4_default([$1], [default])]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the 'pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) + +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004-2005, 2007-2008, 2011-2019, 2021-2022 Free Software +# Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# 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 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59, which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) + +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004, 2011-2019, 2021-2022 Free Software Foundation, +# Inc. +# Written by Scott James Remnant, 2004 +# +# 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. + +# @configure_input@ + +# serial 4245 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.4.7]) +m4_define([LT_PACKAGE_REVISION], [2.4.7]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.4.7' +macro_revision='2.4.7' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) + +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004-2005, 2007, 2009, 2011-2019, 2021-2022 Free +# Software Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# 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 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN), +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) +m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) +m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) +m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) +m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) +m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) +m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) + +# pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*- +# serial 12 (pkg-config-0.29.2) + +dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>. +dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com> +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a +dnl configuration script generated by Autoconf, you may include it under +dnl the same distribution terms that you use for the rest of that +dnl program. + +dnl PKG_PREREQ(MIN-VERSION) +dnl ----------------------- +dnl Since: 0.29 +dnl +dnl Verify that the version of the pkg-config macros are at least +dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's +dnl installed version of pkg-config, this checks the developer's version +dnl of pkg.m4 when generating configure. +dnl +dnl To ensure that this macro is defined, also add: +dnl m4_ifndef([PKG_PREREQ], +dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) +dnl +dnl See the "Since" comment for each macro you use to see what version +dnl of the macros you require. +m4_defun([PKG_PREREQ], +[m4_define([PKG_MACROS_VERSION], [0.29.2]) +m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, + [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) +])dnl PKG_PREREQ + +dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) +dnl ---------------------------------- +dnl Since: 0.16 +dnl +dnl Search for the pkg-config tool and set the PKG_CONFIG variable to +dnl first found in the path. Checks that the version of pkg-config found +dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is +dnl used since that's the first version where most current features of +dnl pkg-config existed. +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +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 +])dnl PKG_PROG_PKG_CONFIG + +dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------------------------------- +dnl Since: 0.18 +dnl +dnl Check to see whether a particular set of modules exists. Similar to +dnl PKG_CHECK_MODULES(), but does not set variables or print errors. +dnl +dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +dnl only at the first occurrence in configure.ac, so if the first place +dnl it's called might be skipped (such as if it is within an "if", you +dnl have 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_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +dnl --------------------------------------------- +dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting +dnl pkg_failed based on the result. +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` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])dnl _PKG_CONFIG + +dnl _PKG_SHORT_ERRORS_SUPPORTED +dnl --------------------------- +dnl Internal check to see if pkg-config supports short errors. +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 +])dnl _PKG_SHORT_ERRORS_SUPPORTED + + +dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl -------------------------------------------------------------- +dnl Since: 0.4.0 +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES might not happen, you should be sure to include an +dnl 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 $2]) + +_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 + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[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])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[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/>.])[]dnl + ]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])dnl PKG_CHECK_MODULES + + +dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl --------------------------------------------------------------------- +dnl Since: 0.29 +dnl +dnl Checks for existence of MODULES and gathers its build flags with +dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags +dnl and VARIABLE-PREFIX_LIBS from --libs. +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to +dnl include an explicit call to PKG_PROG_PKG_CONFIG in your +dnl configure.ac. +AC_DEFUN([PKG_CHECK_MODULES_STATIC], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +_save_PKG_CONFIG=$PKG_CONFIG +PKG_CONFIG="$PKG_CONFIG --static" +PKG_CHECK_MODULES($@) +PKG_CONFIG=$_save_PKG_CONFIG[]dnl +])dnl PKG_CHECK_MODULES_STATIC + + +dnl PKG_INSTALLDIR([DIRECTORY]) +dnl ------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable pkgconfigdir as the location where a module +dnl should install pkg-config .pc files. By default the directory is +dnl $libdir/pkgconfig, but the default can be changed by passing +dnl DIRECTORY. The user can override through the --with-pkgconfigdir +dnl parameter. +AC_DEFUN([PKG_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([pkgconfigdir], + [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, + [with_pkgconfigdir=]pkg_default) +AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_INSTALLDIR + + +dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) +dnl -------------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable noarch_pkgconfigdir as the location where a +dnl module should install arch-independent pkg-config .pc files. By +dnl default the directory is $datadir/pkgconfig, but the default can be +dnl changed by passing DIRECTORY. The user can override through the +dnl --with-noarch-pkgconfigdir parameter. +AC_DEFUN([PKG_NOARCH_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([noarch-pkgconfigdir], + [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, + [with_noarch_pkgconfigdir=]pkg_default) +AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_NOARCH_INSTALLDIR + + +dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, +dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------- +dnl Since: 0.28 +dnl +dnl Retrieves the value of the pkg-config variable for the given module. +AC_DEFUN([PKG_CHECK_VAR], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl + +_PKG_CONFIG([$1], [variable="][$3]["], [$2]) +AS_VAR_COPY([$1], [pkg_cv_][$1]) + +AS_VAR_IF([$1], [""], [$5], [$4])dnl +])dnl PKG_CHECK_VAR + +dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, +dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], +dnl [DESCRIPTION], [DEFAULT]) +dnl ------------------------------------------ +dnl +dnl Prepare a "--with-" configure option using the lowercase +dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and +dnl PKG_CHECK_MODULES in a single macro. +AC_DEFUN([PKG_WITH_MODULES], +[ +m4_pushdef([with_arg], m4_tolower([$1])) + +m4_pushdef([description], + [m4_default([$5], [build with ]with_arg[ support])]) + +m4_pushdef([def_arg], [m4_default([$6], [auto])]) +m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) +m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) + +m4_case(def_arg, + [yes],[m4_pushdef([with_without], [--without-]with_arg)], + [m4_pushdef([with_without],[--with-]with_arg)]) + +AC_ARG_WITH(with_arg, + AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, + [AS_TR_SH([with_]with_arg)=def_arg]) + +AS_CASE([$AS_TR_SH([with_]with_arg)], + [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], + [auto],[PKG_CHECK_MODULES([$1],[$2], + [m4_n([def_action_if_found]) $3], + [m4_n([def_action_if_not_found]) $4])]) + +m4_popdef([with_arg]) +m4_popdef([description]) +m4_popdef([def_arg]) + +])dnl PKG_WITH_MODULES + +dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, +dnl [DESCRIPTION], [DEFAULT]) +dnl ----------------------------------------------- +dnl +dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES +dnl check._[VARIABLE-PREFIX] is exported as make variable. +AC_DEFUN([PKG_HAVE_WITH_MODULES], +[ +PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) + +AM_CONDITIONAL([HAVE_][$1], + [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) +])dnl PKG_HAVE_WITH_MODULES + +dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, +dnl [DESCRIPTION], [DEFAULT]) +dnl ------------------------------------------------------ +dnl +dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after +dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make +dnl and preprocessor variable. +AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], +[ +PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) + +AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], + [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) +])dnl PKG_HAVE_DEFINE_WITH_MODULES + +# Copyright (C) 2002-2021 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.16' +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.16.5], [], + [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 AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.16.5])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001-2021 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], +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2021 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_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$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 +m4_define([_AM_COND_VALUE_$1], [$2])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-2021 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. + + +# 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", "OBJC", "OBJCXX", "UPC", or "GJC". +# 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 + +m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], + [$1], [CXX], [depcc="$CXX" am_compiler_list=], + [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], [OBJCXX], [depcc="$OBJCXX" 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". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$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 + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$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], [dnl +AS_HELP_STRING( + [--enable-dependency-tracking], + [do not reject slow dependency extractors]) +AS_HELP_STRING( + [--disable-dependency-tracking], + [speeds up one-time build])]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999-2021 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_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + # TODO: see whether this extra hack can be removed once we start + # requiring Autoconf 2.70 or later. + AS_CASE([$CONFIG_FILES], + [*\'*], [eval set x "$CONFIG_FILES"], + [*], [set x $CONFIG_FILES]) + shift + # Used to flag and report bootstrapping failures. + am_rc=0 + for am_mf + do + # Strip MF so we end up with the name of the file. + am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile which includes + # dependency-tracking related rules and includes. + # Grep'ing the whole file directly is not great: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ + || continue + am_dirpart=`AS_DIRNAME(["$am_mf"])` + am_filepart=`AS_BASENAME(["$am_mf"])` + AM_RUN_LOG([cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles]) || am_rc=$? + done + if test $am_rc -ne 0; then + AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments + for automatic dependency tracking. If GNU make was not used, consider + re-running the configure script with MAKE="gmake" (or whatever is + necessary). You can also try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking).]) + fi + AS_UNSET([am_dirpart]) + AS_UNSET([am_filepart]) + AS_UNSET([am_mf]) + AS_UNSET([am_rc]) + rm -f conftest-deps.mk +} +])# _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. +# This creates each '.Po' and '.Plo' makefile fragment that we'll 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" MAKE="${MAKE-make}"])]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996-2021 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 macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. +m4_define([AC_PROG_CC], +m4_defn([AC_PROG_CC]) +[_AM_PROG_CC_C_O +]) + +# 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.65])dnl +m4_ifdef([_$0_ALREADY_INIT], + [m4_fatal([$0 expanded multiple times +]m4_defn([_$0_ALREADY_INIT]))], + [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])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], +[AC_DIAGNOSE([obsolete], + [$0: two- and three-arguments forms are deprecated.]) +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_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]), + [ok:ok],, + [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]) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html> +# <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html> +AC_SUBST([mkdir_p], ['$(MKDIR_P)']) +# We need awk for the "check" target (and possibly the TAP driver). 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])], + [m4_define([AC_PROG_CC], + m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES([CXX])], + [m4_define([AC_PROG_CXX], + m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES([OBJC])], + [m4_define([AC_PROG_OBJC], + m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], + [_AM_DEPENDENCIES([OBJCXX])], + [m4_define([AC_PROG_OBJCXX], + m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl +]) +# Variables for tags utilities; see am/tags.am +if test -z "$CTAGS"; then + CTAGS=ctags +fi +AC_SUBST([CTAGS]) +if test -z "$ETAGS"; then + ETAGS=etags +fi +AC_SUBST([ETAGS]) +if test -z "$CSCOPE"; then + CSCOPE=cscope +fi +AC_SUBST([CSCOPE]) + +AC_REQUIRE([AM_SILENT_RULES])dnl +dnl The testsuite driver may need to know about EXEEXT, so add the +dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This +dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542> + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: <https://www.gnu.org/software/coreutils/>. + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) + fi +fi +dnl The trailing newline in this macro's definition is deliberate, for +dnl backward compatibility and to allow trailing 'dnl'-style comments +dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. +]) + +dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + +# 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-2021 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 +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST([install_sh])]) + +# Copyright (C) 2003-2021 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. + +# 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])]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996-2021 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_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless 'enable' is passed literally. +# For symmetry, 'disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], + [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode], + am_maintainer_other[ make rules and dependencies not useful + (and sometimes confusing) to the casual installer])], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001-2021 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_MAKE_INCLUDE() +# ----------------- +# Check whether make has an 'include' directive that can support all +# the idioms we need for our automatic dependency tracking code. +AC_DEFUN([AM_MAKE_INCLUDE], +[AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) +cat > confinc.mk << 'END' +am__doit: + @echo this is the am__doit target >confinc.out +.PHONY: am__doit +END +am__include="#" +am__quote= +# BSD make does it like this. +echo '.include "confinc.mk" # ignored' > confmf.BSD +# Other make implementations (GNU, Solaris 10, AIX) do it like this. +echo 'include confinc.mk # ignored' > confmf.GNU +_am_result=no +for s in GNU BSD; do + AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) + AS_CASE([$?:`cat confinc.out 2>/dev/null`], + ['0:this is the am__doit target'], + [AS_CASE([$s], + [BSD], [am__include='.include' am__quote='"'], + [am__include='include' am__quote=''])]) + if test "$am__include" != "#"; then + _am_result="yes ($s style)" + break + fi +done +rm -f confinc.* confmf.* +AC_MSG_RESULT([${_am_result}]) +AC_SUBST([am__include])]) +AC_SUBST([am__quote])]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997-2021 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_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 is modern enough. +# If it is, 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 +if test x"${MISSING+set}" != xset; then + MISSING="\${SHELL} '$am_aux_dir/missing'" +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + AC_MSG_WARN(['missing' script is too old or missing]) +fi +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001-2021 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_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], +[m4_foreach_w([_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])]) + +# Copyright (C) 1999-2021 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_CC_C_O +# --------------- +# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC +# to automatically call this. +AC_DEFUN([_AM_PROG_CC_C_O], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +AC_LANG_PUSH([C])dnl +AC_CACHE_CHECK( + [whether $CC understands -c and -o together], + [am_cv_prog_cc_c_o], + [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i]) +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +AC_LANG_POP([C])]) + +# For backward compatibility. +AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) + +# Copyright (C) 2001-2021 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_RUN_LOG(COMMAND) +# ------------------- +# Run COMMAND, save the exit status in ac_status, and log it. +# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) +AC_DEFUN([AM_RUN_LOG], +[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD + ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + (exit $ac_status); }]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996-2021 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_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; +esac + +# 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 ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + 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 + 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 + if test "$[2]" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + 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]) +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi +AC_CONFIG_COMMANDS_PRE( + [AC_MSG_CHECKING([that generated files are newer than configure]) + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + AC_MSG_RESULT([done])]) +rm -f conftest.file +]) + +# Copyright (C) 2009-2021 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_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# ("yes" being less verbose, "no" or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], [dnl +AS_HELP_STRING( + [--enable-silent-rules], + [less verbose build output (undo: "make V=1")]) +AS_HELP_STRING( + [--disable-silent-rules], + [verbose build output (undo: "make V=0")])dnl +]) +case $enable_silent_rules in @%:@ ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +dnl +dnl A few 'make' implementations (e.g., NonStop OS and NextStep) +dnl do not support nested variable expansions. +dnl See automake bug#9928 and bug#10237. +am_make=${MAKE-make} +AC_CACHE_CHECK([whether $am_make supports nested variables], + [am_cv_make_support_nested_variables], + [if AS_ECHO([['TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi]) +if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AC_SUBST([AM_V])dnl +AM_SUBST_NOTMAKE([AM_V])dnl +AC_SUBST([AM_DEFAULT_V])dnl +AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001-2021 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-2021 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]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004-2021 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_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. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' + +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + + [m4_case([$1], + [ustar], + [# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) + if test $am_uid -le $am_max_uid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi + AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) + if test $am_gid -le $am_max_gid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi], + + [pax], + [], + + [m4_fatal([Unknown tar format])]) + + AC_MSG_CHECKING([how to create a $1 tar archive]) + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_$1-$_am_tools} + + 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]) + AM_RUN_LOG([cat conftest.dir/file]) + 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/android/Makefile.am b/android/Makefile.am index 309910147a369b54fc56d756de090c78bbc7514d..e3756e89c657f93fbd3d2014e93a965c4e692ace 100644 --- a/android/Makefile.am +++ b/android/Makefile.am @@ -96,6 +96,7 @@ android_bluetooth_default_la_SOURCES = android/hal.h android/hal-bluetooth.c \ android/hal-log.h \ android/hal-ipc.h android/hal-ipc.c \ android/hal-utils.h android/hal-utils.c +android_bluetooth_default_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden android_bluetooth_default_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/android android_bluetooth_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \ -no-undefined @@ -195,6 +196,7 @@ android_audio_a2dp_default_la_SOURCES = android/audio-msg.h \ android/hardware/audio_effect.h \ android/hardware/hardware.h \ android/system/audio.h +android_audio_a2dp_default_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden android_audio_a2dp_default_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/android \ $(SBC_CFLAGS) android_audio_a2dp_default_la_LIBADD = $(SBC_LIBS) -lrt @@ -212,6 +214,7 @@ android_audio_sco_default_la_SOURCES = android/hal-log.h \ android/audio_utils/resampler.c \ android/audio_utils/resampler.h \ android/system/audio.h +android_audio_sco_default_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden android_audio_sco_default_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/android android_audio_sco_default_la_LIBADD = $(SPEEXDSP_LIBS) -lrt android_audio_sco_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \ diff --git a/android/avctp.c b/android/avctp.c index 37b4cec4f0cc6a2213ec2a75d8ff86d394e610f3..d8104a7c2b4514246acabad058a817fcb4db6bcf 100644 --- a/android/avctp.c +++ b/android/avctp.c @@ -905,10 +905,8 @@ send: failed: DBG("AVCTP Browsing: disconnected"); - if (session->browsing) { - avctp_channel_destroy(session->browsing); - session->browsing = NULL; - } + avctp_channel_destroy(session->browsing); + session->browsing = NULL; return FALSE; } diff --git a/android/avdtp.c b/android/avdtp.c index a261a8e5f4b0b19c4a5f782f05d85884c7a8ea6f..e0466853b7b5b3a3d86f39b68fc686b476b0e49b 100644 --- a/android/avdtp.c +++ b/android/avdtp.c @@ -2130,8 +2130,10 @@ struct avdtp *avdtp_new(int fd, size_t imtu, size_t omtu, uint16_t version, return NULL; } - if (set_priority(new_fd, 6) < 0) + if (set_priority(new_fd, 6) < 0) { + close(new_fd); return NULL; + } session = g_new0(struct avdtp, 1); session->io = g_io_channel_unix_new(new_fd); diff --git a/android/gatt.c b/android/gatt.c index e8ba5aabbac25a59863f2a029a1ef1875082cb86..89fcdb11442966c9103768f734ed9891d949a5cc 100644 --- a/android/gatt.c +++ b/android/gatt.c @@ -3730,7 +3730,11 @@ static void handle_client_register_for_notification(const void *buf, notification = new0(struct notification_data, 1); +_Pragma("GCC diagnostic push") +_Pragma("GCC diagnostic ignored \"-Warray-bounds\"") +_Pragma("GCC diagnostic ignored \"-Wstringop-overflow\"") memcpy(¬ification->ch, &cmd->char_id, sizeof(notification->ch)); +_Pragma("GCC diagnostic pop") memcpy(¬ification->service, &cmd->srvc_id, sizeof(notification->service)); notification->conn = conn; diff --git a/android/hal-audio-sbc.c b/android/hal-audio-sbc.c index 9c64d339c610082521bc519eb9f2ce6451abe09e..6f7788aeaaf49bf182053df618a43a64d75adf57 100644 --- a/android/hal-audio-sbc.c +++ b/android/hal-audio-sbc.c @@ -257,7 +257,7 @@ static bool sbc_codec_init(struct audio_preset *preset, uint16_t payload_len, return false; } - sbc_data = calloc(sizeof(struct sbc_data), 1); + sbc_data = calloc(1, sizeof(struct sbc_data)); if (!sbc_data) return false; diff --git a/android/hal-audio.c b/android/hal-audio.c index d37d6098c067bbd3947e11dd7a013611db67c73f..f3d9b40a62fecd58c4f71ebc350b13f015fcf70e 100644 --- a/android/hal-audio.c +++ b/android/hal-audio.c @@ -1618,6 +1618,7 @@ static struct hw_module_methods_t hal_module_methods = { .open = audio_open, }; +__attribute__ ((visibility("default"))) struct audio_module HAL_MODULE_INFO_SYM = { .common = { .tag = HARDWARE_MODULE_TAG, diff --git a/android/hal-bluetooth.c b/android/hal-bluetooth.c index d4442e6202022a3034e0641e88d68e89b3cdfdd2..7d1e5ac63c1c2ad48355e4069bbd1c6231bceeb6 100644 --- a/android/hal-bluetooth.c +++ b/android/hal-bluetooth.c @@ -1117,6 +1117,7 @@ static struct hw_module_methods_t bluetooth_module_methods = { .open = open_bluetooth, }; +__attribute__ ((visibility("default"))) struct hw_module_t HAL_MODULE_INFO_SYM = { .tag = HARDWARE_MODULE_TAG, .version_major = 1, diff --git a/android/hal-sco.c b/android/hal-sco.c index d7c08a68b842a7e252071fdfbf6cd84906203f88..3d66ad357fbe066095ee7fe6f456dcbc4a5ec120 100644 --- a/android/hal-sco.c +++ b/android/hal-sco.c @@ -1507,6 +1507,7 @@ static struct hw_module_methods_t hal_module_methods = { .open = sco_open, }; +__attribute__ ((visibility("default"))) struct audio_module HAL_MODULE_INFO_SYM = { .common = { .tag = HARDWARE_MODULE_TAG, diff --git a/android/handsfree.c b/android/handsfree.c index 2365356c2cf7683f933a29ef2176e333d3a31988..7b803fae52634447b8a5c0ec6870a44d430502e6 100644 --- a/android/handsfree.c +++ b/android/handsfree.c @@ -1243,15 +1243,22 @@ static void at_cmd_cind(struct hfp_context *result, enum hfp_gw_cmd_type type, } buf = g_malloc(len); - - ptr = buf + sprintf(buf, "+CIND:"); + if (sprintf(buf, "+CIND:") != strlen("+CIND:")) { + g_free(buf); + break; + } + ptr = buf + strlen("+CIND:"); for (i = 0; i < IND_COUNT; i++) { - ptr += sprintf(ptr, "(\"%s\",(%d%c%d)),", + int printed; + printed = sprintf(ptr, "(\"%s\",(%d%c%d)),", dev->inds[i].name, dev->inds[i].min, dev->inds[i].max == 1 ? ',' : '-', dev->inds[i].max); + if (printed < 0) + goto fail; + ptr += printed; } ptr--; @@ -1273,6 +1280,7 @@ static void at_cmd_cind(struct hfp_context *result, enum hfp_gw_cmd_type type, break; } +fail: hfp_gw_send_result(dev->gw, HFP_RESULT_ERROR); if (dev->state != HAL_EV_HANDSFREE_CONN_STATE_SLC_CONNECTED) diff --git a/android/hidhost.c b/android/hidhost.c index b4e5c527fafc91412f79658d7983bf6af5112dc4..598bec326ca88c62e48346544d3dff351cc25032 100644 --- a/android/hidhost.c +++ b/android/hidhost.c @@ -796,7 +796,7 @@ static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib) if (dev->hog) { bt_hid_notify_state(dev, HAL_HIDHOST_STATE_DISCONNECTED); - bt_hog_detach(dev->hog); + bt_hog_detach(dev->hog, true); return; } goto fail; @@ -808,7 +808,8 @@ static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib) if (!dev->hog) { /* TODO: Get device details and primary */ dev->hog = bt_hog_new_default("bluez-input-device", dev->vendor, - dev->product, dev->version, NULL); + dev->product, dev->version, + BT_UHID_NONE, NULL); if (!dev->hog) { error("HoG: unable to create session"); goto fail; diff --git a/android/ipc-tester.c b/android/ipc-tester.c index 780e1dc4ce1c7627a3e97981e04ace85ca6e6194..68e2ad10e747f4f0c505ac89dee7918b4c928a56 100644 --- a/android/ipc-tester.c +++ b/android/ipc-tester.c @@ -17,6 +17,7 @@ #include <unistd.h> #include <errno.h> #include <poll.h> +#include <limits.h> #include <sys/socket.h> #include <sys/types.h> diff --git a/android/sco-ipc-api.txt b/android/sco-ipc-api.txt deleted file mode 100644 index 27d5ef2160c1403d55de10ebb2df68429f422aa3..0000000000000000000000000000000000000000 --- a/android/sco-ipc-api.txt +++ /dev/null @@ -1,37 +0,0 @@ -Bluetooth SCO Audio Plugin -========================== - -The SCO Audio Plugin communicate through abstract socket name -"\0bluez_sco_socket". - - .----SCO----. .--Android--. - | Plugin | | Daemon | - | | Command | | - | | --------------------------> | | - | | | | - | | <-------------------------- | | - | | Response | | - | | | | - | | | | - | | | | - '-----------' '-----------' - - - SCO HAL Daemon - ---------------------------------------------------- - - call get_fd() --> Get SCO socket fd - return get_fd() <-- Return SCO socket fd and mtu - -SCO Audio Service (ID 0) -======================== - - Opcode 0x00 - Error response - - Response parameters: Status (1 octet) - - Opcode 0x01 - Get SCO fd command - - Command parameters: Remote address (6 octets) - Response parameters: MTU (2 octets) - File descriptor (inline) diff --git a/android/socket-api.txt b/android/socket-api.txt deleted file mode 100644 index 9f622f9845082a2e7f76554fa65a411dbaa19141..0000000000000000000000000000000000000000 --- a/android/socket-api.txt +++ /dev/null @@ -1,61 +0,0 @@ -Android Socket protocol for Bluetooth -===================================== - -Since Android switched from BlueZ (where sockets where nicely implemented) to -Bluedroid user space stack there is a need to emulate bluetooth sockets. - -Android Bluetooth Socket Hardware Abstraction Layer (HAL) bt_sock.h has -only 2 functions: - -static btsock_interface_t sock_if = { - sizeof(sock_if), - sock_listen, - sock_connect -}; - -with following parameters: - -sock_listen(btsock_type_t type, const char *service_name, - const uint8_t *uuid, int chan, int *sock_fd, int flags) -sock_connect(const bt_bdaddr_t *bdaddr, btsock_type_t type, - const uint8_t *uuid, int chan, int *sock_fd, int flags) - -socket type RFCOMM is only supported at the moment. uuid and channel used -to decide where to connect. - -sockfd is used to return socket fd to Android framework. It is used to inform -framework when remote device is connected. - -listen() -======== - -Listens on RFCOMM socket, socket channel is either found based on uuid or -channel parameter used directly. Returns sock_fd to Android framework. - -Through this sock_fd channel number as (int) needs to be written right after -listen() succeeds. - -When remote device is connected to this socket we shall send accept signal -through sock_fd - -connect() -========= - -Connects to remote device specified in bd_addr parameter. Socket channel is -found by SDP search of remote device by supplied uuid. Returns sock_fd to -Android framework. - -Through this sock_fd channel number as (int) needs to be written right after -connects() succeeds. - -When remote device is connected to this socket we shall send connect signal -through sock_fd - -The format of connect/accept signal is shown below: - -struct hal_sock_connect_signal { - short size; - uint8_t bdaddr[6]; - int channel; - int status; -} __attribute__((packed)); diff --git a/android/system-emulator.c b/android/system-emulator.c index bf1499df0957b51db49bbaecf81474e91f0402a6..50bb088d3188485489637d70f9f41a14c6c444a6 100644 --- a/android/system-emulator.c +++ b/android/system-emulator.c @@ -19,6 +19,7 @@ #include <stdlib.h> #include <signal.h> #include <string.h> +#include <limits.h> #include <libgen.h> #include <poll.h> #include <sys/wait.h> diff --git a/android/tester-main.c b/android/tester-main.c index 317c1de06463ad591525d0123697c6a48bf3b94a..361c519ef5a339b7d78be064a26c680453308d58 100644 --- a/android/tester-main.c +++ b/android/tester-main.c @@ -7,6 +7,7 @@ #define _GNU_SOURCE #include <stdbool.h> #include <unistd.h> +#include <limits.h> #include <libgen.h> #include <sys/un.h> diff --git a/attrib/gatt.c b/attrib/gatt.c index b496dd1ebd95a0d304aa5ac85ae18eccb8836419..3cedae9d167abb3e1b8e2af1858f4e581e29ddad 100644 --- a/attrib/gatt.c +++ b/attrib/gatt.c @@ -1076,10 +1076,12 @@ static void desc_discovered_cb(guint8 status, const guint8 *ipdu, att_data_list_free(list); /* - * If last handle is lower from previous start handle then it is smth - * wrong. Let's stop search, otherwise we might enter infinite loop. + * If last handle is lower from previous start handle or if iterating + * to the next handle from the last possible offset would overflow, then + * something is wrong. Let's stop search, otherwise we might enter + * infinite loop. */ - if (last < dd->start) { + if (last < dd->start || last == G_MAXUINT16) { err = ATT_ECODE_UNLIKELY; goto done; } diff --git a/attrib/gattrib.c b/attrib/gattrib.c index 041b9d289c6452033055472e870bc38d147917cf..1795cd3a72ffc179b06b0856363271c17f57c4e5 100644 --- a/attrib/gattrib.c +++ b/attrib/gattrib.c @@ -21,17 +21,23 @@ #include <glib.h> #include "lib/bluetooth.h" +#include "lib/uuid.h" #include "btio/btio.h" #include "src/log.h" #include "src/shared/util.h" #include "src/shared/att.h" +#include "src/shared/gatt-helpers.h" #include "src/shared/queue.h" +#include "src/shared/gatt-db.h" +#include "src/shared/gatt-client.h" +#include "attrib/att.h" #include "attrib/gattrib.h" struct _GAttrib { int ref_count; struct bt_att *att; + struct bt_gatt_client *client; GIOChannel *io; GDestroyNotify destroy; gpointer destroy_user_data; @@ -145,6 +151,7 @@ void g_attrib_unref(GAttrib *attrib) if (attrib->destroy) attrib->destroy(attrib->destroy_user_data); + bt_gatt_client_unref(attrib->client); bt_att_unref(attrib->att); queue_destroy(attrib->callbacks, attrib_callbacks_destroy); @@ -230,9 +237,9 @@ static void attrib_callback_result(uint8_t opcode, const void *pdu, free(buf); } -static void attrib_callback_notify(struct bt_att_chan *chan, uint8_t opcode, - const void *pdu, uint16_t length, - void *user_data) +static void attrib_callback_notify(struct bt_att_chan *chan, uint16_t mtu, + uint8_t opcode, const void *pdu, + uint16_t length, void *user_data) { uint8_t *buf; struct attrib_callbacks *cb = user_data; @@ -338,6 +345,20 @@ gboolean g_attrib_cancel_all(GAttrib *attrib) return TRUE; } +static void client_notify_cb(uint16_t value_handle, const uint8_t *value, + uint16_t length, void *user_data) +{ + uint8_t *buf = newa(uint8_t, length + 2); + + put_le16(value_handle, buf); + + if (length) + memcpy(buf + 2, value, length); + + attrib_callback_notify(NULL, 0, ATT_OP_HANDLE_NOTIFY, buf, length + 2, + user_data); +} + guint g_attrib_register(GAttrib *attrib, guint8 opcode, guint16 handle, GAttribNotifyFunc func, gpointer user_data, GDestroyNotify notify) @@ -359,6 +380,16 @@ guint g_attrib_register(GAttrib *attrib, guint8 opcode, guint16 handle, queue_push_head(attrib->callbacks, cb); } + if (opcode == ATT_OP_HANDLE_NOTIFY && attrib->client) { + unsigned int id; + + id = bt_gatt_client_register_notify(attrib->client, handle, + NULL, client_notify_cb, cb, + attrib_callbacks_remove); + if (id) + return id; + } + if (opcode == GATTRIB_ALL_REQS) opcode = BT_ATT_ALL_REQUESTS; @@ -410,6 +441,21 @@ gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu) return bt_att_set_mtu(attrib->att, mtu); } +gboolean g_attrib_attach_client(GAttrib *attrib, struct bt_gatt_client *client) +{ + if (!attrib || !client) + return FALSE; + + if (attrib->client) + bt_gatt_client_unref(attrib->client); + + attrib->client = bt_gatt_client_clone(client); + if (!attrib->client) + return FALSE; + + return TRUE; +} + gboolean g_attrib_unregister(GAttrib *attrib, guint id) { if (!attrib) diff --git a/attrib/gattrib.h b/attrib/gattrib.h index c2877d75734240378ca4525de45cf48283eba0ae..0111bfc3f2fa4a332a3f8de0f8dafae1987fde43 100644 --- a/attrib/gattrib.h +++ b/attrib/gattrib.h @@ -19,6 +19,7 @@ extern "C" { #define GATTRIB_ALL_HANDLES 0x0000 struct bt_att; /* Forward declaration for compatibility */ +struct bt_gatt_client; /* Forward declaration for compatibility */ struct _GAttrib; typedef struct _GAttrib GAttrib; @@ -53,6 +54,7 @@ guint g_attrib_register(GAttrib *attrib, guint8 opcode, guint16 handle, uint8_t *g_attrib_get_buffer(GAttrib *attrib, size_t *len); gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu); +gboolean g_attrib_attach_client(GAttrib *attrib, struct bt_gatt_client *client); gboolean g_attrib_unregister(GAttrib *attrib, guint id); gboolean g_attrib_unregister_all(GAttrib *attrib); diff --git a/attrib/gatttool.c b/attrib/gatttool.c index 6a0ddfaad652a16a66f9e5de5cab7e218fbd6b01..4309d20b10b34aa0d78a8ddd94476a19bcec5448 100644 --- a/attrib/gatttool.c +++ b/attrib/gatttool.c @@ -454,26 +454,26 @@ static gboolean parse_uuid(const char *key, const char *value, return TRUE; } -static GOptionEntry primary_char_options[] = { +static const GOptionEntry primary_char_options[] = { { "start", 's' , 0, G_OPTION_ARG_INT, &opt_start, - "Starting handle(optional)", "0x0001" }, + "Starting handle (optional)", "0x0001" }, { "end", 'e' , 0, G_OPTION_ARG_INT, &opt_end, - "Ending handle(optional)", "0xffff" }, + "Ending handle (optional)", "0xffff" }, { "uuid", 'u', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, - parse_uuid, "UUID16 or UUID128(optional)", "0x1801"}, + parse_uuid, "UUID16 or UUID128 (optional)", "0x1801"}, { NULL }, }; -static GOptionEntry char_rw_options[] = { +static const GOptionEntry char_rw_options[] = { { "handle", 'a' , 0, G_OPTION_ARG_INT, &opt_handle, - "Read/Write characteristic by handle(required)", "0x0001" }, + "Read/Write characteristic by handle (required)", "0x0001" }, { "value", 'n' , 0, G_OPTION_ARG_STRING, &opt_value, "Write characteristic value (required for write operation)", "0x0001" }, {NULL}, }; -static GOptionEntry gatt_options[] = { +static const GOptionEntry gatt_options[] = { { "primary", 0, 0, G_OPTION_ARG_NONE, &opt_primary, "Primary Service Discovery", NULL }, { "characteristics", 0, 0, G_OPTION_ARG_NONE, &opt_characteristics, @@ -494,7 +494,7 @@ static GOptionEntry gatt_options[] = { { NULL }, }; -static GOptionEntry options[] = { +static const GOptionEntry options[] = { { "adapter", 'i', 0, G_OPTION_ARG_STRING, &opt_src, "Specify local adapter interface", "hciX" }, { "device", 'b', 0, G_OPTION_ARG_STRING, &opt_dst, diff --git a/attrib/interactive.c b/attrib/interactive.c index 171b957382d09bdafc0efbc2c55bbf79ebf4533e..c0262e87cd08b7fc292f58242243d0083a1123e3 100644 --- a/attrib/interactive.c +++ b/attrib/interactive.c @@ -760,7 +760,7 @@ static void cmd_mtu(int argcp, char **argvp) gatt_exchange_mtu(attrib, opt_mtu, exchange_mtu_cb, NULL); } -static struct { +static const struct { const char *cmd; void (*func)(int argcp, char **argvp); const char *params; diff --git a/bootstrap b/bootstrap deleted file mode 100755 index 91756f94da03a1262c4f72c0c752fc27be835b31..0000000000000000000000000000000000000000 --- a/bootstrap +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -aclocal && \ - autoheader && \ - libtoolize --automake --copy --force && \ - automake --add-missing --copy && \ - autoconf diff --git a/bootstrap-configure b/bootstrap-configure deleted file mode 100755 index 8172840d5fc2ecb96bb496118847ff45de564b03..0000000000000000000000000000000000000000 --- a/bootstrap-configure +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh - -if [ -f config.status ]; then - make maintainer-clean -fi - -./bootstrap && \ - ./configure --enable-maintainer-mode \ - --enable-debug \ - --prefix=/usr \ - --mandir=/usr/share/man \ - --sysconfdir=/etc \ - --localstatedir=/var \ - --enable-tools \ - --enable-manpages \ - --enable-backtrace \ - --enable-testing \ - --enable-experimental \ - --enable-deprecated \ - --enable-nfc \ - --enable-sap \ - --enable-health \ - --enable-android \ - --enable-sixaxis \ - --enable-hid2hci \ - --enable-midi \ - --enable-mesh \ - --enable-btpclient \ - --enable-logger \ - --enable-pie \ - --enable-asan \ - --enable-lsan \ - --enable-ubsan \ - --enable-cups \ - --enable-library \ - --enable-admin \ - --disable-datafiles $* diff --git a/btio/btio.c b/btio/btio.c index 1ad42728df90fe61817540324cb05149e759a0a5..2d277e409aa1073339bdea397b5320c00f6b20c9 100644 --- a/btio/btio.c +++ b/btio/btio.c @@ -5,6 +5,7 @@ * * Copyright (C) 2009-2010 Marcel Holtmann <marcel@holtmann.org> * Copyright (C) 2009-2010 Nokia Corporation + * Copyright 2023-2024 NXP * * */ @@ -15,6 +16,7 @@ #include <stdarg.h> #include <stdlib.h> +#include <stdbool.h> #include <unistd.h> #include <errno.h> #include <poll.h> @@ -69,6 +71,10 @@ struct set_opts { uint32_t priority; uint16_t voice; struct bt_iso_qos qos; + struct bt_iso_base base; + uint8_t bc_sid; + uint8_t bc_num_bis; + uint8_t bc_bis[ISO_MAX_NUM_BIS]; }; struct connect { @@ -768,22 +774,53 @@ static int sco_bind(int sock, const bdaddr_t *src, GError **err) return 0; } -static int iso_bind(int sock, const bdaddr_t *src, uint8_t src_type, - GError **err) +static int iso_bind(int sock, bool server, const bdaddr_t *src, + uint8_t src_type, const bdaddr_t *dst, + uint8_t dst_type, uint8_t bc_sid, + uint8_t num_bis, uint8_t *bis, + GError **err) { - struct sockaddr_iso addr; + struct sockaddr_iso *addr = NULL; + size_t addr_len; + int ret = 0; + + /* If this is an ISO listener and the destination address + * is not BDADDR_ANY, the listener should be bound to the + * broadcaster address + */ + if (server && bacmp(dst, BDADDR_ANY)) + addr_len = sizeof(*addr) + sizeof(*addr->iso_bc); + else + addr_len = sizeof(*addr); - memset(&addr, 0, sizeof(addr)); - addr.iso_family = AF_BLUETOOTH; - bacpy(&addr.iso_bdaddr, src); - addr.iso_bdaddr_type = src_type; + addr = malloc(addr_len); + + if (!addr) + return -ENOMEM; - if (!bind(sock, (struct sockaddr *) &addr, sizeof(addr))) - return 0; + memset(addr, 0, addr_len); + addr->iso_family = AF_BLUETOOTH; + bacpy(&addr->iso_bdaddr, src); + addr->iso_bdaddr_type = src_type; + if (addr_len > sizeof(*addr)) { + bacpy(&addr->iso_bc->bc_bdaddr, dst); + addr->iso_bc->bc_bdaddr_type = dst_type; + addr->iso_bc->bc_sid = bc_sid; + addr->iso_bc->bc_num_bis = num_bis; + memcpy(addr->iso_bc->bc_bis, bis, + addr->iso_bc->bc_num_bis); + } + + if (!bind(sock, (struct sockaddr *)addr, addr_len)) + goto done; + + ret = -errno; ERROR_FAILED(err, "iso_bind", errno); - return -errno; +done: + free(addr); + return ret; } static int sco_connect(int sock, const bdaddr_t *dst) @@ -857,7 +894,7 @@ voice: return TRUE; } -static gboolean iso_set(int sock, struct bt_iso_qos *qos, GError **err) +static gboolean iso_set_qos(int sock, struct bt_iso_qos *qos, GError **err) { if (setsockopt(sock, SOL_BLUETOOTH, BT_ISO_QOS, qos, sizeof(*qos)) < 0) { @@ -868,6 +905,16 @@ static gboolean iso_set(int sock, struct bt_iso_qos *qos, GError **err) return TRUE; } +static gboolean iso_set_base(int sock, struct bt_iso_base *base, GError **err) +{ + if (setsockopt(sock, SOL_BLUETOOTH, BT_ISO_BASE, base->base, + base->base_len) < 0) { + ERROR_FAILED(err, "setsockopt(BT_ISO_BASE)", errno); + return FALSE; + } + + return TRUE; +} static gboolean parse_set_opts(struct set_opts *opts, GError **err, BtIOOption opt1, va_list args) { @@ -965,6 +1012,19 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err, case BT_IO_OPT_QOS: opts->qos = *va_arg(args, struct bt_iso_qos *); break; + case BT_IO_OPT_BASE: + opts->base = *va_arg(args, struct bt_iso_base *); + break; + case BT_IO_OPT_ISO_BC_SID: + opts->bc_sid = va_arg(args, int); + break; + case BT_IO_OPT_ISO_BC_NUM_BIS: + opts->bc_num_bis = va_arg(args, int); + break; + case BT_IO_OPT_ISO_BC_BIS: + memcpy(opts->bc_bis, va_arg(args, uint8_t *), + opts->bc_num_bis); + break; case BT_IO_OPT_INVALID: case BT_IO_OPT_KEY_SIZE: case BT_IO_OPT_SOURCE_CHANNEL: @@ -1289,6 +1349,10 @@ parse_opts: case BT_IO_OPT_MTU: case BT_IO_OPT_VOICE: case BT_IO_OPT_QOS: + case BT_IO_OPT_BASE: + case BT_IO_OPT_ISO_BC_SID: + case BT_IO_OPT_ISO_BC_NUM_BIS: + case BT_IO_OPT_ISO_BC_BIS: default: g_set_error(err, BT_IO_ERROR, EINVAL, "Unknown option %d", opt); @@ -1443,6 +1507,10 @@ static gboolean rfcomm_get(int sock, GError **err, BtIOOption opt1, case BT_IO_OPT_PRIORITY: case BT_IO_OPT_VOICE: case BT_IO_OPT_QOS: + case BT_IO_OPT_BASE: + case BT_IO_OPT_ISO_BC_SID: + case BT_IO_OPT_ISO_BC_NUM_BIS: + case BT_IO_OPT_ISO_BC_BIS: case BT_IO_OPT_INVALID: default: g_set_error(err, BT_IO_ERROR, EINVAL, @@ -1553,6 +1621,10 @@ static gboolean sco_get(int sock, GError **err, BtIOOption opt1, va_list args) case BT_IO_OPT_PRIORITY: case BT_IO_OPT_VOICE: case BT_IO_OPT_QOS: + case BT_IO_OPT_BASE: + case BT_IO_OPT_ISO_BC_SID: + case BT_IO_OPT_ISO_BC_NUM_BIS: + case BT_IO_OPT_ISO_BC_BIS: case BT_IO_OPT_INVALID: default: g_set_error(err, BT_IO_ERROR, EINVAL, @@ -1571,6 +1643,7 @@ static gboolean iso_get(int sock, GError **err, BtIOOption opt1, va_list args) BtIOOption opt = opt1; struct sockaddr_iso src, dst; struct bt_iso_qos qos; + struct bt_iso_base base; socklen_t len; uint32_t phy; @@ -1581,6 +1654,13 @@ static gboolean iso_get(int sock, GError **err, BtIOOption opt1, va_list args) return FALSE; } + if (getsockopt(sock, SOL_BLUETOOTH, BT_ISO_BASE, + &base.base, &len) < 0) { + ERROR_FAILED(err, "getsockopt(BT_ISO_BASE)", errno); + return FALSE; + } + base.base_len = len; + if (!get_src(sock, &src, sizeof(src), err)) return FALSE; @@ -1608,13 +1688,13 @@ static gboolean iso_get(int sock, GError **err, BtIOOption opt1, va_list args) *(va_arg(args, uint8_t *)) = dst.iso_bdaddr_type; break; case BT_IO_OPT_MTU: - *(va_arg(args, uint16_t *)) = qos.out.sdu; + *(va_arg(args, uint16_t *)) = qos.ucast.out.sdu; break; case BT_IO_OPT_IMTU: - *(va_arg(args, uint16_t *)) = qos.in.sdu; + *(va_arg(args, uint16_t *)) = qos.ucast.in.sdu; break; case BT_IO_OPT_OMTU: - *(va_arg(args, uint16_t *)) = qos.out.sdu; + *(va_arg(args, uint16_t *)) = qos.ucast.out.sdu; break; case BT_IO_OPT_PHY: if (get_phy(sock, &phy) < 0) { @@ -1626,6 +1706,9 @@ static gboolean iso_get(int sock, GError **err, BtIOOption opt1, va_list args) case BT_IO_OPT_QOS: *(va_arg(args, struct bt_iso_qos *)) = qos; break; + case BT_IO_OPT_BASE: + *(va_arg(args, struct bt_iso_base *)) = base; + break; case BT_IO_OPT_HANDLE: case BT_IO_OPT_CLASS: case BT_IO_OPT_DEFER_TIMEOUT: @@ -1641,6 +1724,9 @@ static gboolean iso_get(int sock, GError **err, BtIOOption opt1, va_list args) case BT_IO_OPT_FLUSHABLE: case BT_IO_OPT_PRIORITY: case BT_IO_OPT_VOICE: + case BT_IO_OPT_ISO_BC_SID: + case BT_IO_OPT_ISO_BC_NUM_BIS: + case BT_IO_OPT_ISO_BC_BIS: case BT_IO_OPT_INVALID: default: g_set_error(err, BT_IO_ERROR, EINVAL, @@ -1708,6 +1794,78 @@ gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data, return TRUE; } +gboolean bt_io_bcast_accept(GIOChannel *io, BtIOConnect connect, + gpointer user_data, GDestroyNotify destroy, + GError * *err, BtIOOption opt1, ...) +{ + int sock; + char c; + va_list args; + struct sockaddr_iso *addr = NULL; + uint8_t bc_num_bis = 0; + uint8_t bc_bis[ISO_MAX_NUM_BIS] = {0}; + BtIOOption opt = opt1; + + va_start(args, opt1); + + while (opt != BT_IO_OPT_INVALID) { + if (opt == BT_IO_OPT_ISO_BC_NUM_BIS) { + bc_num_bis = va_arg(args, int); + } else if (opt == BT_IO_OPT_ISO_BC_BIS) { + memcpy(bc_bis, va_arg(args, uint8_t *), + bc_num_bis); + } else { + g_set_error(err, BT_IO_ERROR, EINVAL, + "Invalid option %d", opt); + break; + } + + opt = va_arg(args, int); + } + + va_end(args); + + if (*err) + return FALSE; + + sock = g_io_channel_unix_get_fd(io); + + if (bc_num_bis) { + addr = malloc(sizeof(*addr) + sizeof(*addr->iso_bc)); + + if (!addr) { + ERROR_FAILED(err, "poll", ENOMEM); + return FALSE; + } + + memset(addr, 0, sizeof(*addr) + sizeof(*addr->iso_bc)); + addr->iso_family = AF_BLUETOOTH; + + addr->iso_bc->bc_num_bis = bc_num_bis; + memcpy(addr->iso_bc->bc_bis, bc_bis, + addr->iso_bc->bc_num_bis); + + if (bind(sock, (struct sockaddr *)addr, + sizeof(*addr) + sizeof(*addr->iso_bc)) < 0) { + ERROR_FAILED(err, "bind", errno); + } + + free(addr); + + if (*err) + return FALSE; + } + + if (read(sock, &c, 1) < 0) { + ERROR_FAILED(err, "read", errno); + return FALSE; + } + + server_add(io, connect, NULL, user_data, destroy); + + return TRUE; +} + gboolean bt_io_set(GIOChannel *io, GError **err, BtIOOption opt1, ...) { va_list args; @@ -1739,7 +1897,7 @@ gboolean bt_io_set(GIOChannel *io, GError **err, BtIOOption opt1, ...) case BT_IO_SCO: return sco_set(sock, opts.mtu, opts.voice, err); case BT_IO_ISO: - return iso_set(sock, &opts.qos, err); + return iso_set_qos(sock, &opts.qos, err); case BT_IO_INVALID: default: g_set_error(err, BT_IO_ERROR, EINVAL, @@ -1817,10 +1975,16 @@ static GIOChannel *create_io(gboolean server, struct set_opts *opts, ERROR_FAILED(err, "socket(SEQPACKET, ISO)", errno); return NULL; } - if (iso_bind(sock, &opts->src, opts->src_type, err) < 0) + + if (iso_bind(sock, server, &opts->src, opts->src_type, + &opts->dst, opts->dst_type, opts->bc_sid, + opts->bc_num_bis, opts->bc_bis, err) < 0) goto failed; - if (!iso_set(sock, &opts->qos, err)) + if (!iso_set_qos(sock, &opts->qos, err)) goto failed; + if (opts->base.base_len) + if (!iso_set_base(sock, &opts->base, err)) + goto failed; break; case BT_IO_INVALID: default: diff --git a/btio/btio.h b/btio/btio.h index 9636fd46709b852760b7d04469d53ab1197fb61d..3e69092b10e71a02ef2e45c1c138dca0124aa9ca 100644 --- a/btio/btio.h +++ b/btio/btio.h @@ -5,6 +5,7 @@ * * Copyright (C) 2009-2010 Marcel Holtmann <marcel@holtmann.org> * Copyright (C) 2009-2010 Nokia Corporation + * Copyright 2023 NXP * * */ @@ -45,6 +46,10 @@ typedef enum { BT_IO_OPT_VOICE, BT_IO_OPT_PHY, BT_IO_OPT_QOS, + BT_IO_OPT_BASE, + BT_IO_OPT_ISO_BC_SID, + BT_IO_OPT_ISO_BC_NUM_BIS, + BT_IO_OPT_ISO_BC_BIS, } BtIOOption; typedef enum { @@ -70,6 +75,10 @@ typedef void (*BtIOConnect)(GIOChannel *io, GError *err, gpointer user_data); gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data, GDestroyNotify destroy, GError **err); +gboolean bt_io_bcast_accept(GIOChannel *io, BtIOConnect connect, + gpointer user_data, GDestroyNotify destroy, + GError **err, BtIOOption opt1, ...); + gboolean bt_io_set(GIOChannel *io, GError **err, BtIOOption opt1, ...); gboolean bt_io_get(GIOChannel *io, GError **err, BtIOOption opt1, ...); diff --git a/client/adv_monitor.c b/client/adv_monitor.c index 792379fc40d4402b2fc8ae701fe2194967ea16d5..29e67096018bd7bdbf0b14bcafc89cdbd6382338 100644 --- a/client/adv_monitor.c +++ b/client/adv_monitor.c @@ -4,6 +4,7 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2020 Google LLC + * Copyright 2024 NXP * * */ @@ -372,12 +373,11 @@ static void register_reply(DBusMessage *message, void *user_data) if (!dbus_set_error_from_message(&error, message)) { bt_shell_printf("AdvertisementMonitor path registered\n"); - return bt_shell_noninteractive_quit(EXIT_SUCCESS); + return; } bt_shell_printf("Failed to register path: %s\n", error.name); dbus_error_free(&error); - return bt_shell_noninteractive_quit(EXIT_FAILURE); } static void unregister_setup(DBusMessageIter *iter, void *user_data) @@ -408,13 +408,13 @@ void adv_monitor_register_app(DBusConnection *conn) { if (manager.app_registered) { bt_shell_printf("Advertisement Monitor already registered\n"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); + return; } else if (manager.supported_types == NULL || !g_dbus_proxy_method_call(manager.proxy, "RegisterMonitor", register_setup, register_reply, NULL, NULL)) { bt_shell_printf("Failed to register Advertisement Monitor\n"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); + return; } manager.app_registered = TRUE; } diff --git a/client/advertising.c b/client/advertising.c index fb9b049fde78fb8ba0648c2b63142b8c3794fe3f..4a98121a4f93cc05a88479ef41e2ed96c8f85d59 100644 --- a/client/advertising.c +++ b/client/advertising.c @@ -28,7 +28,7 @@ #define AD_IFACE "org.bluez.LEAdvertisement1" struct ad_data { - uint8_t data[25]; + uint8_t data[245]; uint8_t len; }; @@ -43,6 +43,7 @@ struct manufacturer_data { }; struct data { + bool valid; uint8_t type; struct ad_data data; }; @@ -67,9 +68,11 @@ static struct ad { bool tx_power; bool name; bool appearance; + bool rsi; } ad = { .local_appearance = UINT16_MAX, .discoverable = true, + .rsi = true, }; static void ad_release(DBusConnection *conn) @@ -155,7 +158,7 @@ static void print_ad(void) ad.manufacturer.data.len); } - if (ad.data.data.len) { + if (ad.data.valid) { bt_shell_printf("Data Type: 0x%02x\n", ad.data.type); bt_shell_hexdump(ad.data.data.data, ad.data.data.len); } @@ -175,7 +178,8 @@ static void print_ad(void) bt_shell_printf("Appearance: %s\n", ad.appearance ? "on" : "off"); - bt_shell_printf("Discoverable: %s\n", ad.discoverable ? "on": "off"); + bt_shell_printf("Discoverable: %s\n", ad.discoverable ? "on" : "off"); + bt_shell_printf("RSI: %s\n", ad.rsi ? "on" : "off"); if (ad.duration) bt_shell_printf("Duration: %u sec\n", ad.duration); @@ -295,7 +299,7 @@ static gboolean get_manufacturer_data(const GDBusPropertyTable *property, static gboolean includes_exists(const GDBusPropertyTable *property, void *data) { - return ad.tx_power || ad.name || ad.appearance; + return ad.tx_power || ad.name || ad.appearance || ad.rsi; } static gboolean get_includes(const GDBusPropertyTable *property, @@ -323,6 +327,12 @@ static gboolean get_includes(const GDBusPropertyTable *property, dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &str); } + if (ad.rsi) { + const char *str = "rsi"; + + dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &str); + } + dbus_message_iter_close_container(iter, &array); @@ -386,7 +396,7 @@ static gboolean get_timeout(const GDBusPropertyTable *property, static gboolean data_exists(const GDBusPropertyTable *property, void *data) { - return ad.data.type != 0; + return ad.data.valid; } static gboolean get_data(const GDBusPropertyTable *property, @@ -406,12 +416,6 @@ static gboolean get_data(const GDBusPropertyTable *property, return TRUE; } -static gboolean discoverable_exists(const GDBusPropertyTable *property, - void *data) -{ - return ad.discoverable; -} - static gboolean get_discoverable(const GDBusPropertyTable *property, DBusMessageIter *iter, void *user_data) { @@ -488,7 +492,7 @@ static const GDBusPropertyTable ad_props[] = { { "ManufacturerData", "a{qv}", get_manufacturer_data, NULL, manufacturer_data_exists }, { "Data", "a{yv}", get_data, NULL, data_exists }, - { "Discoverable", "b", get_discoverable, NULL, discoverable_exists }, + { "Discoverable", "b", get_discoverable, NULL, NULL }, { "DiscoverableTimeout", "q", get_discoverable_timeout, NULL, discoverable_timeout_exists }, { "Includes", "as", get_includes, NULL, includes_exists }, @@ -748,7 +752,7 @@ void ad_disable_manufacturer(DBusConnection *conn) static void ad_clear_data(void) { - memset(&ad.manufacturer, 0, sizeof(ad.manufacturer)); + memset(&ad.data, 0, sizeof(ad.data)); return bt_shell_noninteractive_quit(EXIT_SUCCESS); } @@ -778,6 +782,7 @@ void ad_advertise_data(DBusConnection *conn, int argc, char *argv[]) return bt_shell_noninteractive_quit(EXIT_FAILURE); ad_clear_data(); + ad.data.valid = true; ad.data.type = val; ad.data.data = data; @@ -1023,3 +1028,20 @@ void ad_advertise_interval(DBusConnection *conn, uint32_t *min, uint32_t *max) return bt_shell_noninteractive_quit(EXIT_SUCCESS); } + +void ad_advertise_rsi(DBusConnection *conn, dbus_bool_t *value) +{ + if (!value) { + bt_shell_printf("RSI: %s\n", ad.rsi ? "on" : "off"); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + } + + if (ad.rsi == *value) + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + + ad.rsi = *value; + + g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Includes"); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} diff --git a/client/advertising.h b/client/advertising.h index 472396efd3810d10f3870ab64462ff31ad4266e3..145ac80452d253779df819aec636151d7a78a174 100644 --- a/client/advertising.h +++ b/client/advertising.h @@ -30,3 +30,4 @@ void ad_advertise_discoverable(DBusConnection *conn, dbus_bool_t *value); void ad_advertise_discoverable_timeout(DBusConnection *conn, long int *value); void ad_advertise_secondary(DBusConnection *conn, const char *value); void ad_advertise_interval(DBusConnection *conn, uint32_t *min, uint32_t *max); +void ad_advertise_rsi(DBusConnection *conn, dbus_bool_t *value); diff --git a/client/agent.c b/client/agent.c index c8e1560e74a863139a0020ddddd658a752da22aa..ff5e57ff27a5d29fc601f55f9d42b96ee71f0ba7 100644 --- a/client/agent.c +++ b/client/agent.c @@ -77,14 +77,17 @@ static void confirm_response(const char *input, void *user_data) { DBusConnection *conn = user_data; - if (!strcmp(input, "yes")) - g_dbus_send_reply(conn, pending_message, DBUS_TYPE_INVALID); - else if (!strcmp(input, "no")) - g_dbus_send_error(conn, pending_message, + if (pending_message != NULL) { + if (!strcmp(input, "yes")) + g_dbus_send_reply(conn, pending_message, + DBUS_TYPE_INVALID); + else if (!strcmp(input, "no")) + g_dbus_send_error(conn, pending_message, "org.bluez.Error.Rejected", NULL); - else - g_dbus_send_error(conn, pending_message, + else + g_dbus_send_error(conn, pending_message, "org.bluez.Error.Canceled", NULL); + } } static void agent_release(DBusConnection *conn) @@ -258,7 +261,7 @@ static DBusMessage *cancel_request(DBusConnection *conn, return dbus_message_new_method_return(msg); } -static const GDBusMethodTable methods[] = { +static const GDBusMethodTable agent_methods[] = { { GDBUS_METHOD("Release", NULL, NULL, release_agent) }, { GDBUS_ASYNC_METHOD("RequestPinCode", GDBUS_ARGS({ "device", "o" }), @@ -286,6 +289,78 @@ static const GDBusMethodTable methods[] = { { } }; +static DBusMessage *auto_confirmation(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + const char *device; + dbus_uint32_t passkey; + + bt_shell_printf("Request confirmation\n"); + + dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device, + DBUS_TYPE_UINT32, &passkey, DBUS_TYPE_INVALID); + + bt_shell_printf("Confirm passkey %06u (auto)", passkey); + + return dbus_message_new_method_return(msg); +} + +static DBusMessage *auto_authorization(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + const char *device; + + bt_shell_printf("Request authorization\n"); + + dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device, + DBUS_TYPE_INVALID); + + bt_shell_printf("Accept pairing (auto)"); + + return dbus_message_new_method_return(msg); +} + +static DBusMessage *auto_authorize_service(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + const char *device, *uuid; + + dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device, + DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID); + + bt_shell_printf("Authorize service %s (auto)", uuid); + + return dbus_message_new_method_return(msg); +} + +static const GDBusMethodTable auto_methods[] = { + { GDBUS_METHOD("Release", NULL, NULL, release_agent) }, + { GDBUS_ASYNC_METHOD("RequestPinCode", + GDBUS_ARGS({ "device", "o" }), + GDBUS_ARGS({ "pincode", "s" }), request_pincode) }, + { GDBUS_METHOD("DisplayPinCode", + GDBUS_ARGS({ "device", "o" }, { "pincode", "s" }), + NULL, display_pincode) }, + { GDBUS_ASYNC_METHOD("RequestPasskey", + GDBUS_ARGS({ "device", "o" }), + GDBUS_ARGS({ "passkey", "u" }), request_passkey) }, + { GDBUS_METHOD("DisplayPasskey", + GDBUS_ARGS({ "device", "o" }, { "passkey", "u" }, + { "entered", "q" }), + NULL, display_passkey) }, + { GDBUS_ASYNC_METHOD("RequestConfirmation", + GDBUS_ARGS({ "device", "o" }, { "passkey", "u" }), + NULL, auto_confirmation) }, + { GDBUS_ASYNC_METHOD("RequestAuthorization", + GDBUS_ARGS({ "device", "o" }), + NULL, auto_authorization) }, + { GDBUS_ASYNC_METHOD("AuthorizeService", + GDBUS_ARGS({ "device", "o" }, { "uuid", "s" }), + NULL, auto_authorize_service) }, + { GDBUS_METHOD("Cancel", NULL, NULL, cancel_request) }, + { } +}; + static void register_agent_setup(DBusMessageIter *iter, void *user_data) { const char *path = AGENT_PATH; @@ -319,6 +394,8 @@ void agent_register(DBusConnection *conn, GDBusProxy *manager, const char *capability) { + const GDBusMethodTable *methods = agent_methods; + if (agent_registered == TRUE) { bt_shell_printf("Agent is already registered\n"); return; @@ -326,6 +403,14 @@ void agent_register(DBusConnection *conn, GDBusProxy *manager, agent_capability = capability; + if (!strcasecmp(agent_capability, "auto")) { + bt_shell_printf("Warning: setting auto response is not secure, " + "it bypass user confirmation/authorization, it " + "shall only be used for test automation.\n"); + agent_capability = ""; + methods = auto_methods; + } + if (g_dbus_register_interface(conn, AGENT_PATH, AGENT_INTERFACE, methods, NULL, NULL, NULL, NULL) == FALSE) { diff --git a/client/assistant.c b/client/assistant.c new file mode 100644 index 0000000000000000000000000000000000000000..16e94664a5c3a45769d1b14f0dda497719ed30d7 --- /dev/null +++ b/client/assistant.c @@ -0,0 +1,415 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright 2024 NXP + * + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdbool.h> +#include <inttypes.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> + +#include <glib.h> + +#include "gdbus/gdbus.h" + +#include "lib/bluetooth.h" +#include "lib/uuid.h" + +#include "src/shared/util.h" +#include "src/shared/shell.h" +#include "src/shared/io.h" +#include "src/shared/queue.h" +#include "print.h" +#include "assistant.h" + +/* String display constants */ +#define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF +#define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF +#define COLORED_DEL COLOR_RED "DEL" COLOR_OFF + +#define MEDIA_ASSISTANT_INTERFACE "org.bluez.MediaAssistant1" + +#define BCODE_LEN 16 + +struct assistant_config { + GDBusProxy *proxy; /* DBus object reference */ + struct iovec *meta; /* Stream metadata LTVs */ + struct bt_iso_qos qos; /* Stream QoS parameters */ +}; + +static DBusConnection *dbus_conn; + +static GList *assistants; + +static char *proxy_description(GDBusProxy *proxy, const char *title, + const char *description) +{ + const char *path; + + path = g_dbus_proxy_get_path(proxy); + + return g_strdup_printf("%s%s%s%s %s ", + description ? "[" : "", + description ? : "", + description ? "] " : "", + title, path); +} + +static void print_assistant(GDBusProxy *proxy, const char *description) +{ + char *str; + + str = proxy_description(proxy, "Assistant", description); + + bt_shell_printf("%s\n", str); + + g_free(str); +} + +static void assistant_added(GDBusProxy *proxy) +{ + assistants = g_list_append(assistants, proxy); + + print_assistant(proxy, COLORED_NEW); +} + +static void proxy_added(GDBusProxy *proxy, void *user_data) +{ + const char *interface; + + interface = g_dbus_proxy_get_interface(proxy); + + if (!strcmp(interface, MEDIA_ASSISTANT_INTERFACE)) + assistant_added(proxy); +} + +static void assistant_removed(GDBusProxy *proxy) +{ + assistants = g_list_remove(assistants, proxy); + + print_assistant(proxy, COLORED_DEL); +} + +static void proxy_removed(GDBusProxy *proxy, void *user_data) +{ + const char *interface; + + interface = g_dbus_proxy_get_interface(proxy); + + if (!strcmp(interface, MEDIA_ASSISTANT_INTERFACE)) + assistant_removed(proxy); +} + +static void assistant_property_changed(GDBusProxy *proxy, const char *name, + DBusMessageIter *iter) +{ + char *str; + + str = proxy_description(proxy, "Assistant", COLORED_CHG); + print_iter(str, name, iter); + g_free(str); +} + +static void property_changed(GDBusProxy *proxy, const char *name, + DBusMessageIter *iter, void *user_data) +{ + const char *interface; + + interface = g_dbus_proxy_get_interface(proxy); + + if (!strcmp(interface, MEDIA_ASSISTANT_INTERFACE)) + assistant_property_changed(proxy, name, iter); +} + +static void assistant_unregister(void *data) +{ + GDBusProxy *proxy = data; + + bt_shell_printf("Assistant %s unregistered\n", + g_dbus_proxy_get_path(proxy)); +} + +static void disconnect_handler(DBusConnection *connection, void *user_data) +{ + g_list_free_full(assistants, assistant_unregister); + assistants = NULL; +} + +static uint8_t *str2bytearray(char *arg, size_t *val_len) +{ + uint8_t value[UINT8_MAX]; + char *entry; + unsigned int i; + + for (i = 0; (entry = strsep(&arg, " \t")) != NULL; i++) { + long val; + char *endptr = NULL; + + if (*entry == '\0') + continue; + + if (i >= G_N_ELEMENTS(value)) { + bt_shell_printf("Too much data\n"); + return NULL; + } + + val = strtol(entry, &endptr, 0); + if (!endptr || *endptr != '\0' || val > UINT8_MAX) { + bt_shell_printf("Invalid value at index %d\n", i); + return NULL; + } + + value[i] = val; + } + + *val_len = i; + + return util_memdup(value, i); +} + +static void append_qos(DBusMessageIter *iter, struct assistant_config *cfg) +{ + DBusMessageIter entry, var, dict; + const char *key = "QoS"; + const char *bcode_key = "BCode"; + uint8_t *bcode = cfg->qos.bcast.bcode; + + dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, + NULL, &entry); + + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); + + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, + "a{sv}", &var); + + dbus_message_iter_open_container(&var, DBUS_TYPE_ARRAY, "{sv}", + &dict); + + g_dbus_dict_append_basic_array(&dict, DBUS_TYPE_STRING, + &bcode_key, DBUS_TYPE_BYTE, + &bcode, BCODE_LEN); + + dbus_message_iter_close_container(&var, &dict); + dbus_message_iter_close_container(&entry, &var); + dbus_message_iter_close_container(iter, &entry); +} + +static void push_setup(DBusMessageIter *iter, void *user_data) +{ + struct assistant_config *cfg = user_data; + DBusMessageIter dict; + const char *meta = "Metadata"; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &dict); + + if (cfg->meta) + g_dbus_dict_append_basic_array(&dict, DBUS_TYPE_STRING, &meta, + DBUS_TYPE_BYTE, &cfg->meta->iov_base, + cfg->meta->iov_len); + + if (cfg->qos.bcast.encryption) + append_qos(&dict, cfg); + + dbus_message_iter_close_container(iter, &dict); +} + +static void push_reply(DBusMessage *message, void *user_data) +{ + struct assistant_config *cfg = user_data; + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message)) { + bt_shell_printf("Failed to push assistant: %s\n", + error.name); + + dbus_error_free(&error); + + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + bt_shell_printf("Assistant %s pushed\n", + g_dbus_proxy_get_path(cfg->proxy)); + + free(cfg->meta); + g_free(cfg); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void assistant_set_bcode_cfg(const char *input, void *user_data) +{ + struct assistant_config *cfg = user_data; + + if (!strcasecmp(input, "a") || !strcasecmp(input, "auto")) { + memset(cfg->qos.bcast.bcode, 0, BCODE_LEN); + } else { + if (strlen(input) > BCODE_LEN) { + bt_shell_printf("Input string too long %s\n", input); + goto fail; + } + + memcpy(cfg->qos.bcast.bcode, input, strlen(input)); + } + + if (!g_dbus_proxy_method_call(cfg->proxy, "Push", + push_setup, push_reply, + cfg, NULL)) { + bt_shell_printf("Failed to push assistant\n"); + goto fail; + } + + return; + +fail: + free(cfg->meta); + g_free(cfg); + + return bt_shell_noninteractive_quit(EXIT_FAILURE); +} + +static void assistant_set_metadata_cfg(const char *input, void *user_data) +{ + struct assistant_config *cfg = user_data; + DBusMessageIter iter, dict, entry, value; + const char *key; + + if (!strcasecmp(input, "a") || !strcasecmp(input, "auto")) + goto done; + + if (!cfg->meta) + cfg->meta = g_new0(struct iovec, 1); + + cfg->meta->iov_base = str2bytearray((char *) input, + &cfg->meta->iov_len); + if (!cfg->meta->iov_base) { + free(cfg->meta); + cfg->meta = NULL; + } + +done: + /* Get QoS property to check if the stream is encrypted */ + if (!g_dbus_proxy_get_property(cfg->proxy, "QoS", &iter)) + goto fail; + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) + goto fail; + + dbus_message_iter_recurse(&iter, &dict); + + if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY) + goto fail; + + dbus_message_iter_recurse(&dict, &entry); + dbus_message_iter_get_basic(&entry, &key); + + if (strcasecmp(key, "Encryption") != 0) + goto fail; + + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &value); + + if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_BYTE) + goto fail; + + dbus_message_iter_get_basic(&value, &cfg->qos.bcast.encryption); + + if (cfg->qos.bcast.encryption) + /* Prompt user to enter the Broadcast Code to decrypt + * the stream + */ + bt_shell_prompt_input("Assistant", + "Enter Broadcast Code (auto/value):", + assistant_set_bcode_cfg, cfg); + else + if (!g_dbus_proxy_method_call(cfg->proxy, "Push", + push_setup, push_reply, + cfg, NULL)) { + bt_shell_printf("Failed to push assistant\n"); + goto fail; + } + + return; + +fail: + free(cfg->meta); + g_free(cfg); + + return bt_shell_noninteractive_quit(EXIT_FAILURE); +} + +static void cmd_push_assistant(int argc, char *argv[]) +{ + struct assistant_config *cfg; + + cfg = new0(struct assistant_config, 1); + if (!cfg) + goto fail; + + /* Search for DBus object */ + cfg->proxy = g_dbus_proxy_lookup(assistants, NULL, argv[1], + MEDIA_ASSISTANT_INTERFACE); + if (!cfg->proxy) { + bt_shell_printf("Assistant %s not found\n", argv[1]); + goto fail; + } + + /* Prompt user to enter metadata */ + bt_shell_prompt_input("Assistant", + "Enter Metadata (auto/value):", + assistant_set_metadata_cfg, cfg); + + return; + +fail: + g_free(cfg); + return bt_shell_noninteractive_quit(EXIT_FAILURE); +} + +static const struct bt_shell_menu assistant_menu = { + .name = "assistant", + .desc = "Media Assistant Submenu", + .entries = { + { "push", "<assistant>", cmd_push_assistant, + "Send stream information to peer" }, + {} }, +}; + +static GDBusClient * client; + +void assistant_add_submenu(void) +{ + bt_shell_add_submenu(&assistant_menu); + + dbus_conn = bt_shell_get_env("DBUS_CONNECTION"); + if (!dbus_conn || client) + return; + + client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez"); + + g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed, + property_changed, NULL); + g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL); +} + +void assistant_remove_submenu(void) +{ + g_dbus_client_unref(client); + client = NULL; +} + diff --git a/client/assistant.h b/client/assistant.h new file mode 100644 index 0000000000000000000000000000000000000000..418b0b84031fc700b55c8cabe848301c4e1e7f37 --- /dev/null +++ b/client/assistant.h @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright 2024 NXP + * + * + */ + +void assistant_add_submenu(void); +void assistant_remove_submenu(void); + diff --git a/client/bluetoothctl-admin.1 b/client/bluetoothctl-admin.1 new file mode 100644 index 0000000000000000000000000000000000000000..308c3a968b3e85387774c772dfeec644b5d73d01 --- /dev/null +++ b/client/bluetoothctl-admin.1 @@ -0,0 +1,61 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BLUETOOTHCTL-ADMIN" "1" "November 2022" "BlueZ" "Linux System Administration" +.SH NAME +bluetoothctl-admin \- Admin Policy Submenu +.SH SYNOPSIS +.sp +\fBbluetoothctl\fP [\-\-options] [admin.commands] +.SH ADMIN POLICY COMMANDS +.SS allow +.sp +Allow service UUIDs and block rest of them. +.INDENT 0.0 +.TP +.B Usage +\fB# allow [clear/uuid1 uuid2 ...]\fP +.TP +.B Example +\fB# allow 0x1101 0x1102 0x1103\fP +.TP +.B Example +\fB# allow clear\fP +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/client/bluetoothctl-admin.rst b/client/bluetoothctl-admin.rst new file mode 100644 index 0000000000000000000000000000000000000000..774af0530e45324c34a7e099aecdb81a1b99e929 --- /dev/null +++ b/client/bluetoothctl-admin.rst @@ -0,0 +1,41 @@ +================== +bluetoothctl-admin +================== + +-------------------- +Admin Policy Submenu +-------------------- + +:Version: BlueZ +:Copyright: Free use of this software is granted under ther terms of the GNU + Lesser General Public Licenses (LGPL). +:Date: November 2022 +:Manual section: 1 +:Manual group: Linux System Administration + +SYNOPSIS +======== + +**bluetoothctl** [--options] [admin.commands] + +Admin Policy Commands +===================== + +allow +----- + +Allow service UUIDs and block rest of them. + +:Usage: **# allow [clear/uuid1 uuid2 ...]** +:Example: **# allow 0x1101 0x1102 0x1103** +:Example: **# allow clear** + +RESOURCES +========= + +http://www.bluez.org + +REPORTING BUGS +============== + +linux-bluetooth@vger.kernel.org diff --git a/client/bluetoothctl-advertise.1 b/client/bluetoothctl-advertise.1 new file mode 100644 index 0000000000000000000000000000000000000000..b4926962b053c8c9ee0c746766f6cbec2cd5f412 --- /dev/null +++ b/client/bluetoothctl-advertise.1 @@ -0,0 +1,278 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BLUETOOTHCTL-ADVERTISE" "1" "November 2022" "BlueZ" "Linux System Administration" +.SH NAME +bluetoothctl-advertise \- Advertise Submenu +.SH SYNOPSIS +.sp +\fBbluetoothctl\fP [\-\-options] [advertise.commands] +.SH ADVERTISE OPTIONS COMMANDS +.SS uuids +.sp +Set/Get advertise uuids. +.INDENT 0.0 +.TP +.B Usage +\fB# uuids [all/uuid1 uuid2 ...]\fP +.TP +.B Example +\fB# uuids 0x1234\fP +.TP +.B Example +\fB# uuids 0x12345678\fP +.TP +.B Example +\fB# uuids 90f95193\-35de\-4306\-a6e9\-699328f15059\fP +.UNINDENT +.SS service +.sp +Set/Get advertise service data. +.INDENT 0.0 +.TP +.B Usage +\fB# service [uuid] [data=xx xx ...]\fP +.UNINDENT +.SS manufacturer +.sp +Set/Get advertise manufacturer data. +.sp +Updating is in real time while advertising. This is currently limited to 25 +bytes and will return an error message of \(dqToo much data\(dq if that maximum has +been exceeded. However, this does not check if the advertising payload length +maximum has been exceeded so you may receive an error from bluetoothd that it +\(dqFailed to register advertisement\(dq which means you need to reduce your +manufacturer data length. +.INDENT 0.0 +.TP +.B Usage +\fB# manufacturer [id] [data=xx xx ...]\fP +.UNINDENT +.SS data +.sp +Set/Get advertise data. +.sp +This allows you to advertise data with a given type. You cannot use a registered +data type value {1} with this command. For LE the advertising shows up in the +primary advertisements. +.sp +If you set only the type of the data without any data (data 0x0c) this will +cause a parse error when turning advertise on. +.sp +You can modify the advertising data while it is advertising. +.sp +To get the currently set data use the command data without any arguments. +.INDENT 0.0 +.TP +.B Usage +\fB# data [type] [data=xx xx ...]\fP +.TP +.B Example +\fB# data 0x0C 01 0x0F 13\fP +.UNINDENT +.SS discoverable +.sp +Set/Get advertise discoverable. +.sp +For LE discoverable on will set the LE General Discoverable Mode flag to true in +the primary advertisement if on. +.sp +This feature can be changed during advertising, but will only trigger LE General +Discoverable Mode even if you had previously selected discoverable\-timeout this +will be ignored. +.sp +Entering the command by itself will show the status of the setting +.INDENT 0.0 +.TP +.B Usage +\fB# discoverable [on/off]\fP +.UNINDENT +.SS discoverable\-timeout +.sp +Set/Get advertise discoverable timeout. +.sp +Using this feature in LE will cause the LE Limited Discoverable Mode flag to be +set in the primary advertisement and The LE General Discoverable Mode flag +will not be set. +.sp +The LE Limited Discoverable Mode flag will automatically turn off after [seconds] +discoverable [on] must be set to use this feature. +.sp +Entering the command by itself will show the current value set. +.INDENT 0.0 +.TP +.B Usage +\fB# discoverable\-timeout [seconds]\fP +.UNINDENT +.SS tx\-power +.sp +Show/Enable/Disable TX power to be advertised. +.sp +This sets the TX Power Level field in the advertising packet. +.sp +The value is in dBm and can be between \-127 and 127. +.sp +When this feature is turned on the LE device will advertise its transmit power +in the primary advertisement. +.sp +This feature can be modified while advertising. +.sp +Entering the command by itself will show the current value set. +.INDENT 0.0 +.TP +.B Usage +\fB# tx\-power [on/off] [power]\fP +.UNINDENT +.SS name +.sp +Configure local name to be advertised. +.sp +Local name to be used in the advertising report. +.sp +If the string is too big to fit into the packet it will be truncated. +.sp +It will either advertise as a complete local name or if it has to be truncated +then a shortened local name. +.INDENT 0.0 +.TP +.B Usage +\fB# name [on/off/name]\fP +.TP +.B Example +\fB# name \(dq0123456789abcdef0123456789abcdef\(dq\fP +.UNINDENT +.SS appearance +.sp +Configure custom appearance to be advertised. +.INDENT 0.0 +.TP +.B Usage +\fB# appearance [on/off/value]\fP +.UNINDENT +.SS duration +.sp +Set/Get advertise duration. +.sp +The Duration parameter configures the length of an Instance. +.sp +The value is in seconds. +.sp +A value of 0 indicates a default value is chosen for the Duration. +.sp +The default is 2 seconds. +.sp +If only one advertising Instance has been added, then the Duration value will be +ignored. +.sp +If multiple advertising Instances have been added, then the Duration value will +be used to determine the length of time each Instance is advertised for. +.sp +The Duration value is used to calculate the number of advertising events that +will be used to advertise each Instance. +.sp +The number of advertising events is calculated by dividing the Duration value by +the advertising interval. +.sp +The advertising interval is determined by the advertising parameters that are +set for each Instance. The advertising interval is the maximum of the +advertising intervals set for each Instance. +.INDENT 0.0 +.TP +.B Usage +\fB# duration [seconds]\fP +.UNINDENT +.SS timeout +.sp +Set/Get advertise timeout. +.INDENT 0.0 +.TP +.B Usage +\fB# timeout [seconds]\fP +.UNINDENT +.SS secondary +.sp +Set/Get advertise secondary channel. +.INDENT 0.0 +.TP +.B Usage +\fB# secondary [1M/2M/Coded]\fP +.UNINDENT +.SS interval +.sp +Set/Get advertise interval. +.sp +The Interval parameter configures the advertising interval of an Instance. +.sp +The value is in milliseconds. +.sp +A value of 0 indicates a default value is chosen for the Interval. +.sp +The default is 100 milliseconds. +.sp +The Interval value is used to calculate the number of advertising events that +will be used to advertise each Instance. +.sp +The number of advertising events is calculated by dividing the Duration value by +the advertising interval. +.sp +The advertising interval is determined by the advertising parameters that are +set for each Instance. +.sp +The advertising interval is the maximum of the advertising intervals set for +each Instance. +.INDENT 0.0 +.TP +.B Usage +\fB# interval [milliseconds]\fP +.UNINDENT +.SS clear +.sp +Clear advertise config. +.sp +This will stop advertising if it is currently advertising. +.sp +If you want to change the advertise configuration while advertising you must +first clear the advertise configuration and then set the new advertise +configuration. +.INDENT 0.0 +.TP +.B Usage +\fB# clear [uuids/service/manufacturer/config\-name...]\fP +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/client/bluetoothctl-advertise.rst b/client/bluetoothctl-advertise.rst new file mode 100644 index 0000000000000000000000000000000000000000..4b56324813ba85bcd35557903fc595c67eab7b5a --- /dev/null +++ b/client/bluetoothctl-advertise.rst @@ -0,0 +1,239 @@ +====================== +bluetoothctl-advertise +====================== + +----------------- +Advertise Submenu +----------------- + +:Version: BlueZ +:Copyright: Free use of this software is granted under ther terms of the GNU + Lesser General Public Licenses (LGPL). +:Date: November 2022 +:Manual section: 1 +:Manual group: Linux System Administration + +SYNOPSIS +======== + +**bluetoothctl** [--options] [advertise.commands] + +Advertise Options Commands +========================== + +uuids +----- + +Set/Get advertise uuids. + +:Usage: **# uuids [all/uuid1 uuid2 ...]** +:Example: **# uuids 0x1234** +:Example: **# uuids 0x12345678** +:Example: **# uuids 90f95193-35de-4306-a6e9-699328f15059** + +service +------- + +Set/Get advertise service data. + +:Usage: **# service [uuid] [data=xx xx ...]** + +manufacturer +------------ + +Set/Get advertise manufacturer data. + +Updating is in real time while advertising. This is currently limited to 25 +bytes and will return an error message of "Too much data" if that maximum has +been exceeded. However, this does not check if the advertising payload length +maximum has been exceeded so you may receive an error from bluetoothd that it +"Failed to register advertisement" which means you need to reduce your +manufacturer data length. + +:Usage: **# manufacturer [id] [data=xx xx ...]** + +data +---- + +Set/Get advertise data. + +This allows you to advertise data with a given type. You cannot use a registered +data type value {1} with this command. For LE the advertising shows up in the +primary advertisements. + +If you set only the type of the data without any data (data 0x0c) this will +cause a parse error when turning advertise on. + +You can modify the advertising data while it is advertising. + +To get the currently set data use the command data without any arguments. + +:Usage: **# data [type] [data=xx xx ...]** +:Example: **# data 0x0C 01 0x0F 13** + +discoverable +------------ + +Set/Get advertise discoverable. + +For LE discoverable on will set the LE General Discoverable Mode flag to true in +the primary advertisement if on. + +This feature can be changed during advertising, but will only trigger LE General +Discoverable Mode even if you had previously selected discoverable-timeout this +will be ignored. + +Entering the command by itself will show the status of the setting + +:Usage: **# discoverable [on/off]** + +discoverable-timeout +-------------------- + +Set/Get advertise discoverable timeout. + +Using this feature in LE will cause the LE Limited Discoverable Mode flag to be +set in the primary advertisement and The LE General Discoverable Mode flag +will not be set. + +The LE Limited Discoverable Mode flag will automatically turn off after [seconds] +discoverable [on] must be set to use this feature. + +Entering the command by itself will show the current value set. + +:Usage: **# discoverable-timeout [seconds]** + +tx-power +-------- + +Show/Enable/Disable TX power to be advertised. + +This sets the TX Power Level field in the advertising packet. + +The value is in dBm and can be between -127 and 127. + +When this feature is turned on the LE device will advertise its transmit power +in the primary advertisement. + +This feature can be modified while advertising. + +Entering the command by itself will show the current value set. + +:Usage: **# tx-power [on/off] [power]** + +name +---- + +Configure local name to be advertised. + +Local name to be used in the advertising report. + +If the string is too big to fit into the packet it will be truncated. + +It will either advertise as a complete local name or if it has to be truncated +then a shortened local name. + +:Usage: **# name [on/off/name]** +:Example: **# name "0123456789abcdef0123456789abcdef"** + +appearance +---------- + +Configure custom appearance to be advertised. + +:Usage: **# appearance [on/off/value]** + +duration +-------- + +Set/Get advertise duration. + +The Duration parameter configures the length of an Instance. + +The value is in seconds. + +A value of 0 indicates a default value is chosen for the Duration. + +The default is 2 seconds. + +If only one advertising Instance has been added, then the Duration value will be +ignored. + +If multiple advertising Instances have been added, then the Duration value will +be used to determine the length of time each Instance is advertised for. + +The Duration value is used to calculate the number of advertising events that +will be used to advertise each Instance. + +The number of advertising events is calculated by dividing the Duration value by +the advertising interval. + +The advertising interval is determined by the advertising parameters that are +set for each Instance. The advertising interval is the maximum of the +advertising intervals set for each Instance. + +:Usage: **# duration [seconds]** + +timeout +------- + +Set/Get advertise timeout. + +:Usage: **# timeout [seconds]** + +secondary +--------- + +Set/Get advertise secondary channel. + +:Usage: **# secondary [1M/2M/Coded]** + +interval +-------- + +Set/Get advertise interval. + +The Interval parameter configures the advertising interval of an Instance. + +The value is in milliseconds. + +A value of 0 indicates a default value is chosen for the Interval. + +The default is 100 milliseconds. + +The Interval value is used to calculate the number of advertising events that +will be used to advertise each Instance. + +The number of advertising events is calculated by dividing the Duration value by +the advertising interval. + +The advertising interval is determined by the advertising parameters that are +set for each Instance. + +The advertising interval is the maximum of the advertising intervals set for +each Instance. + +:Usage: **# interval [milliseconds]** + +clear +----- + +Clear advertise config. + +This will stop advertising if it is currently advertising. + +If you want to change the advertise configuration while advertising you must +first clear the advertise configuration and then set the new advertise +configuration. + +:Usage: **# clear [uuids/service/manufacturer/config-name...]** + +RESOURCES +========= + +http://www.bluez.org + +REPORTING BUGS +============== + +linux-bluetooth@vger.kernel.org diff --git a/client/bluetoothctl-assistant.1 b/client/bluetoothctl-assistant.1 new file mode 100644 index 0000000000000000000000000000000000000000..894a185d3532d56a10ad06bdf703599f0dd2b7b7 --- /dev/null +++ b/client/bluetoothctl-assistant.1 @@ -0,0 +1,88 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BLUETOOTHCTL-ASSISTANT" "1" "August 2024" "BlueZ" "Linux System Administration" +.SH NAME +bluetoothctl-assistant \- Assistant Submenu +.SH SYNOPSIS +.sp +\fBbluetoothctl\fP [\-\-options] [assistant.commands] +.SH ASSISTANT COMMANDS +.SS push +.sp +Send stream information to peer. +.sp +This command is used by a BAP Broadcast Assistant to send +information about a broadcast stream to a peer BAP Scan +Delegator. +.sp +The information is sent via a GATT Write Command for the +BASS Broadcast Audio Scan Control Point characteristic. +.sp +After issuing the command, the user is prompted to enter +stream metadata LTVs to send to the peer. If the auto +option is chosen, the Broadcast Assistant will send the +default metadata discovered about the stream. Otherwise, +the default metadata will be overwritten by the LTVs +entered by the user. +.sp +If the stream is encrypted, the user will also be prompted +to enter the Broadcast Code. This is the key to decrypt the +stream. On the UI level, the Broadcast Code shall be represented +as a string of at least 4 octets, and no more than 16 octets +when represented in UTF\-8. The string will be sent to the peer +via GATT as an array of 16 octets. +.sp +If the auto value is chosen when prompted for the Broadcast +Code, a zero filled array will be sent to the peer. Otherwise, +the string entered by the user will be sent as an array of bytes. +.INDENT 0.0 +.TP +.B Usage +\fB# push <assistant>\fP +.TP +.B Example +.nf +\fB# push /org/bluez/hci0/src_05_1F_EE_F3_F8_7D/dev_00_60_37_31_7E_3F/bis1\fP +\fB[Assistant] Enter Metadata (auto/value): 0x03 0x02 0x04 0x00\fP +\fB[Assistant] Enter Broadcast Code (auto/value): Borne House\fP +.fi +.sp +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/client/bluetoothctl-assistant.rst b/client/bluetoothctl-assistant.rst new file mode 100644 index 0000000000000000000000000000000000000000..fb8c3a0d803f8127e798fdd8a36efa7ad095252e --- /dev/null +++ b/client/bluetoothctl-assistant.rst @@ -0,0 +1,67 @@ +====================== +bluetoothctl-assistant +====================== + +----------------- +Assistant Submenu +----------------- + +:Version: BlueZ +:Copyright: Free use of this software is granted under ther terms of the GNU + Lesser General Public Licenses (LGPL). +:Date: August 2024 +:Manual section: 1 +:Manual group: Linux System Administration + +SYNOPSIS +======== + +**bluetoothctl** [--options] [assistant.commands] + +Assistant Commands +================== + +push +---- + +Send stream information to peer. + +This command is used by a BAP Broadcast Assistant to send +information about a broadcast stream to a peer BAP Scan +Delegator. + +The information is sent via a GATT Write Command for the +BASS Broadcast Audio Scan Control Point characteristic. + +After issuing the command, the user is prompted to enter +stream metadata LTVs to send to the peer. If the auto +option is chosen, the Broadcast Assistant will send the +default metadata discovered about the stream. Otherwise, +the default metadata will be overwritten by the LTVs +entered by the user. + +If the stream is encrypted, the user will also be prompted +to enter the Broadcast Code. This is the key to decrypt the +stream. On the UI level, the Broadcast Code shall be represented +as a string of at least 4 octets, and no more than 16 octets +when represented in UTF-8. The string will be sent to the peer +via GATT as an array of 16 octets. + +If the auto value is chosen when prompted for the Broadcast +Code, a zero filled array will be sent to the peer. Otherwise, +the string entered by the user will be sent as an array of bytes. + +:Usage: **# push <assistant>** +:Example: | **# push /org/bluez/hci0/src_05_1F_EE_F3_F8_7D/dev_00_60_37_31_7E_3F/bis1** + | **[Assistant] Enter Metadata (auto/value): 0x03 0x02 0x04 0x00** + | **[Assistant] Enter Broadcast Code (auto/value): Borne House** + +RESOURCES +========= + +http://www.bluez.org + +REPORTING BUGS +============== + +linux-bluetooth@vger.kernel.org diff --git a/client/bluetoothctl-endpoint.1 b/client/bluetoothctl-endpoint.1 new file mode 100644 index 0000000000000000000000000000000000000000..fd386288c247abf1e49427fefcba71fb05506639 --- /dev/null +++ b/client/bluetoothctl-endpoint.1 @@ -0,0 +1,224 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BLUETOOTHCTL-ENDPOINT" "1" "November 2022" "BlueZ" "Linux System Administration" +.SH NAME +bluetoothctl-endpoint \- Endpoint Submenu +.SH SYNOPSIS +.sp +\fBbluetoothctl\fP [\-\-options] [endpoint.commands] +.SH ENDPOINT COMMANDS +.SS list +.sp +List available endpoints. +.INDENT 0.0 +.TP +.B Usage +\fB# list [local]\fP +.UNINDENT +.SS show +.sp +Endpoint information. +.INDENT 0.0 +.TP +.B Usage +\fB# show [endpoint]\fP +.UNINDENT +.SS register +.sp +Register Endpoint. +.INDENT 0.0 +.TP +.B Usage +\fB# register <UUID> <codec[:company]> [capabilities...]\fP +.TP +.B Example LC3 BAP source +.nf +\fB#endpoint.register 00002bcb\-0000\-1000\-8000\-00805f9b34fb 0x06\fP +\fB#Auto Accept (yes/no):\fP y +\fB#Max Transports (auto/value):\fP a +\fB#Locations:\fP a +\fB#Supported Context (value):\fP 3 +\fB#Context (value):\fP 3 +\fB#CIG (auto/value):\fP a +\fB#CIS (auto/value):\fP a +.fi +.sp +.TP +.B Example LC3 BAP sink with extra capabilities +.nf +\fB#endpoint.register 00002bc9\-0000\-1000\-8000\-00805f9b34fb 0x06 \(dq0x03 0xe5 0x03 0x00 0x02 0xe6 0x07\(dq\fP +\fB#Enter Metadata (value/no):\fP n +\fB#Auto Accept (yes/no):\fP y +\fB#Max Transports (auto/value):\fP a +\fB#Locations:\fP a +\fB#Supported Context (value):\fP 3 +\fB#Context (value):\fP 3 +\fB#CIG (auto/value):\fP a +\fB#CIS (auto/value):\fP a +.fi +.sp +.TP +.B Example LC3 BAP Broadcast source +.nf +\fB#endpoint.register 00001852\-0000\-1000\-8000\-00805f9b34fb 0x06\fP +\fB#Auto Accept (yes/no):\fP y +\fB#Max Transports (auto/value):\fP a +\fB#Locations:\fP 3 +\fB#Supported Context (value):\fP 1 +.fi +.sp +.TP +.B Example LC3 BAP Broadcast sink +.nf +\fB#endpoint.register 00001851\-0000\-1000\-8000\-00805f9b34fb 0x06\fP +\fB#Auto Accept (yes/no):\fP y +\fB#Max Transports (auto/value):\fP a +\fB#Locations:\fP 3 +\fB#Supported Context (value):\fP 1 +.fi +.sp +.UNINDENT +.sp +Note: +.sp +If running the setup with an audio server that has LE Audio support (such as PipeWire) it will +automatically register endpoints according to the configured roles. For more details +about configuring a Broadcast Source with PipeWire check: + <https://gitlab.freedesktop.org/pipewire/pipewire/\-/blob/master/doc/dox/config/pipewire\-props.7.md> +.SS unregister +.sp +Unregister Endpoint. +.INDENT 0.0 +.TP +.B Usage +\fB# unregister <UUID/object>\fP +.UNINDENT +.sp +Note: +.sp +If the endpoint was registered by an audio server, it can\(aqt be unregistered from bluetoothctl. +This must be done by the audio server as well. +.SS config +.sp +Configure Endpoint. +.INDENT 0.0 +.TP +.B Usage +\fB# config <endpoint> <local endpoint> [preset]\fP +.UNINDENT +.sp +Note: +.sp +If the endpoint was registered by an audio server, it can\(aqt be configured from bluetoothctl. +This must be done by the audio server as well. +.SS presets +.sp +List available presets. +.INDENT 0.0 +.TP +.B Usage +\fB# presets <endpoint>/<UUID> [codec[:company]] [preset] [codec config] [metadata]\fP +.TP +.B Example using endpoint +.nf +\fB#presets /local/endpoint/ep0 32_1_1\fP +\fB#presets /local/endpoint/ep0\fP +Preset 32_1_1 +Configuration.#0: len 0x02 type 0x01 +Configuration.Sampling Frequency: 32 Khz (0x06) +Configuration.#1: len 0x02 type 0x02 +Configuration.Frame Duration: 7.5 ms (0x00) +Configuration.#2: len 0x03 type 0x04 +Configuration.Frame Length: 60 (0x003c) +.fi +.sp +.TP +.B Example using UUID +.nf +\fB#presets 00002bc9\-0000\-1000\-8000\-00805f9b34fb 0x06 32_1_1\fP +\fB#presets 00002bc9\-0000\-1000\-8000\-00805f9b34fb 0x06\fP +\&... +\fB*32_1_1\fP +.fi +.sp +.TP +.B Example setting up LC3 custom preset +.nf +\fB#presets 00002bc9\-0000\-1000\-8000\-00805f9b34fb 0x06 custom\fP +\fB#[Codec] Enter frequency (Khz):\fP 48 +\fB#[Codec] Enter frame duration (ms):\fP 10 +\fB#[Codec] Enter channel allocation:\fP 3 +\fB#[Codec] Enter frame length:\fP 100 +\fB#[QoS] Enter Target Latency (Low, Balance, High):\fP Low +\fB#[QoS] Enter SDU Interval (us):\fP 1000 +\fB#[QoS] Enter Framing (Unframed, Framed):\fP Unframed +\fB#[QoS] Enter PHY (1M, 2M):\fP 2M +\fB#[QoS] Enter Max SDU:\fP 200 +\fB#[QoS] Enter RTN:\fP 3 +\fB#[QoS] Enter Max Transport Latency (ms):\fP 10 +\fB#[QoS] Enter Presentation Delay (us):\fP 20000 +\fB#presets 00002bc9\-0000\-1000\-8000\-00805f9b34fb 0x06\fP +\&... +\fB*custom\fP +.fi +.sp +.TP +.B Example setting up LC3 custom preset with extra configuration +.nf +\fB#presets 00002bc9\-0000\-1000\-8000\-00805f9b34fb 0x06 custom \(dq0x03 0xe8 0x00 0x00 0x02 0xe9 0x00\(dq\fP +\fB#[Codec] Enter frequency (Khz):\fP 48 +\fB#[Codec] Enter frame duration (ms):\fP 10 +\fB#[Codec] Enter channel allocation:\fP 3 +\fB#[Codec] Enter frame length:\fP 100 +\fB#[QoS] Enter Target Latency (Low, Balance, High):\fP Low +\fB#[QoS] Enter SDU Interval (us):\fP 1000 +\fB#[QoS] Enter Framing (Unframed, Framed):\fP Unframed +\fB#[QoS] Enter PHY (1M, 2M):\fP 2M +\fB#[QoS] Enter Max SDU:\fP 200 +\fB#[QoS] Enter RTN:\fP 3 +\fB#[QoS] Enter Max Transport Latency (ms):\fP 10 +\fB#[QoS] Enter Presentation Delay (us):\fP 20000 +\fB#presets 00002bc9\-0000\-1000\-8000\-00805f9b34fb 0x06\fP +\&... +\fB*custom\fP +.fi +.sp +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/client/bluetoothctl-endpoint.rst b/client/bluetoothctl-endpoint.rst new file mode 100644 index 0000000000000000000000000000000000000000..d13f37cd97e9b06a2e87dea9fbc318c4df64e8f2 --- /dev/null +++ b/client/bluetoothctl-endpoint.rst @@ -0,0 +1,171 @@ +===================== +bluetoothctl-endpoint +===================== + +---------------- +Endpoint Submenu +---------------- + +:Version: BlueZ +:Copyright: Free use of this software is granted under ther terms of the GNU + Lesser General Public Licenses (LGPL). +:Date: November 2022 +:Manual section: 1 +:Manual group: Linux System Administration + +SYNOPSIS +======== + +**bluetoothctl** [--options] [endpoint.commands] + +Endpoint Commands +================= + +list +---- + +List available endpoints. + +:Usage: **# list [local]** + +show +---- + +Endpoint information. + +:Usage: **# show [endpoint]** + +register +-------- + +Register Endpoint. + +:Usage: **# register <UUID> <codec[:company]> [capabilities...]** +:Example LC3 BAP source: + | **#endpoint.register 00002bcb-0000-1000-8000-00805f9b34fb 0x06** + | **#Auto Accept (yes/no):** y + | **#Max Transports (auto/value):** a + | **#Locations:** a + | **#Supported Context (value):** 3 + | **#Context (value):** 3 + | **#CIG (auto/value):** a + | **#CIS (auto/value):** a +:Example LC3 BAP sink with extra capabilities: + | **#endpoint.register 00002bc9-0000-1000-8000-00805f9b34fb 0x06 "0x03 0xe5 0x03 0x00 0x02 0xe6 0x07"** + | **#Enter Metadata (value/no):** n + | **#Auto Accept (yes/no):** y + | **#Max Transports (auto/value):** a + | **#Locations:** a + | **#Supported Context (value):** 3 + | **#Context (value):** 3 + | **#CIG (auto/value):** a + | **#CIS (auto/value):** a +:Example LC3 BAP Broadcast source: + | **#endpoint.register 00001852-0000-1000-8000-00805f9b34fb 0x06** + | **#Auto Accept (yes/no):** y + | **#Max Transports (auto/value):** a + | **#Locations:** 3 + | **#Supported Context (value):** 1 +:Example LC3 BAP Broadcast sink: + | **#endpoint.register 00001851-0000-1000-8000-00805f9b34fb 0x06** + | **#Auto Accept (yes/no):** y + | **#Max Transports (auto/value):** a + | **#Locations:** 3 + | **#Supported Context (value):** 1 + +Note: + +If running the setup with an audio server that has LE Audio support (such as PipeWire) it will +automatically register endpoints according to the configured roles. For more details +about configuring a Broadcast Source with PipeWire check: +https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/master/doc/dox/config/pipewire-props.7.md + +unregister +---------- + +Unregister Endpoint. + +:Usage: **# unregister <UUID/object>** + +Note: + +If the endpoint was registered by an audio server, it can't be unregistered from bluetoothctl. +This must be done by the audio server as well. + +config +------ + +Configure Endpoint. + +:Usage: **# config <endpoint> <local endpoint> [preset]** + +Note: + +If the endpoint was registered by an audio server, it can't be configured from bluetoothctl. +This must be done by the audio server as well. + +presets +------- + +List available presets. + +:Usage: **# presets <endpoint>/<UUID> [codec[:company]] [preset] [codec config] [metadata]** +:Example using endpoint: + | **#presets /local/endpoint/ep0 32_1_1** + | **#presets /local/endpoint/ep0** + | Preset 32_1_1 + | Configuration.#0: len 0x02 type 0x01 + | Configuration.Sampling Frequency: 32 Khz (0x06) + | Configuration.#1: len 0x02 type 0x02 + | Configuration.Frame Duration: 7.5 ms (0x00) + | Configuration.#2: len 0x03 type 0x04 + | Configuration.Frame Length: 60 (0x003c) +:Example using UUID: + | **#presets 00002bc9-0000-1000-8000-00805f9b34fb 0x06 32_1_1** + | **#presets 00002bc9-0000-1000-8000-00805f9b34fb 0x06** + | ... + | ***32_1_1** +:Example setting up LC3 custom preset: + | **#presets 00002bc9-0000-1000-8000-00805f9b34fb 0x06 custom** + | **#[Codec] Enter frequency (Khz):** 48 + | **#[Codec] Enter frame duration (ms):** 10 + | **#[Codec] Enter channel allocation:** 3 + | **#[Codec] Enter frame length:** 100 + | **#[QoS] Enter Target Latency (Low, Balance, High):** Low + | **#[QoS] Enter SDU Interval (us):** 1000 + | **#[QoS] Enter Framing (Unframed, Framed):** Unframed + | **#[QoS] Enter PHY (1M, 2M):** 2M + | **#[QoS] Enter Max SDU:** 200 + | **#[QoS] Enter RTN:** 3 + | **#[QoS] Enter Max Transport Latency (ms):** 10 + | **#[QoS] Enter Presentation Delay (us):** 20000 + | **#presets 00002bc9-0000-1000-8000-00805f9b34fb 0x06** + | ... + | ***custom** +:Example setting up LC3 custom preset with extra configuration: + | **#presets 00002bc9-0000-1000-8000-00805f9b34fb 0x06 custom "0x03 0xe8 0x00 0x00 0x02 0xe9 0x00"** + | **#[Codec] Enter frequency (Khz):** 48 + | **#[Codec] Enter frame duration (ms):** 10 + | **#[Codec] Enter channel allocation:** 3 + | **#[Codec] Enter frame length:** 100 + | **#[QoS] Enter Target Latency (Low, Balance, High):** Low + | **#[QoS] Enter SDU Interval (us):** 1000 + | **#[QoS] Enter Framing (Unframed, Framed):** Unframed + | **#[QoS] Enter PHY (1M, 2M):** 2M + | **#[QoS] Enter Max SDU:** 200 + | **#[QoS] Enter RTN:** 3 + | **#[QoS] Enter Max Transport Latency (ms):** 10 + | **#[QoS] Enter Presentation Delay (us):** 20000 + | **#presets 00002bc9-0000-1000-8000-00805f9b34fb 0x06** + | ... + | ***custom** + +RESOURCES +========= + +http://www.bluez.org + +REPORTING BUGS +============== + +linux-bluetooth@vger.kernel.org diff --git a/client/bluetoothctl-gatt.1 b/client/bluetoothctl-gatt.1 new file mode 100644 index 0000000000000000000000000000000000000000..5f77486d319ef2f00955e70e152d3617e581df7a --- /dev/null +++ b/client/bluetoothctl-gatt.1 @@ -0,0 +1,215 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BLUETOOTHCTL-GATT" "1" "November 2022" "BlueZ" "Linux System Administration" +.SH NAME +bluetoothctl-gatt \- Generic Attribute Submenu +.SH SYNOPSIS +.sp +\fBbluetoothctl\fP [\-\-options] [gatt.commands] +.SH GENERIC ATTRIBUTE COMMANDS +.SS list\-attributes +.sp +List attributes. +.INDENT 0.0 +.TP +.B Usage +\fB# list\-attributes <attribute/UUID>\fP +.UNINDENT +.SS select\-attribute +.sp +Select attribute. +.INDENT 0.0 +.TP +.B Usage +\fB# select\-attribute <attribute/UUID>\fP +.UNINDENT +.SS attribute\-info +.sp +Select attribute. +.INDENT 0.0 +.TP +.B Usage +\fB# attribute\-info [attribute/UUID]\fP +.UNINDENT +.SS read +.sp +Read attribute value. +.INDENT 0.0 +.TP +.B Usage +\fB# read [offset]\fP +.UNINDENT +.SS write +.sp +Write attribute value. +.INDENT 0.0 +.TP +.B Usage +\fB# write <data=xx xx ...> [offset] [type]\fP +.UNINDENT +.SS acquire\-write +.sp +Acquire Write file descriptor. +.INDENT 0.0 +.TP +.B Usage +\fB# acquire\-write\fP +.UNINDENT +.SS release\-write +.sp +Release Write file descriptor. +.INDENT 0.0 +.TP +.B Usage +\fB# release\-write\fP +.UNINDENT +.SS acquire\-notify +.sp +Acquire Notify file descriptor. +.INDENT 0.0 +.TP +.B Usage +\fB# acquire\-notify\fP +.UNINDENT +.SS release\-notify +.sp +Release Notify file descriptor. +.INDENT 0.0 +.TP +.B Usage +\fB# release\-notify\fP +.UNINDENT +.SS notify +.sp +Notify attribute value. +.INDENT 0.0 +.TP +.B Usage +\fB# notify <on/off>\fP +.UNINDENT +.SS clone +.sp +Clone a device or attribute. +.INDENT 0.0 +.TP +.B Usage +\fB# clone [dev/attribute/UUID]\fP +.UNINDENT +.SS register\-application +.sp +Register application. +.INDENT 0.0 +.TP +.B Usage +\fB# register\-application [UUID ...]\fP +.UNINDENT +.SS unregister\-application +.sp +Unregister application +.INDENT 0.0 +.TP +.B Usage +\fB# unregister\-application\fP +.UNINDENT +.SS register\-service +.sp +Register application service. +.INDENT 0.0 +.TP +.B Usage +\fB# register\-service <UUID> [handle]\fP +.UNINDENT +.SS unregister\-service +.sp +Unregister application service +.INDENT 0.0 +.TP +.B Usage +\fB# unregister\-service <UUID/object>\fP +.UNINDENT +.SS register\-includes +.sp +Register as Included service. +.INDENT 0.0 +.TP +.B Usage +\fB#r egister\-includes <UUID> [handle]\fP +.UNINDENT +.SS unregister\-includes +.sp +Unregister Included service. +.INDENT 0.0 +.TP +.B Usage +\fB# unregister\-includes <Service\-UUID><Inc\-UUID>\fP +.UNINDENT +.SS register\-characteristic +.sp +Register service characteristic. +.INDENT 0.0 +.TP +.B Usage +\fB# register\-characteristic <UUID> <Flags=read,write,notify...> [handle]\fP +.UNINDENT +.SS unregister\-characteristic +.sp +Unregister service characteristic. +.INDENT 0.0 +.TP +.B Usage +\fB# unregister\-characteristic <UUID/object>\fP +.UNINDENT +.SS register\-descriptor +.sp +Register characteristic descriptor. +.INDENT 0.0 +.TP +.B Usage +\fB# register\-descriptor <UUID> <Flags=read,write...> [handle]\fP +.UNINDENT +.SS unregister\-descriptor +.sp +Unregister characteristic descriptor. +.INDENT 0.0 +.TP +.B Usage +\fB# unregister\-descriptor <UUID/object>\fP +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/client/bluetoothctl-gatt.rst b/client/bluetoothctl-gatt.rst new file mode 100644 index 0000000000000000000000000000000000000000..2a239beca83e5b2bd0919b969ff52789a1e16c0d --- /dev/null +++ b/client/bluetoothctl-gatt.rst @@ -0,0 +1,180 @@ +================= +bluetoothctl-gatt +================= + +------------------------- +Generic Attribute Submenu +------------------------- + +:Version: BlueZ +:Copyright: Free use of this software is granted under ther terms of the GNU + Lesser General Public Licenses (LGPL). +:Date: November 2022 +:Manual section: 1 +:Manual group: Linux System Administration + +SYNOPSIS +======== + +**bluetoothctl** [--options] [gatt.commands] + + +Generic Attribute Commands +========================== + +list-attributes +--------------- + +List attributes. + +:Usage: **# list-attributes <attribute/UUID>** + +select-attribute +---------------- + +Select attribute. + +:Usage: **# select-attribute <attribute/UUID>** + +attribute-info +-------------- + +Select attribute. + +:Usage: **# attribute-info [attribute/UUID]** + +read +---- + +Read attribute value. + +:Usage: **# read [offset]** + +write +----- + +Write attribute value. + +:Usage: **# write <data=xx xx ...> [offset] [type]** + +acquire-write +------------- + +Acquire Write file descriptor. + +:Usage: **# acquire-write** + +release-write +------------- + +Release Write file descriptor. + +:Usage: **# release-write** + +acquire-notify +-------------- + +Acquire Notify file descriptor. + +:Usage: **# acquire-notify** + +release-notify +-------------- + +Release Notify file descriptor. + +:Usage: **# release-notify** + +notify +------ + +Notify attribute value. + +:Usage: **# notify <on/off>** + +clone +----- + +Clone a device or attribute. + +:Usage: **# clone [dev/attribute/UUID]** + +register-application +-------------------- + +Register application. + +:Usage: **# register-application [UUID ...]** + +unregister-application +---------------------- + +Unregister application + +:Usage: **# unregister-application** + +register-service +---------------- + +Register application service. + +:Usage: **# register-service <UUID> [handle]** + +unregister-service +------------------ + +Unregister application service + +:Usage: **# unregister-service <UUID/object>** + +register-includes +----------------- + +Register as Included service. + +:Usage: **#r egister-includes <UUID> [handle]** + +unregister-includes +------------------- + +Unregister Included service. + +:Usage: **# unregister-includes <Service-UUID><Inc-UUID>** + +register-characteristic +----------------------- + +Register service characteristic. + +:Usage: **# register-characteristic <UUID> <Flags=read,write,notify...> [handle]** + +unregister-characteristic +------------------------- + +Unregister service characteristic. + +:Usage: **# unregister-characteristic <UUID/object>** + +register-descriptor +------------------- + +Register characteristic descriptor. + +:Usage: **# register-descriptor <UUID> <Flags=read,write...> [handle]** + +unregister-descriptor +--------------------- + +Unregister characteristic descriptor. + +:Usage: **# unregister-descriptor <UUID/object>** + +RESOURCES +========= + +http://www.bluez.org + +REPORTING BUGS +============== + +linux-bluetooth@vger.kernel.org diff --git a/client/bluetoothctl-mgmt.1 b/client/bluetoothctl-mgmt.1 new file mode 100644 index 0000000000000000000000000000000000000000..0452373eb6d29f84476f787f7cea4960e560144f --- /dev/null +++ b/client/bluetoothctl-mgmt.1 @@ -0,0 +1,645 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BLUETOOTHCTL-MGMT" "1" "July 2023" "BlueZ" "Linux System Administration" +.SH NAME +bluetoothctl-mgmt \- Management Submenu +.SH SYNOPSIS +.sp +\fBbluetoothctl\fP [\-\-options] [mgmt.commands] +.SH MGMT COMMANDS +.SS select +.sp +Select a different index +.INDENT 0.0 +.TP +.B Usage +\fB# select <index>\fP +.UNINDENT +.SS revision +.sp +Get the MGMT Revision +.INDENT 0.0 +.TP +.B Usage +\fB# revision\fP +.UNINDENT +.SS commands +.sp +List supported commands +.INDENT 0.0 +.TP +.B Usage +\fB# commands\fP +.UNINDENT +.SS config +.sp +Show configuration info +.INDENT 0.0 +.TP +.B Usage +\fB# config\fP +.UNINDENT +.SS info +.sp +Show controller info +.INDENT 0.0 +.TP +.B Usage +\fB# info\fP +.UNINDENT +.SS extinfo +.sp +Show extended controller info +.INDENT 0.0 +.TP +.B Usage +\fB# extinfo\fP +.UNINDENT +.SS auto\-power +.sp +Power all available features +.INDENT 0.0 +.TP +.B Usage +\fB# auto\-power\fP +.UNINDENT +.SS power +.sp +Toggle powered state +.INDENT 0.0 +.TP +.B Usage +\fB# power <on/off>\fP +.UNINDENT +.SS discov +.sp +Toggle discoverable state +.INDENT 0.0 +.TP +.B Usage +\fB# discov <yes/no/limited> [timeout]\fP +.UNINDENT +.SS connectable +.sp +Toggle connectable state +.INDENT 0.0 +.TP +.B Usage +\fB# connectable <on/off>\fP +.UNINDENT +.SS fast\-conn +.sp +Toggle fast connectable state +.INDENT 0.0 +.TP +.B Usage +\fB# fast\-conn <on/off>\fP +.UNINDENT +.SS bondable +.sp +Toggle bondable state +.INDENT 0.0 +.TP +.B Usage +\fB# bondable <on/off>\fP +.UNINDENT +.SS pairable +.sp +Toggle bondable state +.INDENT 0.0 +.TP +.B Usage +\fB# pairable <on/off>\fP +.UNINDENT +.SS linksec +.sp +Toggle link level security +.INDENT 0.0 +.TP +.B Usage +\fB# linksec <on/off>\fP +.UNINDENT +.SS ssp +.sp +Toggle SSP mode +.INDENT 0.0 +.TP +.B Usage +\fB# spp <on/off>\fP +.UNINDENT +.SS sc +.sp +Toggle SC support +.INDENT 0.0 +.TP +.B Usage +\fB# sc <on/off/only>\fP +.UNINDENT +.SS hs +.sp +Toggle HS support +.INDENT 0.0 +.TP +.B Usage +\fB# hs <on/off>\fP +.UNINDENT +.SS le +.sp +Toggle LE support +.INDENT 0.0 +.TP +.B Usage +\fB# le <on/off>\fP +.UNINDENT +.SS advertising +.sp +Toggle LE advertising +.INDENT 0.0 +.TP +.B Usage +\fB# advertise <on/off>\fP +.UNINDENT +.SS bredr +.sp +Toggle BR/EDR support +.INDENT 0.0 +.TP +.B Usage +\fB# bredr <on/off>\fP +.UNINDENT +.SS privacy +.sp +Toggle privacy support +.INDENT 0.0 +.TP +.B Usage +\fB# privacy <on/off> [irk]\fP +.UNINDENT +.SS class +.sp +Set device major/minor class +.INDENT 0.0 +.TP +.B Usage +\fB# class <major> <minor>\fP +.UNINDENT +.SS disconnect +.sp +Disconnect device +.INDENT 0.0 +.TP +.B Usage +\fB# disconnect [\-t type] <remote address>\fP +.UNINDENT +.SS con +.sp +List connections +.INDENT 0.0 +.TP +.B Usage +\fB# con\fP +.UNINDENT +.SS find +.sp +Discover nearby devices +.INDENT 0.0 +.TP +.B Usage +\fB# find [\-l|\-b] [\-L]\fP +.UNINDENT +.SS find\-service +.sp +Discover nearby service +.INDENT 0.0 +.TP +.B Usage +\fB# find\-service [\-u UUID] [\-r RSSI_Threshold] [\-l|\-b]\fP +.UNINDENT +.SS stop\-find +.sp +Stop discovery +.INDENT 0.0 +.TP +.B Usage +\fB# stop\-find [\-l|\-b]\fP +.UNINDENT +.SS name +.sp +Set local name +.INDENT 0.0 +.TP +.B Usage +\fB# name <name> [shortname]\fP +.UNINDENT +.SS pair +.sp +Pair with a remote device +.INDENT 0.0 +.TP +.B Usage +\fB# pair [\-c cap] [\-t type] <remote address>\fP +.UNINDENT +.SS cancelpair +.sp +Cancel pairing +.INDENT 0.0 +.TP +.B Usage +\fB# cancelpair [\-t type] <remote address>\fP +.UNINDENT +.SS unpair +.sp +Unpair device +.INDENT 0.0 +.TP +.B Usage +\fB# unpair [\-t type] <remote address>\fP +.UNINDENT +.SS keys +.sp +Load Link Keys +.INDENT 0.0 +.TP +.B Usage +\fBkeys\fP +.UNINDENT +.SS ltks +.sp +Load Long Term Keys +.INDENT 0.0 +.TP +.B Usage +\fB# ltks\fP +.UNINDENT +.SS irks +.sp +Load Identity Resolving Keys +.INDENT 0.0 +.TP +.B Usage +\fB# irks [\-\-local index] [\-\-file file path]\fP +.UNINDENT +.SS block +.sp +Block Device +.INDENT 0.0 +.TP +.B Usage +\fB# block [\-t type] <remote address>\fP +.UNINDENT +.SS unblock +.sp +Unblock Device +.INDENT 0.0 +.TP +.B Usage +\fB# unblock [\-t type] <remote address>\fP +.UNINDENT +.SS add\-uuid +.sp +Add UUID +.INDENT 0.0 +.TP +.B Usage +\fB# add\-uuid <UUID> <service class hint>\fP +.UNINDENT +.SS rm\-uuid +.sp +Remove UUID +.INDENT 0.0 +.TP +.B Usage +\fB# rm\-uuid <UUID>\fP +.UNINDENT +.SS clr\-uuids +.sp +Clear UUIDs +.INDENT 0.0 +.TP +.B Usage +\fB# clear\-uuids\fP +.UNINDENT +.SS local\-oob +.sp +Local OOB data +.INDENT 0.0 +.TP +.B Usage +\fB# local\-oob\fP +.UNINDENT +.SS remote\-oob +.sp +Remote OOB data +.INDENT 0.0 +.TP +.B Usage +\fB# remote\-oob [\-t <addr_type>] [\-r <rand192>] [\-h <hash192>] +[\-R <rand256>] [\-H <hash256>] <addr>\fP +.UNINDENT +.SS did +.sp +Set Device ID +.INDENT 0.0 +.TP +.B Usage +\fB# did <source>:<vendor>:<product>:<version>\fP +.UNINDENT +.SS static\-addr +.sp +Set static address +.INDENT 0.0 +.TP +.B Usage +\fB# static\-addr <address>\fP +.UNINDENT +.SS public\-addr +.sp +Set public address +.INDENT 0.0 +.TP +.B Usage +\fB# public\-addr <address>\fP +.UNINDENT +.SS ext\-config +.sp +External configuration +.INDENT 0.0 +.TP +.B Usage +\fB# ext\-config <on/off>\fP +.UNINDENT +.SS debug\-keys +.sp +Toggle debug keys +.INDENT 0.0 +.TP +.B Usage +\fB# debug\-keys <on/off>\fP +.UNINDENT +.SS conn\-info +.sp +Get connection information +.INDENT 0.0 +.TP +.B Usage +\fB# conn\-info [\-t type] <remote address>\fP +.UNINDENT +.SS io\-cap +.sp +Set IO Capability +.INDENT 0.0 +.TP +.B Usage +\fB# io\-cap <cap>\fP +.UNINDENT +.SS scan\-params +.sp +Set Scan Parameters +.INDENT 0.0 +.TP +.B Usage +\fB# scan\-params <interval> <window>\fP +.UNINDENT +.SS get\-clock +.sp +Get Clock Information +.INDENT 0.0 +.TP +.B Usage +\fB# get\-clock [address]\fP +.UNINDENT +.SS add\-device +.sp +Add Device +.INDENT 0.0 +.TP +.B Usage +\fB# add\-device [\-a action] [\-t type] <address>\fP +.UNINDENT +.SS del\-device +.sp +Remove Device +.INDENT 0.0 +.TP +.B Usage +\fB# del\-device [\-t type] <address>\fP +.UNINDENT +.SS clr\-devices +.sp +Clear Devices +.INDENT 0.0 +.TP +.B Usage +\fB# clr\-devices\fP +.UNINDENT +.SS bredr\-oob +.sp +Local OOB data (BR/EDR) +.INDENT 0.0 +.TP +.B Usage +\fB# bredr\-oob\fP +.UNINDENT +.SS le\-oob +.sp +Local OOB data (LE) +.INDENT 0.0 +.TP +.B Usage +\fB# le\-oob\fP +.UNINDENT +.SS advinfo +.sp +Show advertising features +.INDENT 0.0 +.TP +.B Usage +\fB# advinfo\fP +.UNINDENT +.SS advsize +.sp +Show advertising size info +.INDENT 0.0 +.TP +.B Usage +\fB# advsize [options] <instance_id>\fP +.UNINDENT +.SS add\-adv +.sp +Add advertising instance +.INDENT 0.0 +.TP +.B Usage +\fB# add\-adv [options] <instance_id>\fP +.UNINDENT +.SS rm\-adv +.sp +Remove advertising instance +.INDENT 0.0 +.TP +.B Usage +\fB# rm\-adv <instance_id>\fP +.UNINDENT +.SS clr\-adv +.sp +Clear advertising instances +.INDENT 0.0 +.TP +.B Usage +\fB# clr\-adv\fP +.UNINDENT +.SS add\-ext\-adv\-params +.sp +Add extended advertising params +.INDENT 0.0 +.TP +.B Usage +\fB# add\-ext\-adv\-parms [options] <instance_id>\fP +.UNINDENT +.SS add\-ext\-adv\-data +.sp +Add extended advertising data +.INDENT 0.0 +.TP +.B Usage +\fB# add\-ext\-adv\-data [options] <instance_id>\fP +.UNINDENT +.SS appearance +.sp +Set appearance +.INDENT 0.0 +.TP +.B Usage +\fB# appearance <appearance>\fP +.UNINDENT +.SS phy +.sp +Get/Set PHY Configuration +.INDENT 0.0 +.TP +.B Usage +\fB# phy [LE1MTX] [LE1MRX] [LE2MTX] [LE2MRX] [LECODEDTX] [LECODEDRX] +[BR1M1SLOT] [BR1M3SLOT] [BR1M5SLOT][EDR2M1SLOT] [EDR2M3SLOT] +[EDR2M5SLOT][EDR3M1SLOT] [EDR3M3SLOT] [EDR3M5SLOT]\fP +.UNINDENT +.SS wbs +.sp +Toggle Wideband\-Speech support +.INDENT 0.0 +.TP +.B Usage +\fB# wbs <on/off>\fP +.UNINDENT +.SS secinfo +.sp +Show security information +.INDENT 0.0 +.TP +.B Usage +\fB# secinfo\fP +.UNINDENT +.SS expinfo +.sp +Show experimental features +.INDENT 0.0 +.TP +.B Usage +\fB# expinfo\fP +.UNINDENT +.SS exp\-debug +.sp +Set debug feature +.INDENT 0.0 +.TP +.B Usage +\fB# exp\-debug <on/off>\fP +.UNINDENT +.SS exp\-privacy +.sp +Set LL privacy feature +.INDENT 0.0 +.TP +.B Usage +\fB# exp\-privacy <on/off>\fP +.UNINDENT +.SS exp\-quality +.sp +Set bluetooth quality report feature +.INDENT 0.0 +.TP +.B Usage +\fB# exp\-quality <on/off>\fP +.UNINDENT +.SS exp\-offload +.sp +Toggle codec support +.INDENT 0.0 +.TP +.B Usage +\fB# exp\-offload <on/off>\fP +.UNINDENT +.SS read\-sysconfig +.sp +Read System Configuration +.INDENT 0.0 +.TP +.B Usage +\fB# read\-sysconfig\fP +.UNINDENT +.SS set\-sysconfig +.sp +Set System Configuration +.INDENT 0.0 +.TP +.B Usage +\fB# set\-sysconfig <\-v|\-h> [options...]\fP +.UNINDENT +.SS get\-flags +.sp +Get device flags +.SS set\-flags +.sp +Set device flags +.INDENT 0.0 +.TP +.B Usage +\fB# set\-flags [\-f flags] [\-t type] <address>\fP +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/client/bluetoothctl-mgmt.rst b/client/bluetoothctl-mgmt.rst new file mode 100644 index 0000000000000000000000000000000000000000..4baed6480c143b81eb8388ae7a4378c7f527e133 --- /dev/null +++ b/client/bluetoothctl-mgmt.rst @@ -0,0 +1,559 @@ +================= +bluetoothctl-mgmt +================= + +------------------ +Management Submenu +------------------ + +:Version: BlueZ +:Copyright: Free use of this software is granted under ther terms of the GNU + Lesser General Public Licenses (LGPL). +:Date: July 2023 +:Manual section: 1 +:Manual group: Linux System Administration + +SYNOPSIS +======== + +**bluetoothctl** [--options] [mgmt.commands] + +Mgmt Commands +============= + +select +------ + +Select a different index + +:Usage: **# select <index>** + +revision +-------- + +Get the MGMT Revision + +:Usage: **# revision** + +commands +-------- + +List supported commands + +:Usage: **# commands** + +config +------ + +Show configuration info + +:Usage: **# config** + +info +---- + +Show controller info + +:Usage: **# info** + +extinfo +------- + +Show extended controller info + +:Usage: **# extinfo** + +auto-power +---------- + +Power all available features + +:Usage: **# auto-power** + +power +----- + +Toggle powered state + +:Usage: **# power <on/off>** + +discov +------ + +Toggle discoverable state + +:Usage: **# discov <yes/no/limited> [timeout]** + +connectable +----------- + +Toggle connectable state + +:Usage: **# connectable <on/off>** + +fast-conn +--------- + +Toggle fast connectable state + +:Usage: **# fast-conn <on/off>** + +bondable +-------- + +Toggle bondable state + +:Usage: **# bondable <on/off>** + +pairable +-------- + +Toggle bondable state + +:Usage: **# pairable <on/off>** + +linksec +------- + +Toggle link level security + +:Usage: **# linksec <on/off>** + +ssp +--- + +Toggle SSP mode + +:Usage: **# spp <on/off>** + +sc +-- + +Toggle SC support + +:Usage: **# sc <on/off/only>** + +hs +-- + +Toggle HS support + +:Usage: **# hs <on/off>** + +le +-- + +Toggle LE support + +:Usage: **# le <on/off>** + +advertising +----------- + +Toggle LE advertising + +:Usage: **# advertise <on/off>** + +bredr +----- + +Toggle BR/EDR support + +:Usage: **# bredr <on/off>** + +privacy +------- + +Toggle privacy support + +:Usage: **# privacy <on/off> [irk]** + +class +----- + +Set device major/minor class + +:Usage: **# class <major> <minor>** + +disconnect +---------- + +Disconnect device + +:Usage: **# disconnect [-t type] <remote address>** + +con +--- + +List connections + +:Usage: **# con** + +find +---- + +Discover nearby devices + +:Usage: **# find [-l|-b] [-L]** + +find-service +------------ + +Discover nearby service + +:Usage: **# find-service [-u UUID] [-r RSSI_Threshold] [-l|-b]** + +stop-find +--------- + +Stop discovery + +:Usage: **# stop-find [-l|-b]** + +name +---- + +Set local name + +:Usage: **# name <name> [shortname]** + +pair +---- + +Pair with a remote device + +:Usage: **# pair [-c cap] [-t type] <remote address>** + +cancelpair +---------- + +Cancel pairing + +:Usage: **# cancelpair [-t type] <remote address>** + +unpair +------ + +Unpair device + +:Usage: **# unpair [-t type] <remote address>** + +keys +---- + +Load Link Keys + +:Usage: **keys** + +ltks +---- + +Load Long Term Keys + +:Usage: **# ltks** + +irks +---- + +Load Identity Resolving Keys + +:Usage: **# irks [--local index] [--file file path]** + +block +----- + +Block Device + +:Usage: **# block [-t type] <remote address>** + +unblock +------- + +Unblock Device + +:Usage: **# unblock [-t type] <remote address>** + +add-uuid +-------- + +Add UUID + +:Usage: **# add-uuid <UUID> <service class hint>** + +rm-uuid +------- + +Remove UUID + +:Usage: **# rm-uuid <UUID>** + +clr-uuids +--------- + +Clear UUIDs + +:Usage: **# clear-uuids** + +local-oob +--------- + +Local OOB data + +:Usage: **# local-oob** + +remote-oob +---------- + +Remote OOB data + +:Usage: **# remote-oob [-t <addr_type>] [-r <rand192>] [-h <hash192>] + [-R <rand256>] [-H <hash256>] <addr>** + +did +--- + +Set Device ID + +:Usage: **# did <source>:<vendor>:<product>:<version>** + +static-addr +----------- + +Set static address + +:Usage: **# static-addr <address>** + +public-addr +----------- + +Set public address + +:Usage: **# public-addr <address>** + +ext-config +---------- + +External configuration + +:Usage: **# ext-config <on/off>** + +debug-keys +---------- + +Toggle debug keys + +:Usage: **# debug-keys <on/off>** + +conn-info +--------- + +Get connection information + +:Usage: **# conn-info [-t type] <remote address>** + +io-cap +------ + +Set IO Capability + +:Usage: **# io-cap <cap>** + +scan-params +----------- + +Set Scan Parameters + +:Usage: **# scan-params <interval> <window>** + +get-clock +--------- + +Get Clock Information + +:Usage: **# get-clock [address]** + +add-device +---------- + +Add Device + +:Usage: **# add-device [-a action] [-t type] <address>** + +del-device +---------- + +Remove Device + +:Usage: **# del-device [-t type] <address>** + +clr-devices +----------- + +Clear Devices + +:Usage: **# clr-devices** + +bredr-oob +--------- + +Local OOB data (BR/EDR) + +:Usage: **# bredr-oob** + +le-oob +------ + +Local OOB data (LE) + +:Usage: **# le-oob** + +advinfo +------- + +Show advertising features + +:Usage: **# advinfo** + +advsize +------- + +Show advertising size info + +:Usage: **# advsize [options] <instance_id>** + +add-adv +------- + +Add advertising instance + +:Usage: **# add-adv [options] <instance_id>** + +rm-adv +------ + +Remove advertising instance + +:Usage: **# rm-adv <instance_id>** + +clr-adv +------- + +Clear advertising instances + +:Usage: **# clr-adv** + +add-ext-adv-params +------------------ + +Add extended advertising params + +:Usage: **# add-ext-adv-parms [options] <instance_id>** + +add-ext-adv-data +---------------- + +Add extended advertising data + +:Usage: **# add-ext-adv-data [options] <instance_id>** + +appearance +---------- + +Set appearance + +:Usage: **# appearance <appearance>** + +phy +--- + +Get/Set PHY Configuration + +:Usage: **# phy [LE1MTX] [LE1MRX] [LE2MTX] [LE2MRX] [LECODEDTX] [LECODEDRX] + [BR1M1SLOT] [BR1M3SLOT] [BR1M5SLOT][EDR2M1SLOT] [EDR2M3SLOT] + [EDR2M5SLOT][EDR3M1SLOT] [EDR3M3SLOT] [EDR3M5SLOT]** + +wbs +--- + +Toggle Wideband-Speech support + +:Usage: **# wbs <on/off>** + +secinfo +------- + +Show security information + +:Usage: **# secinfo** + +expinfo +------- + +Show experimental features + +:Usage: **# expinfo** + +exp-debug +--------- + +Set debug feature + +:Usage: **# exp-debug <on/off>** + +exp-privacy +----------- + +Set LL privacy feature + +:Usage: **# exp-privacy <on/off>** + +exp-quality +----------- + +Set bluetooth quality report feature + +:Usage: **# exp-quality <on/off>** + +exp-offload +----------- + +Toggle codec support + +:Usage: **# exp-offload <on/off>** + +read-sysconfig +-------------- + +Read System Configuration + +:Usage: **# read-sysconfig** + +set-sysconfig +------------- + +Set System Configuration + +:Usage: **# set-sysconfig <-v|-h> [options...]** + +get-flags +--------- + +Get device flags + + +set-flags +--------- + +Set device flags + +:Usage: **# set-flags [-f flags] [-t type] <address>** + +RESOURCES +========= + +http://www.bluez.org + +REPORTING BUGS +============== + +linux-bluetooth@vger.kernel.org diff --git a/client/bluetoothctl-monitor.1 b/client/bluetoothctl-monitor.1 new file mode 100644 index 0000000000000000000000000000000000000000..202d41a1af311c6e5d7b5bed96734e386a2371e3 --- /dev/null +++ b/client/bluetoothctl-monitor.1 @@ -0,0 +1,111 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BLUETOOTHCTL-MONITOR" "1" "July 2023" "BlueZ" "Linux System Administration" +.SH NAME +bluetoothctl-monitor \- Monitor Submenu +.SH SYNOPSIS +.sp +\fBbluetoothctl\fP [\-\-options] [monitor.commands] +.SH MONITOR COMMANDS +.SS set\-rssi\-threshold +.sp +Set RSSI threshold parameter +.INDENT 0.0 +.TP +.B Usage +\fB# set\-rssi\-threshold <low_threshold> <high_threshold>\fP +.UNINDENT +.SS set\-rssi\-timeout +.sp +Set RSSI timeout parameter +.INDENT 0.0 +.TP +.B Usage +\fB# set\-rssi\-timeout <low_timeout> <high_timeout>\fP +.UNINDENT +.SS set\-rssi\-sampling\-period +.sp +Set RSSI sampling period parameter +.INDENT 0.0 +.TP +.B Usage +\fB# set\-rssi\-timeout <low_timeout> <high_timeout>\fP +.UNINDENT +.SS add\-or\-pattern +.sp +Register \(aqor pattern\(aq type monitor with the specified RSSI parameters +.INDENT 0.0 +.TP +.B Usage +\fB# add\-or\-pattern [patterns=pattern1 pattern2 ...]\fP +.UNINDENT +.SS get\-pattern +.sp +Get advertisement monitor +.INDENT 0.0 +.TP +.B Usage +\fB# get\-pattern <monitor\-id/all>\fP +.UNINDENT +.SS remove\-pattern +.sp +Remove advertisement monitor +.INDENT 0.0 +.TP +.B Usage +\fB# remove\-pattern <monitor\-id/all>\fP +.UNINDENT +.SS get\-supported\-info +.sp +Get advertisement manager supported features and supported monitor types +.INDENT 0.0 +.TP +.B Usage +\fB# get\-supported\-info\fP +.UNINDENT +.SS print\-usage +.sp +Print the command usage +.INDENT 0.0 +.TP +.B Usage +\fB# print\-usage <add\-or\-pattern>\fP +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/client/bluetoothctl-monitor.rst b/client/bluetoothctl-monitor.rst new file mode 100644 index 0000000000000000000000000000000000000000..2357a56ace36b363b39a1643bd640ac04bc0ef0e --- /dev/null +++ b/client/bluetoothctl-monitor.rst @@ -0,0 +1,89 @@ +==================== +bluetoothctl-monitor +==================== + +--------------- +Monitor Submenu +--------------- + +:Version: BlueZ +:Copyright: Free use of this software is granted under ther terms of the GNU + Lesser General Public Licenses (LGPL). +:Date: July 2023 +:Manual section: 1 +:Manual group: Linux System Administration + +SYNOPSIS +======== + +**bluetoothctl** [--options] [monitor.commands] + +Monitor Commands +================ + +set-rssi-threshold +------------------ + +Set RSSI threshold parameter + +:Usage: **# set-rssi-threshold <low_threshold> <high_threshold>** + +set-rssi-timeout +---------------- + +Set RSSI timeout parameter + +:Usage: **# set-rssi-timeout <low_timeout> <high_timeout>** + +set-rssi-sampling-period +------------------------- + +Set RSSI sampling period parameter + +:Usage: **# set-rssi-timeout <low_timeout> <high_timeout>** + +add-or-pattern +-------------- + +Register 'or pattern' type monitor with the specified RSSI parameters + +:Usage: **# add-or-pattern [patterns=pattern1 pattern2 ...]** + +get-pattern +----------- + +Get advertisement monitor + +:Usage: **# get-pattern <monitor-id/all>** + +remove-pattern +-------------- + +Remove advertisement monitor + +:Usage: **# remove-pattern <monitor-id/all>** + +get-supported-info +------------------ + +Get advertisement manager supported features and supported monitor types + +:Usage: **# get-supported-info** + +print-usage +----------- + +Print the command usage + +:Usage: **# print-usage <add-or-pattern>** + +RESOURCES +========= + +http://www.bluez.org + +REPORTING BUGS +============== + +linux-bluetooth@vger.kernel.org + diff --git a/client/bluetoothctl-player.1 b/client/bluetoothctl-player.1 new file mode 100644 index 0000000000000000000000000000000000000000..8745ffabfdbe0e58556d47e0358b4dfafbc93678 --- /dev/null +++ b/client/bluetoothctl-player.1 @@ -0,0 +1,199 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BLUETOOTHCTL-PLAYER" "1" "November 2022" "BlueZ" "Linux System Administration" +.SH NAME +bluetoothctl-player \- Media Player Submenu +.SH SYNOPSIS +.sp +\fBbluetoothctl\fP [\-\-options] [player.commands] +.SH MEDIA PLAYER COMMANDS +.SS list +.sp +List available players. +.INDENT 0.0 +.TP +.B Usage +\fB# list\fP +.UNINDENT +.SS show +.sp +Show player information. +.INDENT 0.0 +.TP +.B Usage +\fB# show [player]\fP +.UNINDENT +.SS select +.sp +Select default player. +.INDENT 0.0 +.TP +.B Usage +\fB# select <player>\fP +.UNINDENT +.SS play +.sp +Start playback. +.INDENT 0.0 +.TP +.B Usage +\fB# play [item]\fP +.UNINDENT +.SS pause +.sp +Pause playback. +.INDENT 0.0 +.TP +.B Usage +\fB# pause\fP +.UNINDENT +.SS stop +.sp +Stop playback. +.INDENT 0.0 +.TP +.B Usage +\fB# stop\fP +.UNINDENT +.SS next +.sp +Jump to next item. +.INDENT 0.0 +.TP +.B Usage +\fB# next\fP +.UNINDENT +.SS previous +.sp +Jump to previous item. +.INDENT 0.0 +.TP +.B Usage +\fB# previous\fP +.UNINDENT +.SS fast\-forward +.sp +Fast forward playback. +.INDENT 0.0 +.TP +.B Usage +\fB# fast\-forward\fP +.UNINDENT +.SS rewind +.sp +Rewind playback. +.INDENT 0.0 +.TP +.B Usage +\fB# rewind\fP +.UNINDENT +.SS equalizer +.sp +Enable/Disable equalizer. +.INDENT 0.0 +.TP +.B Usage +\fB# equalizer <on/off>\fP +.UNINDENT +.SS repeat +.sp +Set repeat mode. +.INDENT 0.0 +.TP +.B Usage +\fB# repeat <singletrack/alltrack/group/off>\fP +.UNINDENT +.SS shuffle +.sp +Set shuffle mode. +.INDENT 0.0 +.TP +.B Usage +\fB# shuffle <alltracks/group/off>\fP +.UNINDENT +.SS scan +.sp +Set scan mode. +.INDENT 0.0 +.TP +.B Usage +\fB# scan <alltracks/group/off>\fP +.UNINDENT +.SS change\-folder +.sp +Change current folder. +.INDENT 0.0 +.TP +.B Usage +\fB# change\-folder <item>\fP +.UNINDENT +.SS list\-items +.sp +List items of current folder. +.INDENT 0.0 +.TP +.B Usage +\fB# list\-items [start] [end]\fP +.UNINDENT +.SS search +.sp +Search items containing string. +.INDENT 0.0 +.TP +.B Usage +\fB# search <string>\fP +.UNINDENT +.SS queue +.sp +Add item to playlist queue. +.INDENT 0.0 +.TP +.B Usage +\fB# queue <item>\fP +.UNINDENT +.SS show\-item +.sp +Show item information. +.INDENT 0.0 +.TP +.B Usage +\fB# show\-item <item>\fP +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/client/bluetoothctl-player.rst b/client/bluetoothctl-player.rst new file mode 100644 index 0000000000000000000000000000000000000000..e45e61a1c5e3dc621f598db5b223c3810fde4e38 --- /dev/null +++ b/client/bluetoothctl-player.rst @@ -0,0 +1,165 @@ +=================== +bluetoothctl-player +=================== + +-------------------- +Media Player Submenu +-------------------- + +:Version: BlueZ +:Copyright: Free use of this software is granted under ther terms of the GNU + Lesser General Public Licenses (LGPL). +:Date: November 2022 +:Manual section: 1 +:Manual group: Linux System Administration + +SYNOPSIS +======== + +**bluetoothctl** [--options] [player.commands] + +Media Player Commands +===================== + +list +---- + +List available players. + +:Usage: **# list** + +show +---- + +Show player information. + +:Usage: **# show [player]** + +select +------ + +Select default player. + +:Usage: **# select <player>** + +play +---- + +Start playback. + +:Usage: **# play [item]** + +pause +----- + +Pause playback. + +:Usage: **# pause** + +stop +---- + +Stop playback. + +:Usage: **# stop** + +next +---- + +Jump to next item. + +:Usage: **# next** + +previous +-------- + +Jump to previous item. + +:Usage: **# previous** + +fast-forward +------------ + +Fast forward playback. + +:Usage: **# fast-forward** + +rewind +------ + +Rewind playback. + +:Usage: **# rewind** + +equalizer +--------- + +Enable/Disable equalizer. + +:Usage: **# equalizer <on/off>** + +repeat +------ + +Set repeat mode. + +:Usage: **# repeat <singletrack/alltrack/group/off>** + +shuffle +------- + +Set shuffle mode. + +:Usage: **# shuffle <alltracks/group/off>** + +scan +---- + +Set scan mode. + +:Usage: **# scan <alltracks/group/off>** + +change-folder +------------- + +Change current folder. + +:Usage: **# change-folder <item>** + +list-items +---------- + +List items of current folder. + +:Usage: **# list-items [start] [end]** + +search +------ + +Search items containing string. + +:Usage: **# search <string>** + +queue +----- + +Add item to playlist queue. + +:Usage: **# queue <item>** + +show-item +--------- + +Show item information. + +:Usage: **# show-item <item>** + +RESOURCES +========= + +http://www.bluez.org + +REPORTING BUGS +============== + +linux-bluetooth@vger.kernel.org diff --git a/client/bluetoothctl-scan.1 b/client/bluetoothctl-scan.1 new file mode 100644 index 0000000000000000000000000000000000000000..bea60a1e095a0074959dee5bd8062e8c9e04f2cf --- /dev/null +++ b/client/bluetoothctl-scan.1 @@ -0,0 +1,172 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BLUETOOTHCTL-SCAN" "1" "July 2023" "BlueZ" "Linux System Administration" +.SH NAME +bluetoothctl-scan \- Scan Submenu +.SH SYNOPSIS +.sp +\fBbluetoothctl\fP [\-\-options] [scan.commands] +.SH SCAN COMMANDS +.SS uuids +.sp +Set/Get UUIDs filter. +.INDENT 0.0 +.TP +.B Usage +\fB# uuids [all/uuid1 uuid2 ...]\fP +.UNINDENT +.SS rssi +.sp +Set/Get RSSI filter, and clears pathloss. +.sp +This sets the minimum rssi value for reporting device advertisements. +.sp +The value is in dBm. +.sp +If one or more discovery filters have been set, the RSSI delta\-threshold imposed +by starting discovery by default will not be applied. +.INDENT 0.0 +.TP +.B Usage +\fB# rssi [rssi]\fP +.TP +.B Example +\fB# rssi \-60\fP +.UNINDENT +.SS pathloss +.sp +Set/Get Pathloss filter, and clears RSSI. +.sp +This sets the maximum pathloss value for reporting device advertisements. +.sp +The value is in dB. +.sp +If one or more discovery filters have been set, the RSSI delta\-threshold +imposed by starting discovery by default will not be applied. +.INDENT 0.0 +.TP +.B Usage +\fB# pathloss [pathloss]\fP +.TP +.B Example +\fB# pathloss 4\fP +.UNINDENT +.SS transport +.sp +Set/Get transport filter. +.sp +Transport parameter determines the type of scan. +.sp +The default is auto. +.sp +Possible values: +.INDENT 0.0 +.IP \(bu 2 +\(dqauto\(dq: interleaved scan +.IP \(bu 2 +\(dqbredr\(dq: BR/EDR inquiry +.IP \(bu 2 +\(dqle\(dq: LE scan only +.UNINDENT +.sp +If \(dqle\(dq or \(dqbredr\(dq Transport is requested and the controller doesn\(aqt support it, +an org.bluez.Error.Failed error will be returned. +.sp +If \(dqauto\(dq transport is requested, the scan will use LE, BREDR, or both, +depending on what\(aqs currently enabled on the controller. +.INDENT 0.0 +.TP +.B Usage +\fB# transport [auto/bredr/le]\fP +.UNINDENT +.SS duplicate\-data +.sp +Set/Get duplicate data filter. +.sp +Disables duplicate detection of advertisement data. +.sp +When enabled, PropertiesChanged signals will be generated for ManufacturerData +and ServiceData every time they are discovered. +.INDENT 0.0 +.TP +.B Usage +\fB# duplicate\-data [on/off]\fP +.UNINDENT +.SS discoverable +.sp +Set/Get discoverable filter. +.sp +Makes the adapter discoverable while discovering. +.sp +If the adapter is already discoverable, setting this filter won\(aqt have any +effect. +.INDENT 0.0 +.TP +.B Usage +\fB# discoverable [on/off]\fP +.UNINDENT +.SS pattern +.sp +Set/Get pattern filter. +.sp +Discover devices where the pattern matches either the prefix of the address or +the device name, which is a convenient way to limit the number of device objects +created during a discovery. +.sp +When set, it disregards device discoverable flags. +.INDENT 0.0 +.TP +.B Note +The pattern matching is ignored if there are other clients that don\(aqt +set any pattern, as it works as a logical OR. Also, setting an empty +string \(dq\(dq pattern will match any device found. +.TP +.B Usage +\fB# pattern [value]\fP +.UNINDENT +.SS clear +.sp +Clears discovery filter. +.INDENT 0.0 +.TP +.B Usage +\fB# clear [uuids/rssi/pathloss/transport/duplicate\-data/discoverable/pattern]\fP +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/client/bluetoothctl-scan.rst b/client/bluetoothctl-scan.rst new file mode 100644 index 0000000000000000000000000000000000000000..54ea2e8fe8e57f9be7b088534c8cc1e07677dd18 --- /dev/null +++ b/client/bluetoothctl-scan.rst @@ -0,0 +1,140 @@ +================= +bluetoothctl-scan +================= + +------------ +Scan Submenu +------------ + +:Version: BlueZ +:Copyright: Free use of this software is granted under ther terms of the GNU + Lesser General Public Licenses (LGPL). +:Date: July 2023 +:Manual section: 1 +:Manual group: Linux System Administration + +SYNOPSIS +======== + +**bluetoothctl** [--options] [scan.commands] + +Scan Commands +============= + +uuids +----- + +Set/Get UUIDs filter. + +:Usage: **# uuids [all/uuid1 uuid2 ...]** + +rssi +---- + +Set/Get RSSI filter, and clears pathloss. + +This sets the minimum rssi value for reporting device advertisements. + +The value is in dBm. + +If one or more discovery filters have been set, the RSSI delta-threshold imposed +by starting discovery by default will not be applied. + +:Usage: **# rssi [rssi]** +:Example: **# rssi -60** + +pathloss +-------- +Set/Get Pathloss filter, and clears RSSI. + +This sets the maximum pathloss value for reporting device advertisements. + +The value is in dB. + +If one or more discovery filters have been set, the RSSI delta-threshold +imposed by starting discovery by default will not be applied. + +:Usage: **# pathloss [pathloss]** +:Example: **# pathloss 4** + +transport +--------- + +Set/Get transport filter. + +Transport parameter determines the type of scan. + +The default is auto. + +Possible values: + +- "auto": interleaved scan +- "bredr": BR/EDR inquiry +- "le": LE scan only + +If "le" or "bredr" Transport is requested and the controller doesn't support it, +an org.bluez.Error.Failed error will be returned. + +If "auto" transport is requested, the scan will use LE, BREDR, or both, +depending on what's currently enabled on the controller. + +:Usage: **# transport [auto/bredr/le]** + +duplicate-data +-------------- + +Set/Get duplicate data filter. + +Disables duplicate detection of advertisement data. + +When enabled, PropertiesChanged signals will be generated for ManufacturerData +and ServiceData every time they are discovered. + +:Usage: **# duplicate-data [on/off]** + +discoverable +------------ + +Set/Get discoverable filter. + +Makes the adapter discoverable while discovering. + +If the adapter is already discoverable, setting this filter won't have any +effect. + +:Usage: **# discoverable [on/off]** + +pattern +------- + +Set/Get pattern filter. + +Discover devices where the pattern matches either the prefix of the address or +the device name, which is a convenient way to limit the number of device objects +created during a discovery. + +When set, it disregards device discoverable flags. + +:Note: The pattern matching is ignored if there are other clients that don't + set any pattern, as it works as a logical OR. Also, setting an empty + string "" pattern will match any device found. + +:Usage: **# pattern [value]** + + +clear +----- + +Clears discovery filter. + +:Usage: **# clear [uuids/rssi/pathloss/transport/duplicate-data/discoverable/pattern]** + +RESOURCES +========= + +http://www.bluez.org + +REPORTING BUGS +============== + +linux-bluetooth@vger.kernel.org diff --git a/client/bluetoothctl-transport.1 b/client/bluetoothctl-transport.1 new file mode 100644 index 0000000000000000000000000000000000000000..038da7ba5ae7f661b03e6b0bf6e4858095567731 --- /dev/null +++ b/client/bluetoothctl-transport.1 @@ -0,0 +1,140 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BLUETOOTHCTL-TRANSPORT" "1" "November 2022" "BlueZ" "Linux System Administration" +.SH NAME +bluetoothctl-transport \- Media Transport Submenu +.SH SYNOPSIS +.sp +\fBbluetoothctl\fP [\-\-options] [transport.commands] +.SH MEDIA TRANSPORT COMMANDS +.SS list +.sp +List available transports. +.INDENT 0.0 +.TP +.B Usage +\fB# list\fP +.UNINDENT +.SS show +.sp +Show transport information. +.INDENT 0.0 +.TP +.B Usage +\fB# show [transport]\fP +.UNINDENT +.SS acquire +.sp +Acquire transport. +.INDENT 0.0 +.TP +.B Usage +\fB# acquire <transport> [transport1...]\fP +.UNINDENT +.sp +Note: +.sp +If running the setup with an audio server that has LE Audio support (such as PipeWire) it will +automatically acquire transports according to the configured roles. +.SS select +.sp +Select transport. For transports created on a Broadcast Sink device only. This moves +the transport to the \(dqbroadcasting\(dq state, pending acquire. +.INDENT 0.0 +.TP +.B Usage +\fB# select <transport> [transport1...]\fP +.UNINDENT +.sp +Note: +If running the setup with an audio server that has LE Audio support (such as PipeWire), it will +prompt it to automatically acquire the transport. +.SS unselect +.sp +Unelect transport. For transports created on a Broadcast Sink device only. This moves +the transport to the \(dqidle\(dq state, pending release by the audio server. If the transport +was acquired by bluetoothctl it can be released straight away, without having to be +unselected. +.INDENT 0.0 +.TP +.B Usage +\fB# unselect <transport> [transport1...]\fP +.UNINDENT +.sp +Note: +If running the setup with an audio server that has LE Audio support (such as PipeWire), it will +prompt it to automatically release the transport. +.SS release +.sp +Release transport. +.INDENT 0.0 +.TP +.B Usage +\fB# release <transport> [transport1...]\fP +.UNINDENT +.sp +Note: +.sp +Transports acquired by an audio server, can only be released by said audio server. +.SS send +.sp +Send contents of a file. +.INDENT 0.0 +.TP +.B Usage +\fB# send <transport> <filename>\fP +.UNINDENT +.SS receive +.sp +Get/Set file to receive. +.INDENT 0.0 +.TP +.B Usage +\fB# receive <transport> [filename]\fP +.UNINDENT +.SS volume +.sp +Get/Set transport volume. +.INDENT 0.0 +.TP +.B Usage +\fB# volume <transport> [value]\fP +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/client/bluetoothctl-transport.rst b/client/bluetoothctl-transport.rst new file mode 100644 index 0000000000000000000000000000000000000000..96156a8cf87b644aa4de31a2438a5dd5cf20dbdd --- /dev/null +++ b/client/bluetoothctl-transport.rst @@ -0,0 +1,116 @@ +====================== +bluetoothctl-transport +====================== + +----------------------- +Media Transport Submenu +----------------------- + +:Version: BlueZ +:Copyright: Free use of this software is granted under ther terms of the GNU + Lesser General Public Licenses (LGPL). +:Date: November 2022 +:Manual section: 1 +:Manual group: Linux System Administration + +SYNOPSIS +======== + +**bluetoothctl** [--options] [transport.commands] + +Media Transport Commands +========================= + +list +---- + +List available transports. + +:Usage: **# list** + +show +---- + +Show transport information. + +:Usage: **# show [transport]** + +acquire +------- + +Acquire transport. + +:Usage: **# acquire <transport> [transport1...]** + +Note: + +If running the setup with an audio server that has LE Audio support (such as PipeWire) it will +automatically acquire transports according to the configured roles. + +select +------- + +Select transport. For transports created on a Broadcast Sink device only. This moves +the transport to the "broadcasting" state, pending acquire. + +:Usage: **# select <transport> [transport1...]** + +Note: +If running the setup with an audio server that has LE Audio support (such as PipeWire), it will +prompt it to automatically acquire the transport. + +unselect +-------- + +Unelect transport. For transports created on a Broadcast Sink device only. This moves +the transport to the "idle" state, pending release by the audio server. If the transport +was acquired by bluetoothctl it can be released straight away, without having to be +unselected. + +:Usage: **# unselect <transport> [transport1...]** + +Note: +If running the setup with an audio server that has LE Audio support (such as PipeWire), it will +prompt it to automatically release the transport. + +release +------- + +Release transport. + +:Usage: **# release <transport> [transport1...]** + +Note: + +Transports acquired by an audio server, can only be released by said audio server. + +send +---- + +Send contents of a file. + +:Usage: **# send <transport> <filename>** + +receive +------- + +Get/Set file to receive. + +:Usage: **# receive <transport> [filename]** + +volume +------ + +Get/Set transport volume. + +:Usage: **# volume <transport> [value]** + +RESOURCES +========= + +http://www.bluez.org + +REPORTING BUGS +============== + +linux-bluetooth@vger.kernel.org diff --git a/client/bluetoothctl.1 b/client/bluetoothctl.1 new file mode 100644 index 0000000000000000000000000000000000000000..7f3c61ada3b559f52ca0c0afe112267accfd3696 --- /dev/null +++ b/client/bluetoothctl.1 @@ -0,0 +1,401 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BLUETOOTHCTL" "1" "November 2022" "BlueZ" "Linux System Administration" +.SH NAME +bluetoothctl \- Bluetooth Control Command Line Tool +.SH SYNOPSIS +.sp +\fBbluetoothctl\fP [\fB\-a\fP \fIcapability\fP] [\fB\-e\fP] [\fB\-m\fP] [\fB\-t\fP \fIseconds\fP] +[\fB\-v\fP] [\fB\-h\fP] +.SH DESCRIPTION +.sp +\fBbluetoothctl(1)\fP interactive bluetooth control tool. The tool works with +Bluetooth Classic (BR/EDR) and Bluetooth Low Energy (LE) controllers. +.sp +The tool is menu driven but can be automated from the command line. +Examples are given in the automation section. +.SH OPTIONS +.INDENT 0.0 +.TP +.BI \-a \ capability\fR,\fB \ \-\-agent \ capability +Register agent handler: <capability> +.TP +.B \-e\fP,\fB \-\-endpoints +Register Media endpoints +.TP +.B \-m\fP,\fB \-\-monitor +Enable monitor output +.TP +.BI \-t \ seconds\fR,\fB \ \-\-timeout \ seconds +Timeout in seconds for non\-interactive mode +.TP +.B \-v\fP,\fB \-\-version +Display version +.TP +.B \-h\fP,\fB \-\-help +Display help +.UNINDENT +.SH COMMANDS +.SS list +.sp +List available controllers. +.INDENT 0.0 +.TP +.B Usage +\fB# list\fP +.UNINDENT +.SS show +.sp +Controller information. +.INDENT 0.0 +.TP +.B Usage +\fB# show [ctrl]\fP +.UNINDENT +.SS select +.sp +Select default controller. +.INDENT 0.0 +.TP +.B Usage +\fB# select <ctrl>\fP +.UNINDENT +.SS devices +.sp +List available devices, with an optional property as the filter. +.INDENT 0.0 +.TP +.B Usage +\fB# devices [Paired/Bonded/Trusted/Connected]\fP +.UNINDENT +.SS system\-alias +.sp +Set controller alias. +.INDENT 0.0 +.TP +.B Usage +\fB# system\-alias <name>\fP +.UNINDENT +.SS reset\-alias +.sp +Reset controller alias. +.INDENT 0.0 +.TP +.B Usage +\fB# reset\-alias\fP +.UNINDENT +.SS power +.sp +Set controller power. +.sp +When the controller is powered off, the USB port the controller is attached to +is put into a suspend state. +.INDENT 0.0 +.TP +.B Usage +\fB# power <on/off>\fP +.UNINDENT +.SS advertise +.sp +Enable/disable advertising with given type. +.sp +If you exit the program advertising will be disabled. +.sp +When advertising the controller should advertise with random address but may +use its public address if it does not support the feature (address of the +device). +.sp +A device can advertise if it initiated the connection to another advertising +device. +.INDENT 0.0 +.TP +.B Usage +\fB# advertise <on/off/type>\fP +.UNINDENT +.SS set\-alias +.sp +Set device alias. +.INDENT 0.0 +.TP +.B Usage +\fB# set\-alias <alias>\fP +.UNINDENT +.SS scan +.sp +Scan for devices. +.sp +For LE, scanning is an important requirement before connecting or pairing. +.sp +The purpose of scanning is to find devices that are advertising with their +discoverable flag set (either limited or general). Once you have found the +address then you can connect or pair. +.sp +Note the following when scanning: +.INDENT 0.0 +.INDENT 3.5 +.INDENT 0.0 +.IP \(bu 2 +When scanning the controller will use a random address that is not +resolvable so the public address is not leaked. A new random address is +created every time scan on is used. +.IP \(bu 2 +When turning on scanning the device will start receiving advertising reports +of what devices are advertising. +.IP \(bu 2 +The filtering of duplicate advertising reports may be enabled depending on +the filtering settings. +.IP \(bu 2 +Device objects found during a scan session will only be persisted if they +are connected/paired otherwise they are removed after some time. +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B Usage +\fB# scan <on/off/bredr/le>\fP +.UNINDENT +.SS pair +.sp +Pair with device. +.sp +This will pair with a device and then trust and connect to it. If the device is +already paired this will first remove the pairing. +.sp +The command can either be used while the controller is in the connected or not +connected state. +.sp +If the controller is already connected then the pair command can be used without +an arguments. If the controller is not connected, the pair command can be given +the address of a device with an active scan report and it will initiate the +connection before pairing. +.sp +Before pairing the agent must be selected to choose the authentication +mechanism. +.INDENT 0.0 +.TP +.B Usage +\fB# pair <dev>\fP +.UNINDENT +.SS pairable +.sp +Set controller pairable mode. +.sp +This enables/disables pairing. If pairing is disabled then the controller will +not accept any pairing requests. +.INDENT 0.0 +.TP +.B Usage +\fB# pairable <on/off>\fP +.UNINDENT +.SS discoverable +.sp +Set discoverable mode. +.sp +This enables/disables discoverable mode. If discoverable is disabled then the +controller will not respond to any scan requests. +.sp +In LE if discoverable if off the controller will just passively scan and not +make scan requests to advertising devices. If on it will make the advertising +requests. +.sp +It will use a random address if supported by the controller. The length of time +\(dqdiscoverable on\(dq is valid is determined by discoverable\-timeout command. +.INDENT 0.0 +.TP +.B Usage +\fB# discoverable <on/off>\fP +.UNINDENT +.SS discoverable\-timeout +.sp +Set discoverable timeout. +.sp +The time in seconds that \(dqdiscoverable on\(dq is valid. +.INDENT 0.0 +.TP +.B Usage +\fB# discoverable\-timeout [value]\fP +.UNINDENT +.SS agent +.sp +Enable/disable agent with given capability. +.sp +This chooses the local authentication mechanism of the controller. It is needed +for pairing and allows you to choose the IO capabilities of the controller. +.sp +The valid agent capabilities are: DisplayOnly, DisplayYesNo, KeyboardDisplay, +KeyboardOnly, NoInputNoOutput. +.INDENT 0.0 +.TP +.B Usage +\fB# agent <on/off/capability>\fP +.UNINDENT +.SS default\-agent +.sp +Set current agent as the default one. +.sp +After selecting the agent this will make it the default agent. +.INDENT 0.0 +.TP +.B Usage +\fB# default\-agent\fP +.UNINDENT +.SS trust +.sp +Trust device. +.INDENT 0.0 +.TP +.B Usage +\fB# trust <dev>\fP +.UNINDENT +.SS untrust +.sp +Untrust device. +.INDENT 0.0 +.TP +.B Usage +\fB# untrust <dev>\fP +.UNINDENT +.SS block +.sp +Block device. +.INDENT 0.0 +.TP +.B Usage +\fB# block <dev>\fP +.UNINDENT +.SS unblock +.sp +Unblock device +.INDENT 0.0 +.TP +.B Usage +\fB# unblock <dev>\fP +.UNINDENT +.SS remove +.sp +Remove device. +.INDENT 0.0 +.TP +.B Usage +\fB# remove <dev>\fP +.UNINDENT +.SS connect +.sp +Connect device. +.sp +This will initiate a connection to a device. +.sp +To connect with an LE device the controller must have an active scan report of +the device it wants to connect to. +.sp +If no advertising report is received before the timeout a +le\-connection\-abort\-by\-local error will be issued. In that case either try +again to connect assuming the device is advertising. +.INDENT 0.0 +.TP +.B Usage +\fB# connect <dev>\fP +.UNINDENT +.SS disconnect +.sp +Disconnect device. +.sp +For LE when disconnecting from an active connection the device address is not +needed. +.INDENT 0.0 +.TP +.B Usage +\fB# disconnect <dev>\fP +.UNINDENT +.SS info +.sp +Device information. +.INDENT 0.0 +.TP +.B Usage +\fB# info <dev>\fP +.UNINDENT +.SH ADVERTISE SUBMENU +.sp +See \fBbluetoothctl\-advertise(1)\fP\&. +.SH MONITOR SUBMENU +.sp +See \fBbluetoothctl\-monitor(1)\fP +.SH SCAN SUBMENU +.sp +See \fBbluetoothctl\-scan(1)\fP +.SH GATT SUBMENU +.sp +See \fBbluetoothctl\-gatt(1)\fP +.SH ADMIN SUBMENU +.sp +See \fBbluetoothctl\-admin(1)\fP +.SH PLAYER SUBMENU +.sp +See \fBbluetoothctl\-player(1)\fP +.SH ENDPOINT SUBMENU +.sp +See \fBbluetoothctl\-endpoint(1)\fP +.SH TRANSPORT SUBMENU +.sp +See \fBbluetoothctl\-transport(1)\fP +.SH MANAGEMENT SUBMENU +.sp +See \fBbluetoothctl\-mgmt(1)\fP +.SH ASSISTANT SUBMENU +.sp +See \fBbluetoothctl\-assistant(1)\fP +.SH AUTOMATION +.sp +Two common ways to automate the tool are to use Here Docs or the program expect. +Using Here Docs to show information about the Bluetooth controller. +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +bluetoothctl <<EOF +list +show +EOF +.EE +.UNINDENT +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH COPYRIGHT +Free use of this software is granted under the terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/client/bluetoothctl.rst b/client/bluetoothctl.rst new file mode 100644 index 0000000000000000000000000000000000000000..7454c1d085f87a53b2f53518c73305562ee85e3c --- /dev/null +++ b/client/bluetoothctl.rst @@ -0,0 +1,363 @@ +============ +bluetoothctl +============ + +----------------------------------- +Bluetooth Control Command Line Tool +----------------------------------- + +:Version: BlueZ +:Copyright: Free use of this software is granted under the terms of the GNU + Lesser General Public Licenses (LGPL). +:Date: November 2022 +:Manual section: 1 +:Manual group: Linux System Administration + +SYNOPSIS +======== + +**bluetoothctl** [**-a** *capability*] [**-e**] [**-m**] [**-t** *seconds*] +[**-v**] [**-h**] + +DESCRIPTION +=========== + +**bluetoothctl(1)** interactive bluetooth control tool. The tool works with +Bluetooth Classic (BR/EDR) and Bluetooth Low Energy (LE) controllers. + +The tool is menu driven but can be automated from the command line. +Examples are given in the automation section. + +OPTIONS +======= + +-a capability, --agent capability Register agent handler: <capability> +-e, --endpoints Register Media endpoints +-m, --monitor Enable monitor output +-t seconds, --timeout seconds Timeout in seconds for non-interactive mode +-v, --version Display version +-h, --help Display help + + +Commands +======== + +list +---- + +List available controllers. + +:Usage: **# list** + +show +---- + +Controller information. + +:Usage: **# show [ctrl]** + +select +------ + +Select default controller. + +:Usage: **# select <ctrl>** + +devices +------- + +List available devices, with an optional property as the filter. + +:Usage: **# devices [Paired/Bonded/Trusted/Connected]** + +system-alias +------------ + +Set controller alias. + +:Usage: **# system-alias <name>** + +reset-alias +----------- + +Reset controller alias. + +:Usage: **# reset-alias** + +power +----- + +Set controller power. + +When the controller is powered off, the USB port the controller is attached to +is put into a suspend state. + +:Usage: **# power <on/off>** + +advertise +--------- + +Enable/disable advertising with given type. + +If you exit the program advertising will be disabled. + +When advertising the controller should advertise with random address but may +use its public address if it does not support the feature (address of the +device). + +A device can advertise if it initiated the connection to another advertising +device. + +:Usage: **# advertise <on/off/type>** + +set-alias +--------- + +Set device alias. + +:Usage: **# set-alias <alias>** + +scan +---- + +Scan for devices. + +For LE, scanning is an important requirement before connecting or pairing. + +The purpose of scanning is to find devices that are advertising with their +discoverable flag set (either limited or general). Once you have found the +address then you can connect or pair. + +Note the following when scanning: + + - When scanning the controller will use a random address that is not + resolvable so the public address is not leaked. A new random address is + created every time scan on is used. + - When turning on scanning the device will start receiving advertising reports + of what devices are advertising. + - The filtering of duplicate advertising reports may be enabled depending on + the filtering settings. + - Device objects found during a scan session will only be persisted if they + are connected/paired otherwise they are removed after some time. + +:Usage: **# scan <on/off/bredr/le>** + +pair +---- + +Pair with device. + +This will pair with a device and then trust and connect to it. If the device is +already paired this will first remove the pairing. + +The command can either be used while the controller is in the connected or not +connected state. + +If the controller is already connected then the pair command can be used without +an arguments. If the controller is not connected, the pair command can be given +the address of a device with an active scan report and it will initiate the +connection before pairing. + +Before pairing the agent must be selected to choose the authentication +mechanism. + +:Usage: **# pair <dev>** + +pairable +-------- + +Set controller pairable mode. + +This enables/disables pairing. If pairing is disabled then the controller will +not accept any pairing requests. + +:Usage: **# pairable <on/off>** + +discoverable +------------ + +Set discoverable mode. + +This enables/disables discoverable mode. If discoverable is disabled then the +controller will not respond to any scan requests. + +In LE if discoverable if off the controller will just passively scan and not +make scan requests to advertising devices. If on it will make the advertising +requests. + +It will use a random address if supported by the controller. The length of time +"discoverable on" is valid is determined by discoverable-timeout command. + +:Usage: **# discoverable <on/off>** + +discoverable-timeout +-------------------- + +Set discoverable timeout. + +The time in seconds that "discoverable on" is valid. + +:Usage: **# discoverable-timeout [value]** + +agent +----- + +Enable/disable agent with given capability. + +This chooses the local authentication mechanism of the controller. It is needed +for pairing and allows you to choose the IO capabilities of the controller. + +The valid agent capabilities are: DisplayOnly, DisplayYesNo, KeyboardDisplay, +KeyboardOnly, NoInputNoOutput. + +:Usage: **# agent <on/off/capability>** + +default-agent +------------- + +Set current agent as the default one. + +After selecting the agent this will make it the default agent. + +:Usage: **# default-agent** + +trust +----- + +Trust device. + +:Usage: **# trust <dev>** + +untrust +------- + +Untrust device. + +:Usage: **# untrust <dev>** + +block +----- + +Block device. + +:Usage: **# block <dev>** + +unblock +------- +Unblock device + +:Usage: **# unblock <dev>** + +remove +------ + +Remove device. + +:Usage: **# remove <dev>** + +connect +------- + +Connect device. + +This will initiate a connection to a device. + +To connect with an LE device the controller must have an active scan report of +the device it wants to connect to. + +If no advertising report is received before the timeout a +le-connection-abort-by-local error will be issued. In that case either try +again to connect assuming the device is advertising. + +:Usage: **# connect <dev>** + +disconnect +---------- + +Disconnect device. + +For LE when disconnecting from an active connection the device address is not +needed. + +:Usage: **# disconnect <dev>** + +info +---- + +Device information. + +:Usage: **# info <dev>** + + +Advertise Submenu +================= + +See **bluetoothctl-advertise(1)**. + +Monitor Submenu +=============== + +See **bluetoothctl-monitor(1)** + +Scan Submenu +============ + +See **bluetoothctl-scan(1)** + +Gatt Submenu +============ + +See **bluetoothctl-gatt(1)** + +Admin Submenu +============= + +See **bluetoothctl-admin(1)** + +Player Submenu +============== + +See **bluetoothctl-player(1)** + +Endpoint Submenu +================ + +See **bluetoothctl-endpoint(1)** + +Transport Submenu +================= + +See **bluetoothctl-transport(1)** + +Management Submenu +================== + +See **bluetoothctl-mgmt(1)** + +Assistant Submenu +================== + +See **bluetoothctl-assistant(1)** + +AUTOMATION +========== +Two common ways to automate the tool are to use Here Docs or the program expect. +Using Here Docs to show information about the Bluetooth controller. + +.. code:: + + bluetoothctl <<EOF + list + show + EOF + + +RESOURCES +========= + +http://www.bluez.org + +REPORTING BUGS +============== + +linux-bluetooth@vger.kernel.org diff --git a/client/gatt.c b/client/gatt.c index 8f2920269118ff003dc4860edac6dbb92ca11d30..4dac8859060ba27c83064ca0ec3d4b65c97e8459 100644 --- a/client/gatt.c +++ b/client/gatt.c @@ -4,6 +4,7 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2014 Intel Corporation. All rights reserved. + * Copyright 2024 NXP * * */ @@ -164,6 +165,7 @@ static void print_service_proxy(GDBusProxy *proxy, const char *description) DBusMessageIter iter; const char *uuid; dbus_bool_t primary; + uint16_t handle; if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE) return; @@ -175,10 +177,16 @@ static void print_service_proxy(GDBusProxy *proxy, const char *description) dbus_message_iter_get_basic(&iter, &primary); + if (g_dbus_proxy_get_property(proxy, "Handle", &iter) == FALSE) + return; + + dbus_message_iter_get_basic(&iter, &handle); + memset(&service, 0, sizeof(service)); service.path = (char *) g_dbus_proxy_get_path(proxy); service.uuid = (char *) uuid; service.primary = primary; + service.handle = handle; print_service(&service, description); } @@ -252,15 +260,22 @@ static void print_characteristic(GDBusProxy *proxy, const char *description) struct chrc chrc; DBusMessageIter iter; const char *uuid; + uint16_t handle; if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE) return; dbus_message_iter_get_basic(&iter, &uuid); + if (g_dbus_proxy_get_property(proxy, "Handle", &iter) == FALSE) + return; + + dbus_message_iter_get_basic(&iter, &handle); + memset(&chrc, 0, sizeof(chrc)); chrc.path = (char *) g_dbus_proxy_get_path(proxy); chrc.uuid = (char *) uuid; + chrc.handle = handle; print_chrc(&chrc, description); } @@ -346,15 +361,22 @@ static void print_descriptor(GDBusProxy *proxy, const char *description) struct desc desc; DBusMessageIter iter; const char *uuid; + uint16_t handle; if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE) return; dbus_message_iter_get_basic(&iter, &uuid); + if (g_dbus_proxy_get_property(proxy, "Handle", &iter) == FALSE) + return; + + dbus_message_iter_get_basic(&iter, &handle); + memset(&desc, 0, sizeof(desc)); desc.path = (char *) g_dbus_proxy_get_path(proxy); desc.uuid = (char *) uuid; + desc.handle = handle; print_desc(&desc, description); } @@ -554,6 +576,241 @@ GDBusProxy *gatt_select_attribute(GDBusProxy *parent, const char *arg) return select_attribute_by_uuid(NULL, arg); } +static char *find_local_attribute(const char *arg, + struct service **service, + struct chrc **chrc, struct desc **desc) +{ + GList *l; + + for (l = local_services; l; l = g_list_next(l)) { + struct service *s = l->data; + GList *cl; + + if (!strcmp(arg, s->path)) { + if (service) + *service = s; + return s->path; + } + + if (!strcmp(arg, s->uuid)) { + if (service) + *service = s; + return s->path; + } + + for (cl = s->chrcs; cl; cl = g_list_next(cl)) { + struct chrc *c = cl->data; + GList *dl; + + if (!strcmp(arg, c->path)) { + if (chrc) + *chrc = c; + return c->path; + } + + if (!strcmp(arg, c->uuid)) { + if (chrc) + *chrc = c; + return c->path; + } + + for (dl = c->descs; dl; dl = g_list_next(dl)) { + struct desc *d = dl->data; + + if (!strcmp(arg, d->path)) { + if (desc) + *desc = d; + return d->path; + } + + if (!strcmp(arg, d->uuid)) { + if (desc) + *desc = d; + return d->path; + } + } + } + } + + return NULL; +} + +char *gatt_select_local_attribute(const char *arg) +{ + return find_local_attribute(arg, NULL, NULL, NULL); +} + +static int parse_offset(const char *arg) +{ + char *endptr = NULL; + unsigned long offset; + + offset = strtoul(arg, &endptr, 0); + if (!endptr || *endptr != '\0' || offset > UINT16_MAX) { + bt_shell_printf("Invalid offload: %s", arg); + return -EINVAL; + } + + return offset; +} + +void gatt_read_local_attribute(char *data, int argc, char *argv[]) +{ + int offset = 0; + struct service *s = NULL; + struct chrc *c = NULL; + struct desc *d = NULL; + + if (!find_local_attribute(data, &s, &c, &d)) { + bt_shell_printf("Unable to find local attribute %s\n", data); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (argc > 1) { + offset = parse_offset(argv[1]); + if (offset < 0) + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (s) { + bt_shell_printf("UUID %s", s->uuid); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + } + + if (c) { + if ((size_t)offset >= c->value_len) { + bt_shell_printf("Invalid offset: %d >= %zd", offset, + c->value_len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + bt_shell_hexdump(&c->value[offset], c->value_len - offset); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + } + + if (d) { + if ((size_t)offset >= d->value_len) { + bt_shell_printf("Invalid offset: %d >= %zd", offset, + d->value_len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + bt_shell_hexdump(&d->value[offset], d->value_len - offset); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + } +} + +static uint8_t *str2bytearray(char *arg, size_t *val_len) +{ + uint8_t value[MAX_ATTR_VAL_LEN]; + char *entry; + unsigned int i; + + for (i = 0; (entry = strsep(&arg, " \t")) != NULL; i++) { + long val; + char *endptr = NULL; + + if (*entry == '\0') + continue; + + if (i >= G_N_ELEMENTS(value)) { + bt_shell_printf("Too much data\n"); + return NULL; + } + + val = strtol(entry, &endptr, 0); + if (!endptr || *endptr != '\0' || val > UINT8_MAX) { + bt_shell_printf("Invalid value at index %d\n", i); + return NULL; + } + + value[i] = val; + } + + *val_len = i; + + return util_memdup(value, i); +} + +static int write_value(size_t *dst_len, uint8_t **dst_value, uint8_t *src_val, + size_t src_len, uint16_t offset, uint16_t max_len) +{ + if ((offset + src_len) > max_len) + return -EOVERFLOW; + + if ((offset + src_len) != *dst_len) { + *dst_len = offset + src_len; + *dst_value = g_realloc(*dst_value, *dst_len); + } + + if (src_val && src_len) + memcpy(*dst_value + offset, src_val, src_len); + + return 0; +} + +void gatt_write_local_attribute(char *data, int argc, char *argv[]) +{ + int offset = 0; + struct service *s = NULL; + struct chrc *c = NULL; + struct desc *d = NULL; + uint8_t *value; + size_t value_len; + + if (!find_local_attribute(data, &s, &c, &d)) { + bt_shell_printf("Unable to find local attribute %s\n", data); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + value = str2bytearray(argv[1], &value_len); + if (!value) + return bt_shell_noninteractive_quit(EXIT_FAILURE); + + if (argc > 2) { + offset = parse_offset(argv[2]); + if (offset < 0) + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (s) { + bt_shell_printf("Unable to overwrite local service %s\n", data); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (c) { + if (write_value(&c->value_len, &c->value, + value, value_len, + offset, c->max_val_len)) { + bt_shell_printf("Unable to write local attribute %s\n", + data); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + bt_shell_printf("[" COLORED_CHG "] Attribute %s (%s) written\n", + c->path, bt_uuidstr_to_str(c->uuid)); + + g_dbus_emit_property_changed(c->service->conn, c->path, + CHRC_INTERFACE, "Value"); + } + + if (d) { + if (write_value(&d->value_len, &d->value, + value, value_len, + offset, d->max_val_len)) { + bt_shell_printf("Unable to write local attribute %s\n", + data); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + bt_shell_printf("[" COLORED_CHG "] Attribute %s (%s) written\n", + d->path, bt_uuidstr_to_str(d->uuid)); + + g_dbus_emit_property_changed(d->chrc->service->conn, d->path, + DESC_INTERFACE, "Value"); + } + + free(value); +} + static char *attribute_generator(const char *text, int state, GList *source) { static int index; @@ -650,20 +907,6 @@ static void read_attribute(GDBusProxy *proxy, uint16_t offset) bt_shell_printf("Attempting to read %s\n", g_dbus_proxy_get_path(proxy)); } -static int parse_offset(const char *arg) -{ - char *endptr = NULL; - unsigned long offset; - - offset = strtoul(arg, &endptr, 0); - if (!endptr || *endptr != '\0' || offset > UINT16_MAX) { - bt_shell_printf("Invalid offload: %s", arg); - return -EINVAL; - } - - return offset; -} - void gatt_read_attribute(GDBusProxy *proxy, int argc, char *argv[]) { const char *iface; @@ -744,11 +987,15 @@ static int sock_send(struct io *io, struct iovec *iov, size_t iovlen) struct msghdr msg; int ret; + ret = io_get_fd(io); + if (ret < 0) + return ret; + memset(&msg, 0, sizeof(msg)); msg.msg_iov = iov; msg.msg_iovlen = iovlen; - ret = sendmsg(io_get_fd(io), &msg, MSG_NOSIGNAL); + ret = sendmsg(ret, &msg, MSG_NOSIGNAL); if (ret < 0) { ret = -errno; bt_shell_printf("sendmsg: %s", strerror(-ret)); @@ -782,38 +1029,6 @@ static void write_attribute(GDBusProxy *proxy, g_dbus_proxy_get_path(proxy)); } -static uint8_t *str2bytearray(char *arg, size_t *val_len) -{ - uint8_t value[MAX_ATTR_VAL_LEN]; - char *entry; - unsigned int i; - - for (i = 0; (entry = strsep(&arg, " \t")) != NULL; i++) { - long int val; - char *endptr = NULL; - - if (*entry == '\0') - continue; - - if (i >= G_N_ELEMENTS(value)) { - bt_shell_printf("Too much data\n"); - return NULL; - } - - val = strtol(entry, &endptr, 0); - if (!endptr || *endptr != '\0' || val > UINT8_MAX) { - bt_shell_printf("Invalid value at index %d\n", i); - return NULL; - } - - value[i] = val; - } - - *val_len = i; - - return util_memdup(value, i); -} - void gatt_write_attribute(GDBusProxy *proxy, int argc, char *argv[]) { const char *iface; @@ -862,6 +1077,11 @@ static bool sock_read(struct io *io, void *user_data) if (io != notify_io.io && !chrc) return true; + if (fd < 0) { + bt_shell_printf("recvmsg: %s", strerror(-fd)); + return false; + } + iov.iov_base = buf; iov.iov_len = sizeof(buf); @@ -1212,7 +1432,7 @@ static gboolean get_uuids(const GDBusPropertyTable *property, dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &entry); - for (uuid = uuids; uuid; uuid = g_list_next(uuid->next)) + for (uuid = uuids; uuid; uuid = g_list_next(uuid)) dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &uuid->data); @@ -1238,7 +1458,7 @@ void gatt_register_app(DBusConnection *conn, GDBusProxy *proxy, return bt_shell_noninteractive_quit(EXIT_FAILURE); } - for (i = 0; i < argc; i++) + for (i = 1; i < argc; i++) uuids = g_list_append(uuids, g_strdup(argv[i])); if (uuids) { @@ -1496,6 +1716,8 @@ static void service_set_primary(const char *input, void *user_data) g_dbus_unregister_interface(service->conn, service->path, SERVICE_INTERFACE); } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static uint16_t parse_handle(const char *arg) @@ -1548,8 +1770,6 @@ void gatt_register_service(DBusConnection *conn, GDBusProxy *proxy, bt_shell_prompt_input(service->path, "Primary (yes/no):", service_set_primary, service); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static struct service *service_find(const char *pattern) @@ -2132,23 +2352,6 @@ static int parse_value_arg(DBusMessageIter *iter, uint8_t **value, int *len) return 0; } -static int write_value(size_t *dst_len, uint8_t **dst_value, uint8_t *src_val, - size_t src_len, uint16_t offset, uint16_t max_len) -{ - if ((offset + src_len) > max_len) - return -EOVERFLOW; - - if ((offset + src_len) != *dst_len) { - *dst_len = offset + src_len; - *dst_value = g_realloc(*dst_value, *dst_len); - } - - if (src_val && src_len) - memcpy(*dst_value + offset, src_val, src_len); - - return 0; -} - static void authorize_write_response(const char *input, void *user_data) { struct authorize_attribute_data *aad = user_data; @@ -2589,6 +2792,8 @@ static void chrc_set_value(const char *input, void *user_data) } chrc->max_val_len = chrc->value_len; + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static gboolean attr_authorization_flag_exists(char **flags) @@ -2645,8 +2850,6 @@ void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy, print_chrc(chrc, COLORED_NEW); bt_shell_prompt_input(chrc->path, "Enter value:", chrc_set_value, chrc); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static struct chrc *chrc_find(const char *pattern) @@ -3015,9 +3218,13 @@ static void proxy_property_changed(GDBusProxy *proxy, const char *name, dbus_message_iter_get_fixed_array(&array, &value, &len); } - write_value(&chrc->value_len, &chrc->value, value, len, - 0, chrc->max_val_len); - bt_shell_hexdump(value, len); + if (write_value(&chrc->value_len, &chrc->value, value, len, + 0, chrc->max_val_len)) { + bt_shell_printf("Unable to update property value for " + "%s\n", name); + } else { + bt_shell_hexdump(value, len); + } } g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE, name); diff --git a/client/gatt.h b/client/gatt.h index fc2b8a8a643cf4499fe86b27f500fb9870457120..bed9d3a68ba684bf4dd13dbc7b03cd6f9d198ff4 100644 --- a/client/gatt.h +++ b/client/gatt.h @@ -32,6 +32,10 @@ void gatt_release_write(GDBusProxy *proxy, const char *arg); void gatt_acquire_notify(GDBusProxy *proxy, const char *arg); void gatt_release_notify(GDBusProxy *proxy, const char *arg); +char *gatt_select_local_attribute(const char *arg); +void gatt_read_local_attribute(char *data, int argc, char *argv[]); +void gatt_write_local_attribute(char *data, int argc, char *argv[]); + void gatt_add_manager(GDBusProxy *proxy); void gatt_remove_manager(GDBusProxy *proxy); diff --git a/client/main.c b/client/main.c index 2816e880f151d8ccfcd5754071838f0e16c45a72..3f8143dde4b817544603e17db8c3a61674b114c9 100644 --- a/client/main.c +++ b/client/main.c @@ -4,7 +4,7 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2012 Intel Corporation. All rights reserved. - * + * Copyright 2024 NXP * */ @@ -22,22 +22,28 @@ #include <glib.h> +#include "src/shared/mainloop.h" #include "src/shared/shell.h" +#include "src/shared/timeout.h" #include "src/shared/util.h" +#include "src/shared/ad.h" #include "gdbus/gdbus.h" +#include "print.h" #include "agent.h" #include "gatt.h" #include "advertising.h" #include "adv_monitor.h" #include "admin.h" #include "player.h" +#include "mgmt.h" +#include "assistant.h" /* String display constants */ #define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF #define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF #define COLORED_DEL COLOR_RED "DEL" COLOR_OFF -#define PROMPT_ON COLOR_BLUE "[bluetooth]" COLOR_OFF "# " +#define PROMPT_ON "[bluetooth]# " #define PROMPT_OFF "Waiting to connect to bluetoothd..." static DBusConnection *dbus_conn; @@ -50,10 +56,12 @@ struct adapter { GDBusProxy *ad_proxy; GDBusProxy *adv_monitor_proxy; GList *devices; + GList *sets; }; static struct adapter *default_ctrl; static GDBusProxy *default_dev; +static char *default_local_attr; static GDBusProxy *default_attr; static GList *ctrl_list; static GList *battery_proxies; @@ -61,6 +69,7 @@ static GList *battery_proxies; static const char *agent_arguments[] = { "on", "off", + "auto", "DisplayOnly", "DisplayYesNo", "KeyboardDisplay", @@ -97,14 +106,14 @@ static void setup_standard_input(void) static void connect_handler(DBusConnection *connection, void *user_data) { - bt_shell_set_prompt(PROMPT_ON); + bt_shell_set_prompt(PROMPT_ON, COLOR_BLUE); } static void disconnect_handler(DBusConnection *connection, void *user_data) { bt_shell_detach(); - bt_shell_set_prompt(PROMPT_OFF); + bt_shell_set_prompt(PROMPT_OFF, NULL); g_list_free_full(ctrl_list, proxy_leak); g_list_free_full(battery_proxies, proxy_leak); @@ -140,10 +149,32 @@ static void print_adapter(GDBusProxy *proxy, const char *description) } +#define DISTANCE_VAL_INVALID 0x7FFF + +static struct set_discovery_filter_args { + char *transport; + char *pattern; + dbus_uint16_t rssi; + dbus_int16_t pathloss; + char **uuids; + size_t uuids_len; + dbus_bool_t duplicate; + dbus_bool_t discoverable; + bool set; + bool active; + unsigned int timeout; +} filter = { + .rssi = DISTANCE_VAL_INVALID, + .pathloss = DISTANCE_VAL_INVALID, + .set = true, +}; + static void print_device(GDBusProxy *proxy, const char *description) { DBusMessageIter iter; const char *address, *name; + uint8_t *flags; + int flags_len = 0; if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE) return; @@ -155,203 +186,39 @@ static void print_device(GDBusProxy *proxy, const char *description) else name = "<unknown>"; - bt_shell_printf("%s%s%sDevice %s %s\n", - description ? "[" : "", - description ? : "", - description ? "] " : "", - address, name); -} - -static void print_fixed_iter(const char *label, const char *name, - DBusMessageIter *iter) -{ - dbus_bool_t *valbool; - dbus_uint32_t *valu32; - dbus_uint16_t *valu16; - dbus_int16_t *vals16; - unsigned char *byte; - int len; - - switch (dbus_message_iter_get_arg_type(iter)) { - case DBUS_TYPE_BOOLEAN: - dbus_message_iter_get_fixed_array(iter, &valbool, &len); - - if (len <= 0) - return; - - bt_shell_printf("%s%s:\n", label, name); - bt_shell_hexdump((void *)valbool, len * sizeof(*valbool)); - - break; - case DBUS_TYPE_UINT32: - dbus_message_iter_get_fixed_array(iter, &valu32, &len); - - if (len <= 0) - return; - - bt_shell_printf("%s%s:\n", label, name); - bt_shell_hexdump((void *)valu32, len * sizeof(*valu32)); - - break; - case DBUS_TYPE_UINT16: - dbus_message_iter_get_fixed_array(iter, &valu16, &len); - - if (len <= 0) - return; - - bt_shell_printf("%s%s:\n", label, name); - bt_shell_hexdump((void *)valu16, len * sizeof(*valu16)); - - break; - case DBUS_TYPE_INT16: - dbus_message_iter_get_fixed_array(iter, &vals16, &len); + if (g_dbus_proxy_get_property(proxy, "AdvertisingFlags", &iter)) { + DBusMessageIter array; - if (len <= 0) - return; - - bt_shell_printf("%s%s:\n", label, name); - bt_shell_hexdump((void *)vals16, len * sizeof(*vals16)); + dbus_message_iter_recurse(&iter, &array); + dbus_message_iter_get_fixed_array(&array, &flags, &flags_len); + } - break; - case DBUS_TYPE_BYTE: - dbus_message_iter_get_fixed_array(iter, &byte, &len); + if (!flags_len) + goto done; - if (len <= 0) + if (!(flags[0] & (BT_AD_FLAG_LIMITED | BT_AD_FLAG_GENERAL))) { + /* Only print hidden/non-discoverable if filter.discoverable is + * not set. + */ + if (filter.discoverable) return; - bt_shell_printf("%s%s:\n", label, name); - bt_shell_hexdump((void *)byte, len * sizeof(*byte)); + bt_shell_printf("%s%s%s" COLOR_BOLDGRAY "Device %s %s" + COLOR_OFF "\n", + description ? "[" : "", + description ? : "", + description ? "] " : "", + address, name); - break; - default: - return; - }; -} - -static void print_iter(const char *label, const char *name, - DBusMessageIter *iter) -{ - dbus_bool_t valbool; - dbus_uint32_t valu32; - dbus_uint16_t valu16; - dbus_int16_t vals16; - unsigned char byte; - const char *valstr; - DBusMessageIter subiter; - char *entry; - - if (iter == NULL) { - bt_shell_printf("%s%s is nil\n", label, name); return; } - switch (dbus_message_iter_get_arg_type(iter)) { - case DBUS_TYPE_INVALID: - bt_shell_printf("%s%s is invalid\n", label, name); - break; - case DBUS_TYPE_STRING: - case DBUS_TYPE_OBJECT_PATH: - dbus_message_iter_get_basic(iter, &valstr); - bt_shell_printf("%s%s: %s\n", label, name, valstr); - break; - case DBUS_TYPE_BOOLEAN: - dbus_message_iter_get_basic(iter, &valbool); - bt_shell_printf("%s%s: %s\n", label, name, - valbool == TRUE ? "yes" : "no"); - break; - case DBUS_TYPE_UINT32: - dbus_message_iter_get_basic(iter, &valu32); - bt_shell_printf("%s%s: 0x%08x\n", label, name, valu32); - break; - case DBUS_TYPE_UINT16: - dbus_message_iter_get_basic(iter, &valu16); - bt_shell_printf("%s%s: 0x%04x\n", label, name, valu16); - break; - case DBUS_TYPE_INT16: - dbus_message_iter_get_basic(iter, &vals16); - bt_shell_printf("%s%s: %d\n", label, name, vals16); - break; - case DBUS_TYPE_BYTE: - dbus_message_iter_get_basic(iter, &byte); - bt_shell_printf("%s%s: 0x%02x (%d)\n", label, name, byte, byte); - break; - case DBUS_TYPE_VARIANT: - dbus_message_iter_recurse(iter, &subiter); - print_iter(label, name, &subiter); - break; - case DBUS_TYPE_ARRAY: - dbus_message_iter_recurse(iter, &subiter); - - if (dbus_type_is_fixed( - dbus_message_iter_get_arg_type(&subiter))) { - print_fixed_iter(label, name, &subiter); - break; - } - - while (dbus_message_iter_get_arg_type(&subiter) != - DBUS_TYPE_INVALID) { - print_iter(label, name, &subiter); - dbus_message_iter_next(&subiter); - } - break; - case DBUS_TYPE_DICT_ENTRY: - dbus_message_iter_recurse(iter, &subiter); - entry = g_strconcat(name, " Key", NULL); - print_iter(label, entry, &subiter); - g_free(entry); - - entry = g_strconcat(name, " Value", NULL); - dbus_message_iter_next(&subiter); - print_iter(label, entry, &subiter); - g_free(entry); - break; - default: - bt_shell_printf("%s%s has unsupported type\n", label, name); - break; - } -} - -static void print_property_with_label(GDBusProxy *proxy, const char *name, - const char *label) -{ - DBusMessageIter iter; - - if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE) - return; - - print_iter("\t", label ? label : name, &iter); -} - -static void print_property(GDBusProxy *proxy, const char *name) -{ - print_property_with_label(proxy, name, NULL); -} - -static void print_uuid(const char *label, const char *uuid) -{ - const char *text; - - text = bt_uuidstr_to_str(uuid); - if (text) { - char str[26]; - unsigned int n; - - str[sizeof(str) - 1] = '\0'; - - n = snprintf(str, sizeof(str), "%s", text); - if (n > sizeof(str) - 1) { - str[sizeof(str) - 2] = '.'; - str[sizeof(str) - 3] = '.'; - if (str[sizeof(str) - 4] == ' ') - str[sizeof(str) - 4] = '.'; - - n = sizeof(str) - 1; - } - - bt_shell_printf("\t%s: %s%*c(%s)\n", label, str, 26 - n, ' ', - uuid); - } else - bt_shell_printf("\t%s: %*c(%s)\n", label, 26, ' ', uuid); +done: + bt_shell_printf("%s%s%sDevice %s %s\n", + description ? "[" : "", + description ? : "", + description ? "] " : "", + address, name); } static void print_uuids(GDBusProxy *proxy) @@ -368,7 +235,7 @@ static void print_uuids(GDBusProxy *proxy) dbus_message_iter_get_basic(&value, &uuid); - print_uuid("UUID", uuid); + print_uuid("\t", "UUID", uuid); dbus_message_iter_next(&value); } @@ -389,13 +256,13 @@ static void print_experimental(GDBusProxy *proxy) dbus_message_iter_get_basic(&value, &uuid); - print_uuid("ExperimentalFeatures", uuid); + print_uuid("\t", "ExperimentalFeatures", uuid); dbus_message_iter_next(&value); } } -static gboolean device_is_child(GDBusProxy *device, GDBusProxy *parent) +static gboolean proxy_is_child(GDBusProxy *device, GDBusProxy *parent) { DBusMessageIter iter; const char *adapter, *path; @@ -432,14 +299,14 @@ static gboolean service_is_child(GDBusProxy *service) "org.bluez.Device1") != NULL; } -static struct adapter *find_parent(GDBusProxy *device) +static struct adapter *find_parent(GDBusProxy *proxy) { GList *list; for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) { struct adapter *adapter = list->data; - if (device_is_child(device, adapter->proxy) == TRUE) + if (proxy_is_child(proxy, adapter->proxy) == TRUE) return adapter; } return NULL; @@ -466,12 +333,12 @@ static void set_default_device(GDBusProxy *proxy, const char *attribute) path = g_dbus_proxy_get_path(proxy); dbus_message_iter_get_basic(&iter, &desc); - desc = g_strdup_printf(COLOR_BLUE "[%s%s%s]" COLOR_OFF "# ", desc, + desc = g_strdup_printf("[%s%s%s]# ", desc, attribute ? ":" : "", attribute ? attribute + strlen(path) : ""); done: - bt_shell_set_prompt(desc ? desc : PROMPT_ON); + bt_shell_set_prompt(desc ? desc : PROMPT_ON, COLOR_BLUE); g_free(desc); } @@ -562,6 +429,27 @@ static void admon_manager_added(GDBusProxy *proxy) adv_monitor_register_app(dbus_conn); } +static void print_set(GDBusProxy *proxy, const char *description) +{ + bt_shell_printf("%s%s%sDeviceSet %s\n", + description ? "[" : "", + description ? : "", + description ? "] " : "", + g_dbus_proxy_get_path(proxy)); +} + +static void set_added(GDBusProxy *proxy) +{ + struct adapter *adapter = find_parent(proxy); + + if (!adapter) + return; + + adapter->sets = g_list_append(adapter->sets, proxy); + print_set(proxy, COLORED_NEW); + bt_shell_set_env(g_dbus_proxy_get_path(proxy), proxy); +} + static void proxy_added(GDBusProxy *proxy, void *user_data) { const char *interface; @@ -597,6 +485,8 @@ static void proxy_added(GDBusProxy *proxy, void *user_data) } else if (!strcmp(interface, "org.bluez.AdvertisementMonitorManager1")) { admon_manager_added(proxy); + } else if (!strcmp(interface, "org.bluez.DeviceSet1")) { + set_added(proxy); } } @@ -604,6 +494,7 @@ static void set_default_attribute(GDBusProxy *proxy) { const char *path; + default_local_attr = NULL; default_attr = proxy; path = g_dbus_proxy_get_path(proxy); @@ -646,6 +537,7 @@ static void adapter_removed(GDBusProxy *proxy) ctrl_list = g_list_remove_link(ctrl_list, ll); g_list_free(adapter->devices); + g_list_free(adapter->sets); g_free(adapter); g_list_free(ll); return; @@ -653,6 +545,19 @@ static void adapter_removed(GDBusProxy *proxy) } } +static void set_removed(GDBusProxy *proxy) +{ + struct adapter *adapter = find_parent(proxy); + + if (!adapter) + return; + + adapter->sets = g_list_remove(adapter->sets, proxy); + + print_set(proxy, COLORED_DEL); + bt_shell_set_env(g_dbus_proxy_get_path(proxy), NULL); +} + static void proxy_removed(GDBusProxy *proxy, void *user_data) { const char *interface; @@ -693,6 +598,8 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data) } else if (!strcmp(interface, "org.bluez.AdvertisementMonitorManager1")) { adv_monitor_remove_manager(dbus_conn); + } else if (!strcmp(interface, "org.bluez.DeviceSet1")) { + set_removed(proxy); } } @@ -719,7 +626,7 @@ static void property_changed(GDBusProxy *proxy, const char *name, interface = g_dbus_proxy_get_interface(proxy); if (!strcmp(interface, "org.bluez.Device1")) { - if (default_ctrl && device_is_child(proxy, + if (default_ctrl && proxy_is_child(proxy, default_ctrl->proxy) == TRUE) { DBusMessageIter addr_iter; char *str; @@ -899,6 +806,11 @@ static gboolean parse_argument(int argc, char *argv[], const char **arg_table, { const char **opt; + if (argc < 2) { + bt_shell_printf("Missing argument to %s\n", argv[0]); + return FALSE; + } + if (!strcmp(argv[1], "help")) { for (opt = arg_table; opt && *opt; opt++) bt_shell_printf("%s\n", *opt); @@ -977,6 +889,8 @@ static void cmd_show(int argc, char *argv[]) bt_shell_printf("Controller %s\n", address); } + print_property(adapter->proxy, "Manufacturer"); + print_property(adapter->proxy, "Version"); print_property(adapter->proxy, "Name"); print_property(adapter->proxy, "Alias"); print_property(adapter->proxy, "Class"); @@ -1156,6 +1070,7 @@ static void cmd_pairable(int argc, char *argv[]) static void cmd_discoverable(int argc, char *argv[]) { + DBusMessageIter iter; dbus_bool_t discoverable; char *str; @@ -1165,6 +1080,18 @@ static void cmd_discoverable(int argc, char *argv[]) if (check_default_ctrl() == FALSE) return bt_shell_noninteractive_quit(EXIT_FAILURE); + if (discoverable && g_dbus_proxy_get_property(default_ctrl->proxy, + "DiscoverableTimeout", &iter)) { + uint32_t value; + + dbus_message_iter_get_basic(&iter, &value); + + if (!value) + bt_shell_printf("Warning: setting discoverable while " + "discoverable-timeout not set(0) is not" + " recommended\n"); + } + str = g_strdup_printf("discoverable %s", discoverable == TRUE ? "on" : "off"); @@ -1255,26 +1182,6 @@ static void cmd_default_agent(int argc, char *argv[]) agent_default(dbus_conn, agent_manager); } -#define DISTANCE_VAL_INVALID 0x7FFF - -static struct set_discovery_filter_args { - char *transport; - char *pattern; - dbus_uint16_t rssi; - dbus_int16_t pathloss; - char **uuids; - size_t uuids_len; - dbus_bool_t duplicate; - dbus_bool_t discoverable; - bool set; - bool active; - unsigned int timeout; -} filter = { - .rssi = DISTANCE_VAL_INVALID, - .pathloss = DISTANCE_VAL_INVALID, - .set = true, -}; - static void start_discovery_reply(DBusMessage *message, void *user_data) { dbus_bool_t enable = GPOINTER_TO_UINT(user_data); @@ -1412,9 +1319,14 @@ static void cmd_scan(int argc, char *argv[]) return bt_shell_noninteractive_quit(EXIT_FAILURE); if (enable == TRUE) { - if (strcmp(mode, "")) { + if (!g_strcmp0(mode, "")) { + g_free(filter.transport); + filter.transport = NULL; + filter.set = false; + } else { g_free(filter.transport); filter.transport = g_strdup(mode); + filter.set = false; } set_discovery_filter(false); @@ -1437,7 +1349,7 @@ static void cmd_scan_filter_uuids(int argc, char *argv[]) char **uuid; for (uuid = filter.uuids; uuid && *uuid; uuid++) - print_uuid("UUID", *uuid); + print_uuid("\t", "UUID", *uuid); return bt_shell_noninteractive_quit(EXIT_SUCCESS); } @@ -1721,6 +1633,39 @@ static struct GDBusProxy *find_device(int argc, char *argv[]) return proxy; } +static struct GDBusProxy *find_set(int argc, char *argv[]) +{ + GDBusProxy *proxy; + + if (check_default_ctrl() == FALSE) + return NULL; + + proxy = find_proxies_by_path(default_ctrl->sets, argv[1]); + if (!proxy) { + bt_shell_printf("DeviceSet %s not available\n", argv[1]); + return NULL; + } + + return proxy; +} + +static void cmd_set_info(int argc, char *argv[]) +{ + GDBusProxy *proxy; + + proxy = find_set(argc, argv); + if (!proxy) + return bt_shell_noninteractive_quit(EXIT_FAILURE); + + bt_shell_printf("DeviceSet %s\n", g_dbus_proxy_get_path(proxy)); + + print_property(proxy, "AutoConnect"); + print_property(proxy, "Devices"); + print_property(proxy, "Size"); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + static void cmd_info(int argc, char *argv[]) { GDBusProxy *proxy; @@ -1730,7 +1675,7 @@ static void cmd_info(int argc, char *argv[]) proxy = find_device(argc, argv); if (!proxy) - return bt_shell_noninteractive_quit(EXIT_FAILURE); + return cmd_set_info(argc, argv); if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE) return bt_shell_noninteractive_quit(EXIT_FAILURE); @@ -1767,6 +1712,7 @@ static void cmd_info(int argc, char *argv[]) print_property(proxy, "TxPower"); print_property(proxy, "AdvertisingFlags"); print_property(proxy, "AdvertisingData"); + print_property(proxy, "Sets"); battery_proxy = find_proxies_by_path(battery_proxies, g_dbus_proxy_get_path(proxy)); @@ -2146,10 +2092,41 @@ static void cmd_set_alias(int argc, char *argv[]) return bt_shell_noninteractive_quit(EXIT_FAILURE); } +static void set_default_local_attribute(char *attr) +{ + char *desc = NULL; + + default_local_attr = attr; + default_attr = NULL; + + desc = g_strdup_printf("[%s]# ", attr); + + bt_shell_set_prompt(desc, COLOR_BLUE); + g_free(desc); +} + static void cmd_select_attribute(int argc, char *argv[]) { GDBusProxy *proxy; + if (!strcasecmp("local", argv[1])) { + char *attr; + + if (argc < 2) { + bt_shell_printf("attribute/UUID required\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + attr = gatt_select_local_attribute(argv[2]); + if (!attr) { + bt_shell_printf("Unable to find %s\n", argv[2]); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + set_default_local_attribute(attr); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + } + if (!default_dev) { bt_shell_printf("No device connected\n"); return bt_shell_noninteractive_quit(EXIT_FAILURE); @@ -2234,6 +2211,11 @@ static void cmd_attribute_info(int argc, char *argv[]) static void cmd_read(int argc, char *argv[]) { + if (default_local_attr) { + gatt_read_local_attribute(default_local_attr, argc, argv); + return; + } + if (!default_attr) { bt_shell_printf("No attribute selected\n"); return bt_shell_noninteractive_quit(EXIT_FAILURE); @@ -2244,6 +2226,11 @@ static void cmd_read(int argc, char *argv[]) static void cmd_write(int argc, char *argv[]) { + if (default_local_attr) { + gatt_write_local_attribute(default_local_attr, argc, argv); + return; + } + if (!default_attr) { bt_shell_printf("No attribute selected\n"); return bt_shell_noninteractive_quit(EXIT_FAILURE); @@ -2419,11 +2406,13 @@ static char *generic_generator(const char *text, int state, index++; - if (g_dbus_proxy_get_property(proxy, property, &iter) == FALSE) + if (!property) + str = g_dbus_proxy_get_path(proxy); + else if (g_dbus_proxy_get_property(proxy, property, &iter)) + dbus_message_iter_get_basic(&iter, &str); + else continue; - dbus_message_iter_get_basic(&iter, &str); - if (!strncasecmp(str, text, len)) return strdup(str); } @@ -2469,6 +2458,23 @@ static char *dev_generator(const char *text, int state) default_ctrl ? default_ctrl->devices : NULL, "Address"); } +static char *set_generator(const char *text, int state) +{ + return generic_generator(text, state, + default_ctrl ? default_ctrl->sets : NULL, NULL); +} + +static char *dev_set_generator(const char *text, int state) +{ + char *str; + + str = dev_generator(text, state); + if (str) + return str; + + return set_generator(text, state); +} + static char *attribute_generator(const char *text, int state) { return gatt_attribute_generator(text, state); @@ -2730,6 +2736,21 @@ static void cmd_advertise_interval(int argc, char *argv[]) ad_advertise_interval(dbus_conn, &min, &max); } +static void cmd_advertise_rsi(int argc, char *argv[]) +{ + dbus_bool_t value; + + if (argc < 2) { + ad_advertise_rsi(dbus_conn, NULL); + return; + } + + if (!parse_argument(argc, argv, NULL, NULL, &value, NULL)) + return bt_shell_noninteractive_quit(EXIT_FAILURE); + + ad_advertise_rsi(dbus_conn, &value); +} + static void ad_clear_uuids(void) { ad_disable_uuids(dbus_conn); @@ -2928,6 +2949,8 @@ static const struct bt_shell_menu advertise_menu = { "Set/Get advertise secondary channel" }, { "interval", "[min] [max] ", cmd_advertise_interval, "Set/Get advertise interval range" }, + { "rsi", "[on/off]", cmd_advertise_rsi, + "Show/Enable/Disable RSI to be advertised", NULL }, { "clear", "[uuids/service/manufacturer/config-name...]", cmd_ad_clear, "Clear advertise config" }, { } }, @@ -3001,8 +3024,9 @@ static const struct bt_shell_menu gatt_menu = { .entries = { { "list-attributes", "[dev/local]", cmd_list_attributes, "List attributes", dev_generator }, - { "select-attribute", "<attribute/UUID>", cmd_select_attribute, - "Select attribute", attribute_generator }, + { "select-attribute", "<attribute/UUID/local> [attribute/UUID]", + cmd_select_attribute, "Select attribute", + attribute_generator }, { "attribute-info", "[attribute/UUID]", cmd_attribute_info, "Select attribute", attribute_generator }, { "read", "[offset]", cmd_read, "Read attribute value" }, @@ -3030,7 +3054,7 @@ static const struct bt_shell_menu gatt_menu = { "Unregister application service" }, { "register-includes", "<UUID> [handle]", cmd_register_includes, "Register as Included service in." }, - { "unregister-includes", "<Service-UUID><Inc-UUID>", + { "unregister-includes", "<Service-UUID> <Inc-UUID>", cmd_unregister_includes, "Unregister Included service." }, { "register-characteristic", @@ -3074,7 +3098,7 @@ static const struct bt_shell_menu main_menu = { NULL }, { "discoverable-timeout", "[value]", cmd_discoverable_timeout, "Set discoverable timeout", NULL }, - { "agent", "<on/off/capability>", cmd_agent, + { "agent", "<on/off/auto/capability>", cmd_agent, "Enable/disable agent with given capability", capability_generator}, { "default-agent",NULL, cmd_default_agent, @@ -3085,8 +3109,8 @@ static const struct bt_shell_menu main_menu = { { "set-alias", "<alias>", cmd_set_alias, "Set device alias" }, { "scan", "<on/off/bredr/le>", cmd_scan, "Scan for devices", scan_generator }, - { "info", "[dev]", cmd_info, "Device information", - dev_generator }, + { "info", "[dev/set]", cmd_info, "Device/Set information", + dev_set_generator }, { "pair", "[dev]", cmd_pair, "Pair with device", dev_generator }, { "cancel-pairing", "[dev]", cmd_cancel_pairing, @@ -3137,13 +3161,25 @@ static const struct bt_shell_opt opt = { static void client_ready(GDBusClient *client, void *user_data) { + unsigned int *timeout_id = user_data; + + if (*timeout_id > 0) + timeout_remove(*timeout_id); setup_standard_input(); } +static bool timeout_quit(void *user_data) +{ + mainloop_exit_failure(); + return true; +} + int main(int argc, char *argv[]) { GDBusClient *client; int status; + int timeout; + unsigned int timeout_id; bt_shell_init(argc, argv, &opt); bt_shell_set_menu(&main_menu); @@ -3151,7 +3187,7 @@ int main(int argc, char *argv[]) bt_shell_add_submenu(&advertise_monitor_menu); bt_shell_add_submenu(&scan_menu); bt_shell_add_submenu(&gatt_menu); - bt_shell_set_prompt(PROMPT_OFF); + bt_shell_set_prompt(PROMPT_OFF, NULL); if (agent_option) auto_register_agent = g_strdup(agent_option); @@ -3169,6 +3205,8 @@ int main(int argc, char *argv[]) admin_add_submenu(); player_add_submenu(); + mgmt_add_submenu(); + assistant_add_submenu(); client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez"); @@ -3179,12 +3217,18 @@ int main(int argc, char *argv[]) g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed, property_changed, NULL); - g_dbus_client_set_ready_watch(client, client_ready, NULL); - + timeout = bt_shell_get_timeout(); + timeout_id = 0; + if (timeout > 0) + timeout_id = timeout_add(timeout * 1000, timeout_quit, NULL, + NULL); + g_dbus_client_set_ready_watch(client, client_ready, &timeout_id); status = bt_shell_run(); admin_remove_submenu(); player_remove_submenu(); + mgmt_remove_submenu(); + assistant_remove_submenu(); g_dbus_client_unref(client); diff --git a/client/mgmt.c b/client/mgmt.c new file mode 100644 index 0000000000000000000000000000000000000000..602b92228ab8db291789227abdba0f05216bb81c --- /dev/null +++ b/client/mgmt.c @@ -0,0 +1,6053 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2011 Intel Corporation. All rights reserved. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdarg.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <poll.h> +#include <getopt.h> +#include <stdbool.h> +#include <wordexp.h> +#include <ctype.h> + +#include "lib/bluetooth.h" +#include "lib/hci.h" +#include "lib/hci_lib.h" +#include "lib/sdp.h" +#include "lib/sdp_lib.h" +#include "lib/uuid.h" + +#include "src/uuid-helper.h" +#include "lib/mgmt.h" + +#include "src/shared/mainloop.h" +#include "src/shared/io.h" +#include "src/shared/util.h" +#include "src/shared/mgmt.h" +#include "src/shared/shell.h" +#include "client/mgmt.h" + +#define SCAN_TYPE_BREDR (1 << BDADDR_BREDR) +#define SCAN_TYPE_LE ((1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM)) +#define SCAN_TYPE_DUAL (SCAN_TYPE_BREDR | SCAN_TYPE_LE) + +static struct mgmt *mgmt = NULL; +static uint16_t mgmt_index = MGMT_INDEX_NONE; + +static bool discovery = false; +static bool resolve_names = true; + +static struct { + uint16_t index; + uint16_t req; + struct mgmt_addr_info addr; +} prompt = { + .index = MGMT_INDEX_NONE, +}; + + +static int pending_index = 0; + +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#endif + +#define PROMPT_ON COLOR_BLUE "[mgmt]" COLOR_OFF "# " + +static void update_prompt(uint16_t index) +{ + char str[32]; + + if (index == MGMT_INDEX_NONE) + snprintf(str, sizeof(str), "[mgmt]# "); + else + snprintf(str, sizeof(str), "[hci%u]# ", index); + + bt_shell_set_prompt(str, COLOR_BLUE); +} + +void mgmt_set_index(const char *arg) +{ + if (!arg || !strcmp(arg, "none") || !strcmp(arg, "any") || + !strcmp(arg, "all")) + mgmt_index = MGMT_INDEX_NONE; + else if (strlen(arg) > 3 && !strncasecmp(arg, "hci", 3)) + mgmt_index = atoi(&arg[3]); + else + mgmt_index = atoi(arg); + + update_prompt(mgmt_index); +} + +static bool parse_setting(int argc, char **argv, uint8_t *val) +{ + if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0) + *val = 1; + else if (strcasecmp(argv[1], "off") == 0) + *val = 0; + else + *val = atoi(argv[1]); + return true; +} + +#define print(fmt, arg...) do { \ + bt_shell_printf(fmt "\n", ## arg); \ +} while (0) + +#define error(fmt, arg...) do { \ + bt_shell_printf(COLOR_RED fmt "\n" COLOR_OFF, ## arg); \ +} while (0) + +static size_t hex2bin(const char *hexstr, uint8_t *buf, size_t buflen) +{ + size_t i, len; + + len = MIN((strlen(hexstr) / 2), buflen); + memset(buf, 0, len); + + for (i = 0; i < len; i++) + sscanf(hexstr + (i * 2), "%02hhX", &buf[i]); + + return len; +} + +static size_t bin2hex(const uint8_t *buf, size_t buflen, char *str, + size_t strlen) +{ + size_t i; + + for (i = 0; i < buflen && i < (strlen / 2); i++) + sprintf(str + (i * 2), "%02x", buf[i]); + + return i; +} + +static void print_eir(const uint8_t *eir, uint16_t eir_len) +{ + uint16_t parsed = 0; + char str[33]; + + while (parsed < eir_len - 1) { + uint8_t field_len = eir[0]; + + if (field_len == 0) + break; + + parsed += field_len + 1; + + if (parsed > eir_len) + break; + + switch (eir[1]) { + case 0x01: + print("Flags: 0x%02x", eir[2]); + break; + case 0x0d: + print("Class of Device: 0x%02x%02x%02x", + eir[4], eir[3], eir[2]); + break; + case 0x0e: + bin2hex(eir + 2, 16, str, sizeof(str)); + print("SSP Hash C-192: %s", str); + break; + case 0x0f: + bin2hex(eir + 2, 16, str, sizeof(str)); + print("SSP Rand R-192: %s", str); + break; + case 0x1b: + ba2str((bdaddr_t *) (eir + 2), str); + print("LE Device Address: %s (%s)", str, + eir[8] ? "random" : "public"); + break; + case 0x1c: + print("LE Role: 0x%02x", eir[2]); + break; + case 0x1d: + bin2hex(eir + 2, 16, str, sizeof(str)); + print("SSP Hash C-256: %s", str); + break; + case 0x1e: + bin2hex(eir + 2, 16, str, sizeof(str)); + print("SSP Rand R-256: %s", str); + break; + case 0x22: + bin2hex(eir + 2, 16, str, sizeof(str)); + print("LE SC Confirmation Value: %s", str); + break; + case 0x23: + bin2hex(eir + 2, 16, str, sizeof(str)); + print("LE SC Random Value: %s", str); + break; + default: + print("Type %u: %u byte%s", eir[1], field_len - 1, + (field_len - 1) == 1 ? "" : "s"); + break; + } + + eir += field_len + 1; + } +} + +static bool load_identity(const char *path, struct mgmt_irk_info *irk) +{ + char *addr, *key; + unsigned int type; + int n; + FILE *fp; + + fp = fopen(path, "r"); + if (!fp) { + error("Failed to open identity file: %s", strerror(errno)); + return false; + } + + n = fscanf(fp, "%m[0-9a-f:] (type %u) %m[0-9a-f]", &addr, &type, &key); + + fclose(fp); + + if (n != 3) + return false; + + str2ba(addr, &irk->addr.bdaddr); + hex2bin(key, irk->val, sizeof(irk->val)); + + free(addr); + free(key); + + switch (type) { + case 0: + irk->addr.type = BDADDR_LE_PUBLIC; + break; + case 1: + irk->addr.type = BDADDR_LE_RANDOM; + break; + default: + error("Invalid address type %u", type); + return false; + } + + return true; +} + +static void controller_error(uint16_t index, uint16_t len, + const void *param, void *user_data) +{ + const struct mgmt_ev_controller_error *ev = param; + + if (len < sizeof(*ev)) { + error("Too short (%u bytes) controller error event", len); + return; + } + + print("hci%u error 0x%02x", index, ev->error_code); +} + +static void index_added(uint16_t index, uint16_t len, + const void *param, void *user_data) +{ + print("hci%u added", index); +} + +static void index_removed(uint16_t index, uint16_t len, + const void *param, void *user_data) +{ + print("hci%u removed", index); +} + +static void unconf_index_added(uint16_t index, uint16_t len, + const void *param, void *user_data) +{ + print("hci%u added (unconfigured)", index); +} + +static void unconf_index_removed(uint16_t index, uint16_t len, + const void *param, void *user_data) +{ + print("hci%u removed (unconfigured)", index); +} + +static void ext_index_added(uint16_t index, uint16_t len, + const void *param, void *user_data) +{ + const struct mgmt_ev_ext_index_added *ev = param; + + print("hci%u added (type %u bus %u)", index, ev->type, ev->bus); +} + +static void ext_index_removed(uint16_t index, uint16_t len, + const void *param, void *user_data) +{ + const struct mgmt_ev_ext_index_removed *ev = param; + + print("hci%u removed (type %u bus %u)", index, ev->type, ev->bus); +} + +static const char *options_str[] = { + "external", + "public-address", +}; + +static const char *options2str(uint32_t options) +{ + static char str[256]; + unsigned i; + int off; + + off = 0; + str[0] = '\0'; + + for (i = 0; i < NELEM(options_str); i++) { + if ((options & (1 << i)) != 0) + off += snprintf(str + off, sizeof(str) - off, "%s ", + options_str[i]); + } + + return str; +} + +static void new_config_options(uint16_t index, uint16_t len, + const void *param, void *user_data) +{ + const uint32_t *ev = param; + + if (len < sizeof(*ev)) { + error("Too short new_config_options event (%u)", len); + return; + } + + print("hci%u new_config_options: %s", index, options2str(get_le32(ev))); +} + +static const char *settings_str[] = { + "powered", + "connectable", + "fast-connectable", + "discoverable", + "bondable", + "link-security", + "ssp", + "br/edr", + "hs", + "le", + "advertising", + "secure-conn", + "debug-keys", + "privacy", + "configuration", + "static-addr", + "phy-configuration", + "wide-band-speech", + "cis-central", + "cis-peripheral", + "iso-broadcaster", + "sync-receiver" +}; + +static const char *settings2str(uint32_t settings) +{ + static char str[256]; + unsigned i; + int off; + + off = 0; + str[0] = '\0'; + + for (i = 0; i < NELEM(settings_str); i++) { + if ((settings & (1 << i)) != 0) + off += snprintf(str + off, sizeof(str) - off, "%s ", + settings_str[i]); + } + + return str; +} + +static void new_settings(uint16_t index, uint16_t len, + const void *param, void *user_data) +{ + const uint32_t *ev = param; + + if (len < sizeof(*ev)) { + error("Too short new_settings event (%u)", len); + return; + } + + print("hci%u new_settings: %s", index, settings2str(get_le32(ev))); +} + +static void discovering(uint16_t index, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_ev_discovering *ev = param; + + if (len < sizeof(*ev)) { + error("Too short (%u bytes) discovering event", len); + return; + } + + print("hci%u type %u discovering %s", index, ev->type, + ev->discovering ? "on" : "off"); + + if (ev->discovering == 0 && discovery) + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void new_link_key(uint16_t index, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_ev_new_link_key *ev = param; + char addr[18]; + + if (len != sizeof(*ev)) { + error("Invalid new_link_key length (%u bytes)", len); + return; + } + + ba2str(&ev->key.addr.bdaddr, addr); + print("hci%u new_link_key %s type 0x%02x pin_len %d store_hint %u", + index, addr, ev->key.type, ev->key.pin_len, ev->store_hint); +} + +static const char *typestr(uint8_t type) +{ + static const char *str[] = { "BR/EDR", "LE Public", "LE Random" }; + + if (type <= BDADDR_LE_RANDOM) + return str[type]; + + return "(unknown)"; +} + +static void connected(uint16_t index, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_ev_device_connected *ev = param; + uint16_t eir_len; + char addr[18]; + + if (len < sizeof(*ev)) { + error("Invalid connected event length (%u bytes)", len); + return; + } + + eir_len = get_le16(&ev->eir_len); + if (len != sizeof(*ev) + eir_len) { + error("Invalid connected event length (%u != eir_len %u)", + len, eir_len); + return; + } + + ba2str(&ev->addr.bdaddr, addr); + print("hci%u %s type %s connected eir_len %u", index, addr, + typestr(ev->addr.type), eir_len); +} + +static void disconnected(uint16_t index, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_ev_device_disconnected *ev = param; + char addr[18]; + uint8_t reason; + + if (len < sizeof(struct mgmt_addr_info)) { + error("Invalid disconnected event length (%u bytes)", len); + return; + } + + if (len < sizeof(*ev)) + reason = MGMT_DEV_DISCONN_UNKNOWN; + else + reason = ev->reason; + + ba2str(&ev->addr.bdaddr, addr); + print("hci%u %s type %s disconnected with reason %u", + index, addr, typestr(ev->addr.type), reason); +} + +static void conn_failed(uint16_t index, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_ev_connect_failed *ev = param; + char addr[18]; + + if (len != sizeof(*ev)) { + error("Invalid connect_failed event length (%u bytes)", len); + return; + } + + ba2str(&ev->addr.bdaddr, addr); + print("hci%u %s type %s connect failed (status 0x%02x, %s)", + index, addr, typestr(ev->addr.type), ev->status, + mgmt_errstr(ev->status)); +} + +static void auth_failed(uint16_t index, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_ev_auth_failed *ev = param; + char addr[18]; + + if (len != sizeof(*ev)) { + error("Invalid auth_failed event length (%u bytes)", len); + return; + } + + ba2str(&ev->addr.bdaddr, addr); + print("hci%u %s auth failed with status 0x%02x (%s)", + index, addr, ev->status, mgmt_errstr(ev->status)); +} + +static void class_of_dev_changed(uint16_t index, uint16_t len, + const void *param, void *user_data) +{ + const struct mgmt_ev_class_of_dev_changed *ev = param; + + if (len != sizeof(*ev)) { + error("Invalid class_of_dev_changed length (%u bytes)", len); + return; + } + + print("hci%u class of device changed: 0x%02x%02x%02x", index, + ev->dev_class[2], ev->dev_class[1], ev->dev_class[0]); +} + +static void local_name_changed(uint16_t index, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_ev_local_name_changed *ev = param; + + if (len != sizeof(*ev)) { + error("Invalid local_name_changed length (%u bytes)", len); + return; + } + + print("hci%u name changed: %s", index, ev->name); +} + +static void confirm_name_rsp(uint8_t status, uint16_t len, + const void *param, void *user_data) +{ + const struct mgmt_rp_confirm_name *rp = param; + char addr[18]; + + if (len == 0 && status != 0) { + error("confirm_name failed with status 0x%02x (%s)", status, + mgmt_errstr(status)); + return; + } + + if (len != sizeof(*rp)) { + error("confirm_name rsp length %u instead of %zu", + len, sizeof(*rp)); + return; + } + + ba2str(&rp->addr.bdaddr, addr); + + if (status != 0) + error("confirm_name for %s failed: 0x%02x (%s)", + addr, status, mgmt_errstr(status)); + else + print("confirm_name succeeded for %s", addr); +} + +static char *eir_get_name(const uint8_t *eir, uint16_t eir_len) +{ + uint8_t parsed = 0; + + if (eir_len < 2) + return NULL; + + while (parsed < eir_len - 1) { + uint8_t field_len = eir[0]; + + if (field_len == 0) + break; + + parsed += field_len + 1; + + if (parsed > eir_len) + break; + + /* Check for short of complete name */ + if (eir[1] == 0x09 || eir[1] == 0x08) + return strndup((char *) &eir[2], field_len - 1); + + eir += field_len + 1; + } + + return NULL; +} + +static unsigned int eir_get_flags(const uint8_t *eir, uint16_t eir_len) +{ + uint8_t parsed = 0; + + if (eir_len < 2) + return 0; + + while (parsed < eir_len - 1) { + uint8_t field_len = eir[0]; + + if (field_len == 0) + break; + + parsed += field_len + 1; + + if (parsed > eir_len) + break; + + /* Check for flags */ + if (eir[1] == 0x01) + return eir[2]; + + eir += field_len + 1; + } + + return 0; +} + +static void device_found(uint16_t index, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_ev_device_found *ev = param; + struct mgmt *mgmt = user_data; + uint16_t eir_len; + uint32_t flags; + + if (len < sizeof(*ev)) { + error("Too short device_found length (%u bytes)", len); + return; + } + + flags = btohl(ev->flags); + + eir_len = get_le16(&ev->eir_len); + if (len != sizeof(*ev) + eir_len) { + error("dev_found: expected %zu bytes, got %u bytes", + sizeof(*ev) + eir_len, len); + return; + } + + if (discovery) { + char addr[18], *name; + + ba2str(&ev->addr.bdaddr, addr); + print("hci%u dev_found: %s type %s rssi %d " + "flags 0x%04x ", index, addr, + typestr(ev->addr.type), ev->rssi, flags); + + if (ev->addr.type != BDADDR_BREDR) + print("AD flags 0x%02x ", + eir_get_flags(ev->eir, eir_len)); + + name = eir_get_name(ev->eir, eir_len); + if (name) + print("name %s", name); + else + print("eir_len %u", eir_len); + + free(name); + } + + if (discovery && (flags & MGMT_DEV_FOUND_CONFIRM_NAME)) { + struct mgmt_cp_confirm_name cp; + + memset(&cp, 0, sizeof(cp)); + memcpy(&cp.addr, &ev->addr, sizeof(cp.addr)); + if (resolve_names) + cp.name_known = 0; + else + cp.name_known = 1; + + mgmt_reply(mgmt, MGMT_OP_CONFIRM_NAME, index, sizeof(cp), &cp, + confirm_name_rsp, NULL, NULL); + } +} + +static void pin_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) { + error("PIN Code reply failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("PIN Reply successful"); +} + +static int mgmt_pin_reply(uint16_t index, const struct mgmt_addr_info *addr, + const char *pin, size_t len) +{ + struct mgmt_cp_pin_code_reply cp; + + memset(&cp, 0, sizeof(cp)); + memcpy(&cp.addr, addr, sizeof(cp.addr)); + cp.pin_len = len; + memcpy(cp.pin_code, pin, len); + + return mgmt_reply(mgmt, MGMT_OP_PIN_CODE_REPLY, index, + sizeof(cp), &cp, pin_rsp, NULL, NULL); +} + +static void pin_neg_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) { + error("PIN Neg reply failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("PIN Negative Reply successful"); +} + +static int mgmt_pin_neg_reply(uint16_t index, const struct mgmt_addr_info *addr) +{ + struct mgmt_cp_pin_code_neg_reply cp; + + memset(&cp, 0, sizeof(cp)); + memcpy(&cp.addr, addr, sizeof(cp.addr)); + + return mgmt_reply(mgmt, MGMT_OP_PIN_CODE_NEG_REPLY, index, + sizeof(cp), &cp, pin_neg_rsp, NULL, NULL); +} + +static void confirm_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) { + error("User Confirm reply failed. status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("User Confirm Reply successful"); +} + +static int mgmt_confirm_reply(uint16_t index, const struct mgmt_addr_info *addr) +{ + struct mgmt_cp_user_confirm_reply cp; + + memset(&cp, 0, sizeof(cp)); + memcpy(&cp.addr, addr, sizeof(*addr)); + + return mgmt_reply(mgmt, MGMT_OP_USER_CONFIRM_REPLY, index, + sizeof(cp), &cp, confirm_rsp, NULL, NULL); +} + +static void confirm_neg_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) { + error("Confirm Neg reply failed. status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("User Confirm Negative Reply successful"); +} + +static int mgmt_confirm_neg_reply(uint16_t index, + const struct mgmt_addr_info *addr) +{ + struct mgmt_cp_user_confirm_reply cp; + + memset(&cp, 0, sizeof(cp)); + memcpy(&cp.addr, addr, sizeof(*addr)); + + return mgmt_reply(mgmt, MGMT_OP_USER_CONFIRM_NEG_REPLY, index, + sizeof(cp), &cp, confirm_neg_rsp, NULL, NULL); +} + +static void passkey_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) { + error("User Passkey reply failed. status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("User Passkey Reply successful"); +} + +static int mgmt_passkey_reply(uint16_t index, const struct mgmt_addr_info *addr, + uint32_t passkey) +{ + struct mgmt_cp_user_passkey_reply cp; + + memset(&cp, 0, sizeof(cp)); + memcpy(&cp.addr, addr, sizeof(*addr)); + put_le32(passkey, &cp.passkey); + + return mgmt_reply(mgmt, MGMT_OP_USER_PASSKEY_REPLY, index, + sizeof(cp), &cp, passkey_rsp, NULL, NULL); +} + +static void passkey_neg_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) { + error("Passkey Neg reply failed. status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("User Passkey Negative Reply successful"); +} + +static int mgmt_passkey_neg_reply(uint16_t index, + const struct mgmt_addr_info *addr) +{ + struct mgmt_cp_user_passkey_reply cp; + + memset(&cp, 0, sizeof(cp)); + memcpy(&cp.addr, addr, sizeof(*addr)); + + return mgmt_reply(mgmt, MGMT_OP_USER_PASSKEY_NEG_REPLY, index, + sizeof(cp), &cp, passkey_neg_rsp, NULL, NULL); +} + +static void prompt_input(const char *input, void *user_data) +{ + size_t len; + + len = strlen(input); + + switch (prompt.req) { + case MGMT_EV_PIN_CODE_REQUEST: + if (len) + mgmt_pin_reply(prompt.index, &prompt.addr, input, len); + else + mgmt_pin_neg_reply(prompt.index, &prompt.addr); + break; + case MGMT_EV_USER_PASSKEY_REQUEST: + if (strlen(input) > 0) + mgmt_passkey_reply(prompt.index, &prompt.addr, + atoi(input)); + else + mgmt_passkey_neg_reply(prompt.index, + &prompt.addr); + break; + case MGMT_EV_USER_CONFIRM_REQUEST: + if (len) { + if (input[0] == 'y' || input[0] == 'Y') + mgmt_confirm_reply(prompt.index, &prompt.addr); + else + mgmt_confirm_neg_reply(prompt.index, + &prompt.addr); + } else { + mgmt_confirm_neg_reply(prompt.index, &prompt.addr); + bt_shell_set_prompt(PROMPT_ON, COLOR_BLUE); + } + break; + } +} + +static void ask(uint16_t index, uint16_t req, const struct mgmt_addr_info *addr, + const char *fmt, ...) +{ + char msg[256]; + va_list ap; + int off; + + prompt.index = index; + prompt.req = req; + memcpy(&prompt.addr, addr, sizeof(*addr)); + + va_start(ap, fmt); + off = vsnprintf(msg, sizeof(msg), fmt, ap); + va_end(ap); + + snprintf(msg + off, sizeof(msg) - off, " %s ", + COLOR_BOLDGRAY ">>" COLOR_OFF); + + bt_shell_prompt_input("", msg, prompt_input, NULL); +} + +static void request_pin(uint16_t index, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_ev_pin_code_request *ev = param; + char addr[18]; + + if (len != sizeof(*ev)) { + error("Invalid pin_code request length (%u bytes)", len); + return; + } + + ba2str(&ev->addr.bdaddr, addr); + print("hci%u %s request PIN", index, addr); + + ask(index, MGMT_EV_PIN_CODE_REQUEST, &ev->addr, + "PIN Request (press enter to reject)"); +} + +static void user_confirm(uint16_t index, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_ev_user_confirm_request *ev = param; + uint32_t val; + char addr[18]; + + if (len != sizeof(*ev)) { + error("Invalid user_confirm request length (%u)", len); + return; + } + + ba2str(&ev->addr.bdaddr, addr); + val = get_le32(&ev->value); + + print("hci%u %s User Confirm %06u hint %u", index, addr, + val, ev->confirm_hint); + + if (ev->confirm_hint) + ask(index, MGMT_EV_USER_CONFIRM_REQUEST, &ev->addr, + "Accept pairing with %s (yes/no)", addr); + else + ask(index, MGMT_EV_USER_CONFIRM_REQUEST, &ev->addr, + "Confirm value %06u for %s (yes/no)", val, addr); +} + +static void request_passkey(uint16_t index, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_ev_user_passkey_request *ev = param; + char addr[18]; + + if (len != sizeof(*ev)) { + error("Invalid passkey request length (%u bytes)", len); + return; + } + + ba2str(&ev->addr.bdaddr, addr); + print("hci%u %s request passkey", index, addr); + + ask(index, MGMT_EV_USER_PASSKEY_REQUEST, &ev->addr, + "Passkey Request (press enter to reject)"); +} + +static void passkey_notify(uint16_t index, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_ev_passkey_notify *ev = param; + char addr[18]; + + if (len != sizeof(*ev)) { + error("Invalid passkey request length (%u bytes)", len); + return; + } + + ba2str(&ev->addr.bdaddr, addr); + print("hci%u %s request passkey", index, addr); + + print("Passkey Notify: %06u (entered %u)", get_le32(&ev->passkey), + ev->entered); +} + +static void local_oob_data_updated(uint16_t index, uint16_t len, + const void *param, void *user_data) +{ + const struct mgmt_ev_local_oob_data_updated *ev = param; + uint16_t eir_len; + + if (len < sizeof(*ev)) { + error("Too small (%u bytes) local_oob_updated event", len); + return; + } + + eir_len = le16_to_cpu(ev->eir_len); + if (len != sizeof(*ev) + eir_len) { + error("local_oob_updated: expected %zu bytes, got %u bytes", + sizeof(*ev) + eir_len, len); + return; + } + + print("hci%u oob data updated: type %u len %u", index, + ev->type, eir_len); +} + +static void advertising_added(uint16_t index, uint16_t len, + const void *param, void *user_data) +{ + const struct mgmt_ev_advertising_added *ev = param; + + if (len < sizeof(*ev)) { + error("Too small (%u bytes) advertising_added event", len); + return; + } + + print("hci%u advertising_added: instance %u", index, ev->instance); +} + +static void advertising_removed(uint16_t index, uint16_t len, + const void *param, void *user_data) +{ + const struct mgmt_ev_advertising_removed *ev = param; + + if (len < sizeof(*ev)) { + error("Too small (%u bytes) advertising_removed event", len); + return; + } + + print("hci%u advertising_removed: instance %u", index, ev->instance); +} + +static void flags_changed(uint16_t index, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_ev_device_flags_changed *ev = param; + char addr[18]; + + if (len < sizeof(*ev)) { + error("Too small (%u bytes) %s event", len, __func__); + return; + } + + ba2str(&ev->addr.bdaddr, addr); + print("hci%u device_flags_changed: %s (%s)", index, addr, + typestr(ev->addr.type)); + print(" supp: 0x%08x curr: 0x%08x", + ev->supported_flags, ev->current_flags); +} + +static void advmon_added(uint16_t index, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_ev_adv_monitor_added *ev = param; + + if (len < sizeof(*ev)) { + error("Too small (%u bytes) %s event", len, __func__); + return; + } + + print("hci%u %s: handle %u", index, __func__, + le16_to_cpu(ev->monitor_handle)); +} + +static void advmon_removed(uint16_t index, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_ev_adv_monitor_removed *ev = param; + + if (len < sizeof(*ev)) { + error("Too small (%u bytes) %s event", len, __func__); + return; + } + + print("hci%u %s: handle %u", index, __func__, + le16_to_cpu(ev->monitor_handle)); +} + +static void version_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_read_version *rp = param; + + if (status != 0) { + error("Reading mgmt version failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + goto done; + } + + if (len < sizeof(*rp)) { + error("Too small version reply (%u bytes)", len); + goto done; + } + + print("MGMT Version %u, revision %u", rp->version, + get_le16(&rp->revision)); + +done: + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_revision(int argc, char **argv) +{ + if (mgmt_send(mgmt, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE, + 0, NULL, version_rsp, NULL, NULL) == 0) { + error("Unable to send read_version cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void commands_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_read_commands *rp = param; + uint16_t num_commands, num_events; + size_t expected_len; + int i; + + if (status != 0) { + error("Read Supported Commands failed: status 0x%02x (%s)", + status, mgmt_errstr(status)); + goto done; + } + + if (len < sizeof(*rp)) { + error("Too small commands reply (%u bytes)", len); + goto done; + } + + num_commands = get_le16(&rp->num_commands); + num_events = get_le16(&rp->num_events); + + expected_len = sizeof(*rp) + num_commands * sizeof(uint16_t) + + num_events * sizeof(uint16_t); + + if (len < expected_len) { + error("Too small commands reply (%u != %zu)", + len, expected_len); + goto done; + } + + print("%u commands:", num_commands); + for (i = 0; i < num_commands; i++) { + uint16_t op = get_le16(rp->opcodes + i); + print("\t%s (0x%04x)", mgmt_opstr(op), op); + } + + print("%u events:", num_events); + for (i = 0; i < num_events; i++) { + uint16_t ev = get_le16(rp->opcodes + num_commands + i); + print("\t%s (0x%04x)", mgmt_evstr(ev), ev); + } + +done: + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_commands(int argc, + char **argv) +{ + if (mgmt_send(mgmt, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE, + 0, NULL, commands_rsp, NULL, NULL) == 0) { + error("Unable to send read_commands cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void config_info_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_read_config_info *rp = param; + uint16_t index = PTR_TO_UINT(user_data); + uint32_t supported_options, missing_options; + + if (status != 0) { + error("Reading hci%u config failed with status 0x%02x (%s)", + index, status, mgmt_errstr(status)); + goto done; + } + + if (len < sizeof(*rp)) { + error("Too small info reply (%u bytes)", len); + goto done; + } + + print("hci%u:\tUnconfigured controller", index); + + print("\tmanufacturer %u", le16_to_cpu(rp->manufacturer)); + + supported_options = le32_to_cpu(rp->supported_options); + print("\tsupported options: %s", options2str(supported_options)); + + missing_options = le32_to_cpu(rp->missing_options); + print("\tmissing options: %s", options2str(missing_options)); + +done: + pending_index--; + + if (pending_index > 0) + return; + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void unconf_index_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_read_unconf_index_list *rp = param; + uint16_t count; + unsigned int i; + + if (status != 0) { + error("Reading index list failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len < sizeof(*rp)) { + error("Too small index list reply (%u bytes)", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + count = le16_to_cpu(rp->num_controllers); + + if (len < sizeof(*rp) + count * sizeof(uint16_t)) { + error("Index count (%u) doesn't match reply length (%u)", + count, len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("Unconfigured index list with %u item%s", + count, count != 1 ? "s" : ""); + + for (i = 0; i < count; i++) { + uint16_t index = le16_to_cpu(rp->index[i]); + + if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, index, 0, NULL, + config_info_rsp, UINT_TO_PTR(index), NULL)) { + error("Unable to send read_config_info cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + pending_index++; + } + + if (!count) + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_config(int argc, char **argv) +{ + if (mgmt_index == MGMT_INDEX_NONE) { + if (!mgmt_send(mgmt, MGMT_OP_READ_UNCONF_INDEX_LIST, + MGMT_INDEX_NONE, 0, NULL, + unconf_index_rsp, mgmt, NULL)) { + error("Unable to send unconf_index_list cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return; + } + + if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, mgmt_index, 0, NULL, + config_info_rsp, UINT_TO_PTR(index), NULL)) { + error("Unable to send read_config_info cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void config_options_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_read_config_info *rp = param; + uint16_t index = PTR_TO_UINT(user_data); + uint32_t supported_options, missing_options; + + if (status != 0) { + error("Reading hci%u config failed with status 0x%02x (%s)", + index, status, mgmt_errstr(status)); + goto done; + } + + if (len < sizeof(*rp)) { + error("Too small info reply (%u bytes)", len); + goto done; + } + + print("hci%u:\tConfiguration options", index); + + supported_options = le32_to_cpu(rp->supported_options); + print("\tsupported options: %s", options2str(supported_options)); + + missing_options = le32_to_cpu(rp->missing_options); + print("\tmissing options: %s", options2str(missing_options)); + +done: + pending_index--; + + if (pending_index > 0) + return; + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void info_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_read_info *rp = param; + uint16_t index = PTR_TO_UINT(user_data); + uint32_t supported_settings, current_settings; + char addr[18]; + + if (status != 0) { + error("Reading hci%u info failed with status 0x%02x (%s)", + index, status, mgmt_errstr(status)); + goto done; + } + + if (len < sizeof(*rp)) { + error("Too small info reply (%u bytes)", len); + goto done; + } + + print("hci%u:\tPrimary controller", index); + + ba2str(&rp->bdaddr, addr); + print("\taddr %s version %u manufacturer %u class 0x%02x%02x%02x", + addr, rp->version, le16_to_cpu(rp->manufacturer), + rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]); + + supported_settings = le32_to_cpu(rp->supported_settings); + print("\tsupported settings: %s", settings2str(supported_settings)); + + current_settings = le32_to_cpu(rp->current_settings); + print("\tcurrent settings: %s", settings2str(current_settings)); + + print("\tname %s", rp->name); + print("\tshort name %s", rp->short_name); + + if (supported_settings & MGMT_SETTING_CONFIGURATION) { + if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, + index, 0, NULL, config_options_rsp, + UINT_TO_PTR(index), NULL)) { + error("Unable to send read_config cmd"); + goto done; + } + return; + } + +done: + pending_index--; + + if (pending_index > 0) + return; + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void ext_info_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_read_ext_info *rp = param; + uint16_t index = PTR_TO_UINT(user_data); + uint32_t supported_settings, current_settings; + char addr[18]; + + if (status != 0) { + error("Reading hci%u info failed with status 0x%02x (%s)", + index, status, mgmt_errstr(status)); + goto done; + } + + if (len < sizeof(*rp)) { + error("Too small info reply (%u bytes)", len); + goto done; + } + + print("hci%u:\tPrimary controller", index); + + ba2str(&rp->bdaddr, addr); + print("\taddr %s version %u manufacturer %u", + addr, rp->version, le16_to_cpu(rp->manufacturer)); + + supported_settings = le32_to_cpu(rp->supported_settings); + print("\tsupported settings: %s", settings2str(supported_settings)); + + current_settings = le32_to_cpu(rp->current_settings); + print("\tcurrent settings: %s", settings2str(current_settings)); + + if (supported_settings & MGMT_SETTING_CONFIGURATION) { + if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, + index, 0, NULL, config_options_rsp, + UINT_TO_PTR(index), NULL)) { + error("Unable to send read_config cmd"); + goto done; + } + return; + } + +done: + pending_index--; + + if (pending_index > 0) + return; + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void index_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_read_index_list *rp = param; + struct mgmt *mgmt = user_data; + uint16_t count; + unsigned int i; + + if (status != 0) { + error("Reading index list failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len < sizeof(*rp)) { + error("Too small index list reply (%u bytes)", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + count = le16_to_cpu(rp->num_controllers); + + if (len < sizeof(*rp) + count * sizeof(uint16_t)) { + error("Index count (%u) doesn't match reply length (%u)", + count, len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("Index list with %u item%s", count, count != 1 ? "s" : ""); + + for (i = 0; i < count; i++) { + uint16_t index = le16_to_cpu(rp->index[i]); + + if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL, + info_rsp, UINT_TO_PTR(index), NULL)) { + error("Unable to send read_info cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + pending_index++; + } + + if (!count) + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_info(int argc, char **argv) +{ + if (mgmt_index == MGMT_INDEX_NONE) { + if (!mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST, + MGMT_INDEX_NONE, 0, NULL, + index_rsp, mgmt, NULL)) { + error("Unable to send index_list cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return; + } + + if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, mgmt_index, 0, NULL, info_rsp, + UINT_TO_PTR(mgmt_index), NULL)) { + error("Unable to send read_info cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void ext_index_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_read_ext_index_list *rp = param; + uint16_t count; + unsigned int i; + + if (status != 0) { + error("Reading ext index list failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len < sizeof(*rp)) { + error("Too small ext index list reply (%u bytes)", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + count = get_le16(&rp->num_controllers); + + if (len < sizeof(*rp) + count * (sizeof(uint16_t) + sizeof(uint8_t))) { + error("Index count (%u) doesn't match reply length (%u)", + count, len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("Extended index list with %u item%s", + count, count != 1 ? "s" : ""); + + for (i = 0; i < count; i++) { + uint16_t index = le16_to_cpu(rp->entry[i].index); + const char *busstr = hci_bustostr(rp->entry[i].bus); + + switch (rp->entry[i].type) { + case 0x00: + print("Primary controller (hci%u,%s)", index, busstr); + if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INFO, + index, 0, NULL, ext_info_rsp, + UINT_TO_PTR(index), NULL)) { + error("Unable to send read_ext_info cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + pending_index++; + break; + case 0x01: + print("Unconfigured controller (hci%u,%s)", + index, busstr); + if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, + index, 0, NULL, config_info_rsp, + UINT_TO_PTR(index), NULL)) { + error("Unable to send read_config cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + pending_index++; + break; + case 0x02: + print("AMP controller (hci%u,%s)", index, busstr); + break; + default: + print("Type %u controller (hci%u,%s)", + rp->entry[i].type, index, busstr); + break; + } + } + + print(""); + + if (!count) + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_extinfo(int argc, char **argv) +{ + if (mgmt_index == MGMT_INDEX_NONE) { + if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INDEX_LIST, + MGMT_INDEX_NONE, 0, NULL, + ext_index_rsp, mgmt, NULL)) { + error("Unable to send ext_index_list cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return; + } + + if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INFO, mgmt_index, 0, NULL, + ext_info_rsp, + UINT_TO_PTR(mgmt_index), NULL)) { + error("Unable to send ext_read_info cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void print_cap(const uint8_t *cap, uint16_t cap_len) +{ + uint16_t parsed = 0; + + while (parsed < cap_len - 1) { + uint8_t field_len = cap[0]; + + if (field_len == 0) + break; + + parsed += field_len + 1; + + if (parsed > cap_len) + break; + + switch (cap[1]) { + case 0x01: + print("\tFlags: 0x%02x", cap[2]); + break; + case 0x02: + print("\tMax Key Size (BR/EDR): %u", cap[2]); + break; + case 0x03: + print("\tMax Key Size (LE): %u", cap[2]); + break; + default: + print("\tType %u: %u byte%s", cap[1], field_len - 1, + (field_len - 1) == 1 ? "" : "s"); + break; + } + + cap += field_len + 1; + } +} + +static void sec_info_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_read_controller_cap *rp = param; + uint16_t index = PTR_TO_UINT(user_data); + + if (status != 0) { + error("Reading hci%u security failed with status 0x%02x (%s)", + index, status, mgmt_errstr(status)); + goto done; + } + + if (len < sizeof(*rp)) { + error("Too small info reply (%u bytes)", len); + goto done; + } + + print("Primary controller (hci%u)", index); + print("\tInfo length: %u", le16_to_cpu(rp->cap_len)); + print_cap(rp->cap, le16_to_cpu(rp->cap_len)); + +done: + pending_index--; + + if (pending_index > 0) + return; + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void sec_index_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_read_ext_index_list *rp = param; + uint16_t count; + unsigned int i; + + if (status != 0) { + error("Reading ext index list failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len < sizeof(*rp)) { + error("Too small ext index list reply (%u bytes)", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + count = get_le16(&rp->num_controllers); + + if (len < sizeof(*rp) + count * (sizeof(uint16_t) + sizeof(uint8_t))) { + error("Index count (%u) doesn't match reply length (%u)", + count, len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + for (i = 0; i < count; i++) { + uint16_t index = le16_to_cpu(rp->entry[i].index); + + if (rp->entry[i].type != 0x00) + continue; + + if (!mgmt_send(mgmt, MGMT_OP_READ_CONTROLLER_CAP, + index, 0, NULL, sec_info_rsp, + UINT_TO_PTR(index), NULL)) { + error("Unable to send read_security_info cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + pending_index++; + } + + if (!count) + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_secinfo(int argc, char **argv) +{ + if (mgmt_index == MGMT_INDEX_NONE) { + if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INDEX_LIST, + MGMT_INDEX_NONE, 0, NULL, + sec_index_rsp, mgmt, NULL)) { + error("Unable to send ext_index_list cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + return; + } + + if (!mgmt_send(mgmt, MGMT_OP_READ_CONTROLLER_CAP, mgmt_index, 0, NULL, + sec_info_rsp, + UINT_TO_PTR(mgmt_index), NULL)) { + error("Unable to send read_security_info cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void exp_info_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_read_exp_features_info *rp = param; + uint16_t index = PTR_TO_UINT(user_data); + + if (status != 0) { + error("Reading hci%u exp features failed with status 0x%02x (%s)", + index, status, mgmt_errstr(status)); + goto done; + } + + if (len < sizeof(*rp)) { + error("Too small info reply (%u bytes)", len); + goto done; + } + + if (index == MGMT_INDEX_NONE) + print("Global"); + else + print("Primary controller (hci%u)", index); + + print("\tNumber of experimental features: %u", + le16_to_cpu(rp->feature_count)); + +done: + pending_index--; + + if (pending_index > 0) + return; + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void exp_index_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_read_ext_index_list *rp = param; + uint16_t count; + unsigned int i; + + if (status != 0) { + error("Reading ext index list failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len < sizeof(*rp)) { + error("Too small ext index list reply (%u bytes)", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + count = get_le16(&rp->num_controllers); + + if (len < sizeof(*rp) + count * (sizeof(uint16_t) + sizeof(uint8_t))) { + error("Index count (%u) doesn't match reply length (%u)", + count, len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + for (i = 0; i < count; i++) { + uint16_t index = le16_to_cpu(rp->entry[i].index); + + if (rp->entry[i].type != 0x00) + continue; + + if (!mgmt_send(mgmt, MGMT_OP_READ_EXP_FEATURES_INFO, + index, 0, NULL, exp_info_rsp, + UINT_TO_PTR(index), NULL)) { + error("Unable to send read_exp_features_info cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + pending_index++; + } +} + +static void cmd_expinfo(int argc, char **argv) +{ + if (mgmt_index == MGMT_INDEX_NONE) { + if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INDEX_LIST, + MGMT_INDEX_NONE, 0, NULL, + exp_index_rsp, mgmt, NULL)) { + error("Unable to send ext_index_list cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (!mgmt_send(mgmt, MGMT_OP_READ_EXP_FEATURES_INFO, + MGMT_INDEX_NONE, 0, NULL, + exp_info_rsp, + UINT_TO_PTR(MGMT_INDEX_NONE), NULL)) { + error("Unable to send read_exp_features_info cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + pending_index++; + return; + } + + if (!mgmt_send(mgmt, MGMT_OP_READ_EXP_FEATURES_INFO, mgmt_index, + 0, NULL, exp_info_rsp, + UINT_TO_PTR(mgmt_index), NULL)) { + error("Unable to send read_exp_features_info cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void exp_debug_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) + error("Set debug feature failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + else + print("Debug feature successfully set"); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_exp_debug(int argc, char **argv) +{ + /* d4992530-b9ec-469f-ab01-6c481c47da1c */ + static const uint8_t uuid[16] = { + 0x1c, 0xda, 0x47, 0x1c, 0x48, 0x6c, 0x01, 0xab, + 0x9f, 0x46, 0xec, 0xb9, 0x30, 0x25, 0x99, 0xd4, + }; + struct mgmt_cp_set_exp_feature cp; + uint8_t val; + + if (parse_setting(argc, argv, &val) == false) + return bt_shell_noninteractive_quit(EXIT_FAILURE); + + memset(&cp, 0, sizeof(cp)); + memcpy(cp.uuid, uuid, 16); + cp.action = val; + + if (mgmt_send(mgmt, MGMT_OP_SET_EXP_FEATURE, mgmt_index, + sizeof(cp), &cp, exp_debug_rsp, NULL, NULL) == 0) { + error("Unable to send debug feature cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void exp_privacy_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) + error("Set LL privacy feature failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + else + print("LL privacy feature successfully set"); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_exp_privacy(int argc, char **argv) +{ + /* 15c0a148-c273-11ea-b3de-0242ac130004 */ + static const uint8_t uuid[16] = { + 0x04, 0x00, 0x13, 0xac, 0x42, 0x02, 0xde, 0xb3, + 0xea, 0x11, 0x73, 0xc2, 0x48, 0xa1, 0xc0, 0x15, + }; + struct mgmt_cp_set_exp_feature cp; + uint8_t val; + + if (parse_setting(argc, argv, &val) == false) + return bt_shell_noninteractive_quit(EXIT_FAILURE); + + memset(&cp, 0, sizeof(cp)); + memcpy(cp.uuid, uuid, 16); + cp.action = val; + + if (mgmt_send(mgmt, MGMT_OP_SET_EXP_FEATURE, mgmt_index, + sizeof(cp), &cp, exp_privacy_rsp, NULL, NULL) == 0) { + error("Unable to send LL privacy feature cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void exp_quality_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) + error("Set Quality Report feature failed: 0x%02x (%s)", + status, mgmt_errstr(status)); + else + print("Quality Report feature successfully set"); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_exp_quality(int argc, char **argv) +{ + /* 330859bc-7506-492d-9370-9a6f0614037f */ + static const uint8_t uuid[16] = { + 0x7f, 0x03, 0x14, 0x06, 0x6f, 0x9a, 0x70, 0x93, + 0x2d, 0x49, 0x06, 0x75, 0xbc, 0x59, 0x08, 0x33, + }; + struct mgmt_cp_set_exp_feature cp; + uint8_t val; + + if (mgmt_index == MGMT_INDEX_NONE) { + error("BQR feature requires a valid controller index"); + return; + } + + if (parse_setting(argc, argv, &val) == false) + return bt_shell_noninteractive_quit(EXIT_FAILURE); + + if (val != 0 && val != 1) { + error("Invalid value %u", val); + return; + } + + memset(&cp, 0, sizeof(cp)); + memcpy(cp.uuid, uuid, 16); + cp.action = val; + + if (mgmt_send(mgmt, MGMT_OP_SET_EXP_FEATURE, mgmt_index, + sizeof(cp), &cp, exp_quality_rsp, NULL, NULL) == 0) { + error("Unable to send quality report feature cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void print_mgmt_tlv(void *data, void *user_data) +{ + const struct mgmt_tlv *entry = data; + char buf[256]; + + bin2hex(entry->value, entry->length, buf, sizeof(buf)); + print("Type: 0x%04x\tLength: %02hhu\tValue: %s", entry->type, + entry->length, buf); +} + +static void read_sysconfig_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + struct mgmt_tlv_list *tlv_list; + + if (status != 0) { + error("Read system configuration failed with status " + "0x%02x (%s)", status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + tlv_list = mgmt_tlv_list_load_from_buf(param, len); + if (!tlv_list) { + error("Unable to parse response of read system configuration"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + mgmt_tlv_list_foreach(tlv_list, print_mgmt_tlv, NULL); + mgmt_tlv_list_free(tlv_list); + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_read_sysconfig(int argc, char **argv) +{ + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (!mgmt_send(mgmt, MGMT_OP_READ_DEF_SYSTEM_CONFIG, index, + 0, NULL, read_sysconfig_rsp, NULL, NULL)) { + error("Unable to send read system configuration cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static bool parse_mgmt_tlv(const char *input, uint16_t *type, uint8_t *length, + uint8_t *value) +{ + int i, value_starting_pos; + + if (sscanf(input, "%4hx:%1hhu:%n", type, length, + &value_starting_pos) < 2) { + return false; + } + + input += value_starting_pos; + + if (*length * 2 != strlen(input)) + return false; + + for (i = 0; i < *length; i++) { + if (sscanf(input + i * 2, "%2hhx", &value[i]) < 1) + return false; + } + + return true; +} + +static void set_sysconfig_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != MGMT_STATUS_SUCCESS) { + error("Could not set default system configuration with status " + "0x%02x (%s)", status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("Set default system configuration success"); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static bool set_sysconfig(int argc, char **argv) +{ + struct mgmt_tlv_list *tlv_list = NULL; + int i; + uint16_t index, type; + uint8_t length; + uint8_t value[256] = {}; + bool success = false; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + tlv_list = mgmt_tlv_list_new(); + if (!tlv_list) { + error("tlv_list failed to init"); + goto failed; + } + + for (i = 0; i < argc; i++) { + if (!parse_mgmt_tlv(argv[i], &type, &length, value)) { + error("failed to parse"); + goto failed; + } + + if (!mgmt_tlv_add(tlv_list, type, length, value)) { + error("failed to add"); + goto failed; + } + } + + if (!mgmt_send_tlv(mgmt, MGMT_OP_SET_DEF_SYSTEM_CONFIG, index, + tlv_list, set_sysconfig_rsp, NULL, NULL)) { + error("Failed to send \"Set Default System Configuration\"" + " command"); + goto failed; + } + + success = true; + +failed: + if (tlv_list) + mgmt_tlv_list_free(tlv_list); + + return success; +} + +static void set_sysconfig_usage(void) +{ + bt_shell_usage(); + print("Parameters:\n\t-v <type:length:value>...\n" + "e.g.:\n\tset-sysconfig -v 001a:2:1234 001f:1:00"); +} + +static void cmd_set_sysconfig(int argc, char **argv) +{ + bool success = false; + + if (strcasecmp(argv[1], "-v") == 0 && argc > 2) { + argc -= 2; + argv += 2; + success = set_sysconfig(argc, argv); + } + + if (!success) { + set_sysconfig_usage(); + bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void auto_power_enable_rsp(uint8_t status, uint16_t len, + const void *param, void *user_data) +{ + uint16_t index = PTR_TO_UINT(user_data); + + print("Successfully enabled controller with index %u", index); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void auto_power_info_rsp(uint8_t status, uint16_t len, + const void *param, void *user_data) +{ + const struct mgmt_rp_read_info *rp = param; + uint16_t index = PTR_TO_UINT(user_data); + uint32_t supported_settings, current_settings, missing_settings; + uint8_t val = 0x01; + + if (status) { + error("Reading info failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + supported_settings = le32_to_cpu(rp->supported_settings); + current_settings = le32_to_cpu(rp->current_settings); + missing_settings = current_settings ^ supported_settings; + + if (missing_settings & MGMT_SETTING_BREDR) + mgmt_send(mgmt, MGMT_OP_SET_BREDR, index, sizeof(val), &val, + NULL, NULL, NULL); + + if (missing_settings & MGMT_SETTING_SSP) + mgmt_send(mgmt, MGMT_OP_SET_SSP, index, sizeof(val), &val, + NULL, NULL, NULL); + + if (missing_settings & MGMT_SETTING_LE) + mgmt_send(mgmt, MGMT_OP_SET_LE, index, sizeof(val), &val, + NULL, NULL, NULL); + + if (missing_settings & MGMT_SETTING_SECURE_CONN) + mgmt_send(mgmt, MGMT_OP_SET_SECURE_CONN, index, + sizeof(val), &val, + NULL, NULL, NULL); + + if (missing_settings & MGMT_SETTING_BONDABLE) + mgmt_send(mgmt, MGMT_OP_SET_BONDABLE, index, sizeof(val), &val, + NULL, NULL, NULL); + + if (current_settings & MGMT_SETTING_POWERED) + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + + if (!mgmt_send(mgmt, MGMT_OP_SET_POWERED, index, sizeof(val), &val, + auto_power_enable_rsp, + UINT_TO_PTR(index), NULL)) { + error("Unable to send set powerd cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void auto_power_index_evt(uint16_t index, uint16_t len, + const void *param, void *user_data) +{ + uint16_t index_filter = PTR_TO_UINT(user_data); + + if (index != index_filter) + return; + + print("New controller with index %u", index); + + if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL, + auto_power_info_rsp, + UINT_TO_PTR(index), NULL)) { + error("Unable to send read info cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void auto_power_index_rsp(uint8_t status, uint16_t len, + const void *param, void *user_data) +{ + const struct mgmt_rp_read_index_list *rp = param; + uint16_t index = PTR_TO_UINT(user_data); + uint16_t i, count; + bool found = false; + + if (status) { + error("Reading index list failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + count = le16_to_cpu(rp->num_controllers); + for (i = 0; i < count; i++) { + if (le16_to_cpu(rp->index[i]) == index) + found = true; + } + + if (!found) { + print("Waiting for index %u to appear", index); + + mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, index, + auto_power_index_evt, + UINT_TO_PTR(index), NULL); + return; + } + + print("Found controller with index %u", index); + + if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL, + auto_power_info_rsp, + UINT_TO_PTR(index), NULL)) { + error("Unable to send read info cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void cmd_auto_power(int argc, char **argv) +{ + int index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (!mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL, + auto_power_index_rsp, + UINT_TO_PTR(index), NULL)) { + error("Unable to send read index list cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void get_flags_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_get_device_flags *rp = param; + + if (status != 0) { + error("Get device flags failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("Supported Flags: 0x%08x", rp->supported_flags); + print("Current Flags: 0x%08x", rp->current_flags); + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static const struct option get_flags_options[] = { + { "help", 0, 0, 'h' }, + { "type", 1, 0, 't' }, + { 0, 0, 0, 0 } +}; + +static void cmd_get_flags(int argc, char **argv) +{ + struct mgmt_cp_get_device_flags cp; + uint8_t type = BDADDR_BREDR; + char addr[18]; + int opt; + uint16_t index; + + while ((opt = getopt_long(argc, argv, "+t:h", get_flags_options, + NULL)) != -1) { + switch (opt) { + case 't': + type = strtol(optarg, NULL, 0); + break; + case 'h': + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + default: + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc < 1) { + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + memset(&cp, 0, sizeof(cp)); + str2ba(argv[0], &cp.addr.bdaddr); + cp.addr.type = type; + + ba2str(&cp.addr.bdaddr, addr); + print("Get device flag of %s (%s)", addr, typestr(cp.addr.type)); + + if (mgmt_send(mgmt, MGMT_OP_GET_DEVICE_FLAGS, index, sizeof(cp), &cp, + get_flags_rsp, NULL, NULL) == 0) { + error("Unable to send Get Device Flags command"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void set_flags_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) { + error("Set device flags failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + bt_shell_noninteractive_quit(EXIT_FAILURE); + } + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static const struct option set_flags_options[] = { + { "help", 0, 0, 'h' }, + { "type", 1, 0, 't' }, + { "flags", 1, 0, 'f' }, + { 0, 0, 0, 0 } +}; + +static void cmd_set_flags(int argc, char **argv) +{ + struct mgmt_cp_set_device_flags cp; + uint8_t type = BDADDR_BREDR; + uint32_t flags = 0; + char addr[18]; + int opt; + uint16_t index; + + while ((opt = getopt_long(argc, argv, "+f:t:h", set_flags_options, + NULL)) != -1) { + switch (opt) { + case 'f': + flags = strtol(optarg, NULL, 0); + break; + case 't': + type = strtol(optarg, NULL, 0); + break; + case 'h': + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + default: + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc < 1) { + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + memset(&cp, 0, sizeof(cp)); + str2ba(argv[0], &cp.addr.bdaddr); + cp.addr.type = type; + cp.current_flags = flags; + + ba2str(&cp.addr.bdaddr, addr); + print("Set device flag of %s (%s)", addr, typestr(cp.addr.type)); + + if (mgmt_send(mgmt, MGMT_OP_SET_DEVICE_FLAGS, index, sizeof(cp), &cp, + set_flags_rsp, NULL, NULL) == 0) { + error("Unable to send Set Device Flags command"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + +} + +/* Wrapper to get the index and opcode to the response callback */ +struct command_data { + uint16_t id; + uint16_t op; + void (*callback) (uint16_t id, uint16_t op, uint8_t status, + uint16_t len, const void *param); +}; + +static void cmd_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + struct command_data *data = user_data; + + data->callback(data->op, data->id, status, len, param); +} + +static unsigned int send_cmd(struct mgmt *mgmt, uint16_t op, uint16_t id, + uint16_t len, const void *param, + void (*cb)(uint16_t id, uint16_t op, + uint8_t status, uint16_t len, + const void *param)) +{ + struct command_data *data; + unsigned int send_id; + + data = new0(struct command_data, 1); + if (!data) + return 0; + + data->id = id; + data->op = op; + data->callback = cb; + + send_id = mgmt_send(mgmt, op, id, len, param, cmd_rsp, data, free); + if (send_id == 0) + free(data); + + return send_id; +} + +static void setting_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len, + const void *param) +{ + const uint32_t *rp = param; + + if (status != 0) { + error("%s for hci%u failed with status 0x%02x (%s)", + mgmt_opstr(op), id, status, mgmt_errstr(status)); + goto done; + } + + if (len < sizeof(*rp)) { + error("Too small %s response (%u bytes)", + mgmt_opstr(op), len); + goto done; + } + + print("hci%u %s complete, settings: %s", id, mgmt_opstr(op), + settings2str(get_le32(rp))); + +done: + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_setting(uint16_t op, int argc, char **argv) +{ + int index; + uint8_t val; + + if (parse_setting(argc, argv, &val) == false) + return bt_shell_noninteractive_quit(EXIT_FAILURE); + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (send_cmd(mgmt, op, index, sizeof(val), &val, setting_rsp) == 0) { + error("Unable to send %s cmd", mgmt_opstr(op)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void cmd_power(int argc, char **argv) +{ + cmd_setting(MGMT_OP_SET_POWERED, argc, argv); +} + +static void cmd_discov(int argc, char **argv) +{ + struct mgmt_cp_set_discoverable cp; + uint16_t index; + + memset(&cp, 0, sizeof(cp)); + + if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0) + cp.val = 1; + else if (strcasecmp(argv[1], "off") == 0) + cp.val = 0; + else if (strcasecmp(argv[1], "limited") == 0) + cp.val = 2; + else + cp.val = atoi(argv[1]); + + if (argc > 2) + cp.timeout = htobs(atoi(argv[2])); + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (send_cmd(mgmt, MGMT_OP_SET_DISCOVERABLE, index, sizeof(cp), &cp, + setting_rsp) == 0) { + error("Unable to send set_discoverable cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void cmd_connectable(int argc, char **argv) +{ + cmd_setting(MGMT_OP_SET_CONNECTABLE, argc, argv); +} + +static void cmd_fast_conn(int argc, char **argv) +{ + cmd_setting(MGMT_OP_SET_FAST_CONNECTABLE, argc, argv); +} + +static void cmd_bondable(int argc, char **argv) +{ + cmd_setting(MGMT_OP_SET_BONDABLE, argc, argv); +} + +static void cmd_linksec(int argc, char **argv) +{ + cmd_setting(MGMT_OP_SET_LINK_SECURITY, argc, argv); +} + +static void cmd_ssp(int argc, char **argv) +{ + cmd_setting(MGMT_OP_SET_SSP, argc, argv); +} + +static void cmd_sc(int argc, char **argv) +{ + uint8_t val; + uint16_t index; + + if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0) + val = 1; + else if (strcasecmp(argv[1], "off") == 0) + val = 0; + else if (strcasecmp(argv[1], "only") == 0) + val = 2; + else + val = atoi(argv[1]); + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (send_cmd(mgmt, MGMT_OP_SET_SECURE_CONN, index, + sizeof(val), &val, setting_rsp) == 0) { + error("Unable to send set_secure_conn cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void cmd_hs(int argc, char **argv) +{ + cmd_setting(MGMT_OP_SET_HS, argc, argv); +} + +static void cmd_le(int argc, char **argv) +{ + cmd_setting(MGMT_OP_SET_LE, argc, argv); +} + +static void cmd_advertising(int argc, char **argv) +{ + cmd_setting(MGMT_OP_SET_ADVERTISING, argc, argv); +} + +static void cmd_bredr(int argc, char **argv) +{ + cmd_setting(MGMT_OP_SET_BREDR, argc, argv); +} + +static void cmd_privacy(int argc, char **argv) +{ + struct mgmt_cp_set_privacy cp; + uint16_t index; + + if (parse_setting(argc, argv, &cp.privacy) == false) + return bt_shell_noninteractive_quit(EXIT_FAILURE); + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (argc > 2) { + if (hex2bin(argv[2], cp.irk, + sizeof(cp.irk)) != sizeof(cp.irk)) { + error("Invalid key format"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } else { + int fd; + + fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + error("open(/dev/urandom): %s", strerror(errno)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (read(fd, cp.irk, sizeof(cp.irk)) != sizeof(cp.irk)) { + error("Reading from urandom failed"); + close(fd); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + close(fd); + } + + if (send_cmd(mgmt, MGMT_OP_SET_PRIVACY, index, sizeof(cp), &cp, + setting_rsp) == 0) { + error("Unable to send Set Privacy command"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void exp_offload_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) + error("Set offload codec failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + else + print("Offload codec feature successfully set"); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_exp_offload_codecs(int argc, char **argv) +{ + /* a6695ace-ee7f-4fb9-881a-5fac66c629af */ + static const uint8_t uuid[16] = { + 0xaf, 0x29, 0xc6, 0x66, 0xac, 0x5f, 0x1a, 0x88, + 0xb9, 0x4f, 0x7f, 0xee, 0xce, 0x5a, 0x69, 0xa6, + }; + + struct mgmt_cp_set_exp_feature cp; + uint8_t val; + uint16_t index; + + if (parse_setting(argc, argv, &val) == false) + return bt_shell_noninteractive_quit(EXIT_FAILURE); + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + memset(&cp, 0, sizeof(cp)); + memcpy(cp.uuid, uuid, 16); + cp.action = val; + + if (mgmt_send(mgmt, MGMT_OP_SET_EXP_FEATURE, index, + sizeof(cp), &cp, exp_offload_rsp, NULL, NULL) == 0) { + error("Unable to send offload codecs feature cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void class_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len, + const void *param) +{ + const struct mgmt_ev_class_of_dev_changed *rp = param; + + if (len == 0 && status != 0) { + error("%s failed, status 0x%02x (%s)", + mgmt_opstr(op), status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len != sizeof(*rp)) { + error("Unexpected %s len %u", mgmt_opstr(op), len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("%s succeeded. Class 0x%02x%02x%02x", mgmt_opstr(op), + rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_class(int argc, char **argv) +{ + uint8_t class[2]; + uint16_t index; + + class[0] = atoi(argv[1]); + class[1] = atoi(argv[2]); + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (send_cmd(mgmt, MGMT_OP_SET_DEV_CLASS, index, sizeof(class), class, + class_rsp) == 0) { + error("Unable to send set_dev_class cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void disconnect_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_disconnect *rp = param; + char addr[18]; + + if (len == 0 && status != 0) { + error("Disconnect failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len != sizeof(*rp)) { + error("Invalid disconnect response length (%u)", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + ba2str(&rp->addr.bdaddr, addr); + + if (status == 0) + print("%s disconnected", addr); + else + error("Disconnecting %s failed with status 0x%02x (%s)", + addr, status, mgmt_errstr(status)); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static const struct option disconnect_options[] = { + { "help", 0, 0, 'h' }, + { "type", 1, 0, 't' }, + { 0, 0, 0, 0 } +}; + +static void cmd_disconnect(int argc, char **argv) +{ + struct mgmt_cp_disconnect cp; + uint8_t type = BDADDR_BREDR; + int opt; + uint16_t index; + + while ((opt = getopt_long(argc, argv, "+t:h", disconnect_options, + NULL)) != -1) { + switch (opt) { + case 't': + type = strtol(optarg, NULL, 0); + break; + case 'h': + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + default: + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + argv += optind; + optind = 0; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + memset(&cp, 0, sizeof(cp)); + str2ba(argv[0], &cp.addr.bdaddr); + cp.addr.type = type; + + if (mgmt_send(mgmt, MGMT_OP_DISCONNECT, index, sizeof(cp), &cp, + disconnect_rsp, NULL, NULL) == 0) { + error("Unable to send disconnect cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void con_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_get_connections *rp = param; + uint16_t count, i; + + if (len < sizeof(*rp)) { + error("Too small (%u bytes) get_connections rsp", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + count = get_le16(&rp->conn_count); + if (len != sizeof(*rp) + count * sizeof(struct mgmt_addr_info)) { + error("Invalid get_connections length (count=%u, len=%u)", + count, len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + for (i = 0; i < count; i++) { + char addr[18]; + + ba2str(&rp->addr[i].bdaddr, addr); + + print("%s type %s", addr, typestr(rp->addr[i].type)); + } + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_con(int argc, char **argv) +{ + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (mgmt_send(mgmt, MGMT_OP_GET_CONNECTIONS, index, 0, NULL, + con_rsp, NULL, NULL) == 0) { + error("Unable to send get_connections cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void find_service_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) { + error("Start Service Discovery failed: status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("Service discovery started"); + discovery = true; +} + +static const struct option find_service_options[] = { + { "help", no_argument, 0, 'h' }, + { "le-only", no_argument, 0, 'l' }, + { "bredr-only", no_argument, 0, 'b' }, + { "uuid", required_argument, 0, 'u' }, + { "rssi", required_argument, 0, 'r' }, + { 0, 0, 0, 0 } +}; + +#define MAX_UUIDS 4 + +static void cmd_find_service(int argc, char **argv) +{ + struct mgmt_cp_start_service_discovery *cp; + uint8_t buf[sizeof(*cp) + 16 * MAX_UUIDS]; + bt_uuid_t uuid; + uint8_t type = SCAN_TYPE_DUAL; + int8_t rssi; + uint16_t count; + int opt; + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + rssi = 127; + count = 0; + + while ((opt = getopt_long(argc, argv, "+lbu:r:h", + find_service_options, NULL)) != -1) { + switch (opt) { + case 'l': + type &= ~SCAN_TYPE_BREDR; + type |= SCAN_TYPE_LE; + break; + case 'b': + type |= SCAN_TYPE_BREDR; + type &= ~SCAN_TYPE_LE; + break; + case 'u': + if (count == MAX_UUIDS) { + print("Max %u UUIDs supported", MAX_UUIDS); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (bt_string_to_uuid(&uuid, optarg) < 0) { + print("Invalid UUID: %s", optarg); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + cp = (void *) buf; + bt_uuid_to_le(&uuid, cp->uuids[count++]); + break; + case 'r': + rssi = atoi(optarg); + break; + case 'h': + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + default: + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + optind = 0; + + cp = (void *) buf; + cp->type = type; + cp->rssi = rssi; + cp->uuid_count = cpu_to_le16(count); + + if (mgmt_send(mgmt, MGMT_OP_START_SERVICE_DISCOVERY, index, + sizeof(*cp) + count * 16, cp, + find_service_rsp, NULL, NULL) == 0) { + error("Unable to send start_service_discovery cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void find_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) { + error("Unable to start discovery. status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("Discovery started"); + discovery = true; +} + +static const struct option find_options[] = { + { "help", 0, 0, 'h' }, + { "le-only", 1, 0, 'l' }, + { "bredr-only", 1, 0, 'b' }, + { "limited", 1, 0, 'L' }, + { 0, 0, 0, 0 } +}; + +static void cmd_find(int argc, char **argv) +{ + struct mgmt_cp_start_discovery cp; + uint8_t op = MGMT_OP_START_DISCOVERY; + uint8_t type = SCAN_TYPE_DUAL; + int opt; + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + while ((opt = getopt_long(argc, argv, "+lbLh", find_options, + NULL)) != -1) { + switch (opt) { + case 'l': + type &= ~SCAN_TYPE_BREDR; + type |= SCAN_TYPE_LE; + break; + case 'b': + type |= SCAN_TYPE_BREDR; + type &= ~SCAN_TYPE_LE; + break; + case 'L': + op = MGMT_OP_START_LIMITED_DISCOVERY; + break; + case 'h': + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + default: + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + optind = 0; + + memset(&cp, 0, sizeof(cp)); + cp.type = type; + + if (mgmt_send(mgmt, op, index, sizeof(cp), &cp, find_rsp, + NULL, NULL) == 0) { + error("Unable to send start_discovery cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void stop_find_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) { + error("Stop Discovery failed: status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + } + + print("Discovery stopped"); + discovery = false; + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static const struct option stop_find_options[] = { + { "help", 0, 0, 'h' }, + { "le-only", 1, 0, 'l' }, + { "bredr-only", 1, 0, 'b' }, + { 0, 0, 0, 0 } +}; + +static void cmd_stop_find(int argc, char **argv) +{ + struct mgmt_cp_stop_discovery cp; + uint8_t type = SCAN_TYPE_DUAL; + int opt; + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + while ((opt = getopt_long(argc, argv, "+lbh", stop_find_options, + NULL)) != -1) { + switch (opt) { + case 'l': + type &= ~SCAN_TYPE_BREDR; + type |= SCAN_TYPE_LE; + break; + case 'b': + type |= SCAN_TYPE_BREDR; + type &= ~SCAN_TYPE_LE; + break; + case 'h': + default: + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + } + } + + optind = 0; + + memset(&cp, 0, sizeof(cp)); + cp.type = type; + + if (mgmt_send(mgmt, MGMT_OP_STOP_DISCOVERY, index, sizeof(cp), &cp, + stop_find_rsp, NULL, NULL) == 0) { + error("Unable to send stop_discovery cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void name_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) + error("Unable to set local name with status 0x%02x (%s)", + status, mgmt_errstr(status)); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_name(int argc, char **argv) +{ + struct mgmt_cp_set_local_name cp; + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + memset(&cp, 0, sizeof(cp)); + strncpy((char *) cp.name, argv[1], HCI_MAX_NAME_LENGTH); + if (argc > 2) + strncpy((char *) cp.short_name, argv[2], + MGMT_MAX_SHORT_NAME_LENGTH - 1); + + if (mgmt_send(mgmt, MGMT_OP_SET_LOCAL_NAME, index, sizeof(cp), &cp, + name_rsp, NULL, NULL) == 0) { + error("Unable to send set_name cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void pair_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_pair_device *rp = param; + char addr[18]; + + if (len == 0 && status != 0) { + error("Pairing failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len != sizeof(*rp)) { + error("Unexpected pair_rsp len %u", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + ba2str(&rp->addr.bdaddr, addr); + + if (status) + error("Pairing with %s (%s) failed. status 0x%02x (%s)", + addr, typestr(rp->addr.type), status, + mgmt_errstr(status)); + else + print("Paired with %s (%s)", addr, typestr(rp->addr.type)); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void register_pair_callbacks(struct mgmt *mgmt, uint16_t index) +{ + mgmt_register(mgmt, MGMT_EV_PIN_CODE_REQUEST, index, request_pin, + mgmt, NULL); + mgmt_register(mgmt, MGMT_EV_USER_CONFIRM_REQUEST, index, user_confirm, + mgmt, NULL); + mgmt_register(mgmt, MGMT_EV_USER_PASSKEY_REQUEST, index, + request_passkey, mgmt, NULL); + mgmt_register(mgmt, MGMT_EV_PASSKEY_NOTIFY, index, + passkey_notify, mgmt, NULL); +} + +static const struct option pair_options[] = { + { "help", 0, 0, 'h' }, + { "capability", 1, 0, 'c' }, + { "type", 1, 0, 't' }, + { 0, 0, 0, 0 } +}; + +static void cmd_pair(int argc, char **argv) +{ + struct mgmt_cp_pair_device cp; + uint8_t cap = 0x01; + uint8_t type = BDADDR_BREDR; + char addr[18]; + int opt; + uint16_t index; + + while ((opt = getopt_long(argc, argv, "+c:t:h", pair_options, + NULL)) != -1) { + switch (opt) { + case 'c': + cap = strtol(optarg, NULL, 0); + break; + case 't': + type = strtol(optarg, NULL, 0); + break; + case 'h': + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + default: + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc < 1) { + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + register_pair_callbacks(mgmt, index); + + memset(&cp, 0, sizeof(cp)); + str2ba(argv[0], &cp.addr.bdaddr); + cp.addr.type = type; + cp.io_cap = cap; + + ba2str(&cp.addr.bdaddr, addr); + print("Pairing with %s (%s)", addr, typestr(cp.addr.type)); + + if (mgmt_send(mgmt, MGMT_OP_PAIR_DEVICE, index, sizeof(cp), &cp, + pair_rsp, NULL, NULL) == 0) { + error("Unable to send pair_device cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void cancel_pair_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_addr_info *rp = param; + char addr[18]; + + if (len == 0 && status != 0) { + error("Cancel Pairing failed with 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len != sizeof(*rp)) { + error("Unexpected cancel_pair_rsp len %u", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + ba2str(&rp->bdaddr, addr); + + if (status) + error("Cancel Pairing with %s (%s) failed. 0x%02x (%s)", + addr, typestr(rp->type), status, + mgmt_errstr(status)); + else + print("Pairing Cancelled with %s", addr); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static const struct option cancel_pair_options[] = { + { "help", 0, 0, 'h' }, + { "type", 1, 0, 't' }, + { 0, 0, 0, 0 } +}; + +static void cmd_cancel_pair(int argc, char **argv) +{ + struct mgmt_addr_info cp; + uint8_t type = BDADDR_BREDR; + int opt; + uint16_t index; + + while ((opt = getopt_long(argc, argv, "+t:h", cancel_pair_options, + NULL)) != -1) { + switch (opt) { + case 't': + type = strtol(optarg, NULL, 0); + break; + case 'h': + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + default: + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc < 1) { + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + memset(&cp, 0, sizeof(cp)); + str2ba(argv[0], &cp.bdaddr); + cp.type = type; + + if (mgmt_reply(mgmt, MGMT_OP_CANCEL_PAIR_DEVICE, index, sizeof(cp), &cp, + cancel_pair_rsp, NULL, NULL) == 0) { + error("Unable to send cancel_pair_device cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void unpair_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_unpair_device *rp = param; + char addr[18]; + + if (len == 0 && status != 0) { + error("Unpair device failed. status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len != sizeof(*rp)) { + error("Unexpected unpair_device_rsp len %u", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + ba2str(&rp->addr.bdaddr, addr); + + if (status) + error("Unpairing %s failed. status 0x%02x (%s)", + addr, status, mgmt_errstr(status)); + else + print("%s unpaired", addr); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static const struct option unpair_options[] = { + { "help", 0, 0, 'h' }, + { "type", 1, 0, 't' }, + { 0, 0, 0, 0 } +}; + +static void cmd_unpair(int argc, char **argv) +{ + struct mgmt_cp_unpair_device cp; + uint8_t type = BDADDR_BREDR; + int opt; + uint16_t index; + + while ((opt = getopt_long(argc, argv, "+t:h", unpair_options, + NULL)) != -1) { + switch (opt) { + case 't': + type = strtol(optarg, NULL, 0); + break; + case 'h': + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + default: + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc < 1) { + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + memset(&cp, 0, sizeof(cp)); + str2ba(argv[0], &cp.addr.bdaddr); + cp.addr.type = type; + cp.disconnect = 1; + + if (mgmt_send(mgmt, MGMT_OP_UNPAIR_DEVICE, index, sizeof(cp), &cp, + unpair_rsp, NULL, NULL) == 0) { + error("Unable to send unpair_device cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void keys_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) + error("Load keys failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + else + print("Keys successfully loaded"); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_keys(int argc, char **argv) +{ + struct mgmt_cp_load_link_keys cp; + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + memset(&cp, 0, sizeof(cp)); + + if (mgmt_send(mgmt, MGMT_OP_LOAD_LINK_KEYS, index, sizeof(cp), &cp, + keys_rsp, NULL, NULL) == 0) { + error("Unable to send load_keys cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void ltks_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) + error("Load keys failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + else + print("Long term keys successfully loaded"); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_ltks(int argc, char **argv) +{ + struct mgmt_cp_load_long_term_keys cp; + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + memset(&cp, 0, sizeof(cp)); + + if (mgmt_send(mgmt, MGMT_OP_LOAD_LONG_TERM_KEYS, index, sizeof(cp), &cp, + ltks_rsp, NULL, NULL) == 0) { + error("Unable to send load_ltks cmd"); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + } +} + +static void irks_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) + error("Load IRKs failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + else + print("Identity Resolving Keys successfully loaded"); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static const struct option irks_options[] = { + { "help", 0, 0, 'h' }, + { "local", 1, 0, 'l' }, + { "file", 1, 0, 'f' }, + { 0, 0, 0, 0 } +}; + +#define MAX_IRKS 4 + +static void cmd_irks(int argc, char **argv) +{ + struct mgmt_cp_load_irks *cp; + uint8_t buf[sizeof(*cp) + 23 * MAX_IRKS]; + uint16_t count, local_index; + char path[PATH_MAX]; + int opt; + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + cp = (void *) buf; + count = 0; + + while ((opt = getopt_long(argc, argv, "+l:f:h", + irks_options, NULL)) != -1) { + switch (opt) { + case 'l': + if (count >= MAX_IRKS) { + error("Number of IRKs exceeded"); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + if (strlen(optarg) > 3 && + strncasecmp(optarg, "hci", 3) == 0) + local_index = atoi(optarg + 3); + else + local_index = atoi(optarg); + snprintf(path, sizeof(path), + "/sys/kernel/debug/bluetooth/hci%u/identity", + local_index); + if (!load_identity(path, &cp->irks[count])) { + error("Unable to load identity"); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + count++; + break; + case 'f': + if (count >= MAX_IRKS) { + error("Number of IRKs exceeded"); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + if (!load_identity(optarg, &cp->irks[count])) { + error("Unable to load identities"); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + count++; + break; + case 'h': + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + default: + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + optind = 0; + + cp->irk_count = cpu_to_le16(count); + + if (mgmt_send(mgmt, MGMT_OP_LOAD_IRKS, index, + sizeof(*cp) + count * 23, cp, + irks_rsp, NULL, NULL) == 0) { + error("Unable to send load_irks cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void block_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len, + const void *param) +{ + const struct mgmt_addr_info *rp = param; + char addr[18]; + + if (len == 0 && status != 0) { + error("%s failed, status 0x%02x (%s)", + mgmt_opstr(op), status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len != sizeof(*rp)) { + error("Unexpected %s len %u", mgmt_opstr(op), len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + ba2str(&rp->bdaddr, addr); + + if (status) + error("%s %s (%s) failed. status 0x%02x (%s)", + mgmt_opstr(op), addr, typestr(rp->type), + status, mgmt_errstr(status)); + else + print("%s %s succeeded", mgmt_opstr(op), addr); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static const struct option block_options[] = { + { "help", 0, 0, 'h' }, + { "type", 1, 0, 't' }, + { 0, 0, 0, 0 } +}; + +static void cmd_block(int argc, char **argv) +{ + struct mgmt_cp_block_device cp; + uint8_t type = BDADDR_BREDR; + int opt; + uint16_t index; + + while ((opt = getopt_long(argc, argv, "+t:h", block_options, + NULL)) != -1) { + switch (opt) { + case 't': + type = strtol(optarg, NULL, 0); + break; + case 'h': + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + default: + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc < 1) { + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + memset(&cp, 0, sizeof(cp)); + str2ba(argv[0], &cp.addr.bdaddr); + cp.addr.type = type; + + if (send_cmd(mgmt, MGMT_OP_BLOCK_DEVICE, index, sizeof(cp), &cp, + block_rsp) == 0) { + error("Unable to send block_device cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void cmd_unblock(int argc, char **argv) +{ + struct mgmt_cp_unblock_device cp; + uint8_t type = BDADDR_BREDR; + int opt; + uint16_t index; + + while ((opt = getopt_long(argc, argv, "+t:h", block_options, + NULL)) != -1) { + switch (opt) { + case 't': + type = strtol(optarg, NULL, 0); + break; + case 'h': + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + default: + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc < 1) { + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + memset(&cp, 0, sizeof(cp)); + str2ba(argv[0], &cp.addr.bdaddr); + cp.addr.type = type; + + if (send_cmd(mgmt, MGMT_OP_UNBLOCK_DEVICE, index, sizeof(cp), &cp, + block_rsp) == 0) { + error("Unable to send unblock_device cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void cmd_add_uuid(int argc, char **argv) +{ + struct mgmt_cp_add_uuid cp; + bt_uuid_t uuid; + uint16_t index; + + if (argc < 3) { + print("UUID and service hint needed"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (bt_string_to_uuid(&uuid, argv[1]) < 0) { + print("Invalid UUID: %s", argv[1]); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + memset(&cp, 0, sizeof(cp)); + bt_uuid_to_le(&uuid, cp.uuid); + + cp.svc_hint = atoi(argv[2]); + + if (send_cmd(mgmt, MGMT_OP_ADD_UUID, index, sizeof(cp), &cp, + class_rsp) == 0) { + error("Unable to send add_uuid cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void cmd_remove_uuid(int argc, char **argv) +{ + struct mgmt_cp_remove_uuid cp; + bt_uuid_t uuid; + uint16_t index; + + if (argc < 2) { + print("UUID needed"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (bt_string_to_uuid(&uuid, argv[1]) < 0) { + print("Invalid UUID: %s", argv[1]); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + memset(&cp, 0, sizeof(cp)); + + bt_uuid_to_le(&uuid, cp.uuid); + + if (send_cmd(mgmt, MGMT_OP_REMOVE_UUID, index, sizeof(cp), &cp, + class_rsp) == 0) { + error("Unable to send remove_uuid cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void cmd_clr_uuids(int argc, char **argv) +{ + char *uuid_any = "00000000-0000-0000-0000-000000000000"; + char *rm_argv[] = { "rm-uuid", uuid_any, NULL }; + + cmd_remove_uuid(2, rm_argv); +} + +static void local_oob_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_read_local_oob_data *rp = param; + char str[33]; + + if (status != 0) { + error("Read Local OOB Data failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len < sizeof(*rp)) { + error("Too small (%u bytes) read_local_oob rsp", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + bin2hex(rp->hash192, 16, str, sizeof(str)); + print("Hash C from P-192: %s", str); + + bin2hex(rp->rand192, 16, str, sizeof(str)); + print("Randomizer R with P-192: %s", str); + + if (len < sizeof(*rp)) + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + + bin2hex(rp->hash256, 16, str, sizeof(str)); + print("Hash C from P-256: %s", str); + + bin2hex(rp->rand256, 16, str, sizeof(str)); + print("Randomizer R with P-256: %s", str); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_local_oob(int argc, char **argv) +{ + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_DATA, index, 0, NULL, + local_oob_rsp, NULL, NULL) == 0) { + error("Unable to send read_local_oob cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void remote_oob_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_addr_info *rp = param; + char addr[18]; + + if (status != 0) { + error("Add Remote OOB Data failed: 0x%02x (%s)", + status, mgmt_errstr(status)); + return; + } + + if (len < sizeof(*rp)) { + error("Too small (%u bytes) add_remote_oob rsp", len); + return; + } + + ba2str(&rp->bdaddr, addr); + print("Remote OOB data added for %s (%u)", addr, rp->type); +} + +static const struct option remote_oob_opt[] = { + { "help", 0, 0, '?' }, + { "type", 1, 0, 't' }, + { 0, 0, 0, 0 } +}; + +static void cmd_remote_oob(int argc, char **argv) +{ + struct mgmt_cp_add_remote_oob_data cp; + int opt; + uint16_t index; + + memset(&cp, 0, sizeof(cp)); + cp.addr.type = BDADDR_BREDR; + + while ((opt = getopt_long(argc, argv, "+t:r:R:h:H:", + remote_oob_opt, NULL)) != -1) { + switch (opt) { + case 't': + cp.addr.type = strtol(optarg, NULL, 0); + break; + case 'r': + hex2bin(optarg, cp.rand192, 16); + break; + case 'h': + hex2bin(optarg, cp.hash192, 16); + break; + case 'R': + hex2bin(optarg, cp.rand256, 16); + break; + case 'H': + hex2bin(optarg, cp.hash256, 16); + break; + default: + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc < 1) { + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + str2ba(argv[0], &cp.addr.bdaddr); + + print("Adding OOB data for %s (%s)", argv[0], typestr(cp.addr.type)); + + if (mgmt_send(mgmt, MGMT_OP_ADD_REMOTE_OOB_DATA, index, + sizeof(cp), &cp, remote_oob_rsp, + NULL, NULL) == 0) { + error("Unable to send add_remote_oob cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void did_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) + error("Set Device ID failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + else + print("Device ID successfully set"); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_did(int argc, char **argv) +{ + struct mgmt_cp_set_device_id cp; + uint16_t vendor, product, version , source; + int result; + uint16_t index; + + result = sscanf(argv[1], "bluetooth:%4hx:%4hx:%4hx", &vendor, &product, + &version); + if (result == 3) { + source = 0x0001; + goto done; + } + + result = sscanf(argv[1], "usb:%4hx:%4hx:%4hx", &vendor, &product, + &version); + if (result == 3) { + source = 0x0002; + goto done; + } + + return; +done: + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + cp.source = htobs(source); + cp.vendor = htobs(vendor); + cp.product = htobs(product); + cp.version = htobs(version); + + if (mgmt_send(mgmt, MGMT_OP_SET_DEVICE_ID, index, sizeof(cp), &cp, + did_rsp, NULL, NULL) == 0) { + error("Unable to send set_device_id cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void static_addr_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) + error("Set static address failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + else + print("Static address successfully set"); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_static_addr(int argc, char **argv) +{ + struct mgmt_cp_set_static_address cp; + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + str2ba(argv[1], &cp.bdaddr); + + if (mgmt_send(mgmt, MGMT_OP_SET_STATIC_ADDRESS, index, sizeof(cp), &cp, + static_addr_rsp, NULL, NULL) == 0) { + error("Unable to send set_static_address cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void options_rsp(uint16_t op, uint16_t id, uint8_t status, + uint16_t len, const void *param) +{ + const uint32_t *rp = param; + + if (status != 0) { + error("%s for hci%u failed with status 0x%02x (%s)", + mgmt_opstr(op), id, status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len < sizeof(*rp)) { + error("Too small %s response (%u bytes)", + mgmt_opstr(op), len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("hci%u %s complete, options: %s", id, mgmt_opstr(op), + options2str(get_le32(rp))); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_public_addr(int argc, char **argv) +{ + struct mgmt_cp_set_public_address cp; + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + str2ba(argv[1], &cp.bdaddr); + + if (send_cmd(mgmt, MGMT_OP_SET_PUBLIC_ADDRESS, index, sizeof(cp), &cp, + options_rsp) == 0) { + error("Unable to send Set Public Address cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void cmd_ext_config(int argc, char **argv) +{ + struct mgmt_cp_set_external_config cp; + uint16_t index; + + if (parse_setting(argc, argv, &cp.config) == false) + return bt_shell_noninteractive_quit(EXIT_FAILURE); + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (send_cmd(mgmt, MGMT_OP_SET_EXTERNAL_CONFIG, index, sizeof(cp), &cp, + options_rsp) == 0) { + error("Unable to send Set External Config cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void cmd_debug_keys(int argc, char **argv) +{ + cmd_setting(MGMT_OP_SET_DEBUG_KEYS, argc, argv); +} + +static void conn_info_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_get_conn_info *rp = param; char addr[18]; + + if (len == 0 && status != 0) { + error("Get Conn Info failed, status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len < sizeof(*rp)) { + error("Unexpected Get Conn Info len %u", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + ba2str(&rp->addr.bdaddr, addr); + + if (status) { + error("Get Conn Info for %s (%s) failed. status 0x%02x (%s)", + addr, typestr(rp->addr.type), + status, mgmt_errstr(status)); + } else { + print("Connection Information for %s (%s)", + addr, typestr(rp->addr.type)); + print("\tRSSI %d\tTX power %d\tmaximum TX power %d", + rp->rssi, rp->tx_power, rp->max_tx_power); + } + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static const struct option conn_info_options[] = { + { "help", 0, 0, 'h' }, + { "type", 1, 0, 't' }, + { 0, 0, 0, 0 } +}; + +static void cmd_conn_info(int argc, char **argv) +{ + struct mgmt_cp_get_conn_info cp; + uint8_t type = BDADDR_BREDR; + int opt; + uint16_t index; + + while ((opt = getopt_long(argc, argv, "+t:h", conn_info_options, + NULL)) != -1) { + switch (opt) { + case 't': + type = strtol(optarg, NULL, 0); + break; + case 'h': + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + default: + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc < 1) { + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + memset(&cp, 0, sizeof(cp)); + str2ba(argv[0], &cp.addr.bdaddr); + cp.addr.type = type; + + if (mgmt_send(mgmt, MGMT_OP_GET_CONN_INFO, index, sizeof(cp), &cp, + conn_info_rsp, NULL, NULL) == 0) { + error("Unable to send get_conn_info cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void io_cap_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) + error("Could not set IO Capability with status 0x%02x (%s)", + status, mgmt_errstr(status)); + else + print("IO Capabilities successfully set"); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_io_cap(int argc, char **argv) +{ + struct mgmt_cp_set_io_capability cp; + uint8_t cap; + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + cap = strtol(argv[1], NULL, 0); + memset(&cp, 0, sizeof(cp)); + cp.io_capability = cap; + + if (mgmt_send(mgmt, MGMT_OP_SET_IO_CAPABILITY, index, sizeof(cp), &cp, + io_cap_rsp, NULL, NULL) == 0) { + error("Unable to send set-io-cap cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void scan_params_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) + error("Set scan parameters failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + else + print("Scan parameters successfully set"); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_scan_params(int argc, char **argv) +{ + struct mgmt_cp_set_scan_params cp; + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + cp.interval = strtol(argv[1], NULL, 0); + cp.window = strtol(argv[2], NULL, 0); + + if (mgmt_send(mgmt, MGMT_OP_SET_SCAN_PARAMS, index, sizeof(cp), &cp, + scan_params_rsp, NULL, NULL) == 0) { + error("Unable to send set_scan_params cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void clock_info_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_get_clock_info *rp = param; + + if (len < sizeof(*rp)) { + error("Unexpected Get Clock Info len %u", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (status) { + error("Get Clock Info failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("Local Clock: %u", le32_to_cpu(rp->local_clock)); + print("Piconet Clock: %u", le32_to_cpu(rp->piconet_clock)); + print("Accurary: %u", le16_to_cpu(rp->accuracy)); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_clock_info(int argc, char **argv) +{ + struct mgmt_cp_get_clock_info cp; + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + memset(&cp, 0, sizeof(cp)); + + if (argc > 1) + str2ba(argv[1], &cp.addr.bdaddr); + + if (mgmt_send(mgmt, MGMT_OP_GET_CLOCK_INFO, index, sizeof(cp), &cp, + clock_info_rsp, NULL, NULL) == 0) { + error("Unable to send get_clock_info cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void add_device_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) + error("Add device failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static const struct option add_device_options[] = { + { "help", 0, 0, 'h' }, + { "action", 1, 0, 'a' }, + { "type", 1, 0, 't' }, + { 0, 0, 0, 0 } +}; + +static void cmd_add_device(int argc, char **argv) +{ + struct mgmt_cp_add_device cp; + uint8_t action = 0x00; + uint8_t type = BDADDR_BREDR; + char addr[18]; + int opt; + uint16_t index; + + while ((opt = getopt_long(argc, argv, "+a:t:h", add_device_options, + NULL)) != -1) { + switch (opt) { + case 'a': + action = strtol(optarg, NULL, 0); + break; + case 't': + type = strtol(optarg, NULL, 0); + break; + case 'h': + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + default: + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc < 1) { + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + memset(&cp, 0, sizeof(cp)); + str2ba(argv[0], &cp.addr.bdaddr); + cp.addr.type = type; + cp.action = action; + + ba2str(&cp.addr.bdaddr, addr); + print("Adding device with %s (%s)", addr, typestr(cp.addr.type)); + + if (mgmt_send(mgmt, MGMT_OP_ADD_DEVICE, index, sizeof(cp), &cp, + add_device_rsp, NULL, NULL) == 0) { + error("Unable to send add device command"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void remove_device_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) + error("Remove device failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static const struct option del_device_options[] = { + { "help", 0, 0, 'h' }, + { "type", 1, 0, 't' }, + { 0, 0, 0, 0 } +}; + +static void cmd_del_device(int argc, char **argv) +{ + struct mgmt_cp_remove_device cp; + uint8_t type = BDADDR_BREDR; + char addr[18]; + int opt; + uint16_t index; + + while ((opt = getopt_long(argc, argv, "+t:h", del_device_options, + NULL)) != -1) { + switch (opt) { + case 't': + type = strtol(optarg, NULL, 0); + break; + case 'h': + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + default: + bt_shell_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc < 1) { + bt_shell_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + memset(&cp, 0, sizeof(cp)); + str2ba(argv[0], &cp.addr.bdaddr); + cp.addr.type = type; + + ba2str(&cp.addr.bdaddr, addr); + print("Removing device with %s (%s)", addr, typestr(cp.addr.type)); + + if (mgmt_send(mgmt, MGMT_OP_REMOVE_DEVICE, index, sizeof(cp), &cp, + remove_device_rsp, NULL, NULL) == 0) { + error("Unable to send remove device command"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void cmd_clr_devices(int argc, char **argv) +{ + char *bdaddr_any = "00:00:00:00:00:00"; + char *rm_argv[] = { "del-device", bdaddr_any, NULL }; + + cmd_del_device(2, rm_argv); +} + +static void local_oob_ext_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_read_local_oob_ext_data *rp = param; + uint16_t eir_len; + + if (status != 0) { + error("Read Local OOB Ext Data failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len < sizeof(*rp)) { + error("Too small (%u bytes) read_local_oob_ext rsp", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + eir_len = le16_to_cpu(rp->eir_len); + if (len != sizeof(*rp) + eir_len) { + error("local_oob_ext: expected %zu bytes, got %u bytes", + sizeof(*rp) + eir_len, len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print_eir(rp->eir, eir_len); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_bredr_oob(int argc, char **argv) +{ + struct mgmt_cp_read_local_oob_ext_data cp; + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + cp.type = SCAN_TYPE_BREDR; + + if (!mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, + index, sizeof(cp), &cp, + local_oob_ext_rsp, NULL, NULL)) { + error("Unable to send read_local_oob_ext cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void cmd_le_oob(int argc, char **argv) +{ + struct mgmt_cp_read_local_oob_ext_data cp; + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + cp.type = SCAN_TYPE_LE; + + if (!mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, + index, sizeof(cp), &cp, + local_oob_ext_rsp, NULL, NULL)) { + error("Unable to send read_local_oob_ext cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static const char *adv_flags_str[] = { + "connectable", + "general-discoverable", + "limited-discoverable", + "managed-flags", + "tx-power", + "scan-rsp-appearance", + "scan-rsp-local-name", + "Secondary-channel-1M", + "Secondary-channel-2M", + "Secondary-channel-CODED", +}; + +static const char *adv_flags2str(uint32_t flags) +{ + static char str[256]; + unsigned i; + int off; + + off = 0; + str[0] = '\0'; + + for (i = 0; i < NELEM(adv_flags_str); i++) { + if ((flags & (1 << i)) != 0) + off += snprintf(str + off, sizeof(str) - off, "%s ", + adv_flags_str[i]); + } + + return str; +} + +static void adv_features_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_read_adv_features *rp = param; + uint32_t supported_flags; + + if (status != 0) { + error("Reading adv features failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len < sizeof(*rp)) { + error("Too small adv features reply (%u bytes)", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len < sizeof(*rp) + rp->num_instances * sizeof(uint8_t)) { + error("Instances count (%u) doesn't match reply length (%u)", + rp->num_instances, len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + supported_flags = le32_to_cpu(rp->supported_flags); + print("Supported flags: %s", adv_flags2str(supported_flags)); + print("Max advertising data len: %u", rp->max_adv_data_len); + print("Max scan response data len: %u", rp->max_scan_rsp_len); + print("Max instances: %u", rp->max_instances); + + print("Instances list with %u item%s", rp->num_instances, + rp->num_instances != 1 ? "s" : ""); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_advinfo(int argc, char **argv) +{ + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (!mgmt_send(mgmt, MGMT_OP_READ_ADV_FEATURES, index, 0, NULL, + adv_features_rsp, NULL, NULL)) { + error("Unable to send advertising features command"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void adv_size_info_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_get_adv_size_info *rp = param; + uint32_t flags; + + if (status != 0) { + error("Reading adv size info failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len < sizeof(*rp)) { + error("Too small adv size info reply (%u bytes)", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + flags = le32_to_cpu(rp->flags); + print("Instance: %u", rp->instance); + print("Flags: %s", adv_flags2str(flags)); + print("Max advertising data len: %u", rp->max_adv_data_len); + print("Max scan response data len: %u", rp->max_scan_rsp_len); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void advsize_usage(void) +{ + bt_shell_usage(); + print("Options:\n" + "\t -c, --connectable \"connectable\" flag\n" + "\t -g, --general-discov \"general-discoverable\" flag\n" + "\t -l, --limited-discov \"limited-discoverable\" flag\n" + "\t -m, --managed-flags \"managed-flags\" flag\n" + "\t -p, --tx-power \"tx-power\" flag\n" + "\t -a, --appearance \"appearance\" flag\n" + "\t -n, --local-name \"local-name\" flag"); +} + +static const struct option advsize_options[] = { + { "help", 0, 0, 'h' }, + { "connectable", 0, 0, 'c' }, + { "general-discov", 0, 0, 'g' }, + { "limited-discov", 0, 0, 'l' }, + { "managed-flags", 0, 0, 'm' }, + { "tx-power", 0, 0, 'p' }, + { "appearance", 0, 0, 'a' }, + { "local-name", 0, 0, 'n' }, + { 0, 0, 0, 0} +}; + +static void cmd_advsize(int argc, char **argv) +{ + struct mgmt_cp_get_adv_size_info cp; + uint8_t instance; + uint32_t flags = 0; + int opt; + uint16_t index; + + while ((opt = getopt_long(argc, argv, "+cglmphna", + advsize_options, NULL)) != -1) { + switch (opt) { + case 'c': + flags |= MGMT_ADV_FLAG_CONNECTABLE; + break; + case 'g': + flags |= MGMT_ADV_FLAG_DISCOV; + break; + case 'l': + flags |= MGMT_ADV_FLAG_LIMITED_DISCOV; + break; + case 'm': + flags |= MGMT_ADV_FLAG_MANAGED_FLAGS; + break; + case 'p': + flags |= MGMT_ADV_FLAG_TX_POWER; + break; + case 'a': + flags |= MGMT_ADV_FLAG_APPEARANCE; + break; + case 'n': + flags |= MGMT_ADV_FLAG_LOCAL_NAME; + break; + default: + advsize_usage(); + optind = 0; + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc != 1) { + advsize_usage(); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + instance = strtol(argv[0], NULL, 0); + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + memset(&cp, 0, sizeof(cp)); + + cp.instance = instance; + cp.flags = cpu_to_le32(flags); + + if (!mgmt_send(mgmt, MGMT_OP_GET_ADV_SIZE_INFO, index, sizeof(cp), &cp, + adv_size_info_rsp, NULL, NULL)) { + error("Unable to send advertising size info command"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void add_adv_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_add_advertising *rp = param; + + if (status != 0) { + error("Add Advertising failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len != sizeof(*rp)) { + error("Invalid Add Advertising response length (%u)", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("Instance added: %u", rp->instance); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void add_adv_usage(void) +{ + bt_shell_usage(); + print("Options:\n" + "\t -u, --uuid <uuid> Service UUID\n" + "\t -d, --adv-data <data> Advertising Data bytes\n" + "\t -s, --scan-rsp <data> Scan Response Data bytes\n" + "\t -t, --timeout <timeout> Timeout in seconds\n" + "\t -D, --duration <duration> Duration in seconds\n" + "\t -P, --phy <phy> Phy type, Specify 1M/2M/CODED\n" + "\t -c, --connectable \"connectable\" flag\n" + "\t -g, --general-discov \"general-discoverable\" flag\n" + "\t -l, --limited-discov \"limited-discoverable\" flag\n" + "\t -n, --scan-rsp-local-name \"local-name\" flag\n" + "\t -a, --scan-rsp-appearance \"appearance\" flag\n" + "\t -m, --managed-flags \"managed-flags\" flag\n" + "\t -p, --tx-power \"tx-power\" flag\n" + "e.g.:\n" + "\tadd-adv -u 180d -u 180f -d 080954657374204C45 1"); +} + +static const struct option add_adv_options[] = { + { "help", 0, 0, 'h' }, + { "uuid", 1, 0, 'u' }, + { "adv-data", 1, 0, 'd' }, + { "scan-rsp", 1, 0, 's' }, + { "timeout", 1, 0, 't' }, + { "duration", 1, 0, 'D' }, + { "phy", 1, 0, 'P' }, + { "connectable", 0, 0, 'c' }, + { "general-discov", 0, 0, 'g' }, + { "limited-discov", 0, 0, 'l' }, + { "managed-flags", 0, 0, 'm' }, + { "tx-power", 0, 0, 'p' }, + { 0, 0, 0, 0} +}; + +static bool parse_bytes(char *optarg, uint8_t **bytes, size_t *len) +{ + unsigned i; + + if (!optarg) { + add_adv_usage(); + return false; + } + + *len = strlen(optarg); + + if (*len % 2) { + error("Malformed data"); + return false; + } + + *len /= 2; + if (*len > UINT8_MAX) { + error("Data too long"); + return false; + } + + *bytes = malloc(*len); + if (!*bytes) { + error("Failed to allocate memory"); + return false; + } + + for (i = 0; i < *len; i++) { + if (sscanf(optarg + (i * 2), "%2hhx", *bytes + i) != 1) { + error("Invalid data"); + free(*bytes); + *bytes = NULL; + return false; + } + } + + return true; +} + +#define MAX_AD_UUID_BYTES 32 + +static void cmd_add_adv(int argc, char **argv) +{ + struct mgmt_cp_add_advertising *cp = NULL; + int opt; + uint8_t *adv_data = NULL, *scan_rsp = NULL; + size_t adv_len = 0, scan_rsp_len = 0; + size_t cp_len; + uint8_t uuids[MAX_AD_UUID_BYTES]; + size_t uuid_bytes = 0; + uint8_t uuid_type = 0; + uint16_t timeout = 0, duration = 0; + uint8_t instance; + bt_uuid_t uuid; + bool success = false; + bool quit = true; + uint32_t flags = 0; + uint16_t index; + + while ((opt = getopt_long(argc, argv, "+u:d:s:t:D:P:cglmphna", + add_adv_options, NULL)) != -1) { + switch (opt) { + case 'u': + if (bt_string_to_uuid(&uuid, optarg) < 0) { + print("Invalid UUID: %s", optarg); + goto done; + } + + if (uuid_type && uuid_type != uuid.type) { + print("UUID types must be consistent"); + goto done; + } + + if (uuid.type == BT_UUID16) { + if (uuid_bytes + 2 >= MAX_AD_UUID_BYTES) { + print("Too many UUIDs"); + goto done; + } + + bt_uuid_to_le(&uuid, uuids + uuid_bytes); + uuid_bytes += 2; + } else if (uuid.type == BT_UUID128) { + if (uuid_bytes + 16 >= MAX_AD_UUID_BYTES) { + print("Too many UUIDs"); + goto done; + } + + bt_uuid_to_le(&uuid, uuids + uuid_bytes); + uuid_bytes += 16; + } else { + printf("Unsupported UUID type"); + goto done; + } + + if (!uuid_type) + uuid_type = uuid.type; + + break; + case 'd': + if (adv_len) { + print("Only one adv-data option allowed"); + goto done; + } + + if (!parse_bytes(optarg, &adv_data, &adv_len)) + goto done; + break; + case 's': + if (scan_rsp_len) { + print("Only one scan-rsp option allowed"); + goto done; + } + + if (!parse_bytes(optarg, &scan_rsp, &scan_rsp_len)) + goto done; + break; + case 't': + timeout = strtol(optarg, NULL, 0); + break; + case 'D': + duration = strtol(optarg, NULL, 0); + break; + case 'c': + flags |= MGMT_ADV_FLAG_CONNECTABLE; + break; + case 'g': + flags |= MGMT_ADV_FLAG_DISCOV; + break; + case 'l': + flags |= MGMT_ADV_FLAG_LIMITED_DISCOV; + break; + case 'm': + flags |= MGMT_ADV_FLAG_MANAGED_FLAGS; + break; + case 'p': + flags |= MGMT_ADV_FLAG_TX_POWER; + break; + case 'n': + flags |= MGMT_ADV_FLAG_LOCAL_NAME; + break; + case 'a': + flags |= MGMT_ADV_FLAG_APPEARANCE; + break; + case 'P': + if (strcasecmp(optarg, "1M") == 0) + flags |= MGMT_ADV_FLAG_SEC_1M; + else if (strcasecmp(optarg, "2M") == 0) + flags |= MGMT_ADV_FLAG_SEC_2M; + else if (strcasecmp(optarg, "CODED") == 0) + flags |= MGMT_ADV_FLAG_SEC_CODED; + else + goto done; + break; + case 'h': + success = true; + /* fall through */ + default: + add_adv_usage(); + optind = 0; + goto done; + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc != 1) { + add_adv_usage(); + goto done; + } + + if (uuid_bytes) + uuid_bytes += 2; + + instance = strtol(argv[0], NULL, 0); + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + cp_len = sizeof(*cp) + uuid_bytes + adv_len + scan_rsp_len; + cp = malloc0(cp_len); + if (!cp) + goto done; + + cp->instance = instance; + put_le32(flags, &cp->flags); + put_le16(timeout, &cp->timeout); + put_le16(duration, &cp->duration); + cp->adv_data_len = adv_len + uuid_bytes; + cp->scan_rsp_len = scan_rsp_len; + + if (uuid_bytes) { + cp->data[0] = uuid_bytes - 1; + cp->data[1] = uuid_type == SDP_UUID16 ? 0x03 : 0x07; + memcpy(cp->data + 2, uuids, uuid_bytes - 2); + } + + if (adv_len) + memcpy(cp->data + uuid_bytes, adv_data, adv_len); + + if (scan_rsp_len) + memcpy(cp->data + uuid_bytes + adv_len, scan_rsp, scan_rsp_len); + + if (!mgmt_send(mgmt, MGMT_OP_ADD_ADVERTISING, index, cp_len, cp, + add_adv_rsp, NULL, NULL)) { + error("Unable to send \"Add Advertising\" command"); + goto done; + } + + quit = false; + +done: + free(adv_data); + free(scan_rsp); + free(cp); + + if (quit) + bt_shell_noninteractive_quit(success ? EXIT_SUCCESS : EXIT_FAILURE); +} + +static void rm_adv_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_remove_advertising *rp = param; + + if (status != 0) { + error("Remove Advertising failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len != sizeof(*rp)) { + error("Invalid Remove Advertising response length (%u)", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("Instance removed: %u", rp->instance); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_rm_adv(int argc, char **argv) +{ + struct mgmt_cp_remove_advertising cp; + uint8_t instance; + uint16_t index; + + instance = strtol(argv[1], NULL, 0); + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + memset(&cp, 0, sizeof(cp)); + + cp.instance = instance; + + if (!mgmt_send(mgmt, MGMT_OP_REMOVE_ADVERTISING, index, sizeof(cp), &cp, + rm_adv_rsp, NULL, NULL)) { + error("Unable to send \"Remove Advertising\" command"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void cmd_clr_adv(int argc, char **argv) +{ + char *all_instances = "0"; + char *rm_argv[] = { "rm-adv", all_instances, NULL }; + + cmd_rm_adv(2, rm_argv); +} + +static void add_ext_adv_params_rsp(uint8_t status, uint16_t len, + const void *param, void *user_data) +{ + const struct mgmt_rp_add_ext_adv_params *rp = param; + + if (status != 0) { + error("Add Ext Adv Params failed status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len != sizeof(*rp)) { + error("Invalid Add Ext Adv Params response length (%u)", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("Instance added: %u", rp->instance); + print("Tx Power: %u", rp->tx_power); + print("Max adv data len: %u", rp->max_adv_data_len); + print("Max scan resp len: %u", rp->max_scan_rsp_len); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void add_ext_adv_params_usage(void) +{ + bt_shell_usage(); + print("Options:\n" + "\t -d, --duration <duration> Duration in seconds\n" + "\t -t, --timeout <timeout> Timeout in seconds\n" + "\t -r, --min-interval <valr> Minimum interval\n" + "\t -x, --max-interval <valr> Maximum interval\n" + "\t -w, --tx-power <power> Tx power\n" + "\t -P, --phy <phy> Phy type, Specify 1M/2M/CODED\n" + "\t -c, --connectable \"connectable\" flag\n" + "\t -g, --general-discov \"general-discoverable\" flag\n" + "\t -l, --limited-discov \"limited-discoverable\" flag\n" + "\t -m, --managed-flags \"managed-flags\" flag\n" + "\t -p, --add-tx-power \"tx-power\" flag\n" + "\t -a, --scan-rsp-appearance \"appearance\" flag\n" + "\t -n, --scan-rsp-local-name \"local-name\" flag\n" + "\t -s, --adv-scan-rsp \"scan resp in adv\" flag\n" + "\t -h, --help Show help\n" + "e.g.:\n" + "\tadd-ext-adv-params -r 0x801 -x 0x802 -P 2M -g 1"); +} + +static const struct option add_ext_adv_params_options[] = { + { "help", 0, 0, 'h' }, + { "duration", 1, 0, 'd' }, + { "timeout", 1, 0, 't' }, + { "min-internal", 1, 0, 'r' }, + { "max-interval", 1, 0, 'x' }, + { "tx-power", 1, 0, 'w' }, + { "phy", 1, 0, 'P' }, + { "connectable", 0, 0, 'c' }, + { "general-discov", 0, 0, 'g' }, + { "limited-discov", 0, 0, 'l' }, + { "scan-rsp-local-name", 0, 0, 'n' }, + { "scan-rsp-appearance", 0, 0, 'a' }, + { "managed-flags", 0, 0, 'm' }, + { "add-tx-power", 0, 0, 'p' }, + { "adv-scan-rsp", 0, 0, 's' }, + { 0, 0, 0, 0} +}; + +static void cmd_add_ext_adv_params(int argc, char **argv) +{ + struct mgmt_cp_add_ext_adv_params *cp = NULL; + int opt; + uint16_t timeout = 0, duration = 0; + uint8_t instance; + bool success = false; + bool quit = true; + uint32_t flags = 0; + uint32_t min_interval = 0; + uint32_t max_interval = 0; + uint8_t tx_power = 0; + uint16_t index; + + while ((opt = getopt_long(argc, argv, "d:t:r:x:w:P:cglmpansh", + add_ext_adv_params_options, NULL)) != -1) { + switch (opt) { + case 'd': + duration = strtol(optarg, NULL, 0); + flags |= MGMT_ADV_PARAM_DURATION; + break; + case 't': + timeout = strtol(optarg, NULL, 0); + flags |= MGMT_ADV_PARAM_TIMEOUT; + break; + case 'r': + min_interval = strtol(optarg, NULL, 0); + break; + case 'x': + max_interval = strtol(optarg, NULL, 0); + break; + case 'w': + tx_power = strtol(optarg, NULL, 0); + flags |= MGMT_ADV_PARAM_TX_POWER; + break; + case 'P': + if (strcasecmp(optarg, "1M") == 0) + flags |= MGMT_ADV_FLAG_SEC_1M; + else if (strcasecmp(optarg, "2M") == 0) + flags |= MGMT_ADV_FLAG_SEC_2M; + else if (strcasecmp(optarg, "CODED") == 0) + flags |= MGMT_ADV_FLAG_SEC_CODED; + else + goto done; + break; + case 'c': + flags |= MGMT_ADV_FLAG_CONNECTABLE; + break; + case 'g': + flags |= MGMT_ADV_FLAG_DISCOV; + break; + case 'l': + flags |= MGMT_ADV_FLAG_LIMITED_DISCOV; + break; + case 'n': + flags |= MGMT_ADV_FLAG_LOCAL_NAME; + break; + case 'a': + flags |= MGMT_ADV_FLAG_APPEARANCE; + break; + case 'm': + flags |= MGMT_ADV_FLAG_MANAGED_FLAGS; + break; + case 'p': + flags |= MGMT_ADV_FLAG_TX_POWER; + break; + case 's': + flags |= MGMT_ADV_PARAM_SCAN_RSP; + break; + case 'h': + success = true; + /* fall through */ + default: + add_ext_adv_params_usage(); + optind = 0; + goto done; + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc != 1) { + add_ext_adv_params_usage(); + goto done; + } + + /* Only if both min_interval and max_interval are defined */ + if (min_interval && max_interval) + flags |= MGMT_ADV_PARAM_INTERVALS; + + instance = strtol(argv[0], NULL, 0); + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + cp = malloc0(sizeof(*cp)); + if (!cp) + goto done; + + cp->instance = instance; + put_le32(flags, &cp->flags); + put_le16(timeout, &cp->timeout); + put_le16(duration, &cp->duration); + put_le32(min_interval, &cp->min_interval); + put_le32(max_interval, &cp->max_interval); + cp->tx_power = tx_power; + + if (!mgmt_send(mgmt, MGMT_OP_ADD_EXT_ADV_PARAMS, index, sizeof(*cp), cp, + add_ext_adv_params_rsp, NULL, NULL)) { + error("Unable to send \"Add Ext Advertising Params\" command"); + goto done; + } + + quit = false; + +done: + free(cp); + + if (quit) + bt_shell_noninteractive_quit(success ? + EXIT_SUCCESS : EXIT_FAILURE); +} + +static void add_ext_adv_data_rsp(uint8_t status, uint16_t len, + const void *param, void *user_data) +{ + const struct mgmt_rp_add_ext_adv_data *rp = param; + + if (status != 0) { + error("Add Ext Advertising Data failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len != sizeof(*rp)) { + error("Invalid Add Ext Advertising Data response length (%u)", + len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("Instance added: %u", rp->instance); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void add_ext_adv_data_usage(void) +{ + bt_shell_usage(); + print("Options:\n" + "\t -u, --uuid <uuid> Service UUID\n" + "\t -d, --adv-data <data> Advertising Data bytes\n" + "\t -s, --scan-rsp <data> Scan Response Data bytes\n" + "e.g.:\n" + "\tadd-ext-adv-data -u 180d -u 180f -d 080954657374204C45 1"); +} + +static const struct option add_ext_adv_data_options[] = { + { "help", 0, 0, 'h' }, + { "uuid", 1, 0, 'u' }, + { "adv-data", 1, 0, 'd' }, + { "scan-rsp", 1, 0, 's' }, + { 0, 0, 0, 0} +}; + +static void cmd_add_ext_adv_data(int argc, char **argv) +{ + struct mgmt_cp_add_ext_adv_data *cp = NULL; + int opt; + uint8_t *adv_data = NULL, *scan_rsp = NULL; + size_t adv_len = 0, scan_rsp_len = 0; + size_t cp_len; + uint8_t uuids[MAX_AD_UUID_BYTES]; + size_t uuid_bytes = 0; + uint8_t uuid_type = 0; + uint8_t instance; + bt_uuid_t uuid; + bool success = false; + bool quit = true; + uint16_t index; + + while ((opt = getopt_long(argc, argv, "+u:d:s:h", + add_ext_adv_data_options, NULL)) != -1) { + switch (opt) { + case 'u': + if (bt_string_to_uuid(&uuid, optarg) < 0) { + print("Invalid UUID: %s", optarg); + goto done; + } + + if (uuid_type && uuid_type != uuid.type) { + print("UUID types must be consistent"); + goto done; + } + + if (uuid.type == BT_UUID16) { + if (uuid_bytes + 2 >= MAX_AD_UUID_BYTES) { + print("Too many UUIDs"); + goto done; + } + + bt_uuid_to_le(&uuid, uuids + uuid_bytes); + uuid_bytes += 2; + } else if (uuid.type == BT_UUID128) { + if (uuid_bytes + 16 >= MAX_AD_UUID_BYTES) { + print("Too many UUIDs"); + goto done; + } + + bt_uuid_to_le(&uuid, uuids + uuid_bytes); + uuid_bytes += 16; + } else { + printf("Unsupported UUID type"); + goto done; + } + + if (!uuid_type) + uuid_type = uuid.type; + + break; + case 'd': + if (adv_len) { + print("Only one adv-data option allowed"); + goto done; + } + + if (!parse_bytes(optarg, &adv_data, &adv_len)) + goto done; + break; + case 's': + if (scan_rsp_len) { + print("Only one scan-rsp option allowed"); + goto done; + } + + if (!parse_bytes(optarg, &scan_rsp, &scan_rsp_len)) + goto done; + break; + case 'h': + success = true; + /* fall through */ + default: + add_ext_adv_data_usage(); + optind = 0; + goto done; + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc != 1) { + add_ext_adv_data_usage(); + goto done; + } + + if (uuid_bytes) + uuid_bytes += 2; + + instance = strtol(argv[0], NULL, 0); + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + cp_len = sizeof(*cp) + uuid_bytes + adv_len + scan_rsp_len; + cp = malloc0(cp_len); + if (!cp) + goto done; + + cp->instance = instance; + cp->adv_data_len = adv_len + uuid_bytes; + cp->scan_rsp_len = scan_rsp_len; + + if (uuid_bytes) { + cp->data[0] = uuid_bytes - 1; + cp->data[1] = uuid_type == SDP_UUID16 ? 0x03 : 0x07; + memcpy(cp->data + 2, uuids, uuid_bytes - 2); + } + + if (adv_len) + memcpy(cp->data + uuid_bytes, adv_data, adv_len); + + if (scan_rsp_len) + memcpy(cp->data + uuid_bytes + adv_len, scan_rsp, scan_rsp_len); + + if (!mgmt_send(mgmt, MGMT_OP_ADD_EXT_ADV_DATA, index, cp_len, cp, + add_ext_adv_data_rsp, NULL, NULL)) { + error("Unable to send \"Add Ext Advertising Data\" command"); + goto done; + } + + quit = false; + +done: + free(adv_data); + free(scan_rsp); + free(cp); + + if (quit) + bt_shell_noninteractive_quit(success ? + EXIT_SUCCESS : EXIT_FAILURE); +} + +static void appearance_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) + error("Could not set Appearance with status 0x%02x (%s)", + status, mgmt_errstr(status)); + else + print("Appearance successfully set"); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_appearance(int argc, char **argv) +{ + struct mgmt_cp_set_appearance cp; + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + cp.appearance = cpu_to_le16(strtol(argv[1], NULL, 0)); + + if (mgmt_send(mgmt, MGMT_OP_SET_APPEARANCE, index, sizeof(cp), &cp, + appearance_rsp, NULL, NULL) == 0) { + error("Unable to send appearance cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static const char *phys_str[] = { + "BR1M1SLOT", + "BR1M3SLOT", + "BR1M5SLOT", + "EDR2M1SLOT", + "EDR2M3SLOT", + "EDR2M5SLOT", + "EDR3M1SLOT", + "EDR3M3SLOT", + "EDR3M5SLOT", + "LE1MTX", + "LE1MRX", + "LE2MTX", + "LE2MRX", + "LECODEDTX", + "LECODEDRX", +}; + +static const char *phys2str(uint32_t phys) +{ + static char str[256]; + unsigned int i; + int off; + + off = 0; + str[0] = '\0'; + + for (i = 0; i < NELEM(phys_str); i++) { + if ((phys & (1 << i)) != 0) + off += snprintf(str + off, sizeof(str) - off, "%s ", + phys_str[i]); + } + + return str; +} + +static bool str2phy(const char *phy_str, uint32_t *phy_val) +{ + unsigned int i; + + for (i = 0; i < NELEM(phys_str); i++) { + if (strcasecmp(phys_str[i], phy_str) == 0) { + *phy_val = (1 << i); + return true; + } + } + + return false; +} + +static void get_phy_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_get_phy_confguration *rp = param; + uint32_t supported_phys, selected_phys, configurable_phys; + + if (status != 0) { + error("Get PHY Configuration failed with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len < sizeof(*rp)) { + error("Too small get-phy reply (%u bytes)", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + supported_phys = get_le32(&rp->supported_phys); + configurable_phys = get_le32(&rp->configurable_phys); + selected_phys = get_le32(&rp->selected_phys); + + print("Supported phys: %s", phys2str(supported_phys)); + print("Configurable phys: %s", phys2str(configurable_phys)); + print("Selected phys: %s", phys2str(selected_phys)); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void get_phy(void) +{ + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (mgmt_send(mgmt, MGMT_OP_GET_PHY_CONFIGURATION, index, 0, NULL, + get_phy_rsp, NULL, NULL) == 0) { + error("Unable to send Get PHY cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void set_phy_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + if (status != 0) { + error("Could not set PHY Configuration with status 0x%02x (%s)", + status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("PHY Configuration successfully set"); + + bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_phy(int argc, char **argv) +{ + struct mgmt_cp_set_phy_confguration cp; + int i; + uint32_t phys = 0; + uint16_t index; + + if (argc < 2) + return get_phy(); + + for (i = 1; i < argc; i++) { + uint32_t phy_val; + + if (str2phy(argv[i], &phy_val)) + phys |= phy_val; + } + + cp.selected_phys = cpu_to_le32(phys); + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (mgmt_send(mgmt, MGMT_OP_SET_PHY_CONFIGURATION, index, sizeof(cp), + &cp, set_phy_rsp, NULL, NULL) == 0) { + error("Unable to send %s cmd", + mgmt_opstr(MGMT_OP_SET_PHY_CONFIGURATION)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void cmd_wbs(int argc, char **argv) +{ + cmd_setting(MGMT_OP_SET_WIDEBAND_SPEECH, argc, argv); +} + +static const char * const advmon_features_str[] = { + "Pattern monitor with logic OR.", +}; + +static const char *advmon_features2str(uint32_t features) +{ + static char str[512]; + unsigned int off, i; + + off = 0; + snprintf(str, sizeof(str), "\n\tNone"); + + for (i = 0; i < NELEM(advmon_features_str); i++) { + if ((features & (1 << i)) != 0 && off < sizeof(str)) + off += snprintf(str + off, sizeof(str) - off, "\n\t%s", + advmon_features_str[i]); + } + + return str; +} + +static void advmon_features_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_read_adv_monitor_features *rp = param; + uint32_t supported_features, enabled_features; + uint16_t num_handles; + int i; + + if (status != MGMT_STATUS_SUCCESS) { + error("Reading adv monitor features failed with status 0x%02x " + "(%s)", status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (len < sizeof(*rp)) { + error("Too small adv monitor features reply (%u bytes)", len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + supported_features = le32_to_cpu(rp->supported_features); + enabled_features = le32_to_cpu(rp->enabled_features); + num_handles = le16_to_cpu(rp->num_handles); + + if (len < sizeof(*rp) + num_handles * sizeof(uint16_t)) { + error("Handles count (%u) doesn't match reply length (%u)", + num_handles, len); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("Supported features:%s", advmon_features2str(supported_features)); + print("Enabled features:%s", advmon_features2str(enabled_features)); + print("Max number of handles: %u", le16_to_cpu(rp->max_num_handles)); + print("Max number of patterns: %u", rp->max_num_patterns); + print("Handles list with %u item%s", num_handles, + num_handles == 0 ? "" : num_handles == 1 ? ":" : "s:"); + for (i = 0; i < num_handles; i++) + print("\t0x%04x ", le16_to_cpu(rp->handles[i])); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_advmon_features(int argc, char **argv) +{ + uint16_t index; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (!mgmt_send(mgmt, MGMT_OP_READ_ADV_MONITOR_FEATURES, index, 0, NULL, + advmon_features_rsp, NULL, NULL)) { + error("Unable to send advertising monitor features command"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void advmon_add_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_add_adv_patterns_monitor *rp = param; + + if (status != MGMT_STATUS_SUCCESS) { + error("Could not add advertisement monitor with status " + "0x%02x (%s)", status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("Advertisement monitor with handle:0x%04x added", + le16_to_cpu(rp->monitor_handle)); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static bool str2pattern(struct mgmt_adv_pattern *pattern, const char *str) +{ + int type_len, offset_len, offset_end_pos, str_len; + int i, j; + char pattern_str[62] = { 0 }; + char tmp; + + if (sscanf(str, "%2hhx%n:%2hhx%n:%61s", &pattern->ad_type, &type_len, + &pattern->offset, &offset_end_pos, pattern_str) != 3) + return false; + + offset_len = offset_end_pos - type_len - 1; + str_len = strlen(pattern_str); + pattern->length = str_len / 2 + str_len % 2; + + if (type_len > 2 || offset_len > 2 || + pattern->offset + pattern->length > 31) + return false; + + for (i = 0, j = 0; i < str_len; i++, j++) { + if (sscanf(&pattern_str[i++], "%2hhx", &pattern->value[j]) + != 1) + return false; + if (i < str_len && sscanf(&pattern_str[i], "%1hhx", &tmp) != 1) + return false; + } + + return true; +} + +static const struct option add_monitor_rssi_options[] = { + { "help", 0, 0, 'h' }, + { "high-threshold", 1, 0, 'R' }, + { "low-threshold", 1, 0, 'r' }, + { "high-timeout", 1, 0, 'T' }, + { "low-timeout", 1, 0, 't' }, + { "sampling", 1, 0, 's' }, + { 0, 0, 0, 0 } +}; + +static void advmon_add_pattern_usage(void) +{ + bt_shell_usage(); + print("patterns format:\n" + "\t<ad_type:offset:pattern> [patterns]\n" + "e.g.:\n" + "\tadd-pattern 0:1:c504 ff:a:9a55beef"); +} + +static void advmon_add_pattern_rssi_usage(void) +{ + bt_shell_usage(); + print("RSSI options:\n" + "\t -R, --high-threshold <dBm> " + "RSSI high threshold. Default: -70\n" + "\t -r, --low-threshold <dBm> " + "RSSI low threshold. Default: -50\n" + "\t -T, --high-timeout <s> " + "RSSI high threshold duration. Default: 0\n" + "\t -t, --low-timeout <s> " + "RSSI low threshold duration. Default: 5\n" + "\t -s, --sampling <N * 100ms> " + "RSSI sampling period. Default: 0\n" + "patterns format:\n" + "\t<ad_type:offset:pattern> [patterns]\n" + "e.g.:\n" + "\tadd-pattern-rssi -R 0xb2 -r -102 0:1:c504 ff:a:9a55beef"); +} + +static void cmd_advmon_add_pattern(int argc, char **argv) +{ + bool success = true; + uint16_t index; + int i, cp_len; + struct mgmt_cp_add_adv_monitor *cp = NULL; + + if (!strcmp(argv[1], "-h")) + goto done; + + argc -= 1; + argv += 1; + + cp_len = sizeof(*cp) + argc * sizeof(struct mgmt_adv_pattern); + cp = malloc0(cp_len); + if (!cp) { + error("Failed to alloc patterns."); + success = false; + goto done; + } + + cp->pattern_count = argc; + + for (i = 0; i < argc; i++) { + if (!str2pattern(&cp->patterns[i], argv[i])) { + error("Failed to parse monitor patterns."); + success = false; + goto done; + } + } + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (!mgmt_send(mgmt, MGMT_OP_ADD_ADV_PATTERNS_MONITOR, index, + cp_len, cp, advmon_add_rsp, NULL, NULL)) { + error("Unable to send Add Advertising Monitor command"); + success = false; + goto done; + } + + free(cp); + return; + +done: + free(cp); + advmon_add_pattern_usage(); + bt_shell_noninteractive_quit(success ? EXIT_SUCCESS : EXIT_FAILURE); +} + +static void cmd_advmon_add_pattern_rssi(int argc, char **argv) +{ + bool success = true; + int opt; + int8_t rssi_low = -70; + int8_t rssi_high = -50; + uint16_t rssi_low_timeout = 5; + uint16_t rssi_high_timeout = 0; + uint8_t rssi_sampling_period = 0; + uint16_t index; + int i, cp_len; + struct mgmt_cp_add_adv_patterns_monitor_rssi *cp = NULL; + + while ((opt = getopt_long(argc, argv, "+hr:R:t:T:s:", + add_monitor_rssi_options, NULL)) != -1) { + switch (opt) { + case 'h': + goto done; + case 'r': + rssi_low = strtol(optarg, NULL, 0); + break; + case 'R': + rssi_high = strtol(optarg, NULL, 0); + break; + case 't': + rssi_low_timeout = strtol(optarg, NULL, 0); + break; + case 'T': + rssi_high_timeout = strtol(optarg, NULL, 0); + break; + case 's': + rssi_sampling_period = strtol(optarg, NULL, 0); + break; + default: + success = false; + goto done; + } + } + + argc -= optind; + argv += optind; + optind = 0; + + cp_len = sizeof(*cp) + argc * sizeof(struct mgmt_adv_pattern); + cp = malloc0(cp_len); + if (!cp) { + error("Failed to alloc patterns."); + success = false; + goto done; + } + + cp->pattern_count = argc; + cp->rssi.high_threshold = rssi_high; + cp->rssi.low_threshold = rssi_low; + cp->rssi.high_threshold_timeout = htobs(rssi_high_timeout); + cp->rssi.low_threshold_timeout = htobs(rssi_low_timeout); + cp->rssi.sampling_period = rssi_sampling_period; + + for (i = 0; i < argc; i++) { + if (!str2pattern(&cp->patterns[i], argv[i])) { + error("Failed to parse monitor patterns."); + success = false; + goto done; + } + } + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (!mgmt_send(mgmt, MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, index, + cp_len, cp, advmon_add_rsp, NULL, NULL)) { + error("Unable to send Add Advertising Monitor RSSI command"); + success = false; + goto done; + } + + free(cp); + return; + +done: + free(cp); + optind = 0; + advmon_add_pattern_rssi_usage(); + bt_shell_noninteractive_quit(success ? EXIT_SUCCESS : EXIT_FAILURE); +} + +static void advmon_remove_rsp(uint8_t status, uint16_t len, const void *param, + void *user_data) +{ + const struct mgmt_rp_remove_adv_monitor *rp = param; + + if (status != MGMT_STATUS_SUCCESS) { + error("Could not remove advertisement monitor with status " + "0x%02x (%s)", status, mgmt_errstr(status)); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + print("Advertisement monitor with handle: 0x%04x removed", + le16_to_cpu(rp->monitor_handle)); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_advmon_remove(int argc, char **argv) +{ + struct mgmt_cp_remove_adv_monitor cp; + uint16_t index, monitor_handle; + + index = mgmt_index; + if (index == MGMT_INDEX_NONE) + index = 0; + + if (sscanf(argv[1], "%hx", &monitor_handle) != 1) { + error("Wrong formatted handle argument"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + cp.monitor_handle = cpu_to_le16(monitor_handle); + if (mgmt_send(mgmt, MGMT_OP_REMOVE_ADV_MONITOR, index, sizeof(cp), &cp, + advmon_remove_rsp, NULL, NULL) == 0) { + error("Unable to send appearance cmd"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void register_mgmt_callbacks(struct mgmt *mgmt, uint16_t index) +{ + mgmt_register(mgmt, MGMT_EV_CONTROLLER_ERROR, index, controller_error, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, index, index_added, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_INDEX_REMOVED, index, index_removed, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_NEW_SETTINGS, index, new_settings, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_DISCOVERING, index, discovering, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_NEW_LINK_KEY, index, new_link_key, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_DEVICE_CONNECTED, index, connected, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_DEVICE_DISCONNECTED, index, disconnected, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_CONNECT_FAILED, index, conn_failed, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_AUTH_FAILED, index, auth_failed, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_CLASS_OF_DEV_CHANGED, index, + class_of_dev_changed, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_LOCAL_NAME_CHANGED, index, + local_name_changed, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_DEVICE_FOUND, index, device_found, + mgmt, NULL); + mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_ADDED, index, + unconf_index_added, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_REMOVED, index, + unconf_index_removed, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_NEW_CONFIG_OPTIONS, index, + new_config_options, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_EXT_INDEX_ADDED, index, + ext_index_added, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_EXT_INDEX_REMOVED, index, + ext_index_removed, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_LOCAL_OOB_DATA_UPDATED, index, + local_oob_data_updated, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_ADVERTISING_ADDED, index, + advertising_added, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_ADVERTISING_REMOVED, index, + advertising_removed, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_DEVICE_FLAGS_CHANGED, index, + flags_changed, NULL, NULL); + mgmt_register(mgmt, MGMT_EV_ADV_MONITOR_ADDED, index, advmon_added, + NULL, NULL); + mgmt_register(mgmt, MGMT_EV_ADV_MONITOR_REMOVED, index, advmon_removed, + NULL, NULL); +} + +static void cmd_select(int argc, char **argv) +{ + mgmt_cancel_all(mgmt); + mgmt_unregister_all(mgmt); + + mgmt_set_index(argv[1]); + + register_mgmt_callbacks(mgmt, mgmt_index); + + print("Selected index %u", mgmt_index); +} + +static const struct bt_shell_menu monitor_menu = { + .name = "monitor", + .desc = "Advertisement Monitor Submenu", + .entries = { + { "features", NULL, + cmd_advmon_features, "Show advertisement monitor " + "features" }, + { "remove", "<handle>", + cmd_advmon_remove, "Remove advertisement monitor " }, + { "add-pattern", "[-,h] <patterns>", + cmd_advmon_add_pattern, "Add advertisement monitor pattern" }, + { "add-pattern-rssi", "[options] <patterns>", + cmd_advmon_add_pattern_rssi, + "Add advertisement monitor pattern with RSSI options" }, + { } }, +}; + +static const struct bt_shell_menu mgmt_menu = { + .name = "mgmt", + .desc = "Management Submenu", + .entries = { + { "select", "<index>", + cmd_select, "Select a different index" }, + { "revision", NULL, + cmd_revision, "Get the MGMT Revision" }, + { "commands", NULL, + cmd_commands, "List supported commands" }, + { "config", NULL, + cmd_config, "Show configuration info" }, + { "info", NULL, + cmd_info, "Show controller info" }, + { "extinfo", NULL, + cmd_extinfo, "Show extended controller info" }, + { "auto-power", NULL, + cmd_auto_power, "Power all available features" }, + { "power", "<on/off>", + cmd_power, "Toggle powered state" }, + { "discov", "<yes/no/limited> [timeout]", + cmd_discov, "Toggle discoverable state" }, + { "connectable", "<on/off>", + cmd_connectable, "Toggle connectable state" }, + { "fast-conn", "<on/off>", + cmd_fast_conn, "Toggle fast connectable state" }, + { "bondable", "<on/off>", + cmd_bondable, "Toggle bondable state" }, + { "pairable", "<on/off>", + cmd_bondable, "Toggle bondable state" }, + { "linksec", "<on/off>", + cmd_linksec, "Toggle link level security" }, + { "ssp", "<on/off>", + cmd_ssp, "Toggle SSP mode" }, + { "sc", "<on/off/only>", + cmd_sc, "Toogle SC support" }, + { "hs", "<on/off>", + cmd_hs, "Toggle HS support" }, + { "le", "<on/off>", + cmd_le, "Toggle LE support" }, + { "advertising", "<on/off>", + cmd_advertising, "Toggle LE advertising", }, + { "bredr", "<on/off>", + cmd_bredr, "Toggle BR/EDR support", }, + { "privacy", "<on/off> [irk]", + cmd_privacy, "Toggle privacy support" }, + { "class", "<major> <minor>", + cmd_class, "Set device major/minor class" }, + { "disconnect", "[-t type] <remote address>", + cmd_disconnect, "Disconnect device" }, + { "con", NULL, + cmd_con, "List connections" }, + { "find", "[-l|-b] [-L]", + cmd_find, "Discover nearby devices" }, + { "find-service", "[-u UUID] [-r RSSI_Threshold] [-l|-b]", + cmd_find_service, "Discover nearby service" }, + { "stop-find", "[-l|-b]", + cmd_stop_find, "Stop discovery" }, + { "name", "<name> [shortname]", + cmd_name, "Set local name" }, + { "pair", "[-c cap] [-t type] <remote address>", + cmd_pair, "Pair with a remote device" }, + { "cancelpair", "[-t type] <remote address>", + cmd_cancel_pair, "Cancel pairing" }, + { "unpair", "[-t type] <remote address>", + cmd_unpair, "Unpair device" }, + { "keys", NULL, + cmd_keys, "Load Link Keys" }, + { "ltks", NULL, + cmd_ltks, "Load Long Term Keys" }, + { "irks", "[--local index] [--file file path]", + cmd_irks, "Load Identity Resolving Keys" }, + { "block", "[-t type] <remote address>", + cmd_block, "Block Device" }, + { "unblock", "[-t type] <remote address>", + cmd_unblock, "Unblock Device" }, + { "add-uuid", "<UUID> <service class hint>", + cmd_add_uuid, "Add UUID" }, + { "rm-uuid", "<UUID>", + cmd_remove_uuid, "Remove UUID" }, + { "clr-uuids", NULL, + cmd_clr_uuids, "Clear UUIDs" }, + { "local-oob", NULL, + cmd_local_oob, "Local OOB data" }, + { "remote-oob", "[-t <addr_type>] [-r <rand192>] " + "[-h <hash192>] [-R <rand256>] " + "[-H <hash256>] <addr>", + cmd_remote_oob, "Remote OOB data" }, + { "did", "<source>:<vendor>:<product>:<version>", + cmd_did, "Set Device ID" }, + { "static-addr", "<address>", + cmd_static_addr, "Set static address" }, + { "public-addr", "<address>", + cmd_public_addr, "Set public address" }, + { "ext-config", "<on/off>", + cmd_ext_config, "External configuration" }, + { "debug-keys", "<on/off>", + cmd_debug_keys, "Toogle debug keys" }, + { "conn-info", "[-t type] <remote address>", + cmd_conn_info, "Get connection information" }, + { "io-cap", "<cap>", + cmd_io_cap, "Set IO Capability" }, + { "scan-params", "<interval> <window>", + cmd_scan_params, "Set Scan Parameters" }, + { "get-clock", "[address]", + cmd_clock_info, "Get Clock Information" }, + { "add-device", "[-a action] [-t type] <address>", + cmd_add_device, "Add Device" }, + { "del-device", "[-t type] <address>", + cmd_del_device, "Remove Device" }, + { "clr-devices", NULL, + cmd_clr_devices, "Clear Devices" }, + { "bredr-oob", NULL, + cmd_bredr_oob, "Local OOB data (BR/EDR)" }, + { "le-oob", NULL, + cmd_le_oob, "Local OOB data (LE)" }, + { "advinfo", NULL, + cmd_advinfo, "Show advertising features" }, + { "advsize", "[options] <instance_id>", + cmd_advsize, "Show advertising size info" }, + { "add-adv", "[options] <instance_id>", + cmd_add_adv, "Add advertising instance" }, + { "rm-adv", "<instance_id>", + cmd_rm_adv, "Remove advertising instance" }, + { "clr-adv", NULL, + cmd_clr_adv, "Clear advertising instances" }, + { "add-ext-adv-params", "[options] <instance_id>", + cmd_add_ext_adv_params, + "Add extended advertising params" }, + { "add-ext-adv-data", "[options] <instance_id>", + cmd_add_ext_adv_data, + "Add extended advertising data" }, + { "appearance", "<appearance>", + cmd_appearance, "Set appearance" }, + { "phy", "[LE1MTX] [LE1MRX] [LE2MTX] [LE2MRX] " + "[LECODEDTX] [LECODEDRX] " + "[BR1M1SLOT] [BR1M3SLOT] [BR1M5SLOT]" + "[EDR2M1SLOT] [EDR2M3SLOT] [EDR2M5SLOT]" + "[EDR3M1SLOT] [EDR3M3SLOT] [EDR3M5SLOT]", + cmd_phy, "Get/Set PHY Configuration" }, + { "wbs", "<on/off>", + cmd_wbs, "Toggle Wideband-Speech support"}, + { "secinfo", NULL, + cmd_secinfo, "Show security information" }, + { "expinfo", NULL, + cmd_expinfo, "Show experimental features" }, + { "exp-debug", "<on/off>", + cmd_exp_debug, "Set debug feature" }, + { "exp-privacy", "<on/off>", + cmd_exp_privacy, "Set LL privacy feature" }, + { "exp-quality", "<on/off>", cmd_exp_quality, + "Set bluetooth quality report feature" }, + { "exp-offload", "<on/off>", + cmd_exp_offload_codecs, "Toggle codec support" }, + { "read-sysconfig", NULL, + cmd_read_sysconfig, "Read System Configuration" }, + { "set-sysconfig", "<-v|-h> [options...]", + cmd_set_sysconfig, "Set System Configuration" }, + { "get-flags", "[-t type] <address>", + cmd_get_flags, "Get device flags" }, + { "set-flags", "[-f flags] [-t type] <address>", + cmd_set_flags, "Set device flags" }, + {} }, +}; + +static void mgmt_debug(const char *str, void *user_data) +{ + const char *prefix = user_data; + + print("%s%s", prefix, str); +} + +bool mgmt_add_submenu(void) +{ + mgmt = mgmt_new_default(); + if (!mgmt) { + fprintf(stderr, "Unable to open mgmt_socket\n"); + return false; + } + + bt_shell_add_submenu(&mgmt_menu); + bt_shell_add_submenu(&monitor_menu); + + if (getenv("MGMT_DEBUG")) + mgmt_set_debug(mgmt, mgmt_debug, "mgmt: ", NULL); + + register_mgmt_callbacks(mgmt, mgmt_index); + + return true; +} + +void mgmt_remove_submenu(void) +{ + mgmt_cancel_all(mgmt); + mgmt_unregister_all(mgmt); + mgmt_unref(mgmt); +} diff --git a/client/mgmt.h b/client/mgmt.h new file mode 100644 index 0000000000000000000000000000000000000000..5a2026eab6a25806e13d0652a57309ca083f77ae --- /dev/null +++ b/client/mgmt.h @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * + * + */ + +bool mgmt_add_submenu(void); +void mgmt_remove_submenu(void); +void mgmt_set_index(const char *arg); diff --git a/client/player.c b/client/player.c index 4324089345c1446b528e7cde49942f94468d47a8..eed8d23066027aaca8645f269d0f1f63f6fed5b4 100644 --- a/client/player.c +++ b/client/player.c @@ -4,6 +4,7 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2020 Intel Corporation. All rights reserved. + * Copyright 2023-2024 NXP * * */ @@ -24,6 +25,8 @@ #include <sys/ioctl.h> #include <sys/uio.h> #include <wordexp.h> +#include <sys/timerfd.h> +#include <sys/stat.h> #include <glib.h> @@ -31,6 +34,7 @@ #include "lib/bluetooth.h" #include "lib/uuid.h" +#include "lib/iso.h" #include "profiles/audio/a2dp-codecs.h" #include "src/shared/lc3.h" @@ -39,6 +43,8 @@ #include "src/shared/shell.h" #include "src/shared/io.h" #include "src/shared/queue.h" +#include "src/shared/bap-debug.h" +#include "print.h" #include "player.h" /* String display constants */ @@ -58,18 +64,63 @@ #define NSEC_USEC(_t) (_t / 1000L) #define SEC_USEC(_t) (_t * 1000000L) #define TS_USEC(_ts) (SEC_USEC((_ts)->tv_sec) + NSEC_USEC((_ts)->tv_nsec)) +#define ROUND_CLOSEST(_x, _y) (((_x) + (_y / 2)) / (_y)) + +#define EP_SRC_LOCATIONS 0x00000003 +#define EP_SNK_LOCATIONS 0x00000003 + +#define EP_SRC_CTXT 0x000f +#define EP_SUPPORTED_SRC_CTXT EP_SRC_CTXT +#define EP_SNK_CTXT 0x0fff +#define EP_SUPPORTED_SNK_CTXT EP_SNK_CTXT + +#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 + +#define BCAST_CODE {0x01, 0x02, 0x68, 0x05, 0x53, 0xf1, 0x41, 0x5a, \ + 0xa2, 0x65, 0xbb, 0xaf, 0xc6, 0xea, 0x03, 0xb8} struct endpoint { char *path; char *uuid; uint8_t codec; + uint16_t cid; + uint16_t vid; struct iovec *caps; + struct iovec *meta; + uint32_t locations; + uint16_t supported_context; + uint16_t context; bool auto_accept; - bool acquiring; - uint8_t cig; - uint8_t cis; - char *transport; + uint8_t max_transports; + uint8_t iso_group; + uint8_t iso_stream; + struct queue *acquiring; + struct queue *transports; DBusMessage *msg; + struct preset *preset; + struct codec_preset *codec_preset; + bool broadcast; + struct iovec *bcode; }; static DBusConnection *dbus_conn; @@ -82,6 +133,7 @@ static GList *endpoints = NULL; static GList *local_endpoints = NULL; static GList *transports = NULL; static struct queue *ios = NULL; +static uint8_t bcast_code[] = BCAST_CODE; struct transport { GDBusProxy *proxy; @@ -89,8 +141,11 @@ struct transport { uint16_t mtu[2]; char *filename; int fd; + struct stat stat; struct io *io; uint32_t seq; + struct io *timer_io; + int num; }; static void endpoint_unregister(void *data) @@ -511,88 +566,6 @@ static char *proxy_description(GDBusProxy *proxy, const char *title, title, path); } -static void print_iter(const char *label, const char *name, - DBusMessageIter *iter) -{ - dbus_bool_t valbool; - dbus_uint32_t valu32; - dbus_uint16_t valu16; - dbus_int16_t vals16; - unsigned char byte; - const char *valstr; - DBusMessageIter subiter; - - if (iter == NULL) { - bt_shell_printf("%s%s is nil\n", label, name); - return; - } - - switch (dbus_message_iter_get_arg_type(iter)) { - case DBUS_TYPE_INVALID: - bt_shell_printf("%s%s is invalid\n", label, name); - break; - case DBUS_TYPE_STRING: - case DBUS_TYPE_OBJECT_PATH: - dbus_message_iter_get_basic(iter, &valstr); - bt_shell_printf("%s%s: %s\n", label, name, valstr); - break; - case DBUS_TYPE_BOOLEAN: - dbus_message_iter_get_basic(iter, &valbool); - bt_shell_printf("%s%s: %s\n", label, name, - valbool == TRUE ? "yes" : "no"); - break; - case DBUS_TYPE_UINT32: - dbus_message_iter_get_basic(iter, &valu32); - bt_shell_printf("%s%s: 0x%08x (%u)\n", label, name, valu32, - valu32); - break; - case DBUS_TYPE_UINT16: - dbus_message_iter_get_basic(iter, &valu16); - bt_shell_printf("%s%s: 0x%04x (%u)\n", label, name, valu16, - valu16); - break; - case DBUS_TYPE_INT16: - dbus_message_iter_get_basic(iter, &vals16); - bt_shell_printf("%s%s: %d\n", label, name, vals16); - break; - case DBUS_TYPE_BYTE: - dbus_message_iter_get_basic(iter, &byte); - bt_shell_printf("%s%s: 0x%02x (%d)\n", label, name, byte, byte); - break; - case DBUS_TYPE_VARIANT: - dbus_message_iter_recurse(iter, &subiter); - print_iter(label, name, &subiter); - break; - case DBUS_TYPE_ARRAY: - dbus_message_iter_recurse(iter, &subiter); - while (dbus_message_iter_get_arg_type(&subiter) != - DBUS_TYPE_INVALID) { - print_iter(label, name, &subiter); - dbus_message_iter_next(&subiter); - } - break; - case DBUS_TYPE_DICT_ENTRY: - dbus_message_iter_recurse(iter, &subiter); - dbus_message_iter_get_basic(&subiter, &valstr); - dbus_message_iter_next(&subiter); - print_iter(label, valstr, &subiter); - break; - default: - bt_shell_printf("%s%s has unsupported type\n", label, name); - break; - } -} - -static void print_property(GDBusProxy *proxy, const char *name) -{ - DBusMessageIter iter; - - if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE) - return; - - print_iter("\t", name, &iter); -} - static void print_media(GDBusProxy *proxy, const char *description) { char *str; @@ -1025,11 +998,6 @@ static const struct bt_shell_menu player_menu = { {} }, }; -static char *endpoint_generator(const char *text, int state) -{ - return generic_generator(text, state, endpoints); -} - static char *local_endpoint_generator(const char *text, int state) { int len = strlen(text); @@ -1051,6 +1019,17 @@ static char *local_endpoint_generator(const char *text, int state) return NULL; } +static char *endpoint_generator(const char *text, int state) +{ + char *ret; + + ret = generic_generator(text, state, endpoints); + if (ret) + return ret; + + return local_endpoint_generator(text, state); +} + static void print_endpoint(void *data, void *user_data) { GDBusProxy *proxy = data; @@ -1128,8 +1107,19 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, bt_shell_printf("\tTransport %s\n", path); print_iter("\t", "Properties", &props); - free(ep->transport); - ep->transport = strdup(path); + if (!ep->max_transports) { + bt_shell_printf("Maximum transports reached: rejecting\n"); + return g_dbus_create_error(msg, + "org.bluez.Error.Rejected", + "Maximum transports reached"); + } + + ep->max_transports--; + + if (!ep->transports) + ep->transports = queue_new(); + + queue_push_tail(ep->transports, strdup(path)); if (ep->auto_accept) { bt_shell_printf("Auto Accepting...\n"); @@ -1142,38 +1132,27 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, return NULL; } -struct codec_capabilities { - uint8_t len; - uint8_t type; - uint8_t data[UINT8_MAX]; -}; - -#define data(args...) ((const unsigned char[]) { args }) - -#define CODEC_DATA(args...) \ - { \ - .iov_base = (void *)data(args), \ - .iov_len = sizeof(data(args)), \ - } - -#define CODEC_CAPABILITIES(_uuid, _codec_id, _data) \ +#define CODEC_CAPABILITIES(_name, _uuid, _codec_id, _data, _meta) \ { \ + .name = _name, \ .uuid = _uuid, \ .codec_id = _codec_id, \ .data = _data, \ + .meta = _meta, \ } -#define LC3_DATA(_freq, _duration, _chan_count, _len_min, _len_max) \ - CODEC_DATA(0x03, LC3_FREQ, _freq, _freq >> 8, \ - 0x02, LC3_DURATION, _duration, \ - 0x02, LC3_CHAN_COUNT, _chan_count, \ - 0x05, LC3_FRAME_LEN, _len_min, _len_min >> 8, _len_max, \ - _len_max >> 8) +#define LC3_DATA(_freq, _duration, _len_min, _len_max) \ + UTIL_IOV_INIT(0x03, LC3_FREQ, _freq, _freq >> 8, \ + 0x02, LC3_DURATION, _duration, \ + 0x05, LC3_FRAME_LEN, _len_min, _len_min >> 8, \ + _len_max, _len_max >> 8) static const struct capabilities { + const char *name; const char *uuid; uint8_t codec_id; struct iovec data; + struct iovec meta; } caps[] = { /* A2DP SBC Source: * @@ -1183,8 +1162,10 @@ static const struct capabilities { * Blocks: 4 8 12 16 * Bitpool Range: 2-64 */ - CODEC_CAPABILITIES(A2DP_SOURCE_UUID, A2DP_CODEC_SBC, - CODEC_DATA(0xff, 0xff, 2, 64)), + CODEC_CAPABILITIES("a2dp_src/sbc", A2DP_SOURCE_UUID, A2DP_CODEC_SBC, + UTIL_IOV_INIT(0xff, 0xff, 2, 64), + UTIL_IOV_INIT()), + /* A2DP SBC Sink: * * Channel Modes: Mono DualChannel Stereo JointStereo @@ -1193,46 +1174,68 @@ static const struct capabilities { * Blocks: 4 8 12 16 * Bitpool Range: 2-64 */ - CODEC_CAPABILITIES(A2DP_SINK_UUID, A2DP_CODEC_SBC, - CODEC_DATA(0xff, 0xff, 2, 64)), + CODEC_CAPABILITIES("a2dp_snk/sbc", A2DP_SINK_UUID, A2DP_CODEC_SBC, + UTIL_IOV_INIT(0xff, 0xff, 2, 64), + UTIL_IOV_INIT()), + /* PAC LC3 Sink: * * Frequencies: 8Khz 11Khz 16Khz 22Khz 24Khz 32Khz 44.1Khz 48Khz * Duration: 7.5 ms 10 ms - * Channel count: 3 - * Frame length: 30-240 + * Frame length: 26-240 */ - CODEC_CAPABILITIES(PAC_SINK_UUID, LC3_ID, - LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY, - 3u, 30, 240)), + CODEC_CAPABILITIES("pac_snk/lc3", PAC_SINK_UUID, LC3_ID, + LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY, 26, + 240), + UTIL_IOV_INIT()), + /* PAC LC3 Source: * * Frequencies: 8Khz 11Khz 16Khz 22Khz 24Khz 32Khz 44.1Khz 48Khz * Duration: 7.5 ms 10 ms * Channel count: 3 - * Frame length: 30-240 + * Frame length: 26-240 */ - CODEC_CAPABILITIES(PAC_SOURCE_UUID, LC3_ID, - LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY, - 3u, 30, 240)), -}; + CODEC_CAPABILITIES("pac_src/lc3", PAC_SOURCE_UUID, LC3_ID, + LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY, 26, + 240), + UTIL_IOV_INIT()), + + /* Broadcast LC3 Source: + * + * Frequencies: 8Khz 11Khz 16Khz 22Khz 24Khz 32Khz 44.1Khz 48Khz + * Duration: 7.5 ms 10 ms + * Channel count: 3 + * Frame length: 26-240 + */ + CODEC_CAPABILITIES("bcaa/lc3", BCAA_SERVICE_UUID, LC3_ID, + LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY, 26, + 240), + UTIL_IOV_INIT()), -struct codec_qos { - uint32_t interval; - uint8_t framing; - char *phy; - uint16_t sdu; - uint8_t rtn; - uint16_t latency; - uint32_t delay; + /* Broadcast LC3 Sink: + * + * Frequencies: 8Khz 11Khz 16Khz 22Khz 24Khz 32Khz 44.1Khz 48Khz + * Duration: 7.5 ms 10 ms + * Channel count: 3 + * Frame length: 26-240 + */ + CODEC_CAPABILITIES("baa/lc3", BAA_SERVICE_UUID, LC3_ID, + LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY, 26, + 240), + UTIL_IOV_INIT()), }; struct codec_preset { - const char *name; + char *name; const struct iovec data; - const struct codec_qos qos; - bool is_default; - uint8_t latency; + const struct iovec meta; + struct bt_bap_qos qos; + uint8_t target_latency; + uint32_t chan_alloc; + bool custom; + bool alt; + struct codec_preset *alt_preset; }; #define SBC_PRESET(_name, _data) \ @@ -1241,13 +1244,6 @@ struct codec_preset { .data = _data, \ } -#define SBC_DEFAULT_PRESET(_name, _data) \ - { \ - .name = _name, \ - .data = _data, \ - .is_default = true, \ - } - static struct codec_preset sbc_presets[] = { /* Table 4.7: Recommended sets of SBC parameters in the SRC device * Other settings: Block length = 16, Allocation method = Loudness, @@ -1257,110 +1253,44 @@ static struct codec_preset sbc_presets[] = { * mono, and 512kb/s for two-channel modes. */ SBC_PRESET("MQ_MONO_44_1", - CODEC_DATA(0x28, 0x15, 2, SBC_BITPOOL_MQ_MONO_44100)), + UTIL_IOV_INIT(0x28, 0x15, 2, SBC_BITPOOL_MQ_MONO_44100)), SBC_PRESET("MQ_MONO_48", - CODEC_DATA(0x18, 0x15, 2, SBC_BITPOOL_MQ_MONO_48000)), + UTIL_IOV_INIT(0x18, 0x15, 2, SBC_BITPOOL_MQ_MONO_48000)), SBC_PRESET("MQ_STEREO_44_1", - CODEC_DATA(0x21, 0x15, 2, SBC_BITPOOL_MQ_JOINT_STEREO_44100)), + UTIL_IOV_INIT(0x21, 0x15, 2, + SBC_BITPOOL_MQ_JOINT_STEREO_44100)), SBC_PRESET("MQ_STEREO_48", - CODEC_DATA(0x11, 0x15, 2, SBC_BITPOOL_MQ_JOINT_STEREO_48000)), + UTIL_IOV_INIT(0x11, 0x15, 2, + SBC_BITPOOL_MQ_JOINT_STEREO_48000)), SBC_PRESET("HQ_MONO_44_1", - CODEC_DATA(0x28, 0x15, 2, SBC_BITPOOL_HQ_MONO_44100)), + UTIL_IOV_INIT(0x28, 0x15, 2, SBC_BITPOOL_HQ_MONO_44100)), SBC_PRESET("HQ_MONO_48", - CODEC_DATA(0x18, 0x15, 2, SBC_BITPOOL_HQ_MONO_48000)), - SBC_DEFAULT_PRESET("HQ_STEREO_44_1", - CODEC_DATA(0x21, 0x15, 2, SBC_BITPOOL_HQ_JOINT_STEREO_44100)), + UTIL_IOV_INIT(0x18, 0x15, 2, SBC_BITPOOL_HQ_MONO_48000)), + SBC_PRESET("HQ_STEREO_44_1", + UTIL_IOV_INIT(0x21, 0x15, 2, + SBC_BITPOOL_HQ_JOINT_STEREO_44100)), SBC_PRESET("HQ_STEREO_48", - CODEC_DATA(0x11, 0x15, 2, SBC_BITPOOL_HQ_JOINT_STEREO_48000)), + UTIL_IOV_INIT(0x11, 0x15, 2, + SBC_BITPOOL_HQ_JOINT_STEREO_48000)), /* Higher bitrates not recommended by A2DP spec, it dual channel to * avoid going above 53 bitpool: * * https://habr.com/en/post/456476/ * https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/issues/1092 */ - SBC_PRESET("XQ_DUAL_44_1", CODEC_DATA(0x24, 0x15, 2, 43)), - SBC_PRESET("XQ_DUAL_48", CODEC_DATA(0x14, 0x15, 2, 39)), + SBC_PRESET("XQ_DUAL_44_1", UTIL_IOV_INIT(0x24, 0x15, 2, 43)), + SBC_PRESET("XQ_DUAL_48", UTIL_IOV_INIT(0x14, 0x15, 2, 39)), /* Ultra high bitpool that fits in 512 kbps mandatory bitrate */ - SBC_PRESET("UQ_STEREO_44_1", CODEC_DATA(0x21, 0x15, 2, 64)), - SBC_PRESET("UQ_STEREO_48", CODEC_DATA(0x11, 0x15, 2, 58)), + SBC_PRESET("UQ_STEREO_44_1", UTIL_IOV_INIT(0x21, 0x15, 2, 64)), + SBC_PRESET("UQ_STEREO_48", UTIL_IOV_INIT(0x11, 0x15, 2, 58)), }; -#define QOS_CONFIG(_interval, _framing, _phy, _sdu, _rtn, _latency, _delay) \ - { \ - .interval = _interval, \ - .framing = _framing, \ - .phy = _phy, \ - .sdu = _sdu, \ - .rtn = _rtn, \ - .latency = _latency, \ - .delay = _delay, \ - } - -#define QOS_UNFRAMED(_interval, _phy, _sdu, _rtn, _latency, _delay) \ - QOS_CONFIG(_interval, 0x00, _phy, _sdu, _rtn, _latency, _delay) - -#define QOS_FRAMED(_interval, _phy, _sdu, _rtn, _latency, _delay) \ - QOS_CONFIG(_interval, 0x01, _phy, _sdu, _rtn, _latency, _delay) - -#define QOS_UNFRAMED_1M(_interval, _sdu, _rtn, _latency, _delay) \ - QOS_UNFRAMED(_interval, "1M", _sdu, _rtn, _latency, _delay) \ - -#define QOS_FRAMED_1M(_interval, _sdu, _rtn, _latency, _delay) \ - QOS_FRAMED(_interval, "1M", _sdu, _rtn, _latency, _delay) \ - -#define QOS_UNFRAMED_2M(_interval, _sdu, _rtn, _latency, _delay) \ - QOS_UNFRAMED(_interval, "2M", _sdu, _rtn, _latency, _delay) \ - -#define QOS_FRAMED_2M(_interval, _sdu, _rtn, _latency, _delay) \ - QOS_FRAMED(_interval, "2M", _sdu, _rtn, _latency, _delay) \ - -#define LC3_7_5_UNFRAMED(_sdu, _rtn, _latency, _delay) \ - QOS_UNFRAMED(7500u, "2M", _sdu, _rtn, _latency, _delay) - -#define LC3_7_5_FRAMED(_sdu, _rtn, _latency, _delay) \ - QOS_FRAMED(7500u, "2M", _sdu, _rtn, _latency, _delay) - -#define LC3_10_UNFRAMED(_sdu, _rtn, _latency, _delay) \ - QOS_UNFRAMED_2M(10000u, _sdu, _rtn, _latency, _delay) - -#define LC3_10_FRAMED(_sdu, _rtn, _latency, _delay) \ - QOS_FRAMED_2M(10000u, _sdu, _rtn, _latency, _delay) - -#define LC3_PRESET_DATA(_freq, _duration, _len) \ - CODEC_DATA(0x02, LC3_CONFIG_FREQ, _freq, \ - 0x02, LC3_CONFIG_DURATION, _duration, \ - 0x03, LC3_CONFIG_FRAME_LEN, _len, _len >> 8) - -#define LC3_PRESET_8KHZ(_duration, _len) \ - LC3_PRESET_DATA(LC3_CONFIG_FREQ_8KHZ, _duration, _len) - -#define LC3_PRESET_11KHZ(_duration, _len) \ - LC3_PRESET_DATA(LC3_CONFIG_FREQ_11KHZ, _duration, _len) - -#define LC3_PRESET_16KHZ(_duration, _len) \ - LC3_PRESET_DATA(LC3_CONFIG_FREQ_16KHZ, _duration, _len) - -#define LC3_PRESET_22KHZ(_duration, _len) \ - LC3_PRESET_DATA(LC3_CONFIG_FREQ_22KHZ, _duration, _len) - -#define LC3_PRESET_24KHZ(_duration, _len) \ - LC3_PRESET_DATA(LC3_CONFIG_FREQ_24KHZ, _duration, _len) - -#define LC3_PRESET_32KHZ(_duration, _len) \ - LC3_PRESET_DATA(LC3_CONFIG_FREQ_32KHZ, _duration, _len) - -#define LC3_PRESET_44KHZ(_duration, _len) \ - LC3_PRESET_DATA(LC3_CONFIG_FREQ_44KHZ, _duration, _len) - -#define LC3_PRESET_48KHZ(_duration, _len) \ - LC3_PRESET_DATA(LC3_CONFIG_FREQ_48KHZ, _duration, _len) - #define LC3_PRESET_LL(_name, _data, _qos) \ { \ .name = _name, \ .data = _data, \ .qos = _qos, \ - .latency = 0x01, \ + .target_latency = 0x01, \ } #define LC3_PRESET(_name, _data, _qos) \ @@ -1368,7 +1298,7 @@ static struct codec_preset sbc_presets[] = { .name = _name, \ .data = _data, \ .qos = _qos, \ - .latency = 0x02, \ + .target_latency = 0x02, \ } #define LC3_PRESET_HR(_name, _data, _qos) \ @@ -1376,140 +1306,291 @@ static struct codec_preset sbc_presets[] = { .name = _name, \ .data = _data, \ .qos = _qos, \ - .latency = 0x03, \ + .target_latency = 0x03, \ } -#define LC3_DEFAULT_PRESET(_name, _data, _qos) \ +#define LC3_PRESET_B(_name, _data, _qos) \ { \ .name = _name, \ .data = _data, \ - .is_default = true, \ .qos = _qos, \ - .latency = 0x02, \ + .target_latency = 0x00, \ } -static struct codec_preset lc3_presets[] = { +static struct codec_preset lc3_ucast_presets[] = { /* Table 4.43: QoS configuration support setting requirements */ - LC3_PRESET("8_1_1", - LC3_PRESET_8KHZ(LC3_CONFIG_DURATION_7_5, 26u), - LC3_7_5_UNFRAMED(26u, 2u, 8u, 40000u)), - LC3_PRESET("8_2_1", - LC3_PRESET_8KHZ(LC3_CONFIG_DURATION_10, 30u), - LC3_10_UNFRAMED(30u, 2u, 10u, 40000u)), - LC3_PRESET("16_1_1", - LC3_PRESET_16KHZ(LC3_CONFIG_DURATION_7_5, 30u), - LC3_7_5_UNFRAMED(30u, 2u, 8u, 40000u)), - LC3_DEFAULT_PRESET("16_2_1", - LC3_PRESET_16KHZ(LC3_CONFIG_DURATION_10, 40u), - LC3_10_UNFRAMED(40u, 2u, 10u, 40000u)), - LC3_PRESET("24_1_1", - LC3_PRESET_24KHZ(LC3_CONFIG_DURATION_7_5, 45u), - LC3_7_5_UNFRAMED(45u, 2u, 8u, 40000u)), - LC3_PRESET("24_2_1", - LC3_PRESET_24KHZ(LC3_CONFIG_DURATION_10, 60u), - LC3_10_UNFRAMED(60u, 2u, 10u, 40000u)), - LC3_PRESET("32_1_1", - LC3_PRESET_32KHZ(LC3_CONFIG_DURATION_7_5, 60u), - LC3_7_5_UNFRAMED(60u, 2u, 8u, 40000u)), - LC3_PRESET("32_2_1", - LC3_PRESET_32KHZ(LC3_CONFIG_DURATION_10, 80u), - LC3_10_UNFRAMED(80u, 2u, 10u, 40000u)), - LC3_PRESET("44_1_1", - LC3_PRESET_44KHZ(LC3_CONFIG_DURATION_7_5, 98u), - QOS_FRAMED_2M(8163u, 98u, 5u, 24u, 40000u)), - LC3_PRESET("44_2_1", - LC3_PRESET_44KHZ(LC3_CONFIG_DURATION_10, 130u), - QOS_FRAMED_2M(10884u, 130u, 5u, 31u, 40000u)), - LC3_PRESET("48_1_1", - LC3_PRESET_48KHZ(LC3_CONFIG_DURATION_7_5, 75u), - LC3_7_5_UNFRAMED(75u, 5u, 15u, 40000u)), - LC3_PRESET("48_2_1", - LC3_PRESET_48KHZ(LC3_CONFIG_DURATION_10, 100u), - LC3_10_UNFRAMED(100u, 5u, 20u, 40000u)), - LC3_PRESET("48_3_1", - LC3_PRESET_48KHZ(LC3_CONFIG_DURATION_7_5, 90u), - LC3_7_5_UNFRAMED(90u, 5u, 15u, 40000u)), - LC3_PRESET("48_4_1", - LC3_PRESET_48KHZ(LC3_CONFIG_DURATION_10, 120u), - LC3_10_UNFRAMED(120u, 5u, 20u, 40000u)), - LC3_PRESET("48_5_1", - LC3_PRESET_48KHZ(LC3_CONFIG_DURATION_7_5, 117u), - LC3_7_5_UNFRAMED(117u, 5u, 15u, 40000u)), - LC3_PRESET("48_6_1", - LC3_PRESET_48KHZ(LC3_CONFIG_DURATION_10, 155u), - LC3_10_UNFRAMED(155u, 5u, 20u, 40000u)), + LC3_PRESET("8_1_1", LC3_CONFIG_8_1, LC3_QOS_8_1_1), + LC3_PRESET("8_2_1", LC3_CONFIG_8_2, LC3_QOS_8_2_1), + LC3_PRESET("16_1_1", LC3_CONFIG_16_1, LC3_QOS_16_1_1), + LC3_PRESET("16_2_1", LC3_CONFIG_16_2, LC3_QOS_16_2_1), + LC3_PRESET("24_1_1", LC3_CONFIG_24_1, LC3_QOS_24_1_1), + LC3_PRESET("24_2_1", LC3_CONFIG_24_2, LC3_QOS_24_2_1), + LC3_PRESET("32_1_1", LC3_CONFIG_32_1, LC3_QOS_32_1_1), + LC3_PRESET("32_2_1", LC3_CONFIG_32_2, LC3_QOS_32_1_1), + LC3_PRESET("44_1_1", LC3_CONFIG_44_1, LC3_QOS_44_1_1), + LC3_PRESET("44_2_1", LC3_CONFIG_44_2, LC3_QOS_44_2_1), + LC3_PRESET("48_1_1", LC3_CONFIG_48_1, LC3_QOS_48_1_1), + LC3_PRESET("48_2_1", LC3_CONFIG_48_2, LC3_QOS_48_2_1), + LC3_PRESET("48_3_1", LC3_CONFIG_48_3, LC3_QOS_48_3_1), + LC3_PRESET("48_4_1", LC3_CONFIG_48_4, LC3_QOS_48_4_1), + LC3_PRESET("48_5_1", LC3_CONFIG_48_5, LC3_QOS_48_5_1), + LC3_PRESET("48_6_1", LC3_CONFIG_48_6, LC3_QOS_48_6_1), /* QoS Configuration settings for high reliability audio data */ - LC3_PRESET_HR("44_1_2", - LC3_PRESET_44KHZ(LC3_CONFIG_DURATION_7_5, 98u), - QOS_FRAMED_2M(8163u, 98u, 23u, 54u, 40000u)), - LC3_PRESET_HR("44_2_2", - LC3_PRESET_44KHZ(LC3_CONFIG_DURATION_10, 130u), - QOS_FRAMED_2M(10884u, 130u, 23u, 71u, 40000u)), - LC3_PRESET_HR("48_1_2", - LC3_PRESET_48KHZ(LC3_CONFIG_DURATION_7_5, 75u), - LC3_7_5_UNFRAMED(75u, 23u, 45u, 40000u)), - LC3_PRESET_HR("48_2_2", - LC3_PRESET_48KHZ(LC3_CONFIG_DURATION_10, 100u), - LC3_10_UNFRAMED(100u, 23u, 60u, 40000u)), - LC3_PRESET_HR("48_3_2", - LC3_PRESET_48KHZ(LC3_CONFIG_DURATION_7_5, 90u), - LC3_7_5_UNFRAMED(90u, 23u, 45u, 40000u)), - LC3_PRESET_HR("48_4_2", - LC3_PRESET_48KHZ(LC3_CONFIG_DURATION_10, 120u), - LC3_10_UNFRAMED(120u, 23u, 60u, 40000u)), - LC3_PRESET_HR("48_5_2", - LC3_PRESET_48KHZ(LC3_CONFIG_DURATION_7_5, 117u), - LC3_7_5_UNFRAMED(117u, 23u, 45u, 40000u)), - LC3_PRESET_HR("48_6_2", - LC3_PRESET_48KHZ(LC3_CONFIG_DURATION_10, 155u), - LC3_10_UNFRAMED(155u, 23u, 60u, 40000u)), + LC3_PRESET_HR("8_1_2", LC3_CONFIG_8_1, LC3_QOS_8_1_2), + LC3_PRESET_HR("8_2_2", LC3_CONFIG_8_2, LC3_QOS_8_2_2), + LC3_PRESET_HR("16_1_2", LC3_CONFIG_16_1, LC3_QOS_16_1_2), + LC3_PRESET_HR("16_2_2", LC3_CONFIG_16_2, LC3_QOS_16_2_2), + LC3_PRESET_HR("24_1_2", LC3_CONFIG_24_1, LC3_QOS_24_1_2), + LC3_PRESET_HR("24_2_2", LC3_CONFIG_24_2, LC3_QOS_24_2_2), + LC3_PRESET_HR("32_1_2", LC3_CONFIG_32_1, LC3_QOS_32_1_2), + LC3_PRESET_HR("32_2_2", LC3_CONFIG_32_2, LC3_QOS_32_2_2), + LC3_PRESET_HR("44_1_2", LC3_CONFIG_44_1, LC3_QOS_44_1_2), + LC3_PRESET_HR("44_2_2", LC3_CONFIG_44_2, LC3_QOS_44_2_2), + LC3_PRESET_HR("48_1_2", LC3_CONFIG_48_1, LC3_QOS_48_1_2), + LC3_PRESET_HR("48_2_2", LC3_CONFIG_48_2, LC3_QOS_48_2_2), + LC3_PRESET_HR("48_3_2", LC3_CONFIG_48_3, LC3_QOS_48_3_2), + LC3_PRESET_HR("48_4_2", LC3_CONFIG_48_4, LC3_QOS_48_4_2), + LC3_PRESET_HR("48_5_2", LC3_CONFIG_48_5, LC3_QOS_48_5_2), + LC3_PRESET_HR("48_6_2", LC3_CONFIG_48_6, LC3_QOS_48_6_2), + /* QoS configuration support setting requirements for the UGG and UGT */ + LC3_PRESET_LL("16_1_gs", LC3_CONFIG_16_1, LC3_QOS_16_1_GS), + LC3_PRESET_LL("16_2_gs", LC3_CONFIG_16_2, LC3_QOS_16_2_GS), + LC3_PRESET_LL("32_1_gs", LC3_CONFIG_32_1, LC3_QOS_32_1_GS), + LC3_PRESET_LL("32_2_gs", LC3_CONFIG_32_2, LC3_QOS_32_2_GS), + LC3_PRESET_LL("48_1_gs", LC3_CONFIG_48_1, LC3_QOS_48_1_GS), + LC3_PRESET_LL("48_2_gs", LC3_CONFIG_48_2, LC3_QOS_48_2_GS), + LC3_PRESET_LL("32_1_gr", LC3_CONFIG_32_1, LC3_QOS_32_1_GR), + LC3_PRESET_LL("32_2_gr", LC3_CONFIG_32_2, LC3_QOS_32_2_GR), + LC3_PRESET_LL("48_1_gr", LC3_CONFIG_48_1, LC3_QOS_48_1_GR), + LC3_PRESET_LL("48_2_gr", LC3_CONFIG_48_2, LC3_QOS_48_2_GR), + LC3_PRESET_LL("48_3_gr", LC3_CONFIG_48_3, LC3_QOS_48_3_GR), + LC3_PRESET_LL("48_4_gr", LC3_CONFIG_48_4, LC3_QOS_48_4_GR), + LC3_PRESET_LL("32_1_gr_l+r", LC3_CONFIG_32_1_AC(2), + LC3_QOS_32_1_GR_AC(2)), + LC3_PRESET_LL("32_2_gr_l+r", LC3_CONFIG_32_2_AC(2), + LC3_QOS_32_2_GR_AC(2)), + LC3_PRESET_LL("48_1_gr_l+r", LC3_CONFIG_48_1_AC(2), + LC3_QOS_48_1_GR_AC(2)), + LC3_PRESET_LL("48_2_gr_l+r", LC3_CONFIG_48_2_AC(2), + LC3_QOS_48_2_GR_AC(2)), + LC3_PRESET_LL("48_3_gr_l+r", LC3_CONFIG_48_3_AC(2), + LC3_QOS_48_3_GR_AC(2)), + LC3_PRESET_LL("48_4_gr_l+r", LC3_CONFIG_48_4_AC(2), + LC3_QOS_48_4_GR_AC(2)), +}; + +static struct codec_preset lc3_bcast_presets[] = { + /* Table 6.4: Broadcast Audio Stream configuration support requirements + * for the Broadcast Source and Broadcast Sink + */ + LC3_PRESET_B("8_1_1", LC3_CONFIG_8_1, LC3_QOS_8_1_1_B), + LC3_PRESET_B("8_2_1", LC3_CONFIG_8_2, LC3_QOS_8_2_1_B), + LC3_PRESET_B("16_1_1", LC3_CONFIG_16_1, LC3_QOS_16_1_1_B), + LC3_PRESET_B("16_2_1", LC3_CONFIG_16_2, LC3_QOS_16_2_1_B), + LC3_PRESET_B("24_1_1", LC3_CONFIG_24_1, LC3_QOS_24_1_1_B), + LC3_PRESET_B("24_2_1", LC3_CONFIG_24_2, LC3_QOS_24_2_1_B), + LC3_PRESET_B("32_1_1", LC3_CONFIG_32_1, LC3_QOS_32_1_1_B), + LC3_PRESET_B("32_2_1", LC3_CONFIG_32_2, LC3_QOS_32_2_1_B), + LC3_PRESET_B("44_1_1", LC3_CONFIG_44_1, LC3_QOS_44_1_1_B), + LC3_PRESET_B("44_2_1", LC3_CONFIG_44_2, LC3_QOS_44_2_1_B), + LC3_PRESET_B("48_1_1", LC3_CONFIG_48_1, LC3_QOS_48_1_1_B), + LC3_PRESET_B("48_2_1", LC3_CONFIG_48_2, LC3_QOS_48_2_1_B), + LC3_PRESET_B("48_3_1", LC3_CONFIG_48_3, LC3_QOS_48_3_1_B), + LC3_PRESET_B("48_4_1", LC3_CONFIG_48_4, LC3_QOS_48_4_1_B), + LC3_PRESET_B("48_5_1", LC3_CONFIG_48_5, LC3_QOS_48_5_1_B), + LC3_PRESET_B("48_6_1", LC3_CONFIG_48_6, LC3_QOS_48_6_1_B), + /* Broadcast Audio Stream configuration settings for high-reliability + * audio data. + */ + LC3_PRESET_B("8_1_2", LC3_CONFIG_8_1, LC3_QOS_8_1_1_B), + LC3_PRESET_B("8_2_2", LC3_CONFIG_8_2, LC3_QOS_8_2_2_B), + LC3_PRESET_B("16_1_2", LC3_CONFIG_16_1, LC3_QOS_16_1_2_B), + LC3_PRESET_B("16_2_2", LC3_CONFIG_16_2, LC3_QOS_16_2_2_B), + LC3_PRESET_B("24_1_2", LC3_CONFIG_24_1, LC3_QOS_24_1_2_B), + LC3_PRESET_B("24_2_2", LC3_CONFIG_24_2, LC3_QOS_24_2_2_B), + LC3_PRESET_B("32_1_2", LC3_CONFIG_32_1, LC3_QOS_32_1_2_B), + LC3_PRESET_B("32_2_2", LC3_CONFIG_32_2, LC3_QOS_32_2_2_B), + LC3_PRESET_B("44_1_2", LC3_CONFIG_44_1, LC3_QOS_44_1_2_B), + LC3_PRESET_B("44_2_2", LC3_CONFIG_44_2, LC3_QOS_44_2_2_B), + LC3_PRESET_B("48_1_2", LC3_CONFIG_48_1, LC3_QOS_48_1_2_B), + LC3_PRESET_B("48_2_2", LC3_CONFIG_48_2, LC3_QOS_48_2_2_B), + LC3_PRESET_B("48_3_2", LC3_CONFIG_48_3, LC3_QOS_48_3_2_B), + LC3_PRESET_B("48_4_2", LC3_CONFIG_48_4, LC3_QOS_48_4_2_B), + LC3_PRESET_B("48_5_2", LC3_CONFIG_48_5, LC3_QOS_48_5_2_B), + LC3_PRESET_B("48_6_2", LC3_CONFIG_48_6, LC3_QOS_48_6_2_B), }; -#define PRESET(_uuid, _presets) \ +static void print_ltv(const char *str, void *user_data) +{ + const char *label = user_data; + + bt_shell_printf("\t%s.%s\n", label, str); +} + +static void print_lc3_caps(uint8_t *data, int len) +{ + const char *label = "Capabilities"; + + bt_bap_debug_caps(data, len, print_ltv, (void *)label); +} + +static void print_lc3_cfg(void *data, int len) +{ + const char *label = "Configuration"; + + bt_bap_debug_config(data, len, print_ltv, (void *)label); +} + +static void print_lc3_meta(void *data, int len) +{ + const char *label = "Metadata"; + + bt_bap_debug_metadata(data, len, print_ltv, (void *)label); +} + +#define PRESET(_uuid, _codec, _presets, _default_index) \ { \ .uuid = _uuid, \ + .codec = _codec, \ + .default_preset = &_presets[_default_index], \ .presets = _presets, \ .num_presets = ARRAY_SIZE(_presets), \ } -static const struct preset { +static struct preset { const char *uuid; + uint8_t codec; + uint16_t cid; + uint16_t vid; + struct queue *custom; + struct codec_preset *default_preset; struct codec_preset *presets; size_t num_presets; } presets[] = { - PRESET(A2DP_SOURCE_UUID, sbc_presets), - PRESET(A2DP_SINK_UUID, sbc_presets), - PRESET(PAC_SINK_UUID, lc3_presets), - PRESET(PAC_SOURCE_UUID, lc3_presets), + PRESET(A2DP_SOURCE_UUID, A2DP_CODEC_SBC, sbc_presets, 6), + PRESET(A2DP_SINK_UUID, A2DP_CODEC_SBC, sbc_presets, 6), + PRESET(PAC_SINK_UUID, LC3_ID, lc3_ucast_presets, 3), + PRESET(PAC_SOURCE_UUID, LC3_ID, lc3_ucast_presets, 3), + PRESET(BCAA_SERVICE_UUID, LC3_ID, lc3_bcast_presets, 3), + PRESET(BAA_SERVICE_UUID, LC3_ID, lc3_bcast_presets, 3), }; -static struct codec_preset *find_preset(const char *uuid, const char *name) +static void parse_vendor_codec(const char *codec, uint16_t *vid, uint16_t *cid) +{ + char **list; + char *endptr = NULL; + + if (!codec) + return; + + list = g_strsplit(codec, ":", 2); + + if (vid) + *vid = strtol(list[0], &endptr, 0); + + if (cid) + *cid = strtol(list[1], &endptr, 0); + + g_strfreev(list); +} + +static struct preset *find_presets(const char *uuid, uint8_t codec, + uint16_t vid, uint16_t cid) { size_t i; - for (i = 0; i < ARRAY_SIZE(presets); i++) { - const struct preset *preset = &presets[i]; + if (codec == 0xff) { + GList *l; - if (!strcasecmp(preset->uuid, uuid)) { - size_t j; + for (l = local_endpoints; l; l = g_list_next(l)) { + struct endpoint *ep = l->data; - for (j = 0; j < preset->num_presets; j++) { - struct codec_preset *p; + if (strcasecmp(ep->uuid, uuid) || ep->codec != codec) + continue; - p = &preset->presets[j]; + if (ep->codec == 0xff && (ep->vid != vid || + ep->cid != cid)) + continue; - if (!name) { - if (p->is_default) - return p; - } else if (!strcmp(p->name, name)) - return p; - } + return ep->preset; } + + return NULL; + } + + for (i = 0; i < ARRAY_SIZE(presets); i++) { + struct preset *preset = &presets[i]; + + if (preset->codec != codec) + continue; + + if (!strcasecmp(preset->uuid, uuid)) + return preset; } return NULL; } +static struct preset *find_vendor_presets(const char *uuid, const char *codec) +{ + uint16_t cid; + uint16_t vid; + + if (!uuid || !codec) + return NULL; + + parse_vendor_codec(codec, &vid, &cid); + + return find_presets(uuid, 0xff, vid, cid); +} + +static struct preset *find_presets_name(const char *uuid, const char *codec) +{ + uint8_t id; + char *endptr = NULL; + + if (!uuid || !codec) + return NULL; + + if (strrchr(codec, ':')) + return find_vendor_presets(uuid, codec); + + id = strtol(codec, &endptr, 0); + + return find_presets(uuid, id, 0x0000, 0x0000); +} + +static bool match_custom_name(const void *data, const void *match_data) +{ + const struct codec_preset *preset = data; + const char *name = match_data; + + return !strcmp(preset->name, name); +} + +static struct codec_preset *preset_find_name(struct preset *preset, + const char *name) +{ + size_t i; + + if (!preset) + return NULL; + + if (!name) + return preset->default_preset; + + for (i = 0; i < preset->num_presets; i++) { + struct codec_preset *p; + + p = &preset->presets[i]; + + if (!strcmp(p->name, name)) + return p; + } + + return queue_find(preset->custom, match_custom_name, name); +} + static DBusMessage *endpoint_select_config_reply(DBusMessage *msg, uint8_t *data, size_t len) { @@ -1574,7 +1655,7 @@ static void select_config_response(const char *input, void *user_data) uint8_t *data; size_t len; - p = find_preset(ep->uuid, input); + p = preset_find_name(ep->preset, input); if (p) { data = p->data.iov_base; len = p->data.iov_len; @@ -1615,6 +1696,13 @@ static DBusMessage *endpoint_select_configuration(DBusConnection *conn, bt_shell_printf("Endpoint: SelectConfiguration\n"); print_iter("\t", "Capabilities", &args); + if (!ep->max_transports) { + bt_shell_printf("Maximum transports reached: rejecting\n"); + return g_dbus_create_error(msg, + "org.bluez.Error.Rejected", + "Maximum transports reached"); + } + if (!ep->auto_accept) { ep->msg = dbus_message_ref(msg); bt_shell_prompt_input("Endpoint", "Enter preset/configuration:", @@ -1622,7 +1710,7 @@ static DBusMessage *endpoint_select_configuration(DBusConnection *conn, return NULL; } - p = find_preset(ep->uuid, NULL); + p = preset_find_name(ep->preset, NULL); if (!p) { reply = g_dbus_create_error(msg, "org.bluez.Error.Rejected", NULL); @@ -1631,8 +1719,11 @@ static DBusMessage *endpoint_select_configuration(DBusConnection *conn, reply = endpoint_select_config_reply(msg, p->data.iov_base, p->data.iov_len); - if (!reply) - return NULL; + if (!reply) { + reply = g_dbus_create_error(msg, "org.bluez.Error.Rejected", + NULL); + return reply; + } bt_shell_printf("Auto Accepting using %s...\n", p->name); @@ -1642,140 +1733,392 @@ static DBusMessage *endpoint_select_configuration(DBusConnection *conn, struct endpoint_config { GDBusProxy *proxy; struct endpoint *ep; - struct iovec *caps; + struct iovec *caps; /* Codec Specific Configuration LTVs */ + struct iovec *meta; /* Metadata LTVs*/ uint8_t target_latency; - const struct codec_qos *qos; + struct bt_bap_qos qos; /* BAP QOS configuration parameters */ }; -static void append_properties(DBusMessageIter *iter, - struct endpoint_config *cfg) +static void append_io_qos(DBusMessageIter *iter, struct bt_bap_io_qos *qos) { - DBusMessageIter dict; - struct codec_qos *qos = (void *)cfg->qos; - const char *key = "Capabilities"; + bt_shell_printf("Interval %u\n", qos->interval); - dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &dict); + g_dbus_dict_append_entry(iter, "Interval", DBUS_TYPE_UINT32, + &qos->interval); - bt_shell_printf("Capabilities: "); - bt_shell_hexdump(cfg->caps->iov_base, cfg->caps->iov_len); + bt_shell_printf("PHY 0x%02x\n", qos->phy); - g_dbus_dict_append_basic_array(&dict, DBUS_TYPE_STRING, &key, - DBUS_TYPE_BYTE, &cfg->caps->iov_base, - cfg->caps->iov_len); + g_dbus_dict_append_entry(iter, "PHY", DBUS_TYPE_BYTE, &qos->phy); - if (!qos) - goto done; + bt_shell_printf("SDU %u\n", qos->sdu); - if (cfg->target_latency) { - bt_shell_printf("TargetLatency 0x%02x\n", qos->interval); - g_dbus_dict_append_entry(&dict, "TargetLatency", - DBUS_TYPE_BYTE, &cfg->target_latency); - } + g_dbus_dict_append_entry(iter, "SDU", DBUS_TYPE_UINT16, &qos->sdu); - if (cfg->ep->cig != BT_ISO_QOS_CIG_UNSET) { - bt_shell_printf("CIG 0x%2.2x\n", cfg->ep->cig); - g_dbus_dict_append_entry(&dict, "CIG", DBUS_TYPE_BYTE, - &cfg->ep->cig); - } + bt_shell_printf("Retransmissions %u\n", qos->rtn); - if (cfg->ep->cis != BT_ISO_QOS_CIS_UNSET) { - bt_shell_printf("CIS 0x%2.2x\n", cfg->ep->cis); - g_dbus_dict_append_entry(&dict, "CIS", DBUS_TYPE_BYTE, - &cfg->ep->cis); - } + g_dbus_dict_append_entry(iter, "Retransmissions", DBUS_TYPE_BYTE, + &qos->rtn); - bt_shell_printf("Interval %u\n", qos->interval); + bt_shell_printf("Latency %u\n", qos->latency); - g_dbus_dict_append_entry(&dict, "Interval", DBUS_TYPE_UINT32, - &qos->interval); + g_dbus_dict_append_entry(iter, "Latency", DBUS_TYPE_UINT16, + &qos->latency); +} - bt_shell_printf("Framing %s\n", qos->framing ? "true" : "false"); +static void append_ucast_qos(DBusMessageIter *iter, struct endpoint_config *cfg) +{ + struct bt_bap_ucast_qos *qos = &cfg->qos.ucast; - g_dbus_dict_append_entry(&dict, "Framing", DBUS_TYPE_BOOLEAN, - &qos->framing); + if (cfg->ep->iso_group != BT_ISO_QOS_GROUP_UNSET) { + bt_shell_printf("CIG 0x%2.2x\n", cfg->ep->iso_group); + g_dbus_dict_append_entry(iter, "CIG", DBUS_TYPE_BYTE, + &cfg->ep->iso_group); + } - bt_shell_printf("PHY %s\n", qos->phy); + if (cfg->ep->iso_stream != BT_ISO_QOS_STREAM_UNSET) { + bt_shell_printf("CIS 0x%2.2x\n", cfg->ep->iso_stream); + g_dbus_dict_append_entry(iter, "CIS", DBUS_TYPE_BYTE, + &cfg->ep->iso_stream); + } - g_dbus_dict_append_entry(&dict, "PHY", DBUS_TYPE_STRING, &qos->phy); + bt_shell_printf("Framing 0x%02x\n", qos->framing); - bt_shell_printf("SDU %u\n", cfg->qos->sdu); + g_dbus_dict_append_entry(iter, "Framing", DBUS_TYPE_BYTE, + &qos->framing); - g_dbus_dict_append_entry(&dict, "SDU", DBUS_TYPE_UINT16, &qos->sdu); + bt_shell_printf("PresentationDelay %u\n", qos->delay); - bt_shell_printf("Retransmissions %u\n", qos->rtn); + g_dbus_dict_append_entry(iter, "PresentationDelay", + DBUS_TYPE_UINT32, &qos->delay); - g_dbus_dict_append_entry(&dict, "Retransmissions", DBUS_TYPE_BYTE, - &qos->rtn); + if (cfg->target_latency) { + bt_shell_printf("TargetLatency 0x%02x\n", cfg->target_latency); + g_dbus_dict_append_entry(iter, "TargetLatency", DBUS_TYPE_BYTE, + &cfg->target_latency); + } - bt_shell_printf("Latency %u\n", qos->latency); + append_io_qos(iter, &qos->io_qos); +} - g_dbus_dict_append_entry(&dict, "Latency", DBUS_TYPE_UINT16, - &qos->latency); +static void append_bcast_qos(DBusMessageIter *iter, struct endpoint_config *cfg) +{ + struct bt_bap_bcast_qos *qos = &cfg->qos.bcast; - bt_shell_printf("Delay %u\n", qos->delay); + if (cfg->ep->iso_group != BT_ISO_QOS_BIG_UNSET) { + bt_shell_printf("BIG 0x%2.2x\n", cfg->ep->iso_group); + g_dbus_dict_append_entry(iter, "BIG", DBUS_TYPE_BYTE, + &cfg->ep->iso_group); + } - g_dbus_dict_append_entry(&dict, "Delay", DBUS_TYPE_UINT32, - &qos->delay); + if (cfg->ep->iso_stream != BT_ISO_QOS_BIS_UNSET) { + bt_shell_printf("BIS 0x%2.2x\n", cfg->ep->iso_stream); + g_dbus_dict_append_entry(iter, "BIS", DBUS_TYPE_BYTE, + &cfg->ep->iso_stream); + } -done: - dbus_message_iter_close_container(iter, &dict); -} + if (qos->sync_factor) { + bt_shell_printf("SyncFactor %u\n", qos->sync_factor); + g_dbus_dict_append_entry(iter, "SyncFactor", DBUS_TYPE_BYTE, + &qos->sync_factor); + } -static struct iovec *iov_append(struct iovec **iov, const void *data, - size_t len) -{ - if (!*iov) { - *iov = new0(struct iovec, 1); - (*iov)->iov_base = new0(uint8_t, UINT8_MAX); + if (qos->options) { + bt_shell_printf("Options %u\n", qos->options); + g_dbus_dict_append_entry(iter, "Options", DBUS_TYPE_BYTE, + &qos->options); } - if (data && len) { - memcpy((*iov)->iov_base + (*iov)->iov_len, data, len); - (*iov)->iov_len += len; + if (qos->skip) { + bt_shell_printf("Skip %u\n", qos->skip); + g_dbus_dict_append_entry(iter, "Skip", DBUS_TYPE_UINT16, + &qos->skip); } - return *iov; -} + if (qos->sync_timeout) { + bt_shell_printf("SyncTimeout %u\n", qos->sync_timeout); + g_dbus_dict_append_entry(iter, "SyncTimeout", DBUS_TYPE_UINT16, + &qos->sync_timeout); + } -static DBusMessage *endpoint_select_properties_reply(struct endpoint *ep, - DBusMessage *msg, - struct codec_preset *preset) -{ - DBusMessage *reply; - DBusMessageIter iter; - struct endpoint_config *cfg; + if (qos->sync_cte_type) { + bt_shell_printf("SyncCteType %u\n", qos->sync_cte_type); + g_dbus_dict_append_entry(iter, "SyncCteType", DBUS_TYPE_BYTE, + &qos->sync_cte_type); + } - reply = dbus_message_new_method_return(msg); - if (!reply) - return NULL; + if (qos->mse) { + bt_shell_printf("MSE %u\n", qos->mse); + g_dbus_dict_append_entry(iter, "MSE", DBUS_TYPE_BYTE, + &qos->mse); + } - cfg = new0(struct endpoint_config, 1); - cfg->ep = ep; + if (qos->timeout) { + bt_shell_printf("Timeout %u\n", qos->timeout); + g_dbus_dict_append_entry(iter, "Timeout", DBUS_TYPE_UINT16, + &qos->timeout); + } - /* Copy capabilities */ - iov_append(&cfg->caps, preset->data.iov_base, preset->data.iov_len); - cfg->target_latency = preset->latency; + if (cfg->ep->bcode->iov_len != 0) { + const char *key = "BCode"; - if (preset->qos.phy) - /* Set QoS parameters */ - cfg->qos = &preset->qos; + bt_shell_printf("BCode:\n"); + bt_shell_hexdump(cfg->ep->bcode->iov_base, + cfg->ep->bcode->iov_len); - dbus_message_iter_init_append(reply, &iter); + g_dbus_dict_append_basic_array(iter, DBUS_TYPE_STRING, + &key, DBUS_TYPE_BYTE, + &cfg->ep->bcode->iov_base, + cfg->ep->bcode->iov_len); + } - append_properties(&iter, cfg); + bt_shell_printf("Framing 0x%02x\n", qos->framing); + + g_dbus_dict_append_entry(iter, "Framing", DBUS_TYPE_BYTE, + &qos->framing); + + bt_shell_printf("PresentationDelay %u\n", qos->delay); + + g_dbus_dict_append_entry(iter, "PresentationDelay", + DBUS_TYPE_UINT32, &qos->delay); + + /* Add BAP codec QOS configuration */ + append_io_qos(iter, &qos->io_qos); +} + +static void append_qos(DBusMessageIter *iter, struct endpoint_config *cfg) +{ + DBusMessageIter entry, var, dict; + const char *key = "QoS"; + + dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, + NULL, &entry); + + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); + + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, + "a{sv}", &var); + + dbus_message_iter_open_container(&var, DBUS_TYPE_ARRAY, "{sv}", + &dict); + + if (cfg->ep->broadcast) + append_bcast_qos(&dict, cfg); + else + append_ucast_qos(&dict, cfg); + + dbus_message_iter_close_container(&var, &dict); + dbus_message_iter_close_container(&entry, &var); + dbus_message_iter_close_container(iter, &entry); +} + +static void append_properties(DBusMessageIter *iter, + struct endpoint_config *cfg) +{ + DBusMessageIter dict; + const char *key = "Capabilities"; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &dict); + + if (cfg->ep->codec == LC3_ID) { + print_lc3_cfg(cfg->caps->iov_base, cfg->caps->iov_len); + } else { + bt_shell_printf("Capabilities: "); + bt_shell_hexdump(cfg->caps->iov_base, cfg->caps->iov_len); + } + + g_dbus_dict_append_basic_array(&dict, DBUS_TYPE_STRING, &key, + DBUS_TYPE_BYTE, &cfg->caps->iov_base, + cfg->caps->iov_len); + + if (cfg->meta && cfg->meta->iov_len) { + const char *meta = "Metadata"; + + g_dbus_dict_append_basic_array(&dict, DBUS_TYPE_STRING, &meta, + DBUS_TYPE_BYTE, &cfg->meta->iov_base, + cfg->meta->iov_len); + + if (cfg->ep->codec == LC3_ID) { + print_lc3_meta(cfg->meta->iov_base, cfg->meta->iov_len); + } else { + bt_shell_printf("Metadata:\n"); + bt_shell_hexdump(cfg->meta->iov_base, + cfg->meta->iov_len); + } + } + + append_qos(&dict, cfg); + + dbus_message_iter_close_container(iter, &dict); +} + +static int parse_chan_alloc(DBusMessageIter *iter, uint32_t *location, + uint8_t *channels) +{ + while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_DICT_ENTRY) { + const char *key; + DBusMessageIter value, entry; + int var; + + dbus_message_iter_recurse(iter, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &value); + + var = dbus_message_iter_get_arg_type(&value); + + if (!strcasecmp(key, "ChannelAllocation")) { + if (var != DBUS_TYPE_UINT32) + return -EINVAL; + dbus_message_iter_get_basic(&value, location); + if (*channels) + *channels = __builtin_popcount(*location); + return 0; + } else if (!strcasecmp(key, "Locations")) { + uint32_t tmp; + + if (var != DBUS_TYPE_UINT32) + return -EINVAL; + + dbus_message_iter_get_basic(&value, &tmp); + *location &= tmp; + + if (*channels) + *channels = __builtin_popcount(*location); + } + + dbus_message_iter_next(iter); + } + + return *location ? 0 : -EINVAL; +} + +static void ltv_find(size_t i, uint8_t l, uint8_t t, uint8_t *v, + void *user_data) +{ + bool *found = user_data; + + *found = true; +} + +static DBusMessage *endpoint_select_properties_reply(struct endpoint *ep, + DBusMessage *msg, + struct codec_preset *preset) +{ + DBusMessage *reply; + DBusMessageIter iter, props; + struct endpoint_config *cfg; + struct bt_bap_io_qos *qos; + uint32_t location = ep->locations; + uint8_t channels = 1; + + if (!preset) + return NULL; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return NULL; + + cfg = new0(struct endpoint_config, 1); + cfg->ep = ep; + + /* Copy capabilities */ + cfg->caps = util_iov_dup(&preset->data, 1); + cfg->target_latency = preset->target_latency; + + dbus_message_iter_init(msg, &iter); + dbus_message_iter_recurse(&iter, &props); + + if (!parse_chan_alloc(&props, &location, &channels)) { + uint32_t chan_alloc = 0; + uint8_t type = LC3_CONFIG_CHAN_ALLOC; + bool found = false; + + if (preset->chan_alloc & location) + chan_alloc = preset->chan_alloc & location; + else if (preset->alt_preset && + preset->alt_preset->chan_alloc & + location) { + chan_alloc = preset->alt_preset->chan_alloc & location; + preset = preset->alt_preset; + + /* Copy alternate capabilities */ + util_iov_free(cfg->caps, 1); + cfg->caps = util_iov_dup(&preset->data, 1); + cfg->target_latency = preset->target_latency; + } else + chan_alloc = location; + + /* Check if Channel Allocation is present in caps */ + util_ltv_foreach(cfg->caps->iov_base, cfg->caps->iov_len, + &type, ltv_find, &found); + + /* If Channel Allocation has not been set directly via + * preset->data then attempt to set it if chan_alloc has been + * set. + */ + if (!found && chan_alloc) { + uint8_t chan_alloc_ltv[] = { + 0x05, LC3_CONFIG_CHAN_ALLOC, chan_alloc & 0xff, + chan_alloc >> 8, chan_alloc >> 16, + chan_alloc >> 24 + }; + + put_le32(chan_alloc, &chan_alloc_ltv[2]); + util_iov_append(cfg->caps, &chan_alloc_ltv, + sizeof(chan_alloc_ltv)); + } + } + + /* Copy metadata */ + if (preset->meta.iov_len) + cfg->meta = util_iov_dup(&preset->meta, 1); + else + cfg->meta = util_iov_dup(ep->meta, 1); + + if (ep->broadcast) + qos = &preset->qos.bcast.io_qos; + else + qos = &preset->qos.ucast.io_qos; + + if (qos->phy) { + /* Set QoS parameters */ + cfg->qos = preset->qos; + /* Adjust the SDU size based on the number of + * locations/channels that is being requested. + */ + if (channels > 1) + qos->sdu *= channels; + } + + dbus_message_iter_init_append(reply, &iter); + + bt_shell_printf("selecting %s...\n", preset->name); + + append_properties(&iter, cfg); free(cfg); return reply; } +static struct codec_preset *endpoint_find_codec_preset(struct endpoint *ep, + const char *name) +{ + if (ep->codec_preset && + (!name || !strcmp(ep->codec_preset->name, name))) + return ep->codec_preset; + + return preset_find_name(ep->preset, name); +} + static void select_properties_response(const char *input, void *user_data) { struct endpoint *ep = user_data; struct codec_preset *p; DBusMessage *reply; - p = find_preset(ep->uuid, input); + p = endpoint_find_codec_preset(ep, input); if (p) { reply = endpoint_select_properties_reply(ep, ep->msg, p); goto done; @@ -1803,6 +2146,13 @@ static DBusMessage *endpoint_select_properties(DBusConnection *conn, bt_shell_printf("Endpoint: SelectProperties\n"); print_iter("\t", "Properties", &args); + if (!ep->max_transports) { + bt_shell_printf("Maximum transports reached: rejecting\n"); + return g_dbus_create_error(msg, + "org.bluez.Error.Rejected", + "Maximum transports reached"); + } + if (!ep->auto_accept) { ep->msg = dbus_message_ref(msg); bt_shell_prompt_input("Endpoint", "Enter preset/configuration:", @@ -1810,26 +2160,37 @@ static DBusMessage *endpoint_select_properties(DBusConnection *conn, return NULL; } - p = find_preset(ep->uuid, NULL); + p = endpoint_find_codec_preset(ep, NULL); if (!p) - NULL; + return NULL; reply = endpoint_select_properties_reply(ep, msg, p); if (!reply) return NULL; - bt_shell_printf("Auto Accepting using %s...\n", p->name); - return reply; } +static bool match_str(const void *data, const void *user_data) +{ + return !strcmp(data, user_data); +} + static DBusMessage *endpoint_clear_configuration(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct endpoint *ep = user_data; + DBusMessageIter args; + const char *path; + + dbus_message_iter_init(msg, &args); - free(ep->transport); - ep->transport = NULL; + dbus_message_iter_get_basic(&args, &path); + + if (ep->max_transports != UINT8_MAX) + ep->max_transports++; + + queue_remove_if(ep->transports, match_str, (void *)path); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } @@ -1853,217 +2214,1526 @@ static struct endpoint *endpoint_find(const char *pattern) return NULL; } -static void cmd_show_endpoint(int argc, char *argv[]) +static void print_aptx_common(a2dp_aptx_t *aptx) { - GDBusProxy *proxy; + bt_shell_printf("\n\t\tFrequencies: "); + if (aptx->frequency & APTX_SAMPLING_FREQ_16000) + bt_shell_printf("16kHz "); + if (aptx->frequency & APTX_SAMPLING_FREQ_32000) + bt_shell_printf("32kHz "); + if (aptx->frequency & APTX_SAMPLING_FREQ_44100) + bt_shell_printf("44.1kHz "); + if (aptx->frequency & APTX_SAMPLING_FREQ_48000) + bt_shell_printf("48kHz "); - proxy = g_dbus_proxy_lookup(endpoints, NULL, argv[1], - BLUEZ_MEDIA_ENDPOINT_INTERFACE); - if (!proxy) { - bt_shell_printf("Endpoint %s not found\n", argv[1]); - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - } + bt_shell_printf("\n\t\tChannel modes: "); + if (aptx->channel_mode & APTX_CHANNEL_MODE_MONO) + bt_shell_printf("Mono "); + if (aptx->channel_mode & APTX_CHANNEL_MODE_STEREO) + bt_shell_printf("Stereo "); +} - bt_shell_printf("Endpoint %s\n", g_dbus_proxy_get_path(proxy)); +static void print_aptx(a2dp_aptx_t *aptx, uint8_t size) +{ + bt_shell_printf("\t\tVendor Specific Value (aptX)"); - print_property(proxy, "UUID"); - print_property(proxy, "Codec"); - print_property(proxy, "Capabilities"); - print_property(proxy, "Device"); - print_property(proxy, "DelayReporting"); + if (size < sizeof(*aptx)) { + bt_shell_printf(" (broken)\n"); + return; + } - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} + print_aptx_common(aptx); -static const GDBusMethodTable endpoint_methods[] = { - { GDBUS_ASYNC_METHOD("SetConfiguration", - GDBUS_ARGS({ "endpoint", "o" }, - { "properties", "a{sv}" } ), - NULL, endpoint_set_configuration) }, - { GDBUS_ASYNC_METHOD("SelectConfiguration", - GDBUS_ARGS({ "caps", "ay" } ), - GDBUS_ARGS({ "cfg", "ay" } ), - endpoint_select_configuration) }, - { GDBUS_ASYNC_METHOD("SelectProperties", - GDBUS_ARGS({ "properties", "a{sv}" } ), - GDBUS_ARGS({ "properties", "a{sv}" } ), - endpoint_select_properties) }, - { GDBUS_ASYNC_METHOD("ClearConfiguration", - GDBUS_ARGS({ "transport", "o" } ), - NULL, endpoint_clear_configuration) }, - { }, -}; + bt_shell_printf("\n"); +} -static void endpoint_free(void *data) +static void print_faststream(a2dp_faststream_t *faststream, uint8_t size) { - struct endpoint *ep = data; + bt_shell_printf("\t\tVendor Specific Value (FastStream)"); - if (ep->caps) { - g_free(ep->caps->iov_base); - g_free(ep->caps); + if (size < sizeof(*faststream)) { + bt_shell_printf(" (broken)\n"); + return; } - if (ep->msg) - dbus_message_unref(ep->msg); + bt_shell_printf("\n\t\tDirections: "); + if (faststream->direction & FASTSTREAM_DIRECTION_SINK) + bt_shell_printf("sink "); + if (faststream->direction & FASTSTREAM_DIRECTION_SOURCE) + bt_shell_printf("source "); - g_free(ep->path); - g_free(ep->uuid); - g_free(ep); + if (faststream->direction & FASTSTREAM_DIRECTION_SINK) { + bt_shell_printf("\n\t\tSink Frequencies: "); + if (faststream->sink_frequency & + FASTSTREAM_SINK_SAMPLING_FREQ_44100) + bt_shell_printf("44.1kHz "); + if (faststream->sink_frequency & + FASTSTREAM_SINK_SAMPLING_FREQ_48000) + bt_shell_printf("48kHz "); + } + + if (faststream->direction & FASTSTREAM_DIRECTION_SOURCE) { + bt_shell_printf("\n\t\tSource Frequencies: "); + if (faststream->source_frequency & + FASTSTREAM_SOURCE_SAMPLING_FREQ_16000) + bt_shell_printf("16kHz "); + } + + bt_shell_printf("\n"); } -static gboolean endpoint_get_uuid(const GDBusPropertyTable *property, - DBusMessageIter *iter, void *data) +static void print_aptx_ll(a2dp_aptx_ll_t *aptx_ll, uint8_t size) { - struct endpoint *ep = data; + a2dp_aptx_ll_new_caps_t *aptx_ll_new; - dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &ep->uuid); + bt_shell_printf("\t\tVendor Specific Value (aptX Low Latency)"); - return TRUE; + if (size < sizeof(*aptx_ll)) { + bt_shell_printf(" (broken)\n"); + return; + } + + print_aptx_common(&aptx_ll->aptx); + + bt_shell_printf("\n\tBidirectional link: %s", + aptx_ll->bidirect_link ? "Yes" : "No"); + + aptx_ll_new = &aptx_ll->new_caps[0]; + if (aptx_ll->has_new_caps && + size >= sizeof(*aptx_ll) + sizeof(*aptx_ll_new)) { + bt_shell_printf("\n\tTarget codec buffer level: %u", + (unsigned int)aptx_ll_new->target_level2 | + ((unsigned int)(aptx_ll_new->target_level1) << 8)); + bt_shell_printf("\n\tInitial codec buffer level: %u", + (unsigned int)aptx_ll_new->initial_level2 | + ((unsigned int)(aptx_ll_new->initial_level1) << 8)); + bt_shell_printf("\n\tSRA max rate: %g", + aptx_ll_new->sra_max_rate / 10000.0); + bt_shell_printf("\n\tSRA averaging time: %us", + (unsigned int)aptx_ll_new->sra_avg_time); + bt_shell_printf("\n\tGood working codec buffer level: %u", + (unsigned int)aptx_ll_new->good_working_level2 | + ((unsigned int)(aptx_ll_new->good_working_level1) << 8) + ); + } + + bt_shell_printf("\n"); } -static gboolean endpoint_get_codec(const GDBusPropertyTable *property, - DBusMessageIter *iter, void *data) +static void print_aptx_hd(a2dp_aptx_hd_t *aptx_hd, uint8_t size) { - struct endpoint *ep = data; + bt_shell_printf("\t\tVendor Specific Value (aptX HD)"); - dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE, &ep->codec); + if (size < sizeof(*aptx_hd)) { + bt_shell_printf(" (broken)\n"); + return; + } - return TRUE; + print_aptx_common(&aptx_hd->aptx); + + bt_shell_printf("\n"); } -static gboolean endpoint_get_capabilities(const GDBusPropertyTable *property, - DBusMessageIter *iter, void *data) +static void print_ldac(a2dp_ldac_t *ldac, uint8_t size) { - struct endpoint *ep = data; - DBusMessageIter array; + bt_shell_printf("\t\tVendor Specific Value (LDAC)"); - dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_BYTE_AS_STRING, &array); + if (size < sizeof(*ldac)) { + bt_shell_printf(" (broken)\n"); + return; + } - dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, - &ep->caps->iov_base, - ep->caps->iov_len); + bt_shell_printf("\n\t\tFrequencies: "); + if (ldac->frequency & LDAC_SAMPLING_FREQ_44100) + bt_shell_printf("44.1kHz "); + if (ldac->frequency & LDAC_SAMPLING_FREQ_48000) + bt_shell_printf("48kHz "); + if (ldac->frequency & LDAC_SAMPLING_FREQ_88200) + bt_shell_printf("88.2kHz "); + if (ldac->frequency & LDAC_SAMPLING_FREQ_96000) + bt_shell_printf("96kHz "); + if (ldac->frequency & LDAC_SAMPLING_FREQ_176400) + bt_shell_printf("176.4kHz "); + if (ldac->frequency & LDAC_SAMPLING_FREQ_192000) + bt_shell_printf("192kHz "); - dbus_message_iter_close_container(iter, &array); + bt_shell_printf("\n\t\tChannel modes: "); + if (ldac->channel_mode & LDAC_CHANNEL_MODE_MONO) + bt_shell_printf("Mono "); + if (ldac->channel_mode & LDAC_CHANNEL_MODE_DUAL) + bt_shell_printf("Dual "); + if (ldac->channel_mode & LDAC_CHANNEL_MODE_STEREO) + bt_shell_printf("Stereo "); - return TRUE; + bt_shell_printf("\n"); } -static const GDBusPropertyTable endpoint_properties[] = { - { "UUID", "s", endpoint_get_uuid, NULL, NULL }, - { "Codec", "y", endpoint_get_codec, NULL, NULL }, - { "Capabilities", "ay", endpoint_get_capabilities, NULL, NULL }, - { } -}; - -static void register_endpoint_setup(DBusMessageIter *iter, void *user_data) +static void print_opus_g(a2dp_opus_g_t *opus, uint8_t size) { - struct endpoint *ep = user_data; - DBusMessageIter dict; - const char *key = "Capabilities"; - - dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &ep->path); + bt_shell_printf("\t\tVendor Specific Value (Opus [Google])"); - dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &dict); - - g_dbus_dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &ep->uuid); + if (size < sizeof(*opus)) { + bt_shell_printf(" (broken)\n"); + return; + } - g_dbus_dict_append_entry(&dict, "Codec", DBUS_TYPE_BYTE, &ep->codec); + bt_shell_printf("\n\t\tFrequencies: "); + if (opus->data & OPUS_G_FREQUENCY_48000) + bt_shell_printf("48kHz "); - g_dbus_dict_append_basic_array(&dict, DBUS_TYPE_STRING, &key, - DBUS_TYPE_BYTE, &ep->caps->iov_base, - ep->caps->iov_len); + bt_shell_printf("\n\t\tChannel modes: "); + if (opus->data & OPUS_G_CHANNELS_MONO) + bt_shell_printf("Mono "); + if (opus->data & OPUS_G_CHANNELS_STEREO) + bt_shell_printf("Stereo "); + if (opus->data & OPUS_G_CHANNELS_DUAL) + bt_shell_printf("Dual Mono "); - bt_shell_printf("Capabilities:\n"); - bt_shell_hexdump(ep->caps->iov_base, ep->caps->iov_len); + bt_shell_printf("\n\t\tFrame durations: "); + if (opus->data & OPUS_G_DURATION_100) + bt_shell_printf("10 ms "); + if (opus->data & OPUS_G_DURATION_200) + bt_shell_printf("20 ms "); - dbus_message_iter_close_container(iter, &dict); + bt_shell_printf("\n"); } -static void register_endpoint_reply(DBusMessage *message, void *user_data) +static void print_vendor(a2dp_vendor_codec_t *vendor, uint8_t size) { - struct endpoint *ep = user_data; - DBusError error; - - dbus_error_init(&error); + uint32_t vendor_id; + uint16_t codec_id; + int i; - if (dbus_set_error_from_message(&error, message)) { - bt_shell_printf("Failed to register endpoint: %s\n", - error.name); - dbus_error_free(&error); - local_endpoints = g_list_remove(local_endpoints, ep); - g_dbus_unregister_interface(dbus_conn, ep->path, - BLUEZ_MEDIA_ENDPOINT_INTERFACE); - return bt_shell_noninteractive_quit(EXIT_FAILURE); + if (size < sizeof(*vendor)) { + bt_shell_printf("\tMedia Codec: Vendor Specific A2DP Codec " + "(broken)"); + return; } - bt_shell_printf("Endpoint %s registered\n", ep->path); + vendor_id = A2DP_GET_VENDOR_ID(*vendor); + codec_id = A2DP_GET_CODEC_ID(*vendor); - return bt_shell_noninteractive_quit(EXIT_SUCCESS); + bt_shell_printf("\tMedia Codec: Vendor Specific A2DP Codec"); + + bt_shell_printf("\n\tVendor ID 0x%08x", vendor_id); + + bt_shell_printf("\n\tVendor Specific Codec ID 0x%04x", codec_id); + + bt_shell_printf("\n\tVendor Specific Data:"); + for (i = 6; i < size; ++i) + bt_shell_printf(" 0x%.02x", ((unsigned char *)vendor)[i]); + bt_shell_printf("\n"); + + if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID) + print_aptx((void *) vendor, size); + else if (vendor_id == FASTSTREAM_VENDOR_ID && + codec_id == FASTSTREAM_CODEC_ID) + print_faststream((void *) vendor, size); + else if (vendor_id == APTX_LL_VENDOR_ID && codec_id == APTX_LL_CODEC_ID) + print_aptx_ll((void *) vendor, size); + else if (vendor_id == APTX_HD_VENDOR_ID && codec_id == APTX_HD_CODEC_ID) + print_aptx_hd((void *) vendor, size); + else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID) + print_ldac((void *) vendor, size); + else if (vendor_id == OPUS_G_VENDOR_ID && codec_id == OPUS_G_CODEC_ID) + print_opus_g((void *) vendor, size); } -static void endpoint_register(struct endpoint *ep) +static void print_mpeg24(a2dp_aac_t *aac, uint8_t size) { - GList *l; + unsigned int freq, bitrate; - if (!g_dbus_register_interface(dbus_conn, ep->path, - BLUEZ_MEDIA_ENDPOINT_INTERFACE, - endpoint_methods, NULL, - endpoint_properties, ep, - endpoint_free)) { - goto fail; + if (size < sizeof(*aac)) { + bt_shell_printf("\tMedia Codec: MPEG24 (broken)\n"); + return; } - for (l = medias; l; l = g_list_next(l)) { - if (!g_dbus_proxy_method_call(l->data, "RegisterEndpoint", - register_endpoint_setup, - register_endpoint_reply, - ep, NULL)) { - g_dbus_unregister_interface(dbus_conn, ep->path, - BLUEZ_MEDIA_ENDPOINT_INTERFACE); - goto fail; - } + freq = AAC_GET_FREQUENCY(*aac); + bitrate = AAC_GET_BITRATE(*aac); + + bt_shell_printf("\tMedia Codec: MPEG24\n\tObject Types: "); + + if (aac->object_type & AAC_OBJECT_TYPE_MPEG2_AAC_LC) + bt_shell_printf("MPEG-2 AAC LC "); + if (aac->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LC) + bt_shell_printf("MPEG-4 AAC LC "); + if (aac->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LTP) + bt_shell_printf("MPEG-4 AAC LTP "); + if (aac->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_SCA) + bt_shell_printf("MPEG-4 AAC scalable "); + + bt_shell_printf("\n\tFrequencies: "); + if (freq & AAC_SAMPLING_FREQ_8000) + bt_shell_printf("8kHz "); + if (freq & AAC_SAMPLING_FREQ_11025) + bt_shell_printf("11.025kHz "); + if (freq & AAC_SAMPLING_FREQ_12000) + bt_shell_printf("12kHz "); + if (freq & AAC_SAMPLING_FREQ_16000) + bt_shell_printf("16kHz "); + if (freq & AAC_SAMPLING_FREQ_22050) + bt_shell_printf("22.05kHz "); + if (freq & AAC_SAMPLING_FREQ_24000) + bt_shell_printf("24kHz "); + if (freq & AAC_SAMPLING_FREQ_32000) + bt_shell_printf("32kHz "); + if (freq & AAC_SAMPLING_FREQ_44100) + bt_shell_printf("44.1kHz "); + if (freq & AAC_SAMPLING_FREQ_48000) + bt_shell_printf("48kHz "); + if (freq & AAC_SAMPLING_FREQ_64000) + bt_shell_printf("64kHz "); + if (freq & AAC_SAMPLING_FREQ_88200) + bt_shell_printf("88.2kHz "); + if (freq & AAC_SAMPLING_FREQ_96000) + bt_shell_printf("96kHz "); + + bt_shell_printf("\n\tChannels: "); + if (aac->channels & AAC_CHANNELS_1) + bt_shell_printf("1 "); + if (aac->channels & AAC_CHANNELS_2) + bt_shell_printf("2 "); + + bt_shell_printf("\n\tBitrate: %u", bitrate); + + bt_shell_printf("\n\tVBR: %s", aac->vbr ? "Yes\n" : "No\n"); +} + +static void print_mpeg12(a2dp_mpeg_t *mpeg, uint8_t size) +{ + uint16_t bitrate; + + if (size < sizeof(*mpeg)) { + bt_shell_printf("\tMedia Codec: MPEG12 (broken)\n"); + return; } + bitrate = MPEG_GET_BITRATE(*mpeg); + + bt_shell_printf("\tMedia Codec: MPEG12\n\tChannel Modes: "); + + if (mpeg->channel_mode & MPEG_CHANNEL_MODE_MONO) + bt_shell_printf("Mono "); + if (mpeg->channel_mode & MPEG_CHANNEL_MODE_DUAL_CHANNEL) + bt_shell_printf("DualChannel "); + if (mpeg->channel_mode & MPEG_CHANNEL_MODE_STEREO) + bt_shell_printf("Stereo "); + if (mpeg->channel_mode & MPEG_CHANNEL_MODE_JOINT_STEREO) + bt_shell_printf("JointStereo"); + + bt_shell_printf("\n\tFrequencies: "); + if (mpeg->frequency & MPEG_SAMPLING_FREQ_16000) + bt_shell_printf("16Khz "); + if (mpeg->frequency & MPEG_SAMPLING_FREQ_22050) + bt_shell_printf("22.05Khz "); + if (mpeg->frequency & MPEG_SAMPLING_FREQ_24000) + bt_shell_printf("24Khz "); + if (mpeg->frequency & MPEG_SAMPLING_FREQ_32000) + bt_shell_printf("32Khz "); + if (mpeg->frequency & MPEG_SAMPLING_FREQ_44100) + bt_shell_printf("44.1Khz "); + if (mpeg->frequency & MPEG_SAMPLING_FREQ_48000) + bt_shell_printf("48Khz "); + + bt_shell_printf("\n\tCRC: %s", mpeg->crc ? "Yes" : "No"); + + bt_shell_printf("\n\tLayer: "); + if (mpeg->layer & MPEG_LAYER_MP1) + bt_shell_printf("1 "); + if (mpeg->layer & MPEG_LAYER_MP2) + bt_shell_printf("2 "); + if (mpeg->layer & MPEG_LAYER_MP3) + bt_shell_printf("3 "); + + if (bitrate & MPEG_BIT_RATE_FREE) { + bt_shell_printf("\n\tBit Rate: Free format"); + } else { + if (mpeg->layer & MPEG_LAYER_MP1) { + bt_shell_printf("\n\tLayer 1 Bit Rate: "); + if (bitrate & MPEG_MP1_BIT_RATE_32000) + bt_shell_printf("32kbps "); + if (bitrate & MPEG_MP1_BIT_RATE_64000) + bt_shell_printf("64kbps "); + if (bitrate & MPEG_MP1_BIT_RATE_96000) + bt_shell_printf("96kbps "); + if (bitrate & MPEG_MP1_BIT_RATE_128000) + bt_shell_printf("128kbps "); + if (bitrate & MPEG_MP1_BIT_RATE_160000) + bt_shell_printf("160kbps "); + if (bitrate & MPEG_MP1_BIT_RATE_192000) + bt_shell_printf("192kbps "); + if (bitrate & MPEG_MP1_BIT_RATE_224000) + bt_shell_printf("224kbps "); + if (bitrate & MPEG_MP1_BIT_RATE_256000) + bt_shell_printf("256kbps "); + if (bitrate & MPEG_MP1_BIT_RATE_320000) + bt_shell_printf("320kbps "); + if (bitrate & MPEG_MP1_BIT_RATE_352000) + bt_shell_printf("352kbps "); + if (bitrate & MPEG_MP1_BIT_RATE_384000) + bt_shell_printf("384kbps "); + if (bitrate & MPEG_MP1_BIT_RATE_416000) + bt_shell_printf("416kbps "); + if (bitrate & MPEG_MP1_BIT_RATE_448000) + bt_shell_printf("448kbps "); + } + + if (mpeg->layer & MPEG_LAYER_MP2) { + bt_shell_printf("\n\tLayer 2 Bit Rate: "); + if (bitrate & MPEG_MP2_BIT_RATE_32000) + bt_shell_printf("32kbps "); + if (bitrate & MPEG_MP2_BIT_RATE_48000) + bt_shell_printf("48kbps "); + if (bitrate & MPEG_MP2_BIT_RATE_56000) + bt_shell_printf("56kbps "); + if (bitrate & MPEG_MP2_BIT_RATE_64000) + bt_shell_printf("64kbps "); + if (bitrate & MPEG_MP2_BIT_RATE_80000) + bt_shell_printf("80kbps "); + if (bitrate & MPEG_MP2_BIT_RATE_96000) + bt_shell_printf("96kbps "); + if (bitrate & MPEG_MP2_BIT_RATE_112000) + bt_shell_printf("112kbps "); + if (bitrate & MPEG_MP2_BIT_RATE_128000) + bt_shell_printf("128kbps "); + if (bitrate & MPEG_MP2_BIT_RATE_160000) + bt_shell_printf("160kbps "); + if (bitrate & MPEG_MP2_BIT_RATE_192000) + bt_shell_printf("192kbps "); + if (bitrate & MPEG_MP2_BIT_RATE_224000) + bt_shell_printf("224kbps "); + if (bitrate & MPEG_MP2_BIT_RATE_256000) + bt_shell_printf("256kbps "); + if (bitrate & MPEG_MP2_BIT_RATE_320000) + bt_shell_printf("320kbps "); + if (bitrate & MPEG_MP2_BIT_RATE_384000) + bt_shell_printf("384kbps "); + } + + if (mpeg->layer & MPEG_LAYER_MP3) { + bt_shell_printf("\n\tLayer 3 Bit Rate: "); + if (bitrate & MPEG_MP3_BIT_RATE_32000) + bt_shell_printf("32kbps "); + if (bitrate & MPEG_MP3_BIT_RATE_40000) + bt_shell_printf("40kbps "); + if (bitrate & MPEG_MP3_BIT_RATE_48000) + bt_shell_printf("48kbps "); + if (bitrate & MPEG_MP3_BIT_RATE_56000) + bt_shell_printf("56kbps "); + if (bitrate & MPEG_MP3_BIT_RATE_64000) + bt_shell_printf("64kbps "); + if (bitrate & MPEG_MP3_BIT_RATE_80000) + bt_shell_printf("80kbps "); + if (bitrate & MPEG_MP3_BIT_RATE_96000) + bt_shell_printf("96kbps "); + if (bitrate & MPEG_MP3_BIT_RATE_112000) + bt_shell_printf("112kbps "); + if (bitrate & MPEG_MP3_BIT_RATE_128000) + bt_shell_printf("128kbps "); + if (bitrate & MPEG_MP3_BIT_RATE_160000) + bt_shell_printf("160kbps "); + if (bitrate & MPEG_MP3_BIT_RATE_192000) + bt_shell_printf("192kbps "); + if (bitrate & MPEG_MP3_BIT_RATE_224000) + bt_shell_printf("224kbps "); + if (bitrate & MPEG_MP3_BIT_RATE_256000) + bt_shell_printf("256kbps "); + if (bitrate & MPEG_MP3_BIT_RATE_320000) + bt_shell_printf("320kbps "); + } + } + + bt_shell_printf("\n\tVBR: %s", mpeg->vbr ? "Yes" : "No"); + + bt_shell_printf("\n\tPayload Format: "); + if (mpeg->mpf) + bt_shell_printf("RFC-2250 RFC-3119\n"); + else + bt_shell_printf("RFC-2250\n"); +} + +static void print_sbc(a2dp_sbc_t *sbc, uint8_t size) +{ + if (size < sizeof(*sbc)) { + bt_shell_printf("\tMedia Codec: SBC (broken)\n"); + return; + } + + bt_shell_printf("\tMedia Codec: SBC\n\tChannel Modes: "); + + if (sbc->channel_mode & SBC_CHANNEL_MODE_MONO) + bt_shell_printf("Mono "); + if (sbc->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL) + bt_shell_printf("DualChannel "); + if (sbc->channel_mode & SBC_CHANNEL_MODE_STEREO) + bt_shell_printf("Stereo "); + if (sbc->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO) + bt_shell_printf("JointStereo"); + + bt_shell_printf("\n\tFrequencies: "); + if (sbc->frequency & SBC_SAMPLING_FREQ_16000) + bt_shell_printf("16Khz "); + if (sbc->frequency & SBC_SAMPLING_FREQ_32000) + bt_shell_printf("32Khz "); + if (sbc->frequency & SBC_SAMPLING_FREQ_44100) + bt_shell_printf("44.1Khz "); + if (sbc->frequency & SBC_SAMPLING_FREQ_48000) + bt_shell_printf("48Khz "); + + bt_shell_printf("\n\tSubbands: "); + if (sbc->allocation_method & SBC_SUBBANDS_4) + bt_shell_printf("4 "); + if (sbc->allocation_method & SBC_SUBBANDS_8) + bt_shell_printf("8"); + + bt_shell_printf("\n\tBlocks: "); + if (sbc->block_length & SBC_BLOCK_LENGTH_4) + bt_shell_printf("4 "); + if (sbc->block_length & SBC_BLOCK_LENGTH_8) + bt_shell_printf("8 "); + if (sbc->block_length & SBC_BLOCK_LENGTH_12) + bt_shell_printf("12 "); + if (sbc->block_length & SBC_BLOCK_LENGTH_16) + bt_shell_printf("16 "); + + bt_shell_printf("\n\tBitpool Range: %d-%d\n", + sbc->min_bitpool, sbc->max_bitpool); +} + +static int print_a2dp_codec(uint8_t codec, void *data, uint8_t size) +{ + int i; + + switch (codec) { + case A2DP_CODEC_SBC: + print_sbc(data, size); + break; + case A2DP_CODEC_MPEG12: + print_mpeg12(data, size); + break; + case A2DP_CODEC_MPEG24: + print_mpeg24(data, size); + break; + case A2DP_CODEC_VENDOR: + print_vendor(data, size); + break; + default: + bt_shell_printf("\tMedia Codec: Unknown\n"); + bt_shell_printf("\t\tCodec Data:"); + for (i = 0; i < size - 2; ++i) + bt_shell_printf(" 0x%.02x", ((unsigned char *)data)[i]); + bt_shell_printf("\n"); + } + + return 0; +} + +static void print_hexdump(const char *label, struct iovec *iov) +{ + if (!iov) + return; + + bt_shell_printf("%s:\n", label); + bt_shell_hexdump(iov->iov_base, iov->iov_len); +} + +static void print_codec(const char *uuid, uint8_t codec, struct iovec *caps, + struct iovec *meta) +{ + if (!strcasecmp(uuid, A2DP_SINK_UUID) || + !strcasecmp(uuid, A2DP_SOURCE_UUID)) { + print_a2dp_codec(codec, caps->iov_base, caps->iov_len); + return; + } + + if (codec != LC3_ID) { + print_hexdump("Capabilities", caps); + print_hexdump("Metadata", meta); + return; + } + + print_lc3_caps(caps->iov_base, caps->iov_len); + + if (!meta) + return; + + print_lc3_meta(meta->iov_base, meta->iov_len); +} + +static void print_capabilities(GDBusProxy *proxy) +{ + DBusMessageIter iter, subiter; + const char *uuid; + uint8_t codec; + struct iovec caps, meta; + + if (!g_dbus_proxy_get_property(proxy, "UUID", &iter)) + return; + + dbus_message_iter_get_basic(&iter, &uuid); + + if (!g_dbus_proxy_get_property(proxy, "Codec", &iter)) + return; + + dbus_message_iter_get_basic(&iter, &codec); + + if (!g_dbus_proxy_get_property(proxy, "Capabilities", &iter)) + return; + + dbus_message_iter_recurse(&iter, &subiter); + + dbus_message_iter_get_fixed_array(&subiter, &caps.iov_base, + (int *)&caps.iov_len); + + if (g_dbus_proxy_get_property(proxy, "Metadata", &iter)) { + dbus_message_iter_recurse(&iter, &subiter); + dbus_message_iter_get_fixed_array(&subiter, &meta.iov_base, + (int *)&meta.iov_len); + } else { + meta.iov_base = NULL; + meta.iov_len = 0; + } + + print_codec(uuid, codec, &caps, &meta); +} + +static void print_preset(struct codec_preset *codec, uint8_t codec_id) +{ + bt_shell_printf("\tPreset %s\n", codec->name); + + if (codec_id == LC3_ID) + print_lc3_cfg(codec->data.iov_base, codec->data.iov_len); +} + +static void print_local_endpoint(struct endpoint *ep) +{ + bt_shell_printf("Endpoint %s\n", ep->path); + bt_shell_printf("\tUUID %s\n", ep->uuid); + bt_shell_printf("\tCodec 0x%02x (%u)\n", ep->codec, ep->codec); + + if (ep->caps) + print_codec(ep->uuid, ep->codec, ep->caps, ep->meta); + + if (ep->codec_preset) + print_preset(ep->codec_preset, ep->codec); + + if (ep->locations) + bt_shell_printf("\tLocations 0x%08x (%u)\n", ep->locations, + ep->locations); + if (ep->supported_context) + bt_shell_printf("\tSupportedContext 0x%08x (%u)\n", + ep->supported_context, ep->supported_context); + if (ep->context) + bt_shell_printf("\tContext 0x%08x (%u)\n", ep->context, + ep->context); +} + +static void print_endpoint_properties(GDBusProxy *proxy) +{ + bt_shell_printf("Endpoint %s\n", g_dbus_proxy_get_path(proxy)); + + print_property(proxy, "UUID"); + print_property(proxy, "Codec"); + print_capabilities(proxy); + print_property(proxy, "Device"); + print_property(proxy, "DelayReporting"); + print_property(proxy, "Locations"); + print_property(proxy, "SupportedContext"); + print_property(proxy, "Context"); + print_property(proxy, "QoS"); +} + +static void print_endpoints(void *data, void *user_data) +{ + print_endpoint_properties(data); +} + +static void print_local_endpoints(void *data, void *user_data) +{ + print_local_endpoint(data); +} + +static void cmd_show_endpoint(int argc, char *argv[]) +{ + GDBusProxy *proxy; + + /* Show all endpoints if no argument is given */ + if (argc != 2) { + g_list_foreach(endpoints, print_endpoints, NULL); + g_list_foreach(local_endpoints, print_local_endpoints, NULL); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + } + + proxy = g_dbus_proxy_lookup(endpoints, NULL, argv[1], + BLUEZ_MEDIA_ENDPOINT_INTERFACE); + if (!proxy) { + struct endpoint *ep; + + ep = endpoint_find(argv[1]); + if (ep) + return print_local_endpoint(ep); + + bt_shell_printf("Endpoint %s not found\n", argv[1]); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + } + + print_endpoint_properties(proxy); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static const GDBusMethodTable endpoint_methods[] = { + { GDBUS_ASYNC_METHOD("SetConfiguration", + GDBUS_ARGS({ "endpoint", "o" }, + { "properties", "a{sv}" } ), + NULL, endpoint_set_configuration) }, + { GDBUS_ASYNC_METHOD("SelectConfiguration", + GDBUS_ARGS({ "caps", "ay" } ), + GDBUS_ARGS({ "cfg", "ay" } ), + endpoint_select_configuration) }, + { GDBUS_ASYNC_METHOD("SelectProperties", + GDBUS_ARGS({ "properties", "a{sv}" } ), + GDBUS_ARGS({ "properties", "a{sv}" } ), + endpoint_select_properties) }, + { GDBUS_ASYNC_METHOD("ClearConfiguration", + GDBUS_ARGS({ "transport", "o" } ), + NULL, endpoint_clear_configuration) }, + { }, +}; + +static void endpoint_free(void *data) +{ + struct endpoint *ep = data; + + util_iov_free(ep->caps, 1); + util_iov_free(ep->meta, 1); + + if (ep->msg) + dbus_message_unref(ep->msg); + + queue_destroy(ep->preset->custom, free); + ep->preset->custom = NULL; + + if (ep->codec == 0xff) + free(ep->preset); + + queue_destroy(ep->acquiring, NULL); + queue_destroy(ep->transports, free); + + g_free(ep->path); + g_free(ep->uuid); + g_free(ep); +} + +static gboolean endpoint_get_uuid(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct endpoint *ep = data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &ep->uuid); + + return TRUE; +} + +static gboolean endpoint_get_codec(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct endpoint *ep = data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE, &ep->codec); + + return TRUE; +} + +static gboolean endpoint_get_capabilities(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct endpoint *ep = data; + DBusMessageIter array; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, &array); + + dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, + &ep->caps->iov_base, + ep->caps->iov_len); + + dbus_message_iter_close_container(iter, &array); + + return TRUE; +} + +struct vendor { + uint16_t cid; + uint16_t vid; +} __packed; + +static gboolean endpoint_get_vendor(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct endpoint *ep = data; + struct vendor vendor = { ep->cid, ep->vid }; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &vendor); + + return TRUE; +} + +static gboolean endpoint_vendor_exists(const GDBusPropertyTable *property, + void *data) +{ + struct endpoint *ep = data; + + return ep->cid && ep->vid; +} + +static gboolean endpoint_get_metadata(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct endpoint *ep = data; + DBusMessageIter array; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, &array); + + dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, + &ep->meta->iov_base, + ep->meta->iov_len); + + dbus_message_iter_close_container(iter, &array); + + return TRUE; +} + +static gboolean endpoint_metadata_exists(const GDBusPropertyTable *property, + void *data) +{ + struct endpoint *ep = data; + + return ep->meta ? TRUE : FALSE; +} + +static gboolean endpoint_get_locations(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct endpoint *ep = data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &ep->locations); + + return TRUE; +} + +static gboolean endpoint_locations_exists(const GDBusPropertyTable *property, + void *data) +{ + struct endpoint *ep = data; + + return ep->supported_context ? TRUE : FALSE; +} + +static gboolean +endpoint_get_supported_context(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct endpoint *ep = data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, + &ep->supported_context); + + return TRUE; +} + +static gboolean +endpoint_supported_context_exists(const GDBusPropertyTable *property, + void *data) +{ + struct endpoint *ep = data; + + return ep->supported_context ? TRUE : FALSE; +} + +static gboolean endpoint_get_context(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct endpoint *ep = data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &ep->context); + + return TRUE; +} + +static gboolean endpoint_context_exists(const GDBusPropertyTable *property, + void *data) +{ + struct endpoint *ep = data; + + return ep->context ? TRUE : FALSE; +} + +static const GDBusPropertyTable endpoint_properties[] = { + { "UUID", "s", endpoint_get_uuid, NULL, NULL }, + { "Codec", "y", endpoint_get_codec, NULL, NULL }, + { "Capabilities", "ay", endpoint_get_capabilities, NULL, NULL }, + { "Metadata", "ay", endpoint_get_metadata, NULL, + endpoint_metadata_exists }, + { "Vendor", "u", endpoint_get_vendor, NULL, endpoint_vendor_exists }, + { "Locations", "u", endpoint_get_locations, NULL, + endpoint_locations_exists }, + { "SupportedContext", "q", endpoint_get_supported_context, NULL, + endpoint_supported_context_exists }, + { "Context", "q", endpoint_get_context, NULL, endpoint_context_exists }, + { } +}; + +static void register_endpoint_setup(DBusMessageIter *iter, void *user_data) +{ + struct endpoint *ep = user_data; + DBusMessageIter dict; + const char *key = "Capabilities"; + const char *meta = "Metadata"; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &ep->path); + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &dict); + + g_dbus_dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &ep->uuid); + + g_dbus_dict_append_entry(&dict, "Codec", DBUS_TYPE_BYTE, &ep->codec); + + if (ep->cid && ep->vid) { + struct vendor vendor = { ep->cid, ep->vid }; + + g_dbus_dict_append_entry(&dict, "Vendor", DBUS_TYPE_UINT32, + &vendor); + } + + if (ep->caps) { + g_dbus_dict_append_basic_array(&dict, DBUS_TYPE_STRING, &key, + DBUS_TYPE_BYTE, &ep->caps->iov_base, + ep->caps->iov_len); + + bt_shell_printf("Capabilities:\n"); + bt_shell_hexdump(ep->caps->iov_base, ep->caps->iov_len); + } + + if (ep->meta) { + g_dbus_dict_append_basic_array(&dict, DBUS_TYPE_STRING, &meta, + DBUS_TYPE_BYTE, &ep->meta->iov_base, + ep->meta->iov_len); + + bt_shell_printf("Metadata:\n"); + bt_shell_hexdump(ep->meta->iov_base, ep->meta->iov_len); + } + + if (ep->locations) + g_dbus_dict_append_entry(&dict, "Locations", DBUS_TYPE_UINT32, + &ep->locations); + + if (ep->supported_context) + g_dbus_dict_append_entry(&dict, "SupportedContext", + DBUS_TYPE_UINT16, + &ep->supported_context); + + if (ep->context) + g_dbus_dict_append_entry(&dict, "Context", DBUS_TYPE_UINT16, + &ep->context); + + dbus_message_iter_close_container(iter, &dict); +} + +static void register_endpoint_reply(DBusMessage *message, void *user_data) +{ + struct endpoint *ep = user_data; + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message)) { + bt_shell_printf("Failed to register endpoint: %s\n", + error.name); + dbus_error_free(&error); + if (g_list_find(local_endpoints, ep)) { + local_endpoints = g_list_remove(local_endpoints, ep); + g_dbus_unregister_interface(dbus_conn, ep->path, + BLUEZ_MEDIA_ENDPOINT_INTERFACE); + } + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + bt_shell_printf("Endpoint %s registered\n", ep->path); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static bool media_supports_uuid(GDBusProxy *proxy, const char *uuid) +{ + DBusMessageIter iter, array; + + if (!g_dbus_proxy_get_property(proxy, "SupportedUUIDs", &iter)) + return false; + + dbus_message_iter_recurse(&iter, &array); + while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) { + const char *support_uuid; + + dbus_message_iter_get_basic(&array, &support_uuid); + + if (!strcasecmp(uuid, support_uuid)) + return true; + + dbus_message_iter_next(&array); + } + + return false; +} + +static void endpoint_register(struct endpoint *ep) +{ + GList *l; + int registered = 0; + + if (!g_dbus_register_interface(dbus_conn, ep->path, + BLUEZ_MEDIA_ENDPOINT_INTERFACE, + endpoint_methods, NULL, + endpoint_properties, ep, + endpoint_free)) { + goto fail; + } + + for (l = medias; l; l = g_list_next(l)) { + if (!media_supports_uuid(l->data, ep->uuid)) + continue; + + if (!g_dbus_proxy_method_call(l->data, "RegisterEndpoint", + register_endpoint_setup, + register_endpoint_reply, + ep, NULL)) { + g_dbus_unregister_interface(dbus_conn, ep->path, + BLUEZ_MEDIA_ENDPOINT_INTERFACE); + goto fail; + } + + registered++; + } + + if (!registered) + goto fail; + return; -fail: - bt_shell_printf("Failed register endpoint\n"); - local_endpoints = g_list_remove(local_endpoints, ep); - return bt_shell_noninteractive_quit(EXIT_FAILURE); +fail: + bt_shell_printf("Failed register endpoint\n"); + local_endpoints = g_list_remove(local_endpoints, ep); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + +} + +static void endpoint_iso_stream(const char *input, void *user_data) +{ + struct endpoint *ep = user_data; + char *endptr = NULL; + int value; + + if (!strcasecmp(input, "a") || !strcasecmp(input, "auto")) { + ep->iso_stream = BT_ISO_QOS_STREAM_UNSET; + } else { + value = strtol(input, &endptr, 0); + + if (!endptr || *endptr != '\0' || value > UINT8_MAX) { + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + ep->iso_stream = value; + } + + endpoint_register(ep); +} + +static void endpoint_iso_group(const char *input, void *user_data) +{ + struct endpoint *ep = user_data; + char *endptr = NULL; + int value; + + if (!strcasecmp(input, "a") || !strcasecmp(input, "auto")) { + ep->iso_group = BT_ISO_QOS_GROUP_UNSET; + } else { + value = strtol(input, &endptr, 0); + + if (!endptr || *endptr != '\0' || value > UINT8_MAX) { + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + ep->iso_group = value; + } + + bt_shell_prompt_input(ep->path, "CIS (auto/value):", + endpoint_iso_stream, ep); +} + +static void endpoint_context(const char *input, void *user_data) +{ + struct endpoint *ep = user_data; + char *endptr = NULL; + int value; + + value = strtol(input, &endptr, 0); + + if (!endptr || *endptr != '\0' || value > UINT16_MAX) { + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + ep->context = value; + + bt_shell_prompt_input(ep->path, "CIG (auto/value):", + endpoint_iso_group, ep); +} + +static void endpoint_supported_context(const char *input, void *user_data) +{ + struct endpoint *ep = user_data; + char *endptr = NULL; + int value; + + value = strtol(input, &endptr, 0); + + if (!endptr || *endptr != '\0' || value > UINT16_MAX) { + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + ep->supported_context = value; + + if (ep->broadcast) { + endpoint_register(ep); + return; + } + + bt_shell_prompt_input(ep->path, "Context (value):", endpoint_context, + ep); +} + +static void endpoint_locations(const char *input, void *user_data) +{ + struct endpoint *ep = user_data; + char *endptr = NULL; + int value; + uint8_t channels; + + value = strtol(input, &endptr, 0); + + if (!endptr || *endptr != '\0') { + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + ep->locations = value; + + channels = __builtin_popcount(value); + /* Automatically set LC3_CHAN_COUNT if only 1 location is supported */ + if (channels == 1) + util_ltv_push(ep->caps, sizeof(channels), LC3_CHAN_COUNT, + &channels); + + bt_shell_prompt_input(ep->path, "Supported Context (value):", + endpoint_supported_context, ep); +} + +static void endpoint_max_transports(const char *input, void *user_data) +{ + struct endpoint *ep = user_data; + char *endptr = NULL; + int value; + + if (!strcasecmp(input, "a") || !strcasecmp(input, "auto")) { + ep->max_transports = UINT8_MAX; + } else { + value = strtol(input, &endptr, 0); + + if (!endptr || *endptr != '\0' || value > UINT8_MAX) { + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + ep->max_transports = value; + } + + bt_shell_prompt_input(ep->path, "Locations:", endpoint_locations, ep); +} + +static void endpoint_auto_accept(const char *input, void *user_data) +{ + struct endpoint *ep = user_data; + + if (!strcasecmp(input, "y") || !strcasecmp(input, "yes")) { + ep->auto_accept = true; + bt_shell_prompt_input(ep->path, "Max Transports (auto/value):", + endpoint_max_transports, ep); + return; + } else if (!strcasecmp(input, "n") || !strcasecmp(input, "no")) { + ep->auto_accept = false; + bt_shell_prompt_input(ep->path, "Max Transports (auto/value):", + endpoint_max_transports, ep); + return; + } else { + bt_shell_printf("Invalid input for Auto Accept\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void endpoint_set_metadata(const char *input, void *user_data) +{ + struct endpoint *ep = user_data; + struct iovec iov; + + if (!strcasecmp(input, "n") || !strcasecmp(input, "no")) { + util_iov_free(ep->meta, 1); + ep->meta = NULL; + goto done; + } + + iov.iov_base = str2bytearray((char *) input, &iov.iov_len); + if (iov.iov_base) { + util_iov_free(ep->meta, 1); + ep->meta = util_iov_dup(&iov, 1); + } + +done: + bt_shell_prompt_input(ep->path, "Auto Accept (yes/no):", + endpoint_auto_accept, ep); +} + +static void endpoint_set_capabilities(const char *input, void *user_data) +{ + struct endpoint *ep = user_data; + struct iovec iov; + + if (!strcasecmp(input, "n") || !strcasecmp(input, "no")) { + util_iov_free(ep->caps, 1); + ep->caps = NULL; + goto done; + } + + iov.iov_base = str2bytearray((char *) input, &iov.iov_len); + if (iov.iov_base) { + util_iov_free(ep->caps, 1); + ep->caps = util_iov_dup(&iov, 1); + } + +done: + bt_shell_prompt_input(ep->path, "Enter Metadata (value/no):", + endpoint_set_metadata, ep); +} + +static char *uuid_generator(const char *text, int state) +{ + int len = strlen(text); + static int index = 0; + size_t i; + + if (!state) { + index = 0; + } + + for (i = index; i < ARRAY_SIZE(caps); i++) { + const struct capabilities *cap = &caps[i]; + + index++; + + if (!strncasecmp(cap->uuid, text, len)) + return strdup(cap->uuid); + } + + return NULL; +} + +static const struct capabilities *find_capabilities(const char *uuid, + uint8_t codec_id) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(caps); i++) { + const struct capabilities *cap = &caps[i]; + + if (strcasecmp(cap->uuid, uuid)) + continue; + + if (cap->codec_id == codec_id) + return cap; + } + + return NULL; +} + +static struct codec_preset *codec_preset_new(const char *name) +{ + struct codec_preset *codec; + + codec = new0(struct codec_preset, 1); + codec->name = strdup(name); + codec->custom = true; + + return codec; +} + +static struct codec_preset *codec_preset_add(struct preset *preset, + const char *name) +{ + struct codec_preset *codec; + + codec = preset_find_name(preset, name); + if (codec) + return codec; + + codec = codec_preset_new(name); + + if (!preset->custom) + preset->custom = queue_new(); + + queue_push_tail(preset->custom, codec); + + return codec; +} + +static void cmd_register_endpoint(int argc, char *argv[]) +{ + struct endpoint *ep; + char *endptr = NULL; + + ep = g_new0(struct endpoint, 1); + ep->uuid = g_strdup(argv[1]); + ep->codec = strtol(argv[2], &endptr, 0); + ep->cid = 0x0000; + ep->vid = 0x0000; + ep->path = g_strdup_printf("%s/ep%u", BLUEZ_MEDIA_ENDPOINT_PATH, + g_list_length(local_endpoints)); + local_endpoints = g_list_append(local_endpoints, ep); + + if (!strcmp(ep->uuid, BCAA_SERVICE_UUID) || + !strcmp(ep->uuid, BAA_SERVICE_UUID)) { + ep->broadcast = true; + } else { + ep->broadcast = false; + } + + if (strrchr(argv[2], ':')) { + ep->codec = 0xff; + parse_vendor_codec(argv[2], &ep->vid, &ep->cid); + ep->preset = new0(struct preset, 1); + ep->preset->default_preset = codec_preset_add(ep->preset, + "custom"); + } else { + ep->preset = find_presets_name(ep->uuid, argv[2]); + } + + if (argc > 3) + endpoint_set_capabilities(argv[3], ep); + else { + const struct capabilities *cap; + + cap = find_capabilities(ep->uuid, ep->codec); + if (cap) { + /* Copy capabilities */ + util_iov_free(ep->caps, 1); + ep->caps = util_iov_dup(&cap->data, 1); + + /* Copy metadata */ + util_iov_free(ep->meta, 1); + ep->meta = util_iov_dup(&cap->meta, 1); + + bt_shell_prompt_input(ep->path, "Auto Accept (yes/no):", + endpoint_auto_accept, ep); + } else + bt_shell_prompt_input(ep->path, "Enter capabilities:", + endpoint_set_capabilities, ep); + } +} + +static void unregister_endpoint_setup(DBusMessageIter *iter, void *user_data) +{ + struct endpoint *ep = user_data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &ep->path); +} + +static void unregister_endpoint_reply(DBusMessage *message, void *user_data) +{ + struct endpoint *ep = user_data; + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message)) { + bt_shell_printf("Failed to unregister endpoint: %s\n", + error.name); + dbus_error_free(&error); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + bt_shell_printf("Endpoint %s unregistered\n", ep->path); + + local_endpoints = g_list_remove(local_endpoints, ep); + g_dbus_unregister_interface(dbus_conn, ep->path, + BLUEZ_MEDIA_ENDPOINT_INTERFACE); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_unregister_endpoint(int argc, char *argv[]) +{ + struct endpoint *ep; + GList *l; + + ep = endpoint_find(argv[1]); + if (!ep) { + bt_shell_printf("Unable to find endpoint object: %s\n", + argv[1]); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + for (l = medias; l; l = g_list_next(l)) { + if (!g_dbus_proxy_method_call(l->data, "UnregisterEndpoint", + unregister_endpoint_setup, + unregister_endpoint_reply, + ep, NULL)) { + bt_shell_printf("Failed unregister endpoint\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void config_endpoint_setup(DBusMessageIter *iter, void *user_data) +{ + struct endpoint_config *cfg = user_data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, + &cfg->ep->path); + + append_properties(iter, cfg); +} + +static void config_endpoint_reply(DBusMessage *message, void *user_data) +{ + struct endpoint_config *cfg = user_data; + struct endpoint *ep = cfg->ep; + DBusError error; + + free(cfg->caps->iov_base); + free(cfg->caps); + free(cfg); + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message)) { + bt_shell_printf("Failed to config endpoint: %s\n", + error.name); + dbus_error_free(&error); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + bt_shell_printf("Endpoint %s configured\n", ep->path); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void endpoint_set_config(struct endpoint_config *cfg) +{ + if (!g_dbus_proxy_method_call(cfg->proxy, "SetConfiguration", + config_endpoint_setup, + config_endpoint_reply, + cfg, NULL)) { + bt_shell_printf("Failed to config endpoint\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } +} + +static void endpoint_config(const char *input, void *user_data) +{ + struct endpoint_config *cfg = user_data; + uint8_t *data; + size_t len = 0; + + data = str2bytearray((char *) input, &len); + + util_iov_append(cfg->caps, data, len); + free(data); + + endpoint_set_config(cfg); +} + +static struct endpoint *endpoint_new(const struct capabilities *cap); + +static void endpoint_set_metadata_cfg(const char *input, void *user_data) +{ + struct endpoint_config *cfg = user_data; + + if (!strcasecmp(input, "n") || !strcasecmp(input, "no")) + goto done; + + if (!cfg->meta) + cfg->meta = g_new0(struct iovec, 1); + + cfg->meta->iov_base = str2bytearray((char *) input, + &cfg->meta->iov_len); + if (!cfg->meta->iov_base) { + free(cfg->meta); + cfg->meta = NULL; + } +done: + endpoint_set_config(cfg); } -static void endpoint_cis(const char *input, void *user_data) +static void config_endpoint_channel_location(const char *input, void *user_data) { - struct endpoint *ep = user_data; + struct endpoint_config *cfg = user_data; char *endptr = NULL; - int value; + uint32_t location; + uint8_t channels = 1; - if (!strcasecmp(input, "a") || !strcasecmp(input, "auto")) { - ep->cis = BT_ISO_QOS_CIS_UNSET; - } else { - value = strtol(input, &endptr, 0); + if (!strcasecmp(input, "n") || !strcasecmp(input, "no")) + goto add_meta; - if (!endptr || *endptr != '\0' || value > UINT8_MAX) { - bt_shell_printf("Invalid argument: %s\n", input); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } + location = strtol(input, &endptr, 0); - ep->cis = value; + if (!endptr || *endptr != '\0') { + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } - endpoint_register(ep); + /* Add Channel Allocation LTV in capabilities */ + location = cpu_to_le32(location); + util_ltv_push(cfg->caps, LC3_CONFIG_CHAN_ALLOC_LEN - 1, + LC3_CONFIG_CHAN_ALLOC, &location); + + /* Adjust the SDU size based on the number of + * locations/channels that is being requested. + */ + channels = __builtin_popcount(location); + if (channels > 1) + cfg->qos.bcast.io_qos.sdu *= channels; + +add_meta: + /* Add metadata */ + bt_shell_prompt_input(cfg->ep->path, "Enter Metadata (value/no):", + endpoint_set_metadata_cfg, cfg); } -static void endpoint_cig(const char *input, void *user_data) +static void config_endpoint_iso_group(const char *input, void *user_data) { - struct endpoint *ep = user_data; + struct endpoint_config *cfg = user_data; char *endptr = NULL; int value; + uint8_t type = LC3_CONFIG_CHAN_ALLOC; + bool found = false; if (!strcasecmp(input, "a") || !strcasecmp(input, "auto")) { - ep->cig = BT_ISO_QOS_CIG_UNSET; + cfg->ep->iso_group = BT_ISO_QOS_GROUP_UNSET; } else { value = strtol(input, &endptr, 0); @@ -2072,314 +3742,595 @@ static void endpoint_cig(const char *input, void *user_data) return bt_shell_noninteractive_quit(EXIT_FAILURE); } - ep->cig = value; + cfg->ep->iso_group = value; } - bt_shell_prompt_input(ep->path, "CIS (auto/value):", endpoint_cis, ep); + /* Check if Channel Allocation is present in caps */ + util_ltv_foreach(cfg->caps->iov_base, + cfg->caps->iov_len, &type, + ltv_find, &found); + + /* Add Channel Allocation if it is not present in caps */ + if (!found) { + bt_shell_prompt_input(cfg->ep->path, + "Enter channel location (value/no):", + config_endpoint_channel_location, cfg); + } else { + /* Add metadata */ + bt_shell_prompt_input(cfg->ep->path, + "Enter Metadata (value/no):", + endpoint_set_metadata_cfg, cfg); + } } -static void endpoint_auto_accept(const char *input, void *user_data) +static void endpoint_set_config_bcast(struct endpoint_config *cfg) { - struct endpoint *ep = user_data; + cfg->ep->bcode = g_new0(struct iovec, 1); + util_iov_append(cfg->ep->bcode, bcast_code, + sizeof(bcast_code)); - if (!strcasecmp(input, "y") || !strcasecmp(input, "yes")) { - ep->auto_accept = true; - } else if (!strcasecmp(input, "n") || !strcasecmp(input, "no")) { - ep->auto_accept = false; - } else { - bt_shell_printf("Invalid input for Auto Accept\n"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); + if ((strcmp(cfg->ep->uuid, BAA_SERVICE_UUID) == 0)) { + /* A broadcast sink endpoint config does not need + * user input. + */ + endpoint_set_config(cfg); + return; } - bt_shell_prompt_input(ep->path, "CIG (auto/value):", endpoint_cig, ep); + bt_shell_prompt_input(cfg->ep->path, + "BIG (auto/value):", + config_endpoint_iso_group, cfg); } -static void endpoint_set_capabilities(const char *input, void *user_data) +static void cmd_config_endpoint(int argc, char *argv[]) { - struct endpoint *ep = user_data; + struct endpoint_config *cfg; + const struct codec_preset *preset; - if (ep->caps) - g_free(ep->caps->iov_base); - else - ep->caps = g_new0(struct iovec, 1); + cfg = new0(struct endpoint_config, 1); - ep->caps->iov_base = str2bytearray((char *) input, &ep->caps->iov_len); + /* Search for the remote endpoint name on DBUS */ + cfg->proxy = g_dbus_proxy_lookup(endpoints, NULL, argv[1], + BLUEZ_MEDIA_ENDPOINT_INTERFACE); + if (!cfg->proxy) { + bt_shell_printf("Endpoint %s not found\n", argv[1]); + goto fail; + } - bt_shell_prompt_input(ep->path, "Auto Accept (yes/no):", - endpoint_auto_accept, ep); + /* Search for the local endpoint */ + cfg->ep = endpoint_find(argv[2]); + if (!cfg->ep) { + bt_shell_printf("Local Endpoint %s not found\n", argv[2]); + goto fail; + } + + if (argc > 3) { + preset = preset_find_name(cfg->ep->preset, argv[3]); + if (!preset) { + bt_shell_printf("Preset %s not found\n", argv[3]); + goto fail; + } + + cfg->caps = g_new0(struct iovec, 1); + /* Copy capabilities */ + util_iov_append(cfg->caps, preset->data.iov_base, + preset->data.iov_len); + cfg->target_latency = preset->target_latency; + + /* Set QoS parameters */ + cfg->qos = preset->qos; + + if (cfg->ep->broadcast) + endpoint_set_config_bcast(cfg); + else + endpoint_set_config(cfg); + + return; + } + + bt_shell_prompt_input(cfg->ep->path, "Enter configuration:", + endpoint_config, cfg); + + return; + +fail: + g_free(cfg); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } -static char *uuid_generator(const char *text, int state) +static void custom_delay(const char *input, void *user_data) { - int len = strlen(text); - static int index = 0; - size_t i; + struct codec_preset *p = user_data; + struct bt_bap_qos *qos = (void *)&p->qos; + char *endptr = NULL; - if (!state) { - index = 0; + if (!p->target_latency) + qos->bcast.delay = strtol(input, &endptr, 0); + else + qos->ucast.delay = strtol(input, &endptr, 0); + + if (!endptr || *endptr != '\0') { + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } - for (i = index; i < ARRAY_SIZE(caps); i++) { - const struct capabilities *cap = &caps[i]; + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} - index++; +static void custom_latency(const char *input, void *user_data) +{ + struct codec_preset *p = user_data; + struct bt_bap_qos *qos = (void *)&p->qos; + char *endptr = NULL; - if (!strncasecmp(cap->uuid, text, len)) - return strdup(cap->uuid); + if (!p->target_latency) + qos->bcast.io_qos.latency = strtol(input, &endptr, 0); + else + qos->ucast.io_qos.latency = strtol(input, &endptr, 0); + + if (!endptr || *endptr != '\0') { + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } - return NULL; + bt_shell_prompt_input("QoS", "Enter Presentation Delay (us):", + custom_delay, user_data); } -static const struct capabilities *find_capabilities(const char *uuid, - uint8_t codec_id) +static void custom_rtn(const char *input, void *user_data) { - size_t i; - - for (i = 0; i < ARRAY_SIZE(caps); i++) { - const struct capabilities *cap = &caps[i]; + struct codec_preset *p = user_data; + struct bt_bap_qos *qos = (void *)&p->qos; + char *endptr = NULL; - if (strcasecmp(cap->uuid, uuid)) - continue; + if (!p->target_latency) + qos->bcast.io_qos.rtn = strtol(input, &endptr, 0); + else + qos->ucast.io_qos.rtn = strtol(input, &endptr, 0); - if (cap->codec_id == codec_id) - return cap; + if (!endptr || *endptr != '\0') { + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } - return NULL; + bt_shell_prompt_input("QoS", "Enter Max Transport Latency (ms):", + custom_latency, user_data); } -static void cmd_register_endpoint(int argc, char *argv[]) +static void custom_sdu(const char *input, void *user_data) { - struct endpoint *ep; + struct codec_preset *p = user_data; + struct bt_bap_qos *qos = (void *)&p->qos; char *endptr = NULL; - ep = g_new0(struct endpoint, 1); - ep->uuid = g_strdup(argv[1]); - ep->codec = strtol(argv[2], &endptr, 0); - ep->path = g_strdup_printf("%s/ep%u", BLUEZ_MEDIA_ENDPOINT_PATH, - g_list_length(local_endpoints)); - local_endpoints = g_list_append(local_endpoints, ep); + if (!p->target_latency) + qos->bcast.io_qos.sdu = strtol(input, &endptr, 0); + else + qos->ucast.io_qos.sdu = strtol(input, &endptr, 0); - if (argc > 3) - endpoint_set_capabilities(argv[3], ep); - else { - const struct capabilities *cap; + if (!endptr || *endptr != '\0') { + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } - cap = find_capabilities(ep->uuid, ep->codec); - if (cap) { - if (ep->caps) - ep->caps->iov_len = 0; + bt_shell_prompt_input("QoS", "Enter RTN:", custom_rtn, user_data); +} - /* Copy capabilities */ - iov_append(&ep->caps, cap->data.iov_base, - cap->data.iov_len); +static void custom_phy(const char *input, void *user_data) +{ + struct codec_preset *p = user_data; + struct bt_bap_io_qos *qos; - bt_shell_prompt_input(ep->path, "Auto Accept (yes/no):", - endpoint_auto_accept, ep); - } else - bt_shell_prompt_input(ep->path, "Enter capabilities:", - endpoint_set_capabilities, ep); + if (!p->target_latency) + qos = &p->qos.bcast.io_qos; + else + qos = &p->qos.ucast.io_qos; + + if (!strcmp(input, "1M")) + qos->phy = 0x01; + else if (!strcmp(input, "2M")) + qos->phy = 0x02; + else { + char *endptr = NULL; + uint8_t phy = strtol(input, &endptr, 0); + + if (!endptr || *endptr != '\0') { + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + switch (phy) { + case 0x01: + case 0x02: + qos->phy = phy; + break; + default: + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } } + + bt_shell_prompt_input("QoS", "Enter Max SDU:", custom_sdu, user_data); } -static void unregister_endpoint_setup(DBusMessageIter *iter, void *user_data) +static void custom_framing(const char *input, void *user_data) { - struct endpoint *ep = user_data; + struct codec_preset *p = user_data; + uint8_t *framing; - dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &ep->path); + if (!p->target_latency) + framing = &p->qos.bcast.framing; + else + framing = &p->qos.ucast.framing; + + if (!strcasecmp(input, "Unframed")) + *framing = 0x00; + else if (!strcasecmp(input, "Framed")) + *framing = 0x01; + else { + char *endptr = NULL; + + *framing = strtol(input, &endptr, 0); + if (!endptr || *endptr != '\0') { + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + bt_shell_prompt_input("QoS", "Enter PHY (1M, 2M):", custom_phy, + user_data); } -static void unregister_endpoint_reply(DBusMessage *message, void *user_data) +static void custom_interval(const char *input, void *user_data) { - struct endpoint *ep = user_data; - DBusError error; + struct codec_preset *p = user_data; + char *endptr = NULL; + struct bt_bap_io_qos *qos; - dbus_error_init(&error); + if (!p->target_latency) + qos = &p->qos.bcast.io_qos; + else + qos = &p->qos.ucast.io_qos; - if (dbus_set_error_from_message(&error, message)) { - bt_shell_printf("Failed to unregister endpoint: %s\n", - error.name); - dbus_error_free(&error); + qos->interval = strtol(input, &endptr, 0); + if (!endptr || *endptr != '\0') { + bt_shell_printf("Invalid argument: %s\n", input); return bt_shell_noninteractive_quit(EXIT_FAILURE); } - bt_shell_printf("Endpoint %s unregistered\n", ep->path); + bt_shell_prompt_input("QoS", "Enter Framing (Unframed, Framed):", + custom_framing, user_data); +} - local_endpoints = g_list_remove(local_endpoints, ep); - g_dbus_unregister_interface(dbus_conn, ep->path, - BLUEZ_MEDIA_ENDPOINT_INTERFACE); +static void custom_target_latency(const char *input, void *user_data) +{ + struct codec_preset *p = user_data; - return bt_shell_noninteractive_quit(EXIT_SUCCESS); + if (!strcasecmp(input, "Low")) + p->target_latency = 0x01; + else if (!strcasecmp(input, "Balance")) + p->target_latency = 0x02; + else if (!strcasecmp(input, "High")) + p->target_latency = 0x03; + else { + char *endptr = NULL; + + p->target_latency = strtol(input, &endptr, 0); + if (!endptr || *endptr != '\0') { + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } + + bt_shell_prompt_input("QoS", "Enter SDU Interval (us):", + custom_interval, user_data); } -static void cmd_unregister_endpoint(int argc, char *argv[]) +static void custom_length(const char *input, void *user_data) { - struct endpoint *ep; - GList *l; + struct codec_preset *p = user_data; + struct iovec *iov = (void *)&p->data; + uint8_t ltv[4] = { 0x03, LC3_CONFIG_FRAME_LEN }; + uint16_t len; + char *endptr = NULL; - ep = endpoint_find(argv[1]); - if (!ep) { - bt_shell_printf("Unable to find endpoint object: %s\n", - argv[1]); + len = strtol(input, &endptr, 0); + if (!endptr || *endptr != '\0') { + bt_shell_printf("Invalid argument: %s\n", input); return bt_shell_noninteractive_quit(EXIT_FAILURE); } - for (l = medias; l; l = g_list_next(l)) { - if (!g_dbus_proxy_method_call(l->data, "UnregisterEndpoint", - unregister_endpoint_setup, - unregister_endpoint_reply, - ep, NULL)) { - bt_shell_printf("Failed unregister endpoint\n"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } + ltv[2] = len; + ltv[3] = len >> 8; - return bt_shell_noninteractive_quit(EXIT_SUCCESS); + util_iov_append(iov, ltv, sizeof(ltv)); + + bt_shell_prompt_input("QoS", "Enter Target Latency " + "(Low, Balance, High):", + custom_target_latency, user_data); } -static void config_endpoint_setup(DBusMessageIter *iter, void *user_data) +static void custom_location(const char *input, void *user_data) { - struct endpoint_config *cfg = user_data; + struct codec_preset *p = user_data; + struct iovec *iov = (void *)&p->data; + uint32_t location; + char *endptr = NULL; - dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, - &cfg->ep->path); + location = strtol(input, &endptr, 0); + if (!endptr || *endptr != '\0') { + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } - append_properties(iter, cfg); + /* Only add Channel Allocation if set */ + if (location) { + uint8_t ltv[6] = { 0x05, LC3_CONFIG_CHAN_ALLOC }; + + location = cpu_to_le32(location); + memcpy(<v[2], &location, sizeof(location)); + util_iov_append(iov, ltv, sizeof(ltv)); + } + + bt_shell_prompt_input("Codec", "Enter frame length:", + custom_length, user_data); } -static void config_endpoint_reply(DBusMessage *message, void *user_data) +static uint8_t val2duration(uint32_t val) { - struct endpoint_config *cfg = user_data; - struct endpoint *ep = cfg->ep; - DBusError error; + switch (val) { + case 7: + return 0x00; + case 10: + return 0x01; + default: + return 0xff; + } +} - free(cfg->caps->iov_base); - free(cfg->caps); - free(cfg); +static void custom_duration(const char *input, void *user_data) +{ + struct codec_preset *p = user_data; + struct iovec *iov = (void *)&p->data; + uint8_t ltv[3] = { 0x02, LC3_CONFIG_DURATION, 0x00 }; + char *endptr = NULL; + uint32_t val; - dbus_error_init(&error); + val = strtol(input, &endptr, 0); + if (!endptr || *endptr != '\0') { + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } - if (dbus_set_error_from_message(&error, message)) { - bt_shell_printf("Failed to config endpoint: %s\n", - error.name); - dbus_error_free(&error); + if (strncmp(input, "0x", 2)) + ltv[2] = val2duration(val); + else + ltv[2] = val; + + if (ltv[2] == 0xff) { + bt_shell_printf("Invalid argument: %s\n", input); return bt_shell_noninteractive_quit(EXIT_FAILURE); } - bt_shell_printf("Endpoint %s configured\n", ep->path); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); + util_iov_append(iov, ltv, sizeof(ltv)); + + bt_shell_prompt_input("Codec", "Enter channel allocation:", + custom_location, user_data); +} + +static uint8_t val2freq(uint32_t val) +{ + switch (val) { + case 8: + return 0x01; + case 11: + return 0x02; + case 16: + return 0x03; + case 22: + return 0x04; + case 24: + return 0x05; + case 32: + return 0x06; + case 44: + return 0x07; + case 48: + return 0x08; + case 88: + return 0x09; + case 96: + return 0x0a; + case 174: + return 0x0b; + case 192: + return 0x0c; + case 384: + return 0x0d; + default: + return 0x00; + } } -static void endpoint_set_config(struct endpoint_config *cfg) +static void custom_frequency(const char *input, void *user_data) { - if (!g_dbus_proxy_method_call(cfg->proxy, "SetConfiguration", - config_endpoint_setup, - config_endpoint_reply, - cfg, NULL)) { - bt_shell_printf("Failed to config endpoint\n"); + struct codec_preset *p = user_data; + struct iovec *iov = (void *)&p->data; + uint8_t ltv[3] = { 0x02, LC3_CONFIG_FREQ, 0x00 }; + uint32_t val; + char *endptr = NULL; + + val = strtol(input, &endptr, 0); + if (!endptr || *endptr != '\0') { + bt_shell_printf("Invalid argument: %s\n", input); return bt_shell_noninteractive_quit(EXIT_FAILURE); } -} -static void endpoint_config(const char *input, void *user_data) -{ - struct endpoint_config *cfg = user_data; - uint8_t *data; - size_t len = 0; + if (strncmp(input, "0x", 2)) + ltv[2] = val2freq(val); + else + ltv[2] = val; - data = str2bytearray((char *) input, &len); + if (!ltv[2]) { + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } - iov_append(&cfg->caps, data, len); - free(data); + /* Reset iov to start over the codec configuration */ + free(iov->iov_base); + iov->iov_base = NULL; + iov->iov_len = 0; + util_iov_append(iov, ltv, sizeof(ltv)); - endpoint_set_config(cfg); + bt_shell_prompt_input("Codec", "Enter frame duration (ms):", + custom_duration, user_data); } -static void cmd_config_endpoint(int argc, char *argv[]) +static void foreach_custom_preset_print(void *data, void *user_data) { - struct endpoint_config *cfg; - const struct codec_preset *preset; + struct codec_preset *p = data; + struct preset *preset = user_data; - cfg = new0(struct endpoint_config, 1); + bt_shell_printf("%s%s\n", p == preset->default_preset ? "*" : "", + p->name); +} - cfg->proxy = g_dbus_proxy_lookup(endpoints, NULL, argv[1], - BLUEZ_MEDIA_ENDPOINT_INTERFACE); - if (!cfg->proxy) { - bt_shell_printf("Endpoint %s not found\n", argv[1]); - goto fail; - } +static void print_presets(struct preset *preset) +{ + size_t i; + struct codec_preset *p; - cfg->ep = endpoint_find(argv[2]); - if (!cfg->ep) { - bt_shell_printf("Local Endpoint %s not found\n", argv[2]); - goto fail; - } + for (i = 0; i < preset->num_presets; i++) { + p = &preset->presets[i]; - if (argc > 3) { - preset = find_preset(cfg->ep->uuid, argv[3]); - if (!preset) { - bt_shell_printf("Preset %s not found\n", argv[3]); - goto fail; - } + if (p == preset->default_preset) + bt_shell_printf("*%s\n", p->name); + else if (preset->default_preset && + p == preset->default_preset->alt_preset) + bt_shell_printf("**%s\n", p->name); + else + bt_shell_printf("%s\n", p->name); + } - /* Copy capabilities */ - iov_append(&cfg->caps, preset->data.iov_base, - preset->data.iov_len); + queue_foreach(preset->custom, foreach_custom_preset_print, preset); +} - /* Set QoS parameters */ - cfg->qos = &preset->qos; +static void custom_chan_alloc(const char *input, void *user_data) +{ + struct codec_preset *p = user_data; + char *endptr = NULL; - endpoint_set_config(cfg); - return; + p->chan_alloc = strtol(input, &endptr, 0); + if (!endptr || *endptr != '\0') { + bt_shell_printf("Invalid argument: %s\n", input); + return bt_shell_noninteractive_quit(EXIT_FAILURE); } - bt_shell_prompt_input(cfg->ep->path, "Enter configuration:", - endpoint_config, cfg); - - return; - -fail: - g_free(cfg); - return bt_shell_noninteractive_quit(EXIT_FAILURE); + if (p->alt_preset) + bt_shell_prompt_input(p->alt_preset->name, + "Enter Channel Allocation: ", + custom_chan_alloc, p->alt_preset); + else + return bt_shell_noninteractive_quit(EXIT_SUCCESS); } static void cmd_presets_endpoint(int argc, char *argv[]) { - size_t i; + struct preset *preset; struct codec_preset *default_preset = NULL; + struct endpoint *ep = NULL; - if (argc > 2) { - default_preset = find_preset(argv[1], argv[2]); - if (!default_preset) { - bt_shell_printf("Preset %s not found\n", argv[2]); + preset = find_presets_name(argv[1], argv[2]); + if (!preset) { + ep = endpoint_find(argv[1]); + if (!ep) { + bt_shell_printf("No preset found\n"); return bt_shell_noninteractive_quit(EXIT_FAILURE); } - - default_preset->is_default = true; + preset = ep->preset; + argv++; + argc--; + } else { + argv += 2; + argc -= 2; } - for (i = 0; i < ARRAY_SIZE(presets); i++) { - const struct preset *preset = &presets[i]; + if (argc > 1) { + default_preset = codec_preset_add(preset, argv[1]); + if (!default_preset) { + bt_shell_printf("Preset %s not found\n", argv[1]); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (ep) + ep->codec_preset = default_preset; + else + preset->default_preset = default_preset; + + if (argc > 2) { + struct codec_preset *alt_preset; + struct iovec *caps = (void *)&default_preset->data; + struct iovec *meta = (void *)&default_preset->meta; + + /* Check if and alternative preset was given */ + alt_preset = preset_find_name(preset, argv[2]); + if (alt_preset) { + default_preset->alt_preset = alt_preset; + bt_shell_prompt_input(default_preset->name, + "Enter Channel Allocation: ", + custom_chan_alloc, + default_preset); + return; + } - if (!strcasecmp(preset->uuid, argv[1])) { - size_t j; + /* Check if Codec Configuration was entered */ + if (strlen(argv[2])) { + caps->iov_base = str2bytearray(argv[2], + &caps->iov_len); + if (!caps->iov_base) { + bt_shell_printf("Invalid configuration " + "%s\n", + argv[2]); + return bt_shell_noninteractive_quit( + EXIT_FAILURE); + } + } - for (j = 0; j < preset->num_presets; j++) { - struct codec_preset *p; + /* Check if metadata was entered */ + if (argc > 3) { + meta->iov_base = str2bytearray(argv[3], + &meta->iov_len); + if (!meta->iov_base) { + bt_shell_printf("Invalid metadata %s\n", + argv[5]); + return bt_shell_noninteractive_quit( + EXIT_FAILURE); + } + } - p = &preset->presets[j]; + /* If configuration was left empty then ask the + * parameters. + */ + if (!caps->iov_base || !caps->iov_len) + goto enter_cc; - if (default_preset && p != default_preset) - p->is_default = false; + bt_shell_prompt_input("QoS", "Enter Target Latency " + "(Low, Balance, High):", + custom_target_latency, + default_preset); - if (p->is_default) - bt_shell_printf("*%s\n", p->name); - else - bt_shell_printf("%s\n", p->name); - } + return; } + } else if (ep && (ep->codec_preset)) + print_preset(ep->codec_preset, ep->codec); + else + print_presets(preset); + +enter_cc: + if (default_preset && default_preset->custom) { + bt_shell_prompt_input("Codec", "Enter frequency (Khz):", + custom_frequency, default_preset); + return; } return bt_shell_noninteractive_quit(EXIT_SUCCESS); @@ -2391,26 +4342,74 @@ static const struct bt_shell_menu endpoint_menu = { .entries = { { "list", "[local]", cmd_list_endpoints, "List available endpoints" }, - { "show", "<endpoint>", cmd_show_endpoint, + { "show", "[endpoint]", cmd_show_endpoint, "Endpoint information", endpoint_generator }, - { "register", "<UUID> <codec> [capabilities...]", + { "register", "<UUID> <codec[:company]> [capabilities...]", cmd_register_endpoint, "Register Endpoint", uuid_generator }, { "unregister", "<UUID/object>", cmd_unregister_endpoint, "Register Endpoint", local_endpoint_generator }, - { "config", "<endpoint> <local endpoint> [preset]", + { "config", "<endpoint> [local endpoint] [preset]", cmd_config_endpoint, "Configure Endpoint", endpoint_generator }, - { "presets", "<UUID> [default]", cmd_presets_endpoint, - "List available presets", + { "presets", "<endpoint>/<UUID> [codec[:company]] [preset] " + "[codec config] [metadata]", + cmd_presets_endpoint, + "List or add presets", uuid_generator }, {} }, }; +static void endpoint_init_bcast(struct endpoint *ep) +{ + if (!strcmp(ep->uuid, BAA_SERVICE_UUID)) { + ep->locations = EP_SNK_LOCATIONS; + ep->supported_context = EP_SUPPORTED_SNK_CTXT; + } else { + ep->locations = EP_SRC_LOCATIONS; + ep->supported_context = EP_SUPPORTED_SRC_CTXT; + } +} + +static void endpoint_init_ucast(struct endpoint *ep) +{ + if (!strcmp(ep->uuid, PAC_SINK_UUID)) { + ep->locations = EP_SNK_LOCATIONS; + ep->supported_context = EP_SUPPORTED_SNK_CTXT; + ep->context = EP_SNK_CTXT; + } else if (!strcmp(ep->uuid, PAC_SOURCE_UUID)) { + ep->locations = EP_SRC_LOCATIONS; + ep->supported_context = EP_SUPPORTED_SRC_CTXT; + ep->context = EP_SRC_CTXT; + } +} + +static void endpoint_init_defaults(struct endpoint *ep) +{ + ep->preset = find_presets(ep->uuid, ep->codec, ep->vid, ep->cid); + ep->max_transports = UINT8_MAX; + ep->auto_accept = true; + + if (!strcmp(ep->uuid, A2DP_SOURCE_UUID) || + !strcmp(ep->uuid, A2DP_SOURCE_UUID)) + return; + + ep->iso_group = BT_ISO_QOS_GROUP_UNSET; + ep->iso_stream = BT_ISO_QOS_STREAM_UNSET; + + ep->broadcast = (strcmp(ep->uuid, BCAA_SERVICE_UUID) && + strcmp(ep->uuid, BAA_SERVICE_UUID)) ? false : true; + + if (ep->broadcast) + endpoint_init_bcast(ep); + else + endpoint_init_ucast(ep); +} + static struct endpoint *endpoint_new(const struct capabilities *cap) { struct endpoint *ep; @@ -2418,10 +4417,13 @@ static struct endpoint *endpoint_new(const struct capabilities *cap) ep = new0(struct endpoint, 1); ep->uuid = g_strdup(cap->uuid); ep->codec = cap->codec_id; - ep->path = g_strdup_printf("%s/ep%u", BLUEZ_MEDIA_ENDPOINT_PATH, - g_list_length(local_endpoints)); + ep->path = g_strdup_printf("%s/%s", BLUEZ_MEDIA_ENDPOINT_PATH, + cap->name); /* Copy capabilities */ - iov_append(&ep->caps, cap->data.iov_base, cap->data.iov_len); + ep->caps = util_iov_dup(&cap->data, 1); + /* Copy metadata */ + ep->meta = util_iov_dup(&cap->meta, 1); + local_endpoints = g_list_append(local_endpoints, ep); return ep; @@ -2430,32 +4432,17 @@ static struct endpoint *endpoint_new(const struct capabilities *cap) static void register_endpoints(GDBusProxy *proxy) { struct endpoint *ep; - DBusMessageIter iter, array; - - if (!g_dbus_proxy_get_property(proxy, "SupportedUUIDs", &iter)) - return; - - dbus_message_iter_recurse(&iter, &array); - while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) { - const char *uuid; - size_t i; - - dbus_message_iter_get_basic(&array, &uuid); - - for (i = 0; i < ARRAY_SIZE(caps); i++) { - const struct capabilities *cap = &caps[i]; + size_t i; - if (strcasecmp(cap->uuid, uuid)) - continue; + for (i = 0; i < ARRAY_SIZE(caps); i++) { + const struct capabilities *cap = &caps[i]; - ep = endpoint_new(cap); - ep->auto_accept = true; - ep->cig = BT_ISO_QOS_CIG_UNSET; - ep->cis = BT_ISO_QOS_CIS_UNSET; - endpoint_register(ep); - } + if (!media_supports_uuid(proxy, cap->uuid)) + continue; - dbus_message_iter_next(&array); + ep = endpoint_new(cap); + endpoint_init_defaults(ep); + endpoint_register(ep); } } @@ -2682,14 +4669,14 @@ static struct endpoint *find_ep_by_transport(const char *path) for (l = local_endpoints; l; l = g_list_next(l)) { struct endpoint *ep = l->data; - if (ep->transport && !strcmp(ep->transport, path)) + if (queue_find(ep->transports, match_str, path)) return ep; } return NULL; } -static struct endpoint *find_link_by_proxy(GDBusProxy *proxy) +static GDBusProxy *find_link_by_proxy(GDBusProxy *proxy) { DBusMessageIter iter, array; @@ -2701,13 +4688,13 @@ static struct endpoint *find_link_by_proxy(GDBusProxy *proxy) while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_OBJECT_PATH) { const char *transport; - struct endpoint *link; dbus_message_iter_get_basic(&array, &transport); - link = find_ep_by_transport(transport); - if (link) - return link; + proxy = g_dbus_proxy_lookup(transports, NULL, transport, + BLUEZ_MEDIA_TRANSPORT_INTERFACE); + if (proxy) + return proxy; } return NULL; @@ -2719,6 +4706,8 @@ static void transport_close(struct transport *transport) return; close(transport->fd); + transport->fd = -1; + free(transport->filename); } @@ -2726,6 +4715,7 @@ static void transport_free(void *data) { struct transport *transport = data; + io_destroy(transport->timer_io); io_destroy(transport->io); free(transport); } @@ -2748,21 +4738,27 @@ static bool transport_recv(struct io *io, void *user_data) uint8_t buf[1024]; int ret, len; - ret = read(io_get_fd(io), buf, sizeof(buf)); + ret = io_get_fd(io); + if (ret < 0) { + bt_shell_printf("io_get_fd() returned %d\n", ret); + return true; + } + + ret = read(ret, buf, sizeof(buf)); if (ret < 0) { bt_shell_printf("Failed to read: %s (%d)\n", strerror(errno), -errno); return true; } - bt_shell_printf("[seq %d] recv: %u bytes\n", transport->seq, ret); + bt_shell_echo("[seq %d] recv: %u bytes", transport->seq, ret); transport->seq++; - if (transport->fd) { + if (transport->filename) { len = write(transport->fd, buf, ret); if (len < 0) - bt_shell_printf("Unable to write: %s (%d)", + bt_shell_printf("Unable to write: %s (%d)\n", strerror(errno), -errno); } @@ -2791,21 +4787,51 @@ static void transport_new(GDBusProxy *proxy, int sk, uint16_t mtu[2]) queue_push_tail(ios, transport); } +static void ep_set_acquiring(struct endpoint *ep, GDBusProxy *proxy, bool value) +{ + bt_shell_printf("Transport %s %s\n", g_dbus_proxy_get_path(proxy), + value ? "acquiring" : "acquiring complete"); + + if (value && !ep->acquiring) + ep->acquiring = queue_new(); + + if (value) + queue_push_tail(ep->acquiring, proxy); + else + queue_remove(ep->acquiring, proxy); +} + +static void transport_set_acquiring(GDBusProxy *proxy, bool value) +{ + struct endpoint *ep; + GDBusProxy *link; + + ep = find_ep_by_transport(g_dbus_proxy_get_path(proxy)); + if (!ep) + return; + + ep_set_acquiring(ep, proxy, value); + + if (!ep->broadcast) { + link = find_link_by_proxy(proxy); + if (link) { + ep = find_ep_by_transport(g_dbus_proxy_get_path(link)); + if (!ep) + return; + + ep_set_acquiring(ep, link, value); + } + } +} + static void acquire_reply(DBusMessage *message, void *user_data) { GDBusProxy *proxy = user_data; - struct endpoint *ep, *link; DBusError error; int sk; uint16_t mtu[2]; - ep = find_ep_by_transport(g_dbus_proxy_get_path(proxy)); - if (ep) { - ep->acquiring = false; - link = find_link_by_proxy(proxy); - if (link) - link->acquiring = false; - } + transport_set_acquiring(proxy, false); dbus_error_init(&error); @@ -2834,33 +4860,98 @@ static void acquire_reply(DBusMessage *message, void *user_data) return bt_shell_noninteractive_quit(EXIT_FAILURE); } -static void transport_acquire(const char *input, void *user_data) +static void select_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + bt_shell_printf("Failed to select: %s\n", error.name); + dbus_error_free(&error); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + bt_shell_printf("Select successful\n"); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void unselect_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + bt_shell_printf("Failed to unselect: %s\n", error.name); + dbus_error_free(&error); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + bt_shell_printf("Unselect successful\n"); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + + +static void prompt_acquire(const char *input, void *user_data) { GDBusProxy *proxy = user_data; - struct endpoint *ep, *link; if (!strcasecmp(input, "y") || !strcasecmp(input, "yes")) { if (g_dbus_proxy_method_call(proxy, "Acquire", NULL, - acquire_reply, proxy, NULL)) + acquire_reply, proxy, NULL)) { + transport_set_acquiring(proxy, true); return; + } bt_shell_printf("Failed acquire transport\n"); } +} + +static void transport_acquire(GDBusProxy *proxy, bool prompt) +{ + struct endpoint *ep; + GDBusProxy *link; - /* Reset acquiring */ + /* only attempt to acquire if transport is configured with a local + * endpoint. + */ ep = find_ep_by_transport(g_dbus_proxy_get_path(proxy)); - if (ep) { - ep->acquiring = false; + if (!ep || queue_find(ep->acquiring, NULL, proxy)) + return; + + if (!ep->broadcast) { link = find_link_by_proxy(proxy); - if (link) - link->acquiring = false; + if (link) { + ep = find_ep_by_transport(g_dbus_proxy_get_path(link)); + /* if link already acquiring wait it to be complete */ + if (!ep || queue_find(ep->acquiring, NULL, link)) + return; + } + } + + if (ep->auto_accept || !prompt) { + if (!prompt) + bt_shell_printf("auto acquiring...\n"); + if (!g_dbus_proxy_method_call(proxy, "Acquire", NULL, + acquire_reply, proxy, NULL)) { + bt_shell_printf("failed acquire transport\n"); + return; + } + + transport_set_acquiring(proxy, true); + return; } + + bt_shell_prompt_input(g_dbus_proxy_get_path(proxy), "acquire (yes/no):", + prompt_acquire, proxy); } static void transport_property_changed(GDBusProxy *proxy, const char *name, DBusMessageIter *iter) { char *str; - struct endpoint *ep, *link; str = proxy_description(proxy, "Transport", COLORED_CHG); print_iter(str, name, iter); @@ -2874,38 +4965,7 @@ static void transport_property_changed(GDBusProxy *proxy, const char *name, if (strcmp(str, "pending")) return; - /* Only attempt to acquire if transport is configured with a local - * endpoint. - */ - ep = find_ep_by_transport(g_dbus_proxy_get_path(proxy)); - if (!ep || ep->acquiring) - return; - - ep->acquiring = true; - - link = find_link_by_proxy(proxy); - if (link) { - bt_shell_printf("Link %s found\n", link->transport); - /* If link already acquiring wait it to be complete */ - if (link->acquiring) - return; - link->acquiring = true; - } - - if (ep->auto_accept) { - bt_shell_printf("Auto Acquiring...\n"); - if (!g_dbus_proxy_method_call(proxy, "Acquire", NULL, - acquire_reply, proxy, NULL)) { - bt_shell_printf("Failed acquire transport\n"); - ep->acquiring = false; - if (link) - link->acquiring = false; - } - return; - } - - bt_shell_prompt_input(g_dbus_proxy_get_path(proxy), "Acquire (yes/no):", - transport_acquire, proxy); + transport_acquire(proxy, true); } static void property_changed(GDBusProxy *proxy, const char *name, @@ -2927,27 +4987,103 @@ static void property_changed(GDBusProxy *proxy, const char *name, transport_property_changed(proxy, name, iter); } -static char *transport_generator(const char *text, int state) -{ - return generic_generator(text, state, transports); +static char *transport_generator(const char *text, int state) +{ + return generic_generator(text, state, transports); +} + +static void cmd_list_transport(int argc, char *argv[]) +{ + GList *l; + + for (l = transports; l; l = g_list_next(l)) { + GDBusProxy *proxy = l->data; + print_transport(proxy, NULL); + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void print_configuration(GDBusProxy *proxy) +{ + DBusMessageIter iter, subiter; + const char *uuid; + uint8_t codec; + uint8_t *data; + int len; + + if (!g_dbus_proxy_get_property(proxy, "UUID", &iter)) + return; + + dbus_message_iter_get_basic(&iter, &uuid); + + if (!g_dbus_proxy_get_property(proxy, "Codec", &iter)) + return; + + dbus_message_iter_get_basic(&iter, &codec); + + if (!g_dbus_proxy_get_property(proxy, "Configuration", &iter)) + return; + + dbus_message_iter_recurse(&iter, &subiter); + + dbus_message_iter_get_fixed_array(&subiter, &data, &len); + + if (!strcasecmp(uuid, A2DP_SINK_UUID) || + !strcasecmp(uuid, A2DP_SOURCE_UUID)) { + print_a2dp_codec(codec, (void *)data, len); + return; + } + + if (codec != LC3_ID) { + print_property(proxy, "Configuration"); + return; + } + + print_lc3_cfg(data, len); + + if (!g_dbus_proxy_get_property(proxy, "Metadata", &iter)) + return; + + dbus_message_iter_recurse(&iter, &subiter); + + dbus_message_iter_get_fixed_array(&subiter, &data, &len); + + print_lc3_meta(data, len); } -static void cmd_list_transport(int argc, char *argv[]) +static void print_transport_properties(GDBusProxy *proxy) { - GList *l; + bt_shell_printf("Transport %s\n", g_dbus_proxy_get_path(proxy)); - for (l = transports; l; l = g_list_next(l)) { - GDBusProxy *proxy = l->data; - print_transport(proxy, NULL); - } + print_property(proxy, "UUID"); + print_property(proxy, "Codec"); + print_configuration(proxy); + print_property(proxy, "Device"); + print_property(proxy, "State"); + print_property(proxy, "Delay"); + print_property(proxy, "Volume"); + print_property(proxy, "Endpoint"); + print_property(proxy, "QoS"); + print_property(proxy, "Location"); + print_property(proxy, "Links"); +} - return bt_shell_noninteractive_quit(EXIT_SUCCESS); +static void print_transports(void *data, void *user_data) +{ + print_transport_properties(data); } static void cmd_show_transport(int argc, char *argv[]) { GDBusProxy *proxy; + /* Show all transports if no argument is given */ + if (argc != 2) { + g_list_foreach(transports, print_transports, NULL); + return bt_shell_noninteractive_quit(EXIT_SUCCESS); + } + proxy = g_dbus_proxy_lookup(transports, NULL, argv[1], BLUEZ_MEDIA_TRANSPORT_INTERFACE); if (!proxy) { @@ -2955,25 +5091,7 @@ static void cmd_show_transport(int argc, char *argv[]) return bt_shell_noninteractive_quit(EXIT_FAILURE); } - bt_shell_printf("Transport %s\n", g_dbus_proxy_get_path(proxy)); - - print_property(proxy, "UUID"); - print_property(proxy, "Codec"); - print_property(proxy, "Configuration"); - print_property(proxy, "Device"); - print_property(proxy, "State"); - print_property(proxy, "Delay"); - print_property(proxy, "Volume"); - print_property(proxy, "Endpoint"); - - print_property(proxy, "Interval"); - print_property(proxy, "Framing"); - print_property(proxy, "SDU"); - print_property(proxy, "Retransmissions"); - print_property(proxy, "Latency"); - print_property(proxy, "Location"); - print_property(proxy, "Metadata"); - print_property(proxy, "Links"); + print_transport_properties(proxy); return bt_shell_noninteractive_quit(EXIT_SUCCESS); } @@ -3010,14 +5128,172 @@ static void cmd_acquire_transport(int argc, char *argv[]) return bt_shell_noninteractive_quit(EXIT_FAILURE); } - if (!g_dbus_proxy_method_call(proxy, "Acquire", NULL, - acquire_reply, proxy, NULL)) { - bt_shell_printf("Failed acquire transport\n"); + transport_acquire(proxy, false); + } + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void set_bcode_cb(const DBusError *error, void *user_data) +{ + GDBusProxy *proxy = user_data; + + if (dbus_error_is_set(error)) { + bt_shell_printf("Failed to set broadcast code: %s\n", + error->name); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + bt_shell_printf("Setting broadcast code succeeded\n"); + + if (!g_dbus_proxy_method_call(proxy, "Select", NULL, + select_reply, proxy, NULL)) + return bt_shell_noninteractive_quit(EXIT_FAILURE); +} + +static void set_bcode(const char *input, void *user_data) +{ + GDBusProxy *proxy = user_data; + char *bcode; + + if (!strcasecmp(input, "n") || !strcasecmp(input, "no")) + bcode = g_new0(char, 16); + else + bcode = g_strdup(input); + + if (g_dbus_proxy_set_property_dict(proxy, "QoS", + set_bcode_cb, user_data, + NULL, "BCode", DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + strlen(bcode), bcode, NULL) == FALSE) { + bt_shell_printf("Setting broadcast code failed\n"); + g_free(bcode); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + g_free(bcode); +} + +static void transport_select(void *data, void *user_data) +{ + GDBusProxy *proxy = data; + DBusMessageIter iter, array, entry, value; + unsigned char encryption; + const char *key; + + if (g_dbus_proxy_get_property(proxy, "QoS", &iter) == FALSE) + return; + + dbus_message_iter_recurse(&iter, &array); + + while (dbus_message_iter_get_arg_type(&array) != + DBUS_TYPE_INVALID) { + dbus_message_iter_recurse(&array, &entry); + dbus_message_iter_get_basic(&entry, &key); + + if (!strcasecmp(key, "Encryption")) { + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &value); + dbus_message_iter_get_basic(&value, &encryption); + if (encryption == 1) { + bt_shell_prompt_input("", + "Enter brocast code[value/no]:", + set_bcode, proxy); + return; + } + break; + } + dbus_message_iter_next(&array); + } + + if (!g_dbus_proxy_method_call(proxy, "Select", NULL, + select_reply, proxy, NULL)) { + bt_shell_printf("Failed select transport\n"); + return; + } +} + +static void transport_unselect(GDBusProxy *proxy, bool prompt) +{ + if (!g_dbus_proxy_method_call(proxy, "Unselect", NULL, + unselect_reply, proxy, NULL)) { + bt_shell_printf("Failed unselect transport\n"); + return; + } +} + +static void set_links_cb(const DBusError *error, void *user_data) +{ + GDBusProxy *link = user_data; + + if (dbus_error_is_set(error)) { + bt_shell_printf("Failed to set link %s: %s\n", + g_dbus_proxy_get_path(link), + error->name); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + bt_shell_printf("Successfully linked transport %s\n", + g_dbus_proxy_get_path(link)); +} + +static void cmd_select_transport(int argc, char *argv[]) +{ + GDBusProxy *proxy = NULL, *link; + struct queue *links = queue_new(); + const char *path; + int i; + + for (i = 1; i < argc; i++) { + link = g_dbus_proxy_lookup(transports, NULL, argv[i], + BLUEZ_MEDIA_TRANSPORT_INTERFACE); + if (!link) { + bt_shell_printf("Transport %s not found\n", argv[i]); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (find_transport(link)) { + bt_shell_printf("Transport %s already acquired\n", + argv[i]); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + queue_push_tail(links, link); + + if (!proxy) { + proxy = link; + continue; + } + + path = g_dbus_proxy_get_path(link); + + if (g_dbus_proxy_set_property_array(proxy, "Links", + DBUS_TYPE_OBJECT_PATH, + &path, 1, set_links_cb, + link, NULL) == FALSE) { + bt_shell_printf("Linking transport %s failed\n", + argv[i]); return bt_shell_noninteractive_quit(EXIT_FAILURE); } } - return bt_shell_noninteractive_quit(EXIT_SUCCESS); + queue_foreach(links, transport_select, NULL); +} + +static void cmd_unselect_transport(int argc, char *argv[]) +{ + GDBusProxy *proxy; + int i; + + for (i = 1; i < argc; i++) { + proxy = g_dbus_proxy_lookup(transports, NULL, argv[i], + BLUEZ_MEDIA_TRANSPORT_INTERFACE); + if (!proxy) { + bt_shell_printf("Transport %s not found\n", argv[i]); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + transport_unselect(proxy, false); + } } static void release_reply(DBusMessage *message, void *user_data) @@ -3090,145 +5366,253 @@ static int open_file(const char *filename, int flags) return fd; } -#define NSEC_USEC(_t) (_t / 1000L) -#define SEC_USEC(_t) (_t * 1000000L) -#define TS_USEC(_ts) (SEC_USEC((_ts)->tv_sec) + NSEC_USEC((_ts)->tv_nsec)) - -static void send_wait(struct timespec *t_start, uint32_t us) +static int elapsed_time(bool reset, int *secs, int *nsecs) { - struct timespec t_now; - struct timespec t_diff; - int64_t delta_us; + static struct timespec start; + struct timespec curr; - /* Skip sleep at start */ - if (!us) - return; + if (reset) { + if (clock_gettime(CLOCK_MONOTONIC, &start) < 0) { + bt_shell_printf("clock_gettime: %s (%d)", + strerror(errno), errno); + return -errno; + } + } - if (clock_gettime(CLOCK_MONOTONIC, &t_now) < 0) { + if (clock_gettime(CLOCK_MONOTONIC, &curr) < 0) { bt_shell_printf("clock_gettime: %s (%d)", strerror(errno), - errno); - return; + errno); + return -errno; } - t_diff.tv_sec = t_now.tv_sec - t_start->tv_sec; - t_diff.tv_nsec = t_now.tv_nsec - t_start->tv_nsec; - - delta_us = us - TS_USEC(&t_diff); - - if (delta_us < 0) { - bt_shell_printf("Send is behind: %" PRId64 " us - skip sleep", - delta_us); - delta_us = 1000; + *secs = curr.tv_sec - start.tv_sec; + *nsecs = curr.tv_nsec - start.tv_nsec; + if (*nsecs < 0) { + (*secs)--; + *nsecs += 1000000000; } - usleep(delta_us); - - if (clock_gettime(CLOCK_MONOTONIC, t_start) < 0) - bt_shell_printf("clock_gettime: %s (%d)", strerror(errno), - errno); + return 0; } -static int transport_send(struct transport *transport, int fd, - struct bt_iso_qos *qos) +static int transport_send_seq(struct transport *transport, int fd, uint32_t num) { - struct timespec t_start; uint8_t *buf; - uint32_t num = 0; + uint32_t i; - if (qos && clock_gettime(CLOCK_MONOTONIC, &t_start) < 0) { - bt_shell_printf("clock_gettime: %s (%d)", strerror(errno), - errno); - return -errno; - } + if (!num) + return 0; buf = malloc(transport->mtu[1]); - if (!buf) { - bt_shell_printf("malloc: %s (%d)", strerror(errno), errno); + if (!buf) return -ENOMEM; - } - - /* num of packets = latency (ms) / interval (us) */ - if (qos) - num = (qos->out.latency * 1000 / qos->out.interval); - for (transport->seq = 0; ; transport->seq++) { + for (i = 0; i < num; i++, transport->seq++) { ssize_t ret; - int queued; + int secs = 0, nsecs = 0; + off_t offset; ret = read(fd, buf, transport->mtu[1]); if (ret <= 0) { if (ret < 0) bt_shell_printf("read failed: %s (%d)", strerror(errno), errno); - close(fd); + free(buf); return ret; } ret = send(transport->sk, buf, ret, 0); if (ret <= 0) { - bt_shell_printf("Send failed: %s (%d)", + bt_shell_printf("send failed: %s (%d)", strerror(errno), errno); + free(buf); return -errno; } - ioctl(transport->sk, TIOCOUTQ, &queued); - - bt_shell_printf("[seq %d] send: %zd bytes " - "(TIOCOUTQ %d bytes)\n", - transport->seq, ret, queued); + elapsed_time(!transport->seq, &secs, &nsecs); - if (qos) { - if (transport->seq && !((transport->seq + 1) % num)) - send_wait(&t_start, num * qos->out.interval); + if (!transport->seq && fstat(fd, &transport->stat) < 0) { + bt_shell_printf("fstat failed: %s (%d)", + strerror(errno), errno); + free(buf); + return -errno; } + + offset = lseek(fd, 0, SEEK_CUR); + + bt_shell_echo("[seq %d %d.%03ds] send: %zd/%zd bytes", + transport->seq, secs, + (nsecs + 500000) / 1000000, + offset, transport->stat.st_size); } free(buf); + + return i; } -static void cmd_send_transport(int argc, char *argv[]) +static bool transport_timer_read(struct io *io, void *user_data) { - GDBusProxy *proxy; - struct transport *transport; - int fd, err; + struct transport *transport = user_data; struct bt_iso_qos qos; socklen_t len; + int ret, fd; + uint64_t exp; - proxy = g_dbus_proxy_lookup(transports, NULL, argv[1], - BLUEZ_MEDIA_TRANSPORT_INTERFACE); - if (!proxy) { - bt_shell_printf("Transport %s not found\n", argv[1]); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } + if (transport->fd < 0) + return false; - transport = find_transport(proxy); - if (!transport) { - bt_shell_printf("Transport %s not acquired\n", argv[1]); - return bt_shell_noninteractive_quit(EXIT_FAILURE); + fd = io_get_fd(io); + if (fd < 0) { + bt_shell_printf("io_get_fd() returned %d\n", fd); + return false; } - if (transport->sk < 0) { - bt_shell_printf("No Transport Socked found\n"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); + ret = read(fd, &exp, sizeof(exp)); + if (ret < 0) { + bt_shell_printf("Failed to read: %s (%d)\n", strerror(errno), + -errno); + return false; } - fd = open_file(argv[2], O_RDONLY); - - bt_shell_printf("Sending ...\n"); - /* Read QoS if available */ memset(&qos, 0, sizeof(qos)); len = sizeof(qos); if (getsockopt(transport->sk, SOL_BLUETOOTH, BT_ISO_QOS, &qos, - &len) < 0) - err = transport_send(transport, fd, NULL); - else - err = transport_send(transport, fd, &qos); + &len) < 0) { + bt_shell_printf("Failed to getsockopt(BT_ISO_QOS): %s (%d)\n", + strerror(errno), -errno); + return false; + } + + ret = transport_send_seq(transport, transport->fd, transport->num); + if (ret < 0) { + bt_shell_printf("Unable to send: %s (%d)\n", + strerror(-ret), ret); + return false; + } - close(fd); + if (!ret) { + transport_close(transport); + return false; + } - if (err < 0) - return bt_shell_noninteractive_quit(EXIT_FAILURE); + return true; +} + +static int transport_send(struct transport *transport, int fd, + struct bt_iso_io_qos *qos) +{ + struct itimerspec ts; + int timer_fd; + + transport->seq = 0; + + if (!qos) + return transport_send_seq(transport, fd, UINT32_MAX); + + if (transport->fd >= 0) + return -EALREADY; + + timer_fd = timerfd_create(CLOCK_MONOTONIC, 0); + if (timer_fd < 0) + return -errno; + + /* Send data in bursts of + * num = ROUND_CLOSEST(Transport_Latency (ms) / SDU_Interval (us)) + * with average data rate = 1 packet / SDU_Interval + */ + transport->num = ROUND_CLOSEST(qos->latency * 1000, qos->interval); + if (!transport->num) + transport->num = 1; + + memset(&ts, 0, sizeof(ts)); + ts.it_value.tv_nsec = 1; + ts.it_interval.tv_nsec = transport->num * qos->interval * 1000; + + if (timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &ts, NULL) < 0) { + close(timer_fd); + return -errno; + } + + transport->fd = fd; + transport->timer_io = io_new(timer_fd); + + io_set_read_handler(transport->timer_io, transport_timer_read, + transport, NULL); + + /* One extra packet to buffers immediately */ + return transport_send_seq(transport, fd, 1); +} + +static void cmd_send_transport(int argc, char *argv[]) +{ + GDBusProxy *proxy; + struct transport *transport; + int fd = -1, err; + struct bt_iso_qos qos; + socklen_t len; + int i; + + for (i = 1; i < argc; i++) { + proxy = g_dbus_proxy_lookup(transports, NULL, argv[i], + BLUEZ_MEDIA_TRANSPORT_INTERFACE); + if (!proxy) { + bt_shell_printf("Transport %s not found\n", argv[i]); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + transport = find_transport(proxy); + if (!transport) { + bt_shell_printf("Transport %s not acquired\n", argv[i]); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (transport->sk < 0) { + bt_shell_printf("No Transport Socked found\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + if (i + 1 < argc) { + fd = open_file(argv[++i], O_RDONLY); + if (fd < 0) + return bt_shell_noninteractive_quit( + EXIT_FAILURE); + } + + bt_shell_printf("Sending ...\n"); + + /* Read QoS if available */ + memset(&qos, 0, sizeof(qos)); + len = sizeof(qos); + if (getsockopt(transport->sk, SOL_BLUETOOTH, BT_ISO_QOS, &qos, + &len) < 0) { + bt_shell_printf("Unable to getsockopt(BT_ISO_QOS): %s", + strerror(errno)); + err = transport_send(transport, fd, NULL); + } else { + struct sockaddr_iso addr; + socklen_t optlen = sizeof(addr); + + err = getpeername(transport->sk, + (struct sockaddr *)&addr, &optlen); + if (!err) { + if (!(bacmp(&addr.iso_bdaddr, BDADDR_ANY))) + err = transport_send(transport, fd, + &qos.bcast.out); + else + err = transport_send(transport, fd, + &qos.ucast.out); + } + } + + if (err < 0) { + bt_shell_printf("Unable to send: %s (%d)\n", + strerror(-err), -err); + close(fd); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + } return bt_shell_noninteractive_quit(EXIT_SUCCESS); } @@ -3321,7 +5705,7 @@ static const struct bt_shell_menu transport_menu = { .entries = { { "list", NULL, cmd_list_transport, "List available transports" }, - { "show", "<transport>", cmd_show_transport, + { "show", "[transport]", cmd_show_transport, "Transport information", transport_generator }, { "acquire", "<transport> [transport1...]", cmd_acquire_transport, @@ -3330,13 +5714,22 @@ static const struct bt_shell_menu transport_menu = { { "release", "<transport> [transport1...]", cmd_release_transport, "Release Transport", transport_generator }, - { "send", "<transport> <filename>", cmd_send_transport, - "Send contents of a file" }, + { "send", "<transport> <filename> [transport1...]", + cmd_send_transport, + "Send contents of a file", + transport_generator }, { "receive", "<transport> [filename]", cmd_receive_transport, - "Get/Set file to receive" }, + "Get/Set file to receive", + transport_generator }, { "volume", "<transport> [value]", cmd_volume_transport, "Get/Set transport volume", transport_generator }, + { "select", "<transport> [transport1...]", cmd_select_transport, + "Select Transport", + transport_generator }, + { "unselect", "<transport> [transport1...]", cmd_unselect_transport, + "Unselect Transport", + transport_generator }, {} }, }; diff --git a/client/print.c b/client/print.c new file mode 100644 index 0000000000000000000000000000000000000000..39f8567eedd3b011457af5bbe2a5a9a207e84611 --- /dev/null +++ b/client/print.c @@ -0,0 +1,238 @@ + +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdbool.h> +#include <inttypes.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> + +#include "gdbus/gdbus.h" + +#include "src/shared/util.h" +#include "src/shared/shell.h" +#include "print.h" + +static void print_fixed_iter(const char *label, const char *name, + DBusMessageIter *iter) +{ + dbus_bool_t *valbool; + dbus_uint32_t *valu32; + dbus_uint16_t *valu16; + dbus_int16_t *vals16; + unsigned char *byte; + int len; + + switch (dbus_message_iter_get_arg_type(iter)) { + case DBUS_TYPE_BOOLEAN: + dbus_message_iter_get_fixed_array(iter, &valbool, &len); + + if (len <= 0) + return; + + bt_shell_printf("%s%s:\n", label, name); + bt_shell_hexdump((void *)valbool, len * sizeof(*valbool)); + + break; + case DBUS_TYPE_UINT32: + dbus_message_iter_get_fixed_array(iter, &valu32, &len); + + if (len <= 0) + return; + + bt_shell_printf("%s%s:\n", label, name); + bt_shell_hexdump((void *)valu32, len * sizeof(*valu32)); + + break; + case DBUS_TYPE_UINT16: + dbus_message_iter_get_fixed_array(iter, &valu16, &len); + + if (len <= 0) + return; + + bt_shell_printf("%s%s:\n", label, name); + bt_shell_hexdump((void *)valu16, len * sizeof(*valu16)); + + break; + case DBUS_TYPE_INT16: + dbus_message_iter_get_fixed_array(iter, &vals16, &len); + + if (len <= 0) + return; + + bt_shell_printf("%s%s:\n", label, name); + bt_shell_hexdump((void *)vals16, len * sizeof(*vals16)); + + break; + case DBUS_TYPE_BYTE: + dbus_message_iter_get_fixed_array(iter, &byte, &len); + + if (len <= 0) + return; + + bt_shell_printf("%s%s:\n", label, name); + bt_shell_hexdump((void *)byte, len * sizeof(*byte)); + + break; + default: + return; + }; +} + +void print_iter(const char *label, const char *name, DBusMessageIter *iter) +{ + dbus_bool_t valbool; + dbus_uint32_t valu32; + dbus_uint16_t valu16; + dbus_int16_t vals16; + unsigned char byte; + const char *valstr; + DBusMessageIter subiter; + char *entry; + + if (iter == NULL) { + bt_shell_printf("%s%s is nil\n", label, name); + return; + } + + switch (dbus_message_iter_get_arg_type(iter)) { + case DBUS_TYPE_INVALID: + bt_shell_printf("%s%s is invalid\n", label, name); + break; + case DBUS_TYPE_STRING: + if (!strcasecmp(name, "UUID")) { + dbus_message_iter_get_basic(iter, &valstr); + print_uuid(label, name, valstr); + break; + } + /* fall through */ + case DBUS_TYPE_OBJECT_PATH: + dbus_message_iter_get_basic(iter, &valstr); + bt_shell_printf("%s%s: %s\n", label, name, valstr); + break; + case DBUS_TYPE_BOOLEAN: + dbus_message_iter_get_basic(iter, &valbool); + bt_shell_printf("%s%s: %s\n", label, name, + valbool == TRUE ? "yes" : "no"); + break; + case DBUS_TYPE_UINT32: + dbus_message_iter_get_basic(iter, &valu32); + bt_shell_printf("%s%s: 0x%08x (%d)\n", label, name, valu32, + valu32); + break; + case DBUS_TYPE_UINT16: + dbus_message_iter_get_basic(iter, &valu16); + bt_shell_printf("%s%s: 0x%04x (%d)\n", label, name, valu16, + valu16); + break; + case DBUS_TYPE_INT16: + dbus_message_iter_get_basic(iter, &vals16); + bt_shell_printf("%s%s: 0x%04x (%d)\n", label, name, vals16, + vals16); + break; + case DBUS_TYPE_BYTE: + dbus_message_iter_get_basic(iter, &byte); + bt_shell_printf("%s%s: 0x%02x (%d)\n", label, name, byte, byte); + break; + case DBUS_TYPE_VARIANT: + dbus_message_iter_recurse(iter, &subiter); + print_iter(label, name, &subiter); + break; + case DBUS_TYPE_ARRAY: + dbus_message_iter_recurse(iter, &subiter); + + if (dbus_type_is_fixed( + dbus_message_iter_get_arg_type(&subiter))) { + print_fixed_iter(label, name, &subiter); + break; + } + + while (dbus_message_iter_get_arg_type(&subiter) != + DBUS_TYPE_INVALID) { + print_iter(label, name, &subiter); + dbus_message_iter_next(&subiter); + } + break; + case DBUS_TYPE_DICT_ENTRY: + dbus_message_iter_recurse(iter, &subiter); + + if (dbus_message_iter_get_arg_type(&subiter) == + DBUS_TYPE_STRING) { + dbus_message_iter_get_basic(&subiter, &valstr); + entry = g_strconcat(name, ".", valstr, NULL); + } else { + entry = g_strconcat(name, ".Key", NULL); + print_iter(label, entry, &subiter); + g_free(entry); + + entry = g_strconcat(name, ".Value", NULL); + } + + dbus_message_iter_next(&subiter); + print_iter(label, entry, &subiter); + g_free(entry); + break; + default: + bt_shell_printf("%s%s has unsupported type\n", label, name); + break; + } +} + +void print_property_with_label(GDBusProxy *proxy, const char *name, + const char *label) +{ + DBusMessageIter iter; + + if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE) + return; + + print_iter("\t", label ? label : name, &iter); +} + +void print_property(GDBusProxy *proxy, const char *name) +{ + print_property_with_label(proxy, name, NULL); +} + +void print_uuid(const char *label, const char *name, const char *uuid) +{ + const char *text; + + text = bt_uuidstr_to_str(uuid); + if (text) { + char str[26]; + unsigned int n; + + str[sizeof(str) - 1] = '\0'; + + n = snprintf(str, sizeof(str), "%s", text); + if (n > sizeof(str) - 1) { + str[sizeof(str) - 2] = '.'; + str[sizeof(str) - 3] = '.'; + if (str[sizeof(str) - 4] == ' ') + str[sizeof(str) - 4] = '.'; + + n = sizeof(str) - 1; + } + + bt_shell_printf("%s%s: %s%*c(%s)\n", label, name, str, 26 - n, + ' ', uuid); + } else + bt_shell_printf("%s%s: %*c(%s)\n", label, name, 26, ' ', uuid); +} diff --git a/client/print.h b/client/print.h new file mode 100644 index 0000000000000000000000000000000000000000..56bcce16a66191180cbdd45a05a6443e77819305 --- /dev/null +++ b/client/print.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2022 Intel Corporation. All rights reserved. + * + * + */ + +void print_property(GDBusProxy *proxy, const char *name); +void print_property_with_label(GDBusProxy *proxy, const char *name, + const char *label); +void print_iter(const char *label, const char *name, DBusMessageIter *iter); +void print_uuid(const char *label, const char *name, const char *uuid); diff --git a/compile b/compile new file mode 100755 index 0000000000000000000000000000000000000000..df363c8fbfbcbba9df21d8c9455b58c038697b61 --- /dev/null +++ b/compile @@ -0,0 +1,348 @@ +#! /bin/sh +# Wrapper for compilers which do not understand '-c -o'. + +scriptversion=2018-03-07.03; # UTC + +# Copyright (C) 1999-2021 Free Software Foundation, Inc. +# Written by Tom Tromey <tromey@cygnus.com>. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to <bug-automake@gnu.org> or send patches to +# <automake-patches@gnu.org>. + +nl=' +' + +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent tools from complaining about whitespace usage. +IFS=" "" $nl" + +file_conv= + +# func_file_conv build_file lazy +# Convert a $build file to $host form and store it in $file +# Currently only supports Windows hosts. If the determined conversion +# type is listed in (the comma separated) LAZY, no conversion will +# take place. +func_file_conv () +{ + file=$1 + case $file in + / | /[!/]*) # absolute file, and not a UNC file + if test -z "$file_conv"; then + # lazily determine how to convert abs files + case `uname -s` in + MINGW*) + file_conv=mingw + ;; + CYGWIN* | MSYS*) + file_conv=cygwin + ;; + *) + file_conv=wine + ;; + esac + fi + case $file_conv/,$2, in + *,$file_conv,*) + ;; + mingw/*) + file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` + ;; + cygwin/* | msys/*) + file=`cygpath -m "$file" || echo "$file"` + ;; + wine/*) + file=`winepath -w "$file" || echo "$file"` + ;; + esac + ;; + esac +} + +# func_cl_dashL linkdir +# Make cl look for libraries in LINKDIR +func_cl_dashL () +{ + func_file_conv "$1" + if test -z "$lib_path"; then + lib_path=$file + else + lib_path="$lib_path;$file" + fi + linker_opts="$linker_opts -LIBPATH:$file" +} + +# func_cl_dashl library +# Do a library search-path lookup for cl +func_cl_dashl () +{ + lib=$1 + found=no + save_IFS=$IFS + IFS=';' + for dir in $lib_path $LIB + do + IFS=$save_IFS + if $shared && test -f "$dir/$lib.dll.lib"; then + found=yes + lib=$dir/$lib.dll.lib + break + fi + if test -f "$dir/$lib.lib"; then + found=yes + lib=$dir/$lib.lib + break + fi + if test -f "$dir/lib$lib.a"; then + found=yes + lib=$dir/lib$lib.a + break + fi + done + IFS=$save_IFS + + if test "$found" != yes; then + lib=$lib.lib + fi +} + +# func_cl_wrapper cl arg... +# Adjust compile command to suit cl +func_cl_wrapper () +{ + # Assume a capable shell + lib_path= + shared=: + linker_opts= + for arg + do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + eat=1 + case $2 in + *.o | *.[oO][bB][jJ]) + func_file_conv "$2" + set x "$@" -Fo"$file" + shift + ;; + *) + func_file_conv "$2" + set x "$@" -Fe"$file" + shift + ;; + esac + ;; + -I) + eat=1 + func_file_conv "$2" mingw + set x "$@" -I"$file" + shift + ;; + -I*) + func_file_conv "${1#-I}" mingw + set x "$@" -I"$file" + shift + ;; + -l) + eat=1 + func_cl_dashl "$2" + set x "$@" "$lib" + shift + ;; + -l*) + func_cl_dashl "${1#-l}" + set x "$@" "$lib" + shift + ;; + -L) + eat=1 + func_cl_dashL "$2" + ;; + -L*) + func_cl_dashL "${1#-L}" + ;; + -static) + shared=false + ;; + -Wl,*) + arg=${1#-Wl,} + save_ifs="$IFS"; IFS=',' + for flag in $arg; do + IFS="$save_ifs" + linker_opts="$linker_opts $flag" + done + IFS="$save_ifs" + ;; + -Xlinker) + eat=1 + linker_opts="$linker_opts $2" + ;; + -*) + set x "$@" "$1" + shift + ;; + *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) + func_file_conv "$1" + set x "$@" -Tp"$file" + shift + ;; + *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) + func_file_conv "$1" mingw + set x "$@" "$file" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift + done + if test -n "$linker_opts"; then + linker_opts="-link$linker_opts" + fi + exec "$@" $linker_opts + exit 1 +} + +eat= + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand '-c -o'. +Remove '-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file 'INSTALL'. + +Report bugs to <bug-automake@gnu.org>. +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; + cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ + icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) + func_cl_wrapper "$@" # Doesn't return... + ;; +esac + +ofile= +cfile= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + # So we strip '-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no '-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # '.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` + +# Create the lock directory. +# Note: use '[/\\:.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + test "$cofile" = "$ofile" || mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/config.guess b/config.guess new file mode 100755 index 0000000000000000000000000000000000000000..7f76b6228f73d674f58cfcc3523f99e253ee5515 --- /dev/null +++ b/config.guess @@ -0,0 +1,1754 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2022 Free Software Foundation, Inc. + +# shellcheck disable=SC2006,SC2268 # see below for rationale + +timestamp='2022-01-09' + +# 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses/>. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess +# +# Please send patches to <config-patches@gnu.org>. + + +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Options: + -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 1992-2022 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 + +# Just in case it came from the environment. +GUESS= + +# 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. + +tmp= +# shellcheck disable=SC2172 +trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 + +set_cc_for_build() { + # prevent multiple calls if $tmp is already set + test "$tmp" && return 0 + : "${TMPDIR=/tmp}" + # shellcheck disable=SC2039,SC3028 + { 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" 2>/dev/null) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } + dummy=$tmp/dummy + case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in + ,,) echo "int x;" > "$dummy.c" + for driver in cc gcc c89 c99 ; do + if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then + CC_FOR_BUILD=$driver + 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 +} + +# 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 ; 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 + +case $UNAME_SYSTEM in +Linux|GNU|GNU/*) + LIBC=unknown + + set_cc_for_build + cat <<-EOF > "$dummy.c" + #include <features.h> + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #elif defined(__GLIBC__) + LIBC=gnu + #else + #include <stdarg.h> + /* First heuristic to detect musl libc. */ + #ifdef __DEFINED_va_list + LIBC=musl + #endif + #endif + EOF + cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + eval "$cc_set_libc" + + # Second heuristic to detect musl libc. + if [ "$LIBC" = unknown ] && + command -v ldd >/dev/null && + ldd --version 2>&1 | grep -q ^musl; then + LIBC=musl + fi + + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + if [ "$LIBC" = unknown ]; then + LIBC=gnu + fi + ;; +esac + +# 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 tuples: *-*-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". + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + echo unknown)` + case $UNAME_MACHINE_ARCH in + aarch64eb) machine=aarch64_be-unknown ;; + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-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) and ABI. + case $UNAME_MACHINE_ARCH in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + 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 + # Determine ABI tags. + case $UNAME_MACHINE_ARCH in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` + ;; + 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/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + GUESS=$machine-${os}${release}${abi-} + ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE + ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE + ;; + *:SecBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE + ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE + ;; + *:MidnightBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE + ;; + *:ekkoBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE + ;; + *:SolidBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE + ;; + *:OS108:*:*) + GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE + ;; + macppc:MirBSD:*:*) + GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE + ;; + *:MirBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE + ;; + *:Sortix:*:*) + GUESS=$UNAME_MACHINE-unknown-sortix + ;; + *:Twizzler:*:*) + GUESS=$UNAME_MACHINE-unknown-twizzler + ;; + *:Redox:*:*) + GUESS=$UNAME_MACHINE-unknown-redox + ;; + mips:OSF1:*.*) + GUESS=mips-dec-osf1 + ;; + alpha:OSF1:*:*) + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + trap '' 0 + 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. + OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + GUESS=$UNAME_MACHINE-dec-osf$OSF_REL + ;; + Amiga*:UNIX_System_V:4.0:*) + GUESS=m68k-unknown-sysv4 + ;; + *:[Aa]miga[Oo][Ss]:*:*) + GUESS=$UNAME_MACHINE-unknown-amigaos + ;; + *:[Mm]orph[Oo][Ss]:*:*) + GUESS=$UNAME_MACHINE-unknown-morphos + ;; + *:OS/390:*:*) + GUESS=i370-ibm-openedition + ;; + *:z/VM:*:*) + GUESS=s390-ibm-zvmoe + ;; + *:OS400:*:*) + GUESS=powerpc-ibm-os400 + ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + GUESS=arm-acorn-riscix$UNAME_RELEASE + ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + GUESS=arm-unknown-riscos + ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + GUESS=hppa1.1-hitachi-hiuxmpp + ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + case `(/bin/universe) 2>/dev/null` in + att) GUESS=pyramid-pyramid-sysv3 ;; + *) GUESS=pyramid-pyramid-bsd ;; + esac + ;; + NILE*:*:*:dcosx) + GUESS=pyramid-pyramid-svr4 + ;; + DRS?6000:unix:4.0:6*) + GUESS=sparc-icl-nx6 + ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) GUESS=sparc-icl-nx7 ;; + esac + ;; + s390x:SunOS:*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL + ;; + sun4H:SunOS:5.*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-hal-solaris2$SUN_REL + ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris2$SUN_REL + ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + GUESS=i386-pc-auroraux$UNAME_RELEASE + ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + set_cc_for_build + SUN_ARCH=i386 + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if test "$CC_FOR_BUILD" != no_compiler_found; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH=x86_64 + fi + fi + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$SUN_ARCH-pc-solaris2$SUN_REL + ;; + 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. + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris3$SUN_REL + ;; + 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'. + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` + GUESS=sparc-sun-sunos$SUN_REL + ;; + sun3*:SunOS:*:*) + GUESS=m68k-sun-sunos$UNAME_RELEASE + ;; + 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) + GUESS=m68k-sun-sunos$UNAME_RELEASE + ;; + sun4) + GUESS=sparc-sun-sunos$UNAME_RELEASE + ;; + esac + ;; + aushp:SunOS:*:*) + GUESS=sparc-auspex-sunos$UNAME_RELEASE + ;; + # 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:*:*) + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + GUESS=m68k-milan-mint$UNAME_RELEASE + ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + GUESS=m68k-hades-mint$UNAME_RELEASE + ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + GUESS=m68k-unknown-mint$UNAME_RELEASE + ;; + m68k:machten:*:*) + GUESS=m68k-apple-machten$UNAME_RELEASE + ;; + powerpc:machten:*:*) + GUESS=powerpc-apple-machten$UNAME_RELEASE + ;; + RISC*:Mach:*:*) + GUESS=mips-dec-mach_bsd4.3 + ;; + RISC*:ULTRIX:*:*) + GUESS=mips-dec-ultrix$UNAME_RELEASE + ;; + VAX*:ULTRIX*:*:*) + GUESS=vax-dec-ultrix$UNAME_RELEASE + ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + GUESS=clipper-intergraph-clix$UNAME_RELEASE + ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + 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; } + GUESS=mips-mips-riscos$UNAME_RELEASE + ;; + Motorola:PowerMAX_OS:*:*) + GUESS=powerpc-motorola-powermax + ;; + Motorola:*:4.3:PL8-*) + GUESS=powerpc-harris-powermax + ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + GUESS=powerpc-harris-powermax + ;; + Night_Hawk:Power_UNIX:*:*) + GUESS=powerpc-harris-powerunix + ;; + m88k:CX/UX:7*:*) + GUESS=m88k-harris-cxux7 + ;; + m88k:*:4*:R4*) + GUESS=m88k-motorola-sysv4 + ;; + m88k:*:3*:R3*) + GUESS=m88k-motorola-sysv3 + ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 + then + if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ + test "$TARGET_BINARY_INTERFACE"x = x + then + GUESS=m88k-dg-dgux$UNAME_RELEASE + else + GUESS=m88k-dg-dguxbcs$UNAME_RELEASE + fi + else + GUESS=i586-dg-dgux$UNAME_RELEASE + fi + ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + GUESS=m88k-dolphin-sysv3 + ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + GUESS=m88k-motorola-sysv3 + ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + GUESS=m88k-tektronix-sysv3 + ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + GUESS=m68k-tektronix-bsd + ;; + *:IRIX*:*:*) + IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` + GUESS=mips-sgi-irix$IRIX_REL + ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id + ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + GUESS=i386-ibm-aix + ;; + ia64:AIX:*:*) + if test -x /usr/bin/oslevel ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE + fi + GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV + ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + 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 + GUESS=$SYSTEM_NAME + else + GUESS=rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + GUESS=rs6000-ibm-aix3.2.4 + else + GUESS=rs6000-ibm-aix3.2 + fi + ;; + *:AIX:*:[4567]) + 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 test -x /usr/bin/lslpp ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE + fi + GUESS=$IBM_ARCH-ibm-aix$IBM_REV + ;; + *:AIX:*:*) + GUESS=rs6000-ibm-aix + ;; + ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) + GUESS=romp-ibm-bsd4.4 + ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to + ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + GUESS=rs6000-bull-bosx + ;; + DPX/2?00:B.O.S.:*:*) + GUESS=m68k-bull-sysv3 + ;; + 9000/[34]??:4.3bsd:1.*:*) + GUESS=m68k-hp-bsd + ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + GUESS=m68k-hp-bsd4.4 + ;; + 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 test -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 test "$HP_ARCH" = ""; then + 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 test "$HP_ARCH" = hppa2.0w + then + 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 -q __LP64__ + then + HP_ARCH=hppa2.0w + else + HP_ARCH=hppa64 + fi + fi + GUESS=$HP_ARCH-hp-hpux$HPUX_REV + ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + GUESS=ia64-hp-hpux$HPUX_REV + ;; + 3050*:HI-UX:*:*) + 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; } + GUESS=unknown-hitachi-hiuxwe2 + ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) + GUESS=hppa1.1-hp-bsd + ;; + 9000/8??:4.3bsd:*:*) + GUESS=hppa1.0-hp-bsd + ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + GUESS=hppa1.0-hp-mpeix + ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) + GUESS=hppa1.1-hp-osf + ;; + hp8??:OSF1:*:*) + GUESS=hppa1.0-hp-osf + ;; + i*86:OSF1:*:*) + if test -x /usr/sbin/sysversion ; then + GUESS=$UNAME_MACHINE-unknown-osf1mk + else + GUESS=$UNAME_MACHINE-unknown-osf1 + fi + ;; + parisc*:Lites*:*:*) + GUESS=hppa1.1-hp-lites + ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + GUESS=c1-convex-bsd + ;; + 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*:*) + GUESS=c34-convex-bsd + ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + GUESS=c38-convex-bsd + ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + GUESS=c4-convex-bsd + ;; + CRAY*Y-MP:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=ymp-cray-unicos$CRAY_REL + ;; + 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:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=t90-cray-unicos$CRAY_REL + ;; + CRAY*T3E:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=alphaev5-cray-unicosmk$CRAY_REL + ;; + CRAY*SV1:*:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=sv1-cray-unicos$CRAY_REL + ;; + *:UNICOS/mp:*:*) + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=craynv-cray-unicosmp$CRAY_REL + ;; + 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/ /_/'` + GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; + 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/ /_/'` + GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE + ;; + sparc*:BSD/OS:*:*) + GUESS=sparc-unknown-bsdi$UNAME_RELEASE + ;; + *:BSD/OS:*:*) + GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE + ;; + arm:FreeBSD:*:*) + UNAME_PROCESSOR=`uname -p` + set_cc_for_build + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi + else + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf + fi + ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case $UNAME_PROCESSOR in + amd64) + UNAME_PROCESSOR=x86_64 ;; + i386) + UNAME_PROCESSOR=i586 ;; + esac + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL + ;; + i*:CYGWIN*:*) + GUESS=$UNAME_MACHINE-pc-cygwin + ;; + *:MINGW64*:*) + GUESS=$UNAME_MACHINE-pc-mingw64 + ;; + *:MINGW*:*) + GUESS=$UNAME_MACHINE-pc-mingw32 + ;; + *:MSYS*:*) + GUESS=$UNAME_MACHINE-pc-msys + ;; + i*:PW*:*) + GUESS=$UNAME_MACHINE-pc-pw32 + ;; + *:SerenityOS:*:*) + GUESS=$UNAME_MACHINE-pc-serenity + ;; + *:Interix*:*) + case $UNAME_MACHINE in + x86) + GUESS=i586-pc-interix$UNAME_RELEASE + ;; + authenticamd | genuineintel | EM64T) + GUESS=x86_64-unknown-interix$UNAME_RELEASE + ;; + IA64) + GUESS=ia64-unknown-interix$UNAME_RELEASE + ;; + esac ;; + i*:UWIN*:*) + GUESS=$UNAME_MACHINE-pc-uwin + ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + GUESS=x86_64-pc-cygwin + ;; + prep*:SunOS:5.*:*) + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=powerpcle-unknown-solaris2$SUN_REL + ;; + *:GNU:*:*) + # the GNU system + GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` + GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL + ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC + ;; + *:Minix:*:*) + GUESS=$UNAME_MACHINE-unknown-minix + ;; + aarch64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` 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 -q ld.so.1 + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + arm*:Linux:*:*) + set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi + else + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf + fi + fi + ;; + avr32*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + cris:Linux:*:*) + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; + crisv32:Linux:*:*) + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; + e2k:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + frv:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + hexagon:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + i*86:Linux:*:*) + GUESS=$UNAME_MACHINE-pc-linux-$LIBC + ;; + ia64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + k1om:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + m32r*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + m68*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + mips:Linux:*:* | mips64:Linux:*:*) + set_cc_for_build + IS_GLIBC=0 + test x"${LIBC}" = xgnu && IS_GLIBC=1 + sed 's/^ //' << EOF > "$dummy.c" + #undef CPU + #undef mips + #undef mipsel + #undef mips64 + #undef mips64el + #if ${IS_GLIBC} && defined(_ABI64) + LIBCABI=gnuabi64 + #else + #if ${IS_GLIBC} && defined(_ABIN32) + LIBCABI=gnuabin32 + #else + LIBCABI=${LIBC} + #endif + #endif + + #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 + CPU=mipsisa64r6 + #else + #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 + CPU=mipsisa32r6 + #else + #if defined(__mips64) + CPU=mips64 + #else + CPU=mips + #endif + #endif + #endif + + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + MIPS_ENDIAN=el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + MIPS_ENDIAN= + #else + MIPS_ENDIAN= + #endif + #endif +EOF + cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` + eval "$cc_set_vars" + test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } + ;; + mips64el:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + openrisc*:Linux:*:*) + GUESS=or1k-unknown-linux-$LIBC + ;; + or32:Linux:*:* | or1k*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + padre:Linux:*:*) + GUESS=sparc-unknown-linux-$LIBC + ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + GUESS=hppa64-unknown-linux-$LIBC + ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; + PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; + *) GUESS=hppa-unknown-linux-$LIBC ;; + esac + ;; + ppc64:Linux:*:*) + GUESS=powerpc64-unknown-linux-$LIBC + ;; + ppc:Linux:*:*) + GUESS=powerpc-unknown-linux-$LIBC + ;; + ppc64le:Linux:*:*) + GUESS=powerpc64le-unknown-linux-$LIBC + ;; + ppcle:Linux:*:*) + GUESS=powerpcle-unknown-linux-$LIBC + ;; + riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + s390:Linux:*:* | s390x:Linux:*:*) + GUESS=$UNAME_MACHINE-ibm-linux-$LIBC + ;; + sh64*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + sh*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + tile*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + vax:Linux:*:*) + GUESS=$UNAME_MACHINE-dec-linux-$LIBC + ;; + x86_64:Linux:*:*) + set_cc_for_build + LIBCABI=$LIBC + if test "$CC_FOR_BUILD" != no_compiler_found; then + if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_X32 >/dev/null + then + LIBCABI=${LIBC}x32 + fi + fi + GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI + ;; + xtensa*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + 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. + GUESS=i386-sequent-sysv4 + ;; + 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. + GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION + ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + GUESS=$UNAME_MACHINE-pc-os2-emx + ;; + i*86:XTS-300:*:STOP) + GUESS=$UNAME_MACHINE-unknown-stop + ;; + i*86:atheos:*:*) + GUESS=$UNAME_MACHINE-unknown-atheos + ;; + i*86:syllable:*:*) + GUESS=$UNAME_MACHINE-pc-syllable + ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + GUESS=i386-unknown-lynxos$UNAME_RELEASE + ;; + i*86:*DOS:*:*) + GUESS=$UNAME_MACHINE-pc-msdosdjgpp + ;; + i*86:*:4.*:*) + UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL + else + GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL + fi + ;; + 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 + GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + GUESS=$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 + GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL + else + GUESS=$UNAME_MACHINE-pc-sysv32 + fi + ;; + 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 i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configure will decide that + # this is a cross-build. + GUESS=i586-pc-msdosdjgpp + ;; + Intel:Mach:3*:*) + GUESS=i386-pc-mach3 + ;; + paragon:*:*:*) + GUESS=i860-intel-osf1 + ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 + fi + ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + GUESS=m68010-convergent-sysv + ;; + mc68k:UNIX:SYSTEM5:3.51m) + GUESS=m68k-convergent-sysv + ;; + M680?0:D-NIX:5.3:*) + GUESS=m68k-diab-dnix + ;; + 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; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + 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; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + GUESS=m68k-unknown-lynxos$UNAME_RELEASE + ;; + mc68030:UNIX_System_V:4.*:*) + GUESS=m68k-atari-sysv4 + ;; + TSUNAMI:LynxOS:2.*:*) + GUESS=sparc-unknown-lynxos$UNAME_RELEASE + ;; + rs6000:LynxOS:2.*:*) + GUESS=rs6000-unknown-lynxos$UNAME_RELEASE + ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + GUESS=powerpc-unknown-lynxos$UNAME_RELEASE + ;; + SM[BE]S:UNIX_SV:*:*) + GUESS=mips-dde-sysv$UNAME_RELEASE + ;; + RM*:ReliantUNIX-*:*:*) + GUESS=mips-sni-sysv4 + ;; + RM*:SINIX-*:*:*) + GUESS=mips-sni-sysv4 + ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + GUESS=$UNAME_MACHINE-sni-sysv4 + else + GUESS=ns32k-sni-sysv + fi + ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <Richard.M.Bartel@ccMail.Census.GOV> + GUESS=i586-unisys-sysv4 + ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <hewes@openmarket.com>. + # How about differentiating between stratus architectures? -djm + GUESS=hppa1.1-stratus-sysv4 + ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + GUESS=i860-stratus-sysv4 + ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + GUESS=$UNAME_MACHINE-stratus-vos + ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + GUESS=hppa1.1-stratus-vos + ;; + mc68*:A/UX:*:*) + GUESS=m68k-apple-aux$UNAME_RELEASE + ;; + news*:NEWS-OS:6*:*) + GUESS=mips-sony-newsos6 + ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if test -d /usr/nec; then + GUESS=mips-nec-sysv$UNAME_RELEASE + else + GUESS=mips-unknown-sysv$UNAME_RELEASE + fi + ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + GUESS=powerpc-be-beos + ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + GUESS=powerpc-apple-beos + ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + GUESS=i586-pc-beos + ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + GUESS=i586-pc-haiku + ;; + x86_64:Haiku:*:*) + GUESS=x86_64-unknown-haiku + ;; + SX-4:SUPER-UX:*:*) + GUESS=sx4-nec-superux$UNAME_RELEASE + ;; + SX-5:SUPER-UX:*:*) + GUESS=sx5-nec-superux$UNAME_RELEASE + ;; + SX-6:SUPER-UX:*:*) + GUESS=sx6-nec-superux$UNAME_RELEASE + ;; + SX-7:SUPER-UX:*:*) + GUESS=sx7-nec-superux$UNAME_RELEASE + ;; + SX-8:SUPER-UX:*:*) + GUESS=sx8-nec-superux$UNAME_RELEASE + ;; + SX-8R:SUPER-UX:*:*) + GUESS=sx8r-nec-superux$UNAME_RELEASE + ;; + SX-ACE:SUPER-UX:*:*) + GUESS=sxace-nec-superux$UNAME_RELEASE + ;; + Power*:Rhapsody:*:*) + GUESS=powerpc-apple-rhapsody$UNAME_RELEASE + ;; + *:Rhapsody:*:*) + GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE + ;; + arm64:Darwin:*:*) + GUESS=aarch64-apple-darwin$UNAME_RELEASE + ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + if command -v xcode-select > /dev/null 2> /dev/null && \ + ! xcode-select --print-path > /dev/null 2> /dev/null ; then + # Avoid executing cc if there is no toolchain installed as + # cc will be a stub that puts up a graphical alert + # prompting the user to install developer tools. + CC_FOR_BUILD=no_compiler_found + else + set_cc_for_build + fi + if test "$CC_FOR_BUILD" != no_compiler_found; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc + if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_PPC >/dev/null + then + UNAME_PROCESSOR=powerpc + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # uname -m returns i386 or x86_64 + UNAME_PROCESSOR=$UNAME_MACHINE + fi + GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE + ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = x86; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE + ;; + *:QNX:*:4*) + GUESS=i386-pc-qnx + ;; + NEO-*:NONSTOP_KERNEL:*:*) + GUESS=neo-tandem-nsk$UNAME_RELEASE + ;; + NSE-*:NONSTOP_KERNEL:*:*) + GUESS=nse-tandem-nsk$UNAME_RELEASE + ;; + NSR-*:NONSTOP_KERNEL:*:*) + GUESS=nsr-tandem-nsk$UNAME_RELEASE + ;; + NSV-*:NONSTOP_KERNEL:*:*) + GUESS=nsv-tandem-nsk$UNAME_RELEASE + ;; + NSX-*:NONSTOP_KERNEL:*:*) + GUESS=nsx-tandem-nsk$UNAME_RELEASE + ;; + *:NonStop-UX:*:*) + GUESS=mips-compaq-nonstopux + ;; + BS2000:POSIX*:*:*) + GUESS=bs2000-siemens-sysv + ;; + DS/*:UNIX_System_V:*:*) + GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE + ;; + *: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 + elif test "x${cputype-}" != x; then + UNAME_MACHINE=$cputype + fi + GUESS=$UNAME_MACHINE-unknown-plan9 + ;; + *:TOPS-10:*:*) + GUESS=pdp10-unknown-tops10 + ;; + *:TENEX:*:*) + GUESS=pdp10-unknown-tenex + ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + GUESS=pdp10-dec-tops20 + ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + GUESS=pdp10-xkl-tops20 + ;; + *:TOPS-20:*:*) + GUESS=pdp10-unknown-tops20 + ;; + *:ITS:*:*) + GUESS=pdp10-unknown-its + ;; + SEI:*:*:SEIUX) + GUESS=mips-sei-seiux$UNAME_RELEASE + ;; + *:DragonFly:*:*) + DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL + ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case $UNAME_MACHINE in + A*) GUESS=alpha-dec-vms ;; + I*) GUESS=ia64-dec-vms ;; + V*) GUESS=vax-dec-vms ;; + esac ;; + *:XENIX:*:SysV) + GUESS=i386-pc-xenix + ;; + i*86:skyos:*:*) + SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` + GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL + ;; + i*86:rdos:*:*) + GUESS=$UNAME_MACHINE-pc-rdos + ;; + i*86:Fiwix:*:*) + GUESS=$UNAME_MACHINE-pc-fiwix + ;; + *:AROS:*:*) + GUESS=$UNAME_MACHINE-unknown-aros + ;; + x86_64:VMkernel:*:*) + GUESS=$UNAME_MACHINE-unknown-esx + ;; + amd64:Isilon\ OneFS:*:*) + GUESS=x86_64-unknown-onefs + ;; + *:Unleashed:*:*) + GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE + ;; +esac + +# Do we have a guess based on uname results? +if test "x$GUESS" != x; then + echo "$GUESS" + exit +fi + +# No uname command or uname output not recognized. +set_cc_for_build +cat > "$dummy.c" <<EOF +#ifdef _SEQUENT_ +#include <sys/types.h> +#include <sys/utsname.h> +#endif +#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) +#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) +#include <signal.h> +#if defined(_SIZE_T_) || defined(SIGLOST) +#include <sys/utsname.h> +#endif +#endif +#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 (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 +#if defined(_SIZE_T_) || defined(SIGLOST) + struct utsname un; + uname (&un); + printf ("vax-dec-ultrix%s\n", un.release); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif +#endif +#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) +#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) +#if defined(_SIZE_T_) || defined(SIGLOST) + struct utsname *un; + uname (&un); + printf ("mips-dec-ultrix%s\n", un.release); exit (0); +#else + printf ("mips-dec-ultrix\n"); exit (0); +#endif +#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; } + +echo "$0: unable to guess system type" >&2 + +case $UNAME_MACHINE:$UNAME_SYSTEM in + mips:Linux | mips64:Linux) + # If we got here on MIPS GNU/Linux, output extra information. + cat >&2 <<EOF + +NOTE: MIPS GNU/Linux systems require a C compiler to fully recognize +the system type. Please install a C compiler and try again. +EOF + ;; +esac + +cat >&2 <<EOF + +This script (version $timestamp), has failed to recognize the +operating system you are using. If your script is old, overwrite *all* +copies of config.guess and config.sub with the latest versions from: + + https://git.savannah.gnu.org/cgit/config.git/plain/config.guess +and + https://git.savannah.gnu.org/cgit/config.git/plain/config.sub +EOF + +our_year=`echo $timestamp | sed 's,-.*,,'` +thisyear=`date +%Y` +# shellcheck disable=SC2003 +script_age=`expr "$thisyear" - "$our_year"` +if test "$script_age" -lt 3 ; then + cat >&2 <<EOF + +If $0 has already been updated, send the following data and any +information you think might be pertinent to config-patches@gnu.org to +provide the necessary 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 +fi + +exit 1 + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000000000000000000000000000000000000..0488e5bb48eada9630b784bc7ccb6c84b76a3f17 --- /dev/null +++ b/config.h.in @@ -0,0 +1,145 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Directory for the Android daemon storage files */ +#undef ANDROID_STORAGEDIR + +/* Directory for the configuration files */ +#undef CONFIGDIR + +/* Define if external plugin support is required */ +#undef EXTERNAL_PLUGINS + +/* Define to 1 if you have the backtrace support. */ +#undef HAVE_BACKTRACE_SUPPORT + +/* Define to 1 if you have the declaration of 'basename', and to 0 if you + don't. */ +#undef HAVE_DECL_BASENAME + +/* Define to 1 if you have the <dlfcn.h> header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the 'explicit_bzero' function. */ +#undef HAVE_EXPLICIT_BZERO + +/* Define to 1 if you have the 'getrandom' function. */ +#undef HAVE_GETRANDOM + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the 'asan' library (-lasan). */ +#undef HAVE_LIBASAN + +/* Define to 1 if you have the 'lsan' library (-llsan). */ +#undef HAVE_LIBLSAN + +/* Define to 1 if you have the 'ubsan' library (-lubsan). */ +#undef HAVE_LIBUBSAN + +/* Define to 1 if you have the <linux/if_alg.h> header file. */ +#undef HAVE_LINUX_IF_ALG_H + +/* Define to 1 if you have the <linux/types.h> header file. */ +#undef HAVE_LINUX_TYPES_H + +/* Define to 1 if you have the <linux/uhid.h> header file. */ +#undef HAVE_LINUX_UHID_H + +/* Define to 1 if you have the <linux/uinput.h> header file. */ +#undef HAVE_LINUX_UINPUT_H + +/* Define to 1 if you have the 'rawmemchr' function. */ +#undef HAVE_RAWMEMCHR + +/* Define to 1 if you have the <readline/readline.h> header file. */ +#undef HAVE_READLINE_READLINE_H + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdio.h> header file. */ +#undef HAVE_STDIO_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/random.h> header file. */ +#undef HAVE_SYS_RANDOM_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 udev is required */ +#undef HAVE_UDEV + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the <valgrind/memcheck.h> header file. */ +#undef HAVE_VALGRIND_MEMCHECK_H + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#undef LT_OBJDIR + +/* Directory for the mesh daemon storage files */ +#undef MESH_STORAGEDIR + +/* Define if threading support is required */ +#undef NEED_THREADS + +/* 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 home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if all of the C89 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ +#undef STDC_HEADERS + +/* Directory for the storage files */ +#undef STORAGEDIR + +/* Version number of package */ +#undef VERSION + +/* Define to the equivalent of the C99 'restrict' keyword, or to + nothing if this is not supported. Do not define if restrict is + supported only directly. */ +#undef restrict +/* Work around a bug in older versions of Sun C++, which did not + #define __restrict__ or support _Restrict or __restrict__ + even though the corresponding Sun C compiler ended up with + "#define restrict _Restrict" or "#define restrict __restrict__" + in the previous line. This workaround can be removed once + we assume Oracle Developer Studio 12.5 (2016) or later. */ +#if defined __SUNPRO_CC && !defined __RESTRICT && !defined __restrict__ +# define _Restrict +# define __restrict__ +#endif diff --git a/config.sub b/config.sub new file mode 100755 index 0000000000000000000000000000000000000000..dba16e84c77c7d25871d80c24deff717faf4c094 --- /dev/null +++ b/config.sub @@ -0,0 +1,1890 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2022 Free Software Foundation, Inc. + +# shellcheck disable=SC2006,SC2268 # see below for rationale + +timestamp='2022-01-03' + +# 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses/>. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to <config-patches@gnu.org>. +# +# 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. + +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub + +# 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. + +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Options: + -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 1992-2022 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 ;; + + *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 + +# Split fields of configuration type +# shellcheck disable=SC2162 +saved_IFS=$IFS +IFS="-" read field1 field2 field3 field4 <<EOF +$1 +EOF +IFS=$saved_IFS + +# Separate into logical components for further validation +case $1 in + *-*-*-*-*) + echo Invalid configuration \`"$1"\': more than four components >&2 + exit 1 + ;; + *-*-*-*) + basic_machine=$field1-$field2 + basic_os=$field3-$field4 + ;; + *-*-*) + # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two + # parts + maybe_os=$field2-$field3 + case $maybe_os in + nto-qnx* | linux-* | uclinux-uclibc* \ + | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ + | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ + | storm-chaos* | os2-emx* | rtmk-nova*) + basic_machine=$field1 + basic_os=$maybe_os + ;; + android-linux) + basic_machine=$field1-unknown + basic_os=linux-android + ;; + *) + basic_machine=$field1-$field2 + basic_os=$field3 + ;; + esac + ;; + *-*) + # A lone config we happen to match not fitting any pattern + case $field1-$field2 in + decstation-3100) + basic_machine=mips-dec + basic_os= + ;; + *-*) + # Second component is usually, but not always the OS + case $field2 in + # Prevent following clause from handling this valid os + sun*os*) + basic_machine=$field1 + basic_os=$field2 + ;; + zephyr*) + basic_machine=$field1-unknown + basic_os=$field2 + ;; + # Manufacturers + dec* | mips* | sequent* | encore* | pc533* | 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 \ + | microblaze* | sim | cisco \ + | oki | wec | wrs | winbond) + basic_machine=$field1-$field2 + basic_os= + ;; + *) + basic_machine=$field1 + basic_os=$field2 + ;; + esac + ;; + esac + ;; + *) + # Convert single-component short-hands not valid as part of + # multi-component configurations. + case $field1 in + 386bsd) + basic_machine=i386-pc + basic_os=bsd + ;; + a29khif) + basic_machine=a29k-amd + basic_os=udi + ;; + adobe68k) + basic_machine=m68010-adobe + basic_os=scout + ;; + alliant) + basic_machine=fx80-alliant + basic_os= + ;; + altos | altos3068) + basic_machine=m68k-altos + basic_os= + ;; + am29k) + basic_machine=a29k-none + basic_os=bsd + ;; + amdahl) + basic_machine=580-amdahl + basic_os=sysv + ;; + amiga) + basic_machine=m68k-unknown + basic_os= + ;; + amigaos | amigados) + basic_machine=m68k-unknown + basic_os=amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + basic_os=sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + basic_os=sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + basic_os=bsd + ;; + aros) + basic_machine=i386-pc + basic_os=aros + ;; + aux) + basic_machine=m68k-apple + basic_os=aux + ;; + balance) + basic_machine=ns32k-sequent + basic_os=dynix + ;; + blackfin) + basic_machine=bfin-unknown + basic_os=linux + ;; + cegcc) + basic_machine=arm-unknown + basic_os=cegcc + ;; + convex-c1) + basic_machine=c1-convex + basic_os=bsd + ;; + convex-c2) + basic_machine=c2-convex + basic_os=bsd + ;; + convex-c32) + basic_machine=c32-convex + basic_os=bsd + ;; + convex-c34) + basic_machine=c34-convex + basic_os=bsd + ;; + convex-c38) + basic_machine=c38-convex + basic_os=bsd + ;; + cray) + basic_machine=j90-cray + basic_os=unicos + ;; + crds | unos) + basic_machine=m68k-crds + basic_os= + ;; + da30) + basic_machine=m68k-da30 + basic_os= + ;; + decstation | pmax | pmin | dec3100 | decstatn) + basic_machine=mips-dec + basic_os= + ;; + delta88) + basic_machine=m88k-motorola + basic_os=sysv3 + ;; + dicos) + basic_machine=i686-pc + basic_os=dicos + ;; + djgpp) + basic_machine=i586-pc + basic_os=msdosdjgpp + ;; + ebmon29k) + basic_machine=a29k-amd + basic_os=ebmon + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + basic_os=ose + ;; + gmicro) + basic_machine=tron-gmicro + basic_os=sysv + ;; + go32) + basic_machine=i386-pc + basic_os=go32 + ;; + h8300hms) + basic_machine=h8300-hitachi + basic_os=hms + ;; + h8300xray) + basic_machine=h8300-hitachi + basic_os=xray + ;; + h8500hms) + basic_machine=h8500-hitachi + basic_os=hms + ;; + harris) + basic_machine=m88k-harris + basic_os=sysv3 + ;; + hp300 | hp300hpux) + basic_machine=m68k-hp + basic_os=hpux + ;; + hp300bsd) + basic_machine=m68k-hp + basic_os=bsd + ;; + hppaosf) + basic_machine=hppa1.1-hp + basic_os=osf + ;; + hppro) + basic_machine=hppa1.1-hp + basic_os=proelf + ;; + i386mach) + basic_machine=i386-mach + basic_os=mach + ;; + isi68 | isi) + basic_machine=m68k-isi + basic_os=sysv + ;; + m68knommu) + basic_machine=m68k-unknown + basic_os=linux + ;; + magnum | m3230) + basic_machine=mips-mips + basic_os=sysv + ;; + merlin) + basic_machine=ns32k-utek + basic_os=sysv + ;; + mingw64) + basic_machine=x86_64-pc + basic_os=mingw64 + ;; + mingw32) + basic_machine=i686-pc + basic_os=mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + basic_os=mingw32ce + ;; + monitor) + basic_machine=m68k-rom68k + basic_os=coff + ;; + morphos) + basic_machine=powerpc-unknown + basic_os=morphos + ;; + moxiebox) + basic_machine=moxie-unknown + basic_os=moxiebox + ;; + msdos) + basic_machine=i386-pc + basic_os=msdos + ;; + msys) + basic_machine=i686-pc + basic_os=msys + ;; + mvs) + basic_machine=i370-ibm + basic_os=mvs + ;; + nacl) + basic_machine=le32-unknown + basic_os=nacl + ;; + ncr3000) + basic_machine=i486-ncr + basic_os=sysv4 + ;; + netbsd386) + basic_machine=i386-pc + basic_os=netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + basic_os=linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + basic_os=newsos + ;; + news1000) + basic_machine=m68030-sony + basic_os=newsos + ;; + necv70) + basic_machine=v70-nec + basic_os=sysv + ;; + nh3000) + basic_machine=m68k-harris + basic_os=cxux + ;; + nh[45]000) + basic_machine=m88k-harris + basic_os=cxux + ;; + nindy960) + basic_machine=i960-intel + basic_os=nindy + ;; + mon960) + basic_machine=i960-intel + basic_os=mon960 + ;; + nonstopux) + basic_machine=mips-compaq + basic_os=nonstopux + ;; + os400) + basic_machine=powerpc-ibm + basic_os=os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + basic_os=ose + ;; + os68k) + basic_machine=m68k-none + basic_os=os68k + ;; + paragon) + basic_machine=i860-intel + basic_os=osf + ;; + parisc) + basic_machine=hppa-unknown + basic_os=linux + ;; + psp) + basic_machine=mipsallegrexel-sony + basic_os=psp + ;; + pw32) + basic_machine=i586-unknown + basic_os=pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + basic_os=rdos + ;; + rdos32) + basic_machine=i386-pc + basic_os=rdos + ;; + rom68k) + basic_machine=m68k-rom68k + basic_os=coff + ;; + sa29200) + basic_machine=a29k-amd + basic_os=udi + ;; + sei) + basic_machine=mips-sei + basic_os=seiux + ;; + sequent) + basic_machine=i386-sequent + basic_os= + ;; + sps7) + basic_machine=m68k-bull + basic_os=sysv2 + ;; + st2000) + basic_machine=m68k-tandem + basic_os= + ;; + stratus) + basic_machine=i860-stratus + basic_os=sysv4 + ;; + sun2) + basic_machine=m68000-sun + basic_os= + ;; + sun2os3) + basic_machine=m68000-sun + basic_os=sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + basic_os=sunos4 + ;; + sun3) + basic_machine=m68k-sun + basic_os= + ;; + sun3os3) + basic_machine=m68k-sun + basic_os=sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + basic_os=sunos4 + ;; + sun4) + basic_machine=sparc-sun + basic_os= + ;; + sun4os3) + basic_machine=sparc-sun + basic_os=sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + basic_os=sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + basic_os=solaris2 + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + basic_os= + ;; + sv1) + basic_machine=sv1-cray + basic_os=unicos + ;; + symmetry) + basic_machine=i386-sequent + basic_os=dynix + ;; + t3e) + basic_machine=alphaev5-cray + basic_os=unicos + ;; + t90) + basic_machine=t90-cray + basic_os=unicos + ;; + toad1) + basic_machine=pdp10-xkl + basic_os=tops20 + ;; + tpf) + basic_machine=s390x-ibm + basic_os=tpf + ;; + udi29k) + basic_machine=a29k-amd + basic_os=udi + ;; + ultra3) + basic_machine=a29k-nyu + basic_os=sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + basic_os=none + ;; + vaxv) + basic_machine=vax-dec + basic_os=sysv + ;; + vms) + basic_machine=vax-dec + basic_os=vms + ;; + vsta) + basic_machine=i386-pc + basic_os=vsta + ;; + vxworks960) + basic_machine=i960-wrs + basic_os=vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + basic_os=vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + basic_os=vxworks + ;; + xbox) + basic_machine=i686-pc + basic_os=mingw32 + ;; + ymp) + basic_machine=ymp-cray + basic_os=unicos + ;; + *) + basic_machine=$1 + basic_os= + ;; + esac + ;; +esac + +# Decode 1-component or ad-hoc basic machines +case $basic_machine in + # 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) + cpu=hppa1.1 + vendor=winbond + ;; + op50n) + cpu=hppa1.1 + vendor=oki + ;; + op60c) + cpu=hppa1.1 + vendor=oki + ;; + ibm*) + cpu=i370 + vendor=ibm + ;; + orion105) + cpu=clipper + vendor=highlevel + ;; + mac | mpw | mac-mpw) + cpu=m68k + vendor=apple + ;; + pmac | pmac-mpw) + cpu=powerpc + vendor=apple + ;; + + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + cpu=m68000 + vendor=att + ;; + 3b*) + cpu=we32k + vendor=att + ;; + bluegene*) + cpu=powerpc + vendor=ibm + basic_os=cnk + ;; + decsystem10* | dec10*) + cpu=pdp10 + vendor=dec + basic_os=tops10 + ;; + decsystem20* | dec20*) + cpu=pdp10 + vendor=dec + basic_os=tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + cpu=m68k + vendor=motorola + ;; + dpx2*) + cpu=m68k + vendor=bull + basic_os=sysv3 + ;; + encore | umax | mmax) + cpu=ns32k + vendor=encore + ;; + elxsi) + cpu=elxsi + vendor=elxsi + basic_os=${basic_os:-bsd} + ;; + fx2800) + cpu=i860 + vendor=alliant + ;; + genix) + cpu=ns32k + vendor=ns + ;; + h3050r* | hiux*) + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + cpu=m68000 + vendor=hp + ;; + hp9k3[2-9][0-9]) + cpu=m68k + vendor=hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + i*86v32) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv32 + ;; + i*86v4*) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv4 + ;; + i*86v) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv + ;; + i*86sol2) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=solaris2 + ;; + j90 | j90-cray) + cpu=j90 + vendor=cray + basic_os=${basic_os:-unicos} + ;; + iris | iris4d) + cpu=mips + vendor=sgi + case $basic_os in + irix*) + ;; + *) + basic_os=irix4 + ;; + esac + ;; + miniframe) + cpu=m68000 + vendor=convergent + ;; + *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) + cpu=m68k + vendor=atari + basic_os=mint + ;; + news-3600 | risc-news) + cpu=mips + vendor=sony + basic_os=newsos + ;; + next | m*-next) + cpu=m68k + vendor=next + case $basic_os in + openstep*) + ;; + nextstep*) + ;; + ns2*) + basic_os=nextstep2 + ;; + *) + basic_os=nextstep3 + ;; + esac + ;; + np1) + cpu=np1 + vendor=gould + ;; + op50n-* | op60c-*) + cpu=hppa1.1 + vendor=oki + basic_os=proelf + ;; + pa-hitachi) + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 + ;; + pbd) + cpu=sparc + vendor=tti + ;; + pbb) + cpu=m68k + vendor=tti + ;; + pc532) + cpu=ns32k + vendor=pc532 + ;; + pn) + cpu=pn + vendor=gould + ;; + power) + cpu=power + vendor=ibm + ;; + ps2) + cpu=i386 + vendor=ibm + ;; + rm[46]00) + cpu=mips + vendor=siemens + ;; + rtpc | rtpc-*) + cpu=romp + vendor=ibm + ;; + sde) + cpu=mipsisa32 + vendor=sde + basic_os=${basic_os:-elf} + ;; + simso-wrs) + cpu=sparclite + vendor=wrs + basic_os=vxworks + ;; + tower | tower-32) + cpu=m68k + vendor=ncr + ;; + vpp*|vx|vx-*) + cpu=f301 + vendor=fujitsu + ;; + w65) + cpu=w65 + vendor=wdc + ;; + w89k-*) + cpu=hppa1.1 + vendor=winbond + basic_os=proelf + ;; + none) + cpu=none + vendor=none + ;; + leon|leon[3-9]) + cpu=sparc + vendor=$basic_machine + ;; + leon-*|leon[3-9]-*) + cpu=sparc + vendor=`echo "$basic_machine" | sed 's/-.*//'` + ;; + + *-*) + # shellcheck disable=SC2162 + saved_IFS=$IFS + IFS="-" read cpu vendor <<EOF +$basic_machine +EOF + IFS=$saved_IFS + ;; + # 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) + cpu=$basic_machine + vendor=pc + ;; + # These rules are duplicated from below for sake of the special case above; + # i.e. things that normalized to x86 arches should also default to "pc" + pc98) + cpu=i386 + vendor=pc + ;; + x64 | amd64) + cpu=x86_64 + vendor=pc + ;; + # Recognize the basic CPU types without company name. + *) + cpu=$basic_machine + vendor=unknown + ;; +esac + +unset -v basic_machine + +# Decode basic machines in the full and proper CPU-Company form. +case $cpu-$vendor in + # Here we handle the default manufacturer of certain CPU types in canonical form. It is in + # some cases the only manufacturer, in others, it is the most popular. + craynv-unknown) + vendor=cray + basic_os=${basic_os:-unicosmp} + ;; + c90-unknown | c90-cray) + vendor=cray + basic_os=${Basic_os:-unicos} + ;; + fx80-unknown) + vendor=alliant + ;; + romp-unknown) + vendor=ibm + ;; + mmix-unknown) + vendor=knuth + ;; + microblaze-unknown | microblazeel-unknown) + vendor=xilinx + ;; + rs6000-unknown) + vendor=ibm + ;; + vax-unknown) + vendor=dec + ;; + pdp11-unknown) + vendor=dec + ;; + we32k-unknown) + vendor=att + ;; + cydra-unknown) + vendor=cydrome + ;; + i370-ibm*) + vendor=ibm + ;; + orion-unknown) + vendor=highlevel + ;; + xps-unknown | xps100-unknown) + cpu=xps100 + vendor=honeywell + ;; + + # Here we normalize CPU types with a missing or matching vendor + armh-unknown | armh-alt) + cpu=armv7l + vendor=alt + basic_os=${basic_os:-linux-gnueabihf} + ;; + dpx20-unknown | dpx20-bull) + cpu=rs6000 + vendor=bull + basic_os=${basic_os:-bosx} + ;; + + # Here we normalize CPU types irrespective of the vendor + amd64-*) + cpu=x86_64 + ;; + blackfin-*) + cpu=bfin + basic_os=linux + ;; + c54x-*) + cpu=tic54x + ;; + c55x-*) + cpu=tic55x + ;; + c6x-*) + cpu=tic6x + ;; + e500v[12]-*) + cpu=powerpc + basic_os=${basic_os}"spe" + ;; + mips3*-*) + cpu=mips64 + ;; + ms1-*) + cpu=mt + ;; + m68knommu-*) + cpu=m68k + basic_os=linux + ;; + m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*) + cpu=s12z + ;; + openrisc-*) + cpu=or32 + ;; + parisc-*) + cpu=hppa + basic_os=linux + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + cpu=i586 + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*) + cpu=i686 + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + cpu=i686 + ;; + pentium4-*) + cpu=i786 + ;; + pc98-*) + cpu=i386 + ;; + ppc-* | ppcbe-*) + cpu=powerpc + ;; + ppcle-* | powerpclittle-*) + cpu=powerpcle + ;; + ppc64-*) + cpu=powerpc64 + ;; + ppc64le-* | powerpc64little-*) + cpu=powerpc64le + ;; + sb1-*) + cpu=mipsisa64sb1 + ;; + sb1el-*) + cpu=mipsisa64sb1el + ;; + sh5e[lb]-*) + cpu=`echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/'` + ;; + spur-*) + cpu=spur + ;; + strongarm-* | thumb-*) + cpu=arm + ;; + tx39-*) + cpu=mipstx39 + ;; + tx39el-*) + cpu=mipstx39el + ;; + x64-*) + cpu=x86_64 + ;; + xscale-* | xscalee[bl]-*) + cpu=`echo "$cpu" | sed 's/^xscale/arm/'` + ;; + arm64-* | aarch64le-*) + cpu=aarch64 + ;; + + # Recognize the canonical CPU Types that limit and/or modify the + # company names they are paired with. + cr16-*) + basic_os=${basic_os:-elf} + ;; + crisv32-* | etraxfs*-*) + cpu=crisv32 + vendor=axis + ;; + cris-* | etrax*-*) + cpu=cris + vendor=axis + ;; + crx-*) + basic_os=${basic_os:-elf} + ;; + neo-tandem) + cpu=neo + vendor=tandem + ;; + nse-tandem) + cpu=nse + vendor=tandem + ;; + nsr-tandem) + cpu=nsr + vendor=tandem + ;; + nsv-tandem) + cpu=nsv + vendor=tandem + ;; + nsx-tandem) + cpu=nsx + vendor=tandem + ;; + mipsallegrexel-sony) + cpu=mipsallegrexel + vendor=sony + ;; + tile*-*) + basic_os=${basic_os:-linux-gnu} + ;; + + *) + # Recognize the canonical CPU types that are allowed with any + # company name. + case $cpu in + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | abacus \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \ + | alphapca5[67] | alpha64pca5[67] \ + | am33_2.0 \ + | amdgcn \ + | arc | arceb | arc32 | arc64 \ + | arm | arm[lb]e | arme[lb] | armv* \ + | avr | avr32 \ + | asmjs \ + | ba \ + | be32 | be64 \ + | bfin | bpf | bs2000 \ + | c[123]* | c30 | [cjt]90 | c4x \ + | c8051 | clipper | craynv | csky | cydra \ + | d10v | d30v | dlx | dsp16xx \ + | e2k | elxsi | epiphany \ + | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \ + | h8300 | h8500 \ + | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i*86 | i860 | i960 | ia16 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | loongarch32 | loongarch64 | loongarchx32 \ + | m32c | m32r | m32rle \ + | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \ + | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \ + | m88110 | m88k | maxq | mb | mcore | mep | metag \ + | microblaze | microblazeel \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64eb | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r3 | mipsisa32r3el \ + | mipsisa32r5 | mipsisa32r5el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r3 | mipsisa64r3el \ + | mipsisa64r5 | mipsisa64r5el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mmix \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nfp \ + | nios | nios2 | nios2eb | nios2el \ + | none | np1 | ns16k | ns32k | nvptx \ + | open8 \ + | or1k* \ + | or32 \ + | orion \ + | picochip \ + | pdp10 | pdp11 | pj | pjl | pn | power \ + | powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \ + | pru \ + | pyramid \ + | riscv | riscv32 | riscv32be | riscv64 | riscv64be \ + | rl78 | romp | rs6000 | rx \ + | s390 | s390x \ + | score \ + | sh | shl \ + | sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \ + | sh[1234]e[lb] | sh[12345][lb]e | sh[23]ele | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \ + | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \ + | spu \ + | tahoe \ + | thumbv7* \ + | tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \ + | tron \ + | ubicom32 \ + | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \ + | vax \ + | visium \ + | w65 \ + | wasm32 | wasm64 \ + | we32k \ + | x86 | x86_64 | xc16x | xgate | xps100 \ + | xstormy16 | xtensa* \ + | ymp \ + | z8k | z80) + ;; + + *) + echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2 + exit 1 + ;; + esac + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $vendor in + digital*) + vendor=dec + ;; + commodore*) + vendor=cbm + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if test x$basic_os != x +then + +# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just +# set os. +case $basic_os in + gnu/linux*) + kernel=linux + os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` + ;; + os2-emx) + kernel=os2 + os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` + ;; + nto-qnx*) + kernel=nto + os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` + ;; + *-*) + # shellcheck disable=SC2162 + saved_IFS=$IFS + IFS="-" read kernel os <<EOF +$basic_os +EOF + IFS=$saved_IFS + ;; + # Default OS when just kernel was specified + nto*) + kernel=nto + os=`echo "$basic_os" | sed -e 's|nto|qnx|'` + ;; + linux*) + kernel=linux + os=`echo "$basic_os" | sed -e 's|linux|gnu|'` + ;; + *) + kernel= + os=$basic_os + ;; +esac + +# Now, normalize the OS (knowing we just have one component, it's not a kernel, +# etc.) +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. + auroraux) + os=auroraux + ;; + bluegene*) + os=cnk + ;; + solaris1 | solaris1.*) + os=`echo "$os" | sed -e 's|solaris1|sunos4|'` + ;; + solaris) + os=solaris2 + ;; + unixware*) + os=sysv4.2uw + ;; + # es1800 is here to avoid being matched by es* (a different OS) + es1800*) + os=ose + ;; + # Some version numbers need modification + chorusos*) + os=chorusos + ;; + isc) + os=isc2.2 + ;; + sco6) + os=sco5v6 + ;; + sco5) + os=sco3.2v5 + ;; + sco4) + os=sco3.2v4 + ;; + sco3.2.[4-9]*) + os=`echo "$os" | sed -e 's/sco3.2./sco3.2v/'` + ;; + sco*v* | scout) + # Don't match below + ;; + sco*) + os=sco3.2v2 + ;; + psos*) + os=psos + ;; + qnx*) + os=qnx + ;; + hiux*) + os=hiuxwe2 + ;; + lynx*178) + os=lynxos178 + ;; + lynx*5) + os=lynxos5 + ;; + lynxos*) + # don't get caught up in next wildcard + ;; + lynx*) + os=lynxos + ;; + mac[0-9]*) + os=`echo "$os" | sed -e 's|mac|macos|'` + ;; + opened*) + os=openedition + ;; + os400*) + os=os400 + ;; + sunos5*) + os=`echo "$os" | sed -e 's|sunos5|solaris2|'` + ;; + sunos6*) + os=`echo "$os" | sed -e 's|sunos6|solaris3|'` + ;; + wince*) + os=wince + ;; + 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 + ;; + # 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 + ;; + ose*) + os=ose + ;; + *mint | mint[0-9]* | *MiNT | MiNT[0-9]*) + os=mint + ;; + dicos*) + os=dicos + ;; + pikeos*) + # Until real need of OS specific support for + # particular features comes up, bare metal + # configurations are quite functional. + case $cpu in + arm*) + os=eabi + ;; + *) + os=elf + ;; + esac + ;; + *) + # No normalization, but not necessarily accepted, that comes below. + ;; +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. + +kernel= +case $cpu-$vendor in + score-*) + os=elf + ;; + spu-*) + os=elf + ;; + *-acorn) + os=riscix1.2 + ;; + arm*-rebel) + kernel=linux + os=gnu + ;; + arm*-semi) + os=aout + ;; + c4x-* | tic4x-*) + os=coff + ;; + c8051-*) + os=elf + ;; + clipper-intergraph) + os=clix + ;; + hexagon-*) + os=elf + ;; + tic54x-*) + os=coff + ;; + tic55x-*) + os=coff + ;; + tic6x-*) + 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 + ;; + 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 + ;; + pru-*) + os=elf + ;; + *-be) + os=beos + ;; + *-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 + ;; + *-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 + ;; + *-wrs) + os=vxworks + ;; + *) + os=none + ;; +esac + +fi + +# Now, validate our (potentially fixed-up) OS. +case $os in + # Sometimes we do "kernel-libc", so those need to count as OSes. + musl* | newlib* | relibc* | uclibc*) + ;; + # Likewise for "kernel-abi" + eabi* | gnueabi*) + ;; + # VxWorks passes extra cpu info in the 4th filed. + simlinux | simwindows | spe) + ;; + # Now accept the basic system types. + # The portable systems comes first. + # Each alternative MUST end in a * to match a version number. + gnu* | android* | bsd* | mach* | minix* | genix* | ultrix* | irix* \ + | *vms* | esix* | aix* | cnk* | sunos | sunos[34]* \ + | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ + | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \ + | hiux* | abug | nacl* | netware* | windows* \ + | os9* | macos* | osx* | ios* \ + | mpw* | magic* | mmixware* | mon960* | lnews* \ + | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ + | aos* | aros* | cloudabi* | sortix* | twizzler* \ + | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \ + | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \ + | mirbsd* | netbsd* | dicos* | openedition* | ose* \ + | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \ + | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \ + | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ + | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ + | udi* | lites* | ieee* | go32* | aux* | hcos* \ + | chorusrdb* | cegcc* | glidix* | serenity* \ + | cygwin* | msys* | pe* | moss* | proelf* | rtems* \ + | midipix* | mingw32* | mingw64* | mint* \ + | uxpv* | beos* | mpeix* | udk* | moxiebox* \ + | interix* | uwin* | mks* | rhapsody* | darwin* \ + | openstep* | oskit* | conix* | pw32* | nonstopux* \ + | storm-chaos* | tops10* | tenex* | tops20* | its* \ + | os2* | vos* | palmos* | uclinux* | nucleus* | morphos* \ + | scout* | superux* | sysv* | rtmk* | tpf* | windiss* \ + | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \ + | skyos* | haiku* | rdos* | toppers* | drops* | es* \ + | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ + | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ + | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \ + | fiwix* ) + ;; + # This one is extra strict with allowed versions + sco3.2v2 | sco3.2v[4-9]* | sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + ;; + none) + ;; + *) + echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2 + exit 1 + ;; +esac + +# As a final step for OS-related things, validate the OS-kernel combination +# (given a valid OS), if there is a kernel. +case $kernel-$os in + linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ + | linux-musl* | linux-relibc* | linux-uclibc* ) + ;; + uclinux-uclibc* ) + ;; + -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* ) + # These are just libc implementations, not actual OSes, and thus + # require a kernel. + echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 + exit 1 + ;; + kfreebsd*-gnu* | kopensolaris*-gnu*) + ;; + vxworks-simlinux | vxworks-simwindows | vxworks-spe) + ;; + nto-qnx*) + ;; + os2-emx) + ;; + *-eabi* | *-gnueabi*) + ;; + -*) + # Blank kernel with real OS is always fine. + ;; + *-*) + echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 + exit 1 + ;; +esac + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +case $vendor in + unknown) + case $cpu-$os in + *-riscix*) + vendor=acorn + ;; + *-sunos*) + vendor=sun + ;; + *-cnk* | *-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 + ;; + *-clix*) + vendor=intergraph + ;; + *-mvs* | *-opened*) + vendor=ibm + ;; + *-os400*) + vendor=ibm + ;; + s390-* | s390x-*) + 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 + ;; +esac + +echo "$cpu-$vendor-${kernel:+$kernel-}$os" +exit + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100755 index 0000000000000000000000000000000000000000..410616f0ab2d664301855a7b10fd7b24c61d6ddb --- /dev/null +++ b/configure @@ -0,0 +1,19902 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.72 for bluez 5.79. +# +# +# Copyright (C) 1992-1996, 1998-2017, 2020-2023 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 ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else case e in #( + e) case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac ;; +esac +fi + + + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. +as_nl=' +' +export as_nl +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi +if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi + +# The user is always right. +if ${PATH_SEPARATOR+false} :; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + 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 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed 'exec'. +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else case e in #( + e) case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ) +then : + +else case e in #( + e) exitcode=1; echo positional parameters were not saved. ;; +esac +fi +test x\$exitcode = x0 || exit 1 +blah=\$(echo \$(echo blah)) +test x\"\$blah\" = xblah || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 + + test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ + || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null +then : + as_have_required=yes +else case e in #( + e) as_have_required=no ;; +esac +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null +then : + +else case e in #( + e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : + CONFIG_SHELL=$as_shell as_have_required=yes + if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null +then : + break 2 +fi +fi + done;; + esac + as_found=false +done +IFS=$as_save_IFS +if $as_found +then : + +else case e in #( + e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi ;; +esac +fi + + + if test "x$CONFIG_SHELL" != x +then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed 'exec'. +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno +then : + printf "%s\n" "$0: This script requires a shell more modern than all" + printf "%s\n" "$0: the shells that I found on your system." + if test ${ZSH_VERSION+y} ; then + printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" + printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." + else + printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi ;; +esac +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`printf "%s\n" "$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 || +printf "%s\n" 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" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else case e in #( + e) as_fn_append () + { + eval $1=\$$1\$2 + } ;; +esac +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else case e in #( + e) as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } ;; +esac +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + printf "%s\n" "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +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 + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# 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 + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + t clear + :clear + 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" || + { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # 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 +} + + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + +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 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + 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 -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +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='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" +as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated + +# Sed expression to map a string onto a valid variable name. +as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" +as_tr_sh="eval sed '$as_sed_sh'" # deprecated + +SHELL=${CONFIG_SHELL-/bin/sh} + + +test -n "$DJDIR" || exec 7<&0 </dev/null +exec 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/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= + +# Identity of this package. +PACKAGE_NAME='bluez' +PACKAGE_TARNAME='bluez' +PACKAGE_VERSION='5.79' +PACKAGE_STRING='bluez 5.79' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +ac_default_prefix=/usr/local +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stddef.h> +#ifdef HAVE_STDIO_H +# include <stdio.h> +#endif +#ifdef HAVE_STDLIB_H +# include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +# include <string.h> +#endif +#ifdef HAVE_INTTYPES_H +# include <inttypes.h> +#endif +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif" + +ac_header_c_list= +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +PLUGIN_PHONEBOOK +LIBEDATESERVER_LIBS +LIBEDATESERVER_CFLAGS +LIBEBOOK_LIBS +LIBEBOOK_CFLAGS +SPEEXDSP_LIBS +SPEEXDSP_CFLAGS +SBC_LIBS +SBC_CFLAGS +ANDROID_FALSE +ANDROID_TRUE +MESH_STORAGEDIR +CONFIGDIR +PKGLIBEXECDIR +PKGBINDIR +ADMIN_FALSE +ADMIN_TRUE +LOGGER_FALSE +LOGGER_TRUE +HID2HCI_FALSE +HID2HCI_TRUE +SIXAXIS_FALSE +SIXAXIS_TRUE +EXTERNAL_PLUGINS_FALSE +EXTERNAL_PLUGINS_TRUE +DEPRECATED_FALSE +DEPRECATED_TRUE +EXPERIMENTAL_FALSE +EXPERIMENTAL_TRUE +TESTING_FALSE +TESTING_TRUE +RUN_RST2MAN_FALSE +RUN_RST2MAN_TRUE +MANPAGES_FALSE +MANPAGES_TRUE +RST2MAN +DATAFILES_FALSE +DATAFILES_TRUE +SYSTEMD_USERUNITDIR +SYSTEMD_SYSTEMUNITDIR +SYSTEMD_FALSE +SYSTEMD_TRUE +READLINE_FALSE +READLINE_TRUE +CLIENT_FALSE +CLIENT_TRUE +LIBSHARED_ELL_FALSE +LIBSHARED_ELL_TRUE +EXTERNAL_ELL_FALSE +EXTERNAL_ELL_TRUE +ELL_LIBS +ELL_CFLAGS +BTPCLIENT_FALSE +BTPCLIENT_TRUE +OBEX_FALSE +OBEX_TRUE +ICAL_LIBS +ICAL_CFLAGS +ALSA_LIBS +ALSA_CFLAGS +MIDI_FALSE +MIDI_TRUE +JSONC_LIBS +JSONC_CFLAGS +MESH_FALSE +MESH_TRUE +CUPS_SERVERBIN +CUPS_SERVERBIN_FALSE +CUPS_SERVERBIN_TRUE +CUPS_FALSE +CUPS_TRUE +UDEV_DIR +UDEV_LIBS +UDEV_CFLAGS +MONITOR_FALSE +MONITOR_TRUE +TOOLS_FALSE +TOOLS_TRUE +ASHA_FALSE +ASHA_TRUE +CSIP_FALSE +CSIP_TRUE +MICP_FALSE +MICP_TRUE +VCP_FALSE +VCP_TRUE +CCP_FALSE +CCP_TRUE +MCP_FALSE +MCP_TRUE +BASS_FALSE +BASS_TRUE +BAP_FALSE +BAP_TRUE +HEALTH_FALSE +HEALTH_TRUE +HOG_FALSE +HOG_TRUE +HID_FALSE +HID_TRUE +NETWORK_FALSE +NETWORK_TRUE +AVRCP_FALSE +AVRCP_TRUE +A2DP_FALSE +A2DP_TRUE +SAP_FALSE +SAP_TRUE +NFC_FALSE +NFC_TRUE +TEST_FALSE +TEST_TRUE +LIBRARY_FALSE +LIBRARY_TRUE +BACKTRACE_LIBS +BACKTRACE_CFLAGS +ZSH_COMPLETIONS_FALSE +ZSH_COMPLETIONS_TRUE +ZSH_COMPLETIONDIR +DBUS_SESSIONBUSDIR +DBUS_SYSTEMBUSDIR +DBUS_CONFDIR +DBUS_LIBS +DBUS_CFLAGS +GTHREAD_LIBS +GTHREAD_CFLAGS +GLIB_LIBS +GLIB_CFLAGS +VALGRIND_FALSE +VALGRIND_TRUE +MISC_LDFLAGS +MISC_CFLAGS +ASAN_LIB +DBUS_RUN_SESSION_FALSE +DBUS_RUN_SESSION_TRUE +COVERAGE_FALSE +COVERAGE_TRUE +enable_valgrind +enable_dbus_run_session +enable_coverage +LT_SYS_LIBRARY_PATH +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +MANIFEST_TOOL +RANLIB +ac_ct_AR +AR +DLLTOOL +OBJDUMP +FILECMD +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +EGREP +GREP +SED +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +LIBTOOL +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +am__nodep +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +WARNING_CFLAGS +PKG_CONFIG_LIBDIR +PKG_CONFIG_PATH +PKG_CONFIG +MAINT +MAINTAINER_MODE_FALSE +MAINTAINER_MODE_TRUE +AM_BACKSLASH +AM_DEFAULT_VERBOSITY +AM_DEFAULT_V +AM_V +CSCOPE +ETAGS +CTAGS +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +runstatedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL +am__quote' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_silent_rules +enable_maintainer_mode +enable_dependency_tracking +enable_static +enable_shared +with_pic +enable_fast_install +with_aix_soname +with_gnu_ld +with_sysroot +enable_libtool_lock +enable_optimization +enable_asan +enable_lsan +enable_ubsan +enable_debug +enable_pie +enable_threads +with_dbusconfdir +with_dbussystembusdir +with_dbussessionbusdir +with_zsh_completion_dir +enable_backtrace +enable_library +enable_test +enable_nfc +enable_sap +enable_a2dp +enable_avrcp +enable_network +enable_hid +enable_hog +enable_health +enable_bap +enable_bass +enable_mcp +enable_ccp +enable_vcp +enable_micp +enable_csip +enable_asha +enable_tools +enable_monitor +enable_udev +with_udevdir +enable_cups +enable_mesh +enable_midi +enable_obex +enable_btpclient +enable_external_ell +enable_client +enable_systemd +with_systemdsystemunitdir +with_systemduserunitdir +enable_datafiles +enable_manpages +enable_testing +enable_experimental +enable_deprecated +enable_external_plugins +enable_sixaxis +enable_hid2hci +enable_logger +enable_admin +enable_android +with_phonebook +' + ac_precious_vars='build_alias +host_alias +target_alias +PKG_CONFIG +PKG_CONFIG_PATH +PKG_CONFIG_LIBDIR +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +LT_SYS_LIBRARY_PATH +GLIB_CFLAGS +GLIB_LIBS +GTHREAD_CFLAGS +GTHREAD_LIBS +DBUS_CFLAGS +DBUS_LIBS +UDEV_CFLAGS +UDEV_LIBS +JSONC_CFLAGS +JSONC_LIBS +ALSA_CFLAGS +ALSA_LIBS +ICAL_CFLAGS +ICAL_LIBS +ELL_CFLAGS +ELL_LIBS +SBC_CFLAGS +SBC_LIBS +SPEEXDSP_CFLAGS +SPEEXDSP_LIBS +LIBEBOOK_CFLAGS +LIBEBOOK_LIBS +LIBEDATESERVER_CFLAGS +LIBEDATESERVER_LIBS' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# 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' +runstatedir='${localstatedir}/run' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +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= ;; + *) ac_optarg=yes ;; + esac + + 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_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: '$ac_useropt'" + ac_useropt_orig=$ac_useropt + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=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_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: '$ac_useropt'" + ac_useropt_orig=$ac_useropt + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$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 ;; + + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + + -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_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: '$ac_useropt'" + ac_useropt_orig=$ac_useropt + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: '$ac_useropt'" + ac_useropt_orig=$ac_useropt + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=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 ;; + + -*) as_fn_error $? "unrecognized option: '$ac_option' +Try '$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: '$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + printf "%s\n" "$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'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +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 runstatedir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +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 + 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 .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# 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 -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X"$as_myself" | + 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 .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + 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 bluez 5.79 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] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] + --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/bluez] + --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 + case $ac_init_help in + short | recursive ) echo "Configuration of bluez 5.79:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-silent-rules less verbose build output (undo: "make V=1") + --disable-silent-rules verbose build output (undo: "make V=0") + --enable-maintainer-mode + enable make rules and dependencies not useful (and + sometimes confusing) to the casual installer + --enable-dependency-tracking + do not reject slow dependency extractors + --disable-dependency-tracking + speeds up one-time build + --enable-static[=PKGS] build static libraries [default=no] + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + --disable-optimization disable code optimization through compiler + --enable-asan enable linking with address sanitizer + --enable-lsan enable linking with address sanitizer + --enable-ubsan enable linking with address sanitizer + --enable-debug enable compiling with debugging information + --enable-pie enable position independent executables flag + --enable-threads enable threading support + --enable-backtrace compile backtrace support + --enable-library install Bluetooth library + --enable-test enable test/example scripts + --enable-nfc enable NFC paring + --enable-sap enable SAP profile + --disable-a2dp disable A2DP profile + --disable-avrcp disable AVRCP profile + --disable-network disable network profiles + --disable-hid disable HID profile + --disable-hog disable HoG profile + --enable-health enable health profiles + --disable-bap disable BAP profile + --disable-bass disable BASS service + --disable-mcp disable MCP profile + --disable-ccp disable CCP profile + --disable-vcp disable VCP profile + --disable-micp disable MICP profile + --disable-csip disable CSIP profile + --disable-asha disable ASHA support + --disable-tools disable Bluetooth tools + --disable-monitor disable Bluetooth monitor + --disable-udev disable udev device support + --disable-cups disable CUPS printer support + --enable-mesh enable Mesh profile support + --enable-midi enable MIDI support + --disable-obex disable OBEX profile support + --enable-btpclient enable BTP client + --enable-external-ell enable external Embedded Linux library + --disable-client disable command line client + --disable-systemd disable systemd integration + --disable-datafiles do not install configuration and data files + --disable-manpages disable building of manual pages + --enable-testing enable testing tools + --enable-experimental enable experimental tools + --enable-deprecated enable deprecated tools + --enable-external-plugins + enable support for external plugins + --enable-sixaxis enable sixaxis plugin + --enable-hid2hci enable hid2hci tool + --enable-logger enable HCI logger service + --enable-admin enable admin policy plugin + --enable-android enable BlueZ for Android + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use + both] + --with-aix-soname=aix|svr4|both + shared library versioning (aka "SONAME") variant to + provide on AIX, [default=aix]. + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-sysroot[=DIR] Search for dependent libraries within DIR (or the + compiler's sysroot if not specified). + --with-dbusconfdir=DIR path to D-Bus configuration directory + --with-dbussystembusdir=DIR + path to D-Bus system bus services directory + --with-dbussessionbusdir=DIR + path to D-Bus session bus services directory + --with-zsh-completion-dir=DIR + path to install zsh completions + --with-udevdir=DIR path to udev directory + --with-systemdsystemunitdir=DIR + path to systemd system unit directory + --with-systemduserunitdir=DIR + path to systemd user unit directory + --with-phonebook=PLUGIN obexd phonebook plugin (default=dummy) + +Some influential environment variables: + PKG_CONFIG path to pkg-config utility + PKG_CONFIG_PATH + directories to add to pkg-config's search path + PKG_CONFIG_LIBDIR + path overriding pkg-config's built-in search path + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + LT_SYS_LIBRARY_PATH + User-defined run-time library search path. + GLIB_CFLAGS C compiler flags for GLIB, overriding pkg-config + GLIB_LIBS linker flags for GLIB, overriding pkg-config + GTHREAD_CFLAGS + C compiler flags for GTHREAD, overriding pkg-config + GTHREAD_LIBS + linker flags for GTHREAD, overriding pkg-config + DBUS_CFLAGS C compiler flags for DBUS, overriding pkg-config + DBUS_LIBS linker flags for DBUS, overriding pkg-config + UDEV_CFLAGS C compiler flags for UDEV, overriding pkg-config + UDEV_LIBS linker flags for UDEV, overriding pkg-config + JSONC_CFLAGS + C compiler flags for JSONC, overriding pkg-config + JSONC_LIBS linker flags for JSONC, overriding pkg-config + ALSA_CFLAGS C compiler flags for ALSA, overriding pkg-config + ALSA_LIBS linker flags for ALSA, overriding pkg-config + ICAL_CFLAGS C compiler flags for ICAL, overriding pkg-config + ICAL_LIBS linker flags for ICAL, overriding pkg-config + ELL_CFLAGS C compiler flags for ELL, overriding pkg-config + ELL_LIBS linker flags for ELL, overriding pkg-config + SBC_CFLAGS C compiler flags for SBC, overriding pkg-config + SBC_LIBS linker flags for SBC, overriding pkg-config + SPEEXDSP_CFLAGS + C compiler flags for SPEEXDSP, overriding pkg-config + SPEEXDSP_LIBS + linker flags for SPEEXDSP, overriding pkg-config + LIBEBOOK_CFLAGS + C compiler flags for LIBEBOOK, overriding pkg-config + LIBEBOOK_LIBS + linker flags for LIBEBOOK, overriding pkg-config + LIBEDATESERVER_CFLAGS + C compiler flags for LIBEDATESERVER, overriding pkg-config + LIBEDATESERVER_LIBS + linker flags for LIBEDATESERVER, 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. + +Report bugs to the package provider. +_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" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && 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=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`printf "%s\n" "$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 configure.gnu first; this name is used for a wrapper for + # Metaconfig's "Configure" on case-insensitive file systems. + 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 + printf "%s\n" "$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 +bluez configure 5.79 +generated by GNU Autoconf 2.72 + +Copyright (C) 2023 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 + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest.beam + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext +then : + ac_retval=0 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 ;; +esac +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + } +then : + ac_retval=0 +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 ;; +esac +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + eval "$3=yes" +else case e in #( + e) eval "$3=no" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac +fi +eval ac_res=\$$3 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case <limits.h> declares $2. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (void); below. */ + +#include <limits.h> +#undef $2 + +/* 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 $2 (void); +/* 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_$2 || defined __stub___$2 +choke me +#endif + +int +main (void) +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + eval "$3=yes" +else case e in #( + e) eval "$3=no" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; +esac +fi +eval ac_res=\$$3 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR +# ------------------------------------------------------------------ +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR. +ac_fn_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +printf %s "checking whether $as_decl_name is declared... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + eval ac_save_FLAGS=\$$6 + as_fn_append $6 " $5" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main (void) +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + eval "$3=yes" +else case e in #( + e) eval "$3=no" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + eval $6=\$ac_save_FLAGS + ;; +esac +fi +eval ac_res=\$$3 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_check_decl +ac_configure_args_raw= +for ac_arg +do + case $ac_arg in + *\'*) + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append ac_configure_args_raw " '$ac_arg'" +done + +case $ac_configure_args_raw in + *$as_nl*) + ac_safe_unquote= ;; + *) + ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. + ac_unsafe_a="$ac_unsafe_z#~" + ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" + ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; +esac + +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by bluez $as_me 5.79, which was +generated by GNU Autoconf 2.72. Invocation command line was + + $ $0$ac_configure_args_raw + +_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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + printf "%s\n" "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=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append 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 + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset 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=$? + # Sanitize IFS. + IFS=" "" $as_nl" + # Save into config.log some information that might help in debugging. + { + echo + + printf "%s\n" "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + 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_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; 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 + + printf "%s\n" "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + printf "%s\n" "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + printf "%s\n" "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + printf "%s\n" "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + printf "%s\n" "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + printf "%s\n" "$as_me: caught signal $ac_signal" + printf "%s\n" "$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'; as_fn_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 + +printf "%s\n" "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h + +printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h + +printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h + +printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h + +printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h + +printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +if test -n "$CONFIG_SITE"; then + ac_site_files="$CONFIG_SITE" +elif test "x$prefix" != xNONE; then + ac_site_files="$prefix/share/config.site $prefix/etc/config.site" +else + ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" +fi + +for ac_site_file in $ac_site_files +do + case $ac_site_file in #( + */*) : + ;; #( + *) : + ac_site_file=./$ac_site_file ;; +esac + if test -f "$ac_site_file" && test -r "$ac_site_file"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See 'config.log' for more details" "$LINENO" 5; } + 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. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +printf "%s\n" "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +printf "%s\n" "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Test code for whether the C compiler supports C89 (global declarations) +ac_c_conftest_c89_globals=' +/* Does the compiler advertise C89 conformance? + Do not test the value of __STDC__, because some compilers set it to 0 + while being otherwise adequately conformant. */ +#if !defined __STDC__ +# error "Compiler does not advertise C89 conformance" +#endif + +#include <stddef.h> +#include <stdarg.h> +struct stat; +/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ +struct buf { int x; }; +struct buf * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (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; +} + +/* C89 style stringification. */ +#define noexpand_stringify(a) #a +const char *stringified = noexpand_stringify(arbitrary+token=sequence); + +/* C89 style token pasting. Exercises some of the corner cases that + e.g. old MSVC gets wrong, but not very hard. */ +#define noexpand_concat(a,b) a##b +#define expand_concat(a,b) noexpand_concat(a,b) +extern int vA; +extern int vbee; +#define aye A +#define bee B +int *pvA = &expand_concat(v,aye); +int *pvbee = &noexpand_concat(v,bee); + +/* 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 do not provoke an error unfortunately, instead are silently treated + as an "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 is necessary to write \x00 == 0 to get something + that is 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 **, int *(*)(struct buf *, struct stat *, int), + int, int);' + +# Test code for whether the C compiler supports C89 (body of main). +ac_c_conftest_c89_main=' +ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); +' + +# Test code for whether the C compiler supports C99 (global declarations) +ac_c_conftest_c99_globals=' +/* Does the compiler advertise C99 conformance? */ +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L +# error "Compiler does not advertise C99 conformance" +#endif + +// See if C++-style comments work. + +#include <stdbool.h> +extern int puts (const char *); +extern int printf (const char *, ...); +extern int dprintf (int, const char *, ...); +extern void *malloc (size_t); +extern void free (void *); + +// Check varargs macros. These examples are taken from C99 6.10.3.5. +// dprintf is used instead of fprintf to avoid needing to declare +// FILE and stderr. +#define debug(...) dprintf (2, __VA_ARGS__) +#define showlist(...) puts (#__VA_ARGS__) +#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) +static void +test_varargs_macros (void) +{ + int x = 1234; + int y = 5678; + debug ("Flag"); + debug ("X = %d\n", x); + showlist (The first, second, and third items.); + report (x>y, "x is %d but y is %d", x, y); +} + +// Check long long types. +#define BIG64 18446744073709551615ull +#define BIG32 4294967295ul +#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) +#if !BIG_OK + #error "your preprocessor is broken" +#endif +#if BIG_OK +#else + #error "your preprocessor is broken" +#endif +static long long int bignum = -9223372036854775807LL; +static unsigned long long int ubignum = BIG64; + +struct incomplete_array +{ + int datasize; + double data[]; +}; + +struct named_init { + int number; + const wchar_t *name; + double average; +}; + +typedef const char *ccp; + +static inline int +test_restrict (ccp restrict text) +{ + // Iterate through items via the restricted pointer. + // Also check for declarations in for loops. + for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) + continue; + return 0; +} + +// Check varargs and va_copy. +static bool +test_varargs (const char *format, ...) +{ + va_list args; + va_start (args, format); + va_list args_copy; + va_copy (args_copy, args); + + const char *str = ""; + int number = 0; + float fnumber = 0; + + while (*format) + { + switch (*format++) + { + case '\''s'\'': // string + str = va_arg (args_copy, const char *); + break; + case '\''d'\'': // int + number = va_arg (args_copy, int); + break; + case '\''f'\'': // float + fnumber = va_arg (args_copy, double); + break; + default: + break; + } + } + va_end (args_copy); + va_end (args); + + return *str && number && fnumber; +} +' + +# Test code for whether the C compiler supports C99 (body of main). +ac_c_conftest_c99_main=' + // Check bool. + _Bool success = false; + success |= (argc != 0); + + // Check restrict. + if (test_restrict ("String literal") == 0) + success = true; + char *restrict newvar = "Another string"; + + // Check varargs. + success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); + test_varargs_macros (); + + // Check flexible array members. + struct incomplete_array *ia = + malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); + ia->datasize = 10; + for (int i = 0; i < ia->datasize; ++i) + ia->data[i] = i * 1.234; + // Work around memory leak warnings. + free (ia); + + // Check named initializers. + struct named_init ni = { + .number = 34, + .name = L"Test wide string", + .average = 543.34343, + }; + + ni.number = 58; + + int dynamic_array[ni.number]; + dynamic_array[0] = argv[0][0]; + dynamic_array[ni.number - 1] = 543; + + // work around unused variable warnings + ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' + || dynamic_array[ni.number - 1] != 543); +' + +# Test code for whether the C compiler supports C11 (global declarations) +ac_c_conftest_c11_globals=' +/* Does the compiler advertise C11 conformance? */ +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L +# error "Compiler does not advertise C11 conformance" +#endif + +// Check _Alignas. +char _Alignas (double) aligned_as_double; +char _Alignas (0) no_special_alignment; +extern char aligned_as_int; +char _Alignas (0) _Alignas (int) aligned_as_int; + +// Check _Alignof. +enum +{ + int_alignment = _Alignof (int), + int_array_alignment = _Alignof (int[100]), + char_alignment = _Alignof (char) +}; +_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); + +// Check _Noreturn. +int _Noreturn does_not_return (void) { for (;;) continue; } + +// Check _Static_assert. +struct test_static_assert +{ + int x; + _Static_assert (sizeof (int) <= sizeof (long int), + "_Static_assert does not work in struct"); + long int y; +}; + +// Check UTF-8 literals. +#define u8 syntax error! +char const utf8_literal[] = u8"happens to be ASCII" "another string"; + +// Check duplicate typedefs. +typedef long *long_ptr; +typedef long int *long_ptr; +typedef long_ptr long_ptr; + +// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. +struct anonymous +{ + union { + struct { int i; int j; }; + struct { int k; long int l; } w; + }; + int m; +} v1; +' + +# Test code for whether the C compiler supports C11 (body of main). +ac_c_conftest_c11_main=' + _Static_assert ((offsetof (struct anonymous, i) + == offsetof (struct anonymous, w.k)), + "Anonymous union alignment botch"); + v1.i = 2; + v1.w.k = 5; + ok |= v1.i != 5; +' + +# Test code for whether the C compiler supports C11 (complete). +ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} +${ac_c_conftest_c11_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + ${ac_c_conftest_c11_main} + return ok; +} +" + +# Test code for whether the C compiler supports C99 (complete). +ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + return ok; +} +" + +# Test code for whether the C compiler supports C89 (complete). +ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + return ok; +} +" + +as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" +as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" +as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" +as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" +as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" +as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" +as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" +as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" +as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" + +# Auxiliary files required by this configure script. +ac_aux_files="config.guess config.sub ltmain.sh compile missing install-sh" + +# Locations in which to look for auxiliary files. +ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." + +# Search for a directory containing all of the required auxiliary files, +# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. +# If we don't find one directory that contains all the files we need, +# we report the set of missing files from the *first* directory in +# $ac_aux_dir_candidates and give up. +ac_missing_aux_files="" +ac_first_candidate=: +printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in $ac_aux_dir_candidates +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + as_found=: + + printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 + ac_aux_dir_found=yes + ac_install_sh= + for ac_aux in $ac_aux_files + do + # As a special case, if "install-sh" is required, that requirement + # can be satisfied by any of "install-sh", "install.sh", or "shtool", + # and $ac_install_sh is set appropriately for whichever one is found. + if test x"$ac_aux" = x"install-sh" + then + if test -f "${as_dir}install-sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 + ac_install_sh="${as_dir}install-sh -c" + elif test -f "${as_dir}install.sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 + ac_install_sh="${as_dir}install.sh -c" + elif test -f "${as_dir}shtool"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 + ac_install_sh="${as_dir}shtool install -c" + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} install-sh" + else + break + fi + fi + else + if test -f "${as_dir}${ac_aux}"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" + else + break + fi + fi + fi + done + if test "$ac_aux_dir_found" = yes; then + ac_aux_dir="$as_dir" + break + fi + ac_first_candidate=false + + as_found=false +done +IFS=$as_save_IFS +if $as_found +then : + +else case e in #( + e) as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 ;; +esac +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. +if test -f "${ac_aux_dir}config.guess"; then + ac_config_guess="$SHELL ${ac_aux_dir}config.guess" +fi +if test -f "${ac_aux_dir}config.sub"; then + ac_config_sub="$SHELL ${ac_aux_dir}config.sub" +fi +if test -f "$ac_aux_dir/configure"; then + ac_configure="$SHELL ${ac_aux_dir}configure" +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,) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 +printf "%s\n" "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 +printf "%s\n" "$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 + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 +printf "%s\n" "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 +printf "%s\n" "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 +printf "%s\n" "$as_me: former value: '$ac_old_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 +printf "%s\n" "$as_me: current value: '$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`printf "%s\n" "$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. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' + and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +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.16' + + + + # 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. +# Reject install programs that cannot install multiple files. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +printf %s "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test ${ac_cv_path_install+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + # Account for fact that we put trailing slashes in our PATH walk. +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 as_fn_executable_p "$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 + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + ;; +esac +fi + if test ${ac_cv_path_install+y}; 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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +printf "%s\n" "$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' + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +printf %s "checking whether build environment is sane... " >&6; } +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; +esac + +# 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 ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + 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 + 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". + as_fn_error $? "ls -t appears to fail. Make sure there is not a broken + alias in your environment" "$LINENO" 5 + fi + if test "$2" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error $? "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi + +rm -f conftest.file + +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 $. +# By default was 's,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`printf "%s\n" "$program_transform_name" | sed "$ac_script"` + + +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` + + + if test x"${MISSING+set}" != xset; then + MISSING="\${SHELL} '$am_aux_dir/missing'" +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 +printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# 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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_STRIP+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +printf "%s\n" "$STRIP" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_STRIP+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +printf "%s\n" "$ac_ct_STRIP" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&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" + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 +printf %s "checking for a race-free mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if test ${ac_cv_path_mkdir+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue + case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir ('*'coreutils) '* | \ + *'BusyBox '* | \ + '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 + ;; +esac +fi + + test -d ./--version && rmdir ./--version + if test ${ac_cv_path_mkdir+y}; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use plain mkdir -p, + # in the hope it doesn't have the bugs of ancient mkdir. + MKDIR_P='mkdir -p' + fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +printf "%s\n" "$MKDIR_P" >&6; } + +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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_AWK+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +printf "%s\n" "$AWK" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval test \${ac_cv_prog_make_${ac_make}_set+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 ;; +esac +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + SET_MAKE= +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "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 + +# Check whether --enable-silent-rules was given. +if test ${enable_silent_rules+y} +then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in # ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=1;; +esac +am_make=${MAKE-make} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +printf %s "checking whether $am_make supports nested variables... " >&6; } +if test ${am_cv_make_support_nested_variables+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if printf "%s\n" 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +printf "%s\n" "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + 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' + VERSION='5.79' + + +printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h + + +printf "%s\n" "#define VERSION \"$VERSION\"" >>confdefs.h + +# 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"} + +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html> +# <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html> +mkdir_p='$(MKDIR_P)' + +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AMTAR='$${TAR-tar}' + + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar pax cpio none' + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to create a pax tar archive" >&5 +printf %s "checking how to create a pax tar archive... " >&6; } + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_pax-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + { echo "$as_me:$LINENO: $_am_tar --version" >&5 + ($_am_tar --version) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && break + done + am__tar="$_am_tar --format=posix -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=posix -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x pax -w "$$tardir"' + am__tar_='pax -L -x pax -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H pax -L' + am__tar_='find "$tardir" -print | cpio -o -H pax -L' + am__untar='cpio -i -H pax -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_pax}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + { echo "$as_me:$LINENO: tardir=conftest.dir && eval $am__tar_ >conftest.tar" >&5 + (tardir=conftest.dir && eval $am__tar_ >conftest.tar) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + rm -rf conftest.dir + if test -s conftest.tar; then + { echo "$as_me:$LINENO: $am__untar <conftest.tar" >&5 + ($am__untar <conftest.tar) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + { echo "$as_me:$LINENO: cat conftest.dir/file" >&5 + (cat conftest.dir/file) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + grep GrepMe conftest.dir/file >/dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + if test ${am_cv_prog_tar_pax+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) am_cv_prog_tar_pax=$_am_tool ;; +esac +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_pax" >&5 +printf "%s\n" "$am_cv_prog_tar_pax" >&6; } + + + + + +# Variables for tags utilities; see am/tags.am +if test -z "$CTAGS"; then + CTAGS=ctags +fi + +if test -z "$ETAGS"; then + ETAGS=etags +fi + +if test -z "$CSCOPE"; then + CSCOPE=cscope +fi + + + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542> + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: <https://www.gnu.org/software/coreutils/>. + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 + fi +fi + +ac_config_headers="$ac_config_headers config.h" + + +# Check whether --enable-silent-rules was given. +if test ${enable_silent_rules+y} +then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in # ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=0;; +esac +am_make=${MAKE-make} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +printf %s "checking whether $am_make supports nested variables... " >&6; } +if test ${am_cv_make_support_nested_variables+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if printf "%s\n" 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +printf "%s\n" "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +printf %s "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. +if test ${enable_maintainer_mode+y} +then : + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else case e in #( + e) USE_MAINTAINER_MODE=no ;; +esac +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 +printf "%s\n" "$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + + + + + + + + + + + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKG_CONFIG+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +printf "%s\n" "$PKG_CONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac ;; +esac +fi +ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG +if test -n "$ac_pt_PKG_CONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 +printf "%s\n" "$ac_pt_PKG_CONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKG_CONFIG" = x; then + PKG_CONFIG="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKG_CONFIG=$ac_pt_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_path_PKG_CONFIG" +fi + +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=0.9.0 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 +printf %s "checking pkg-config is at least version $_pkg_min_version... " >&6; } + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + PKG_CONFIG="" + fi +fi + + + with_cflags="" + if (test "$USE_MAINTAINER_MODE" = "yes"); then + with_cflags="$with_cflags -Wall -Werror -Wextra" + with_cflags="$with_cflags -Wno-unused-parameter" + with_cflags="$with_cflags -Wno-missing-field-initializers" + with_cflags="$with_cflags -Wdeclaration-after-statement" + with_cflags="$with_cflags -Wmissing-declarations" + with_cflags="$with_cflags -Wredundant-decls" + with_cflags="$with_cflags -Wcast-align" + with_cflags="$with_cflags -Wswitch-enum" + with_cflags="$with_cflags -Wformat -Wformat-security" + with_cflags="$with_cflags -DG_DISABLE_DEPRECATED" + with_cflags="$with_cflags -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_28" + with_cflags="$with_cflags -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_32" + fi + WARNING_CFLAGS=$with_cflags + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 +printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } +cat > confinc.mk << 'END' +am__doit: + @echo this is the am__doit target >confinc.out +.PHONY: am__doit +END +am__include="#" +am__quote= +# BSD make does it like this. +echo '.include "confinc.mk" # ignored' > confmf.BSD +# Other make implementations (GNU, Solaris 10, AIX) do it like this. +echo 'include confinc.mk # ignored' > confmf.GNU +_am_result=no +for s in GNU BSD; do + { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 + (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + case $?:`cat confinc.out 2>/dev/null` in #( + '0:this is the am__doit target') : + case $s in #( + BSD) : + am__include='.include' am__quote='"' ;; #( + *) : + am__include='include' am__quote='' ;; +esac ;; #( + *) : + ;; +esac + if test "$am__include" != "#"; then + _am_result="yes ($s style)" + break + fi +done +rm -f confinc.* confmf.* +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 +printf "%s\n" "${_am_result}" >&6; } + +# Check whether --enable-dependency-tracking was given. +if test ${enable_dependency_tracking+y} +then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + +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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" + fi +fi +fi ;; +esac +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "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:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. +set dummy ${ac_tool_prefix}clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "clang", so it can be a program name with args. +set dummy clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +fi + + +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See 'config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion -version; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM 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. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +printf %s "checking whether the C compiler works... " >&6; } +ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.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 ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +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 | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test ${ac_cv_exeext+y} && 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 case e in #( + e) ac_file='' ;; +esac +fi +if test -z "$ac_file" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See 'config.log' for more details" "$LINENO" 5; } +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +printf %s "checking for C compiler default output file name... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +printf "%s\n" "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +printf %s "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +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 | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else case e in #( + e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See 'config.log' for more details" "$LINENO" 5; } ;; +esac +fi +rm -f conftest conftest$ac_cv_exeext +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +printf "%s\n" "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +int +main (void) +{ +FILE *f = fopen ("conftest.out", "w"); + if (!f) + return 1; + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +printf %s "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error 77 "cannot run C compiled programs. +If you meant to cross compile, use '--host'. +See 'config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +printf "%s\n" "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext \ + conftest.o conftest.obj conftest.out +ac_clean_files=$ac_clean_files_save +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +printf %s "checking for suffix of object files... " >&6; } +if test ${ac_cv_objext+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + 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 ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +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 | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else case e in #( + e) printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See 'config.log' for more details" "$LINENO" 5; } ;; +esac +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +printf "%s\n" "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 +printf %s "checking whether the compiler supports GNU C... " >&6; } +if test ${ac_cv_c_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_compiler_gnu=yes +else case e in #( + e) ac_compiler_gnu=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+y} +ac_save_CFLAGS=$CFLAGS +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +printf %s "checking whether $CC accepts -g... " >&6; } +if test ${ac_cv_prog_cc_g+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_g=yes +else case e in #( + e) CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + +else case e in #( + e) ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +printf "%s\n" "$ac_cv_prog_cc_g" >&6; } +if test $ac_test_CFLAGS; 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 +ac_prog_cc_stdc=no +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 +printf %s "checking for $CC option to enable C11 features... " >&6; } +if test ${ac_cv_prog_cc_c11+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_cv_prog_cc_c11=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c11_program +_ACEOF +for ac_arg in '' -std=gnu11 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c11" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC ;; +esac +fi + +if test "x$ac_cv_prog_cc_c11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else case e in #( + e) if test "x$ac_cv_prog_cc_c11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } + CC="$CC $ac_cv_prog_cc_c11" ;; +esac +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 + ac_prog_cc_stdc=c11 ;; +esac +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 +printf %s "checking for $CC option to enable C99 features... " >&6; } +if test ${ac_cv_prog_cc_c99+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c99_program +_ACEOF +for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC ;; +esac +fi + +if test "x$ac_cv_prog_cc_c99" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else case e in #( + e) if test "x$ac_cv_prog_cc_c99" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } + CC="$CC $ac_cv_prog_cc_c99" ;; +esac +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 + ac_prog_cc_stdc=c99 ;; +esac +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 +printf %s "checking for $CC option to enable C89 features... " >&6; } +if test ${ac_cv_prog_cc_c89+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c89_program +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC ;; +esac +fi + +if test "x$ac_cv_prog_cc_c89" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else case e in #( + e) if test "x$ac_cv_prog_cc_c89" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } + CC="$CC $ac_cv_prog_cc_c89" ;; +esac +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 + ac_prog_cc_stdc=c89 ;; +esac +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 + + + 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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 +printf %s "checking whether $CC understands -c and -o together... " >&6; } +if test ${am_cv_prog_cc_c_o+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 + ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +depcc="$CC" am_compiler_list= + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +printf %s "checking dependency style of $depcc... " >&6; } +if test ${am_cv_CC_dependencies_compiler_type+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +printf "%s\n" "$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 + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5 +printf %s "checking for C/C++ restrict keyword... " >&6; } +if test ${ac_cv_c_restrict+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_cv_c_restrict=no + # Put '__restrict__' first, to avoid problems with glibc and non-GCC; see: + # https://lists.gnu.org/archive/html/bug-autoconf/2016-02/msg00006.html + # Put 'restrict' last, because C++ lacks it. + for ac_kw in __restrict__ __restrict _Restrict restrict; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +typedef int *int_ptr; + int foo (int_ptr $ac_kw ip) { return ip[0]; } + int bar (int [$ac_kw]); /* Catch GCC bug 14050. */ + int bar (int ip[$ac_kw]) { return ip[0]; } + +int +main (void) +{ +int s[1]; + int *$ac_kw t = s; + t[0] = 0; + return foo (t) + bar (t); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_c_restrict=$ac_kw +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + test "$ac_cv_c_restrict" != no && break + done + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5 +printf "%s\n" "$ac_cv_c_restrict" >&6; } + + case $ac_cv_c_restrict in + restrict) ;; + no) printf "%s\n" "#define restrict /**/" >>confdefs.h + ;; + *) printf "%s\n" "#define restrict $ac_cv_c_restrict" >>confdefs.h + ;; + 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 +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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" + fi +fi +fi ;; +esac +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "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:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. +set dummy ${ac_tool_prefix}clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "clang", so it can be a program name with args. +set dummy clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +fi + + +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See 'config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion -version; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 +printf %s "checking whether the compiler supports GNU C... " >&6; } +if test ${ac_cv_c_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_compiler_gnu=yes +else case e in #( + e) ac_compiler_gnu=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+y} +ac_save_CFLAGS=$CFLAGS +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +printf %s "checking whether $CC accepts -g... " >&6; } +if test ${ac_cv_prog_cc_g+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_g=yes +else case e in #( + e) CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + +else case e in #( + e) ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +printf "%s\n" "$ac_cv_prog_cc_g" >&6; } +if test $ac_test_CFLAGS; 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 +ac_prog_cc_stdc=no +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 +printf %s "checking for $CC option to enable C11 features... " >&6; } +if test ${ac_cv_prog_cc_c11+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_cv_prog_cc_c11=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c11_program +_ACEOF +for ac_arg in '' -std=gnu11 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c11" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC ;; +esac +fi + +if test "x$ac_cv_prog_cc_c11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else case e in #( + e) if test "x$ac_cv_prog_cc_c11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } + CC="$CC $ac_cv_prog_cc_c11" ;; +esac +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 + ac_prog_cc_stdc=c11 ;; +esac +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 +printf %s "checking for $CC option to enable C99 features... " >&6; } +if test ${ac_cv_prog_cc_c99+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c99_program +_ACEOF +for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC ;; +esac +fi + +if test "x$ac_cv_prog_cc_c99" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else case e in #( + e) if test "x$ac_cv_prog_cc_c99" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } + CC="$CC $ac_cv_prog_cc_c99" ;; +esac +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 + ac_prog_cc_stdc=c99 ;; +esac +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 +printf %s "checking for $CC option to enable C89 features... " >&6; } +if test ${ac_cv_prog_cc_c89+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c89_program +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC ;; +esac +fi + +if test "x$ac_cv_prog_cc_c89" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else case e in #( + e) if test "x$ac_cv_prog_cc_c89" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } + CC="$CC $ac_cv_prog_cc_c89" ;; +esac +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 + ac_prog_cc_stdc=c89 ;; +esac +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 + + + 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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 +printf %s "checking whether $CC understands -c and -o together... " >&6; } +if test ${am_cv_prog_cc_c_o+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 + ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +depcc="$CC" am_compiler_list= + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +printf %s "checking dependency style of $depcc... " >&6; } +if test ${am_cv_CC_dependencies_compiler_type+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +printf "%s\n" "$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 + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${CC-cc} accepts -fPIE" >&5 +printf %s "checking whether ${CC-cc} accepts -fPIE... " >&6; } +if test ${ac_cv_prog_cc_pie+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) + 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* + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_pie" >&5 +printf "%s\n" "$ac_cv_prog_cc_pie" >&6; } + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${CC-cc} accepts -fsanitize=address" >&5 +printf %s "checking whether ${CC-cc} accepts -fsanitize=address... " >&6; } +if test ${ac_cv_prog_cc_asan+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) + echo 'void f(){}' > asan.c + if test -z "`${CC-cc} -fsanitize=address -c asan.c 2>&1`"; then + ac_cv_prog_cc_asan=yes + else + ac_cv_prog_cc_asan=no + fi + rm -rf asan* + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_asan" >&5 +printf "%s\n" "$ac_cv_prog_cc_asan" >&6; } + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${CC-cc} accepts -fsanitize=leak" >&5 +printf %s "checking whether ${CC-cc} accepts -fsanitize=leak... " >&6; } +if test ${ac_cv_prog_cc_lsan+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) + echo 'void f(){}' > lsan.c + if test -z "`${CC-cc} -fsanitize=leak -c lsan.c 2>&1`"; then + ac_cv_prog_cc_lsan=yes + else + ac_cv_prog_cc_lsan=no + fi + rm -rf lsan* + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_lsan" >&5 +printf "%s\n" "$ac_cv_prog_cc_lsan" >&6; } + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${CC-cc} accepts -fsanitize=undefined" >&5 +printf %s "checking whether ${CC-cc} accepts -fsanitize=undefined... " >&6; } +if test ${ac_cv_prog_cc_ubsan+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) + echo 'void f(){}' > ubsan.c + if test -z "`${CC-cc} -fsanitize=undefined -c ubsan.c 2>&1`"; then + ac_cv_prog_cc_ubsan=yes + else + ac_cv_prog_cc_ubsan=no + fi + rm -rf ubsan* + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_ubsan" >&5 +printf "%s\n" "$ac_cv_prog_cc_ubsan" >&6; } + + + + + + + + +case `pwd` in + *\ * | *\ *) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +printf "%s\n" "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.4.7' +macro_revision='2.4.7' + + + + + + + + + + + + + + +ltmain=$ac_aux_dir/ltmain.sh + + + + # Make sure we can run config.sub. +$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +printf %s "checking build system type... " >&6; } +if test ${ac_cv_build+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +printf "%s\n" "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +printf %s "checking host system type... " >&6; } +if test ${ac_cv_host+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 +fi + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +printf "%s\n" "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 +printf %s "checking how to print strings... " >&6; } +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "" +} + +case $ECHO in + printf*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: printf" >&5 +printf "%s\n" "printf" >&6; } ;; + print*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 +printf "%s\n" "print -r" >&6; } ;; + *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cat" >&5 +printf "%s\n" "cat" >&6; } ;; +esac + + + + + + + + + + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +printf %s "checking for a sed that does not truncate output... " >&6; } +if test ${ac_cv_path_SED+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in sed gsed + do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_SED" || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in #( +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +#( +*) + ac_count=0 + printf %s 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + printf "%s\n" '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +printf "%s\n" "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +printf %s "checking for grep that handles long lines and -e... " >&6; } +if test ${ac_cv_path_GREP+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in grep ggrep + do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in #( +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +#( +*) + ac_count=0 + printf %s 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + printf "%s\n" 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +printf "%s\n" "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +printf %s "checking for egrep... " >&6; } +if test ${ac_cv_path_EGREP+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in egrep + do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in #( +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +#( +*) + ac_count=0 + printf %s 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + printf "%s\n" 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +printf "%s\n" "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + EGREP_TRADITIONAL=$EGREP + ac_cv_path_EGREP_TRADITIONAL=$EGREP + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +printf %s "checking for fgrep... " >&6; } +if test ${ac_cv_path_FGREP+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in fgrep + do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_FGREP" || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in #( +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +#( +*) + ac_count=0 + printf %s 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + printf "%s\n" 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +printf "%s\n" "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test ${with_gnu_ld+y} +then : + withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes +else case e in #( + e) with_gnu_ld=no ;; +esac +fi + +ac_prog=ld +if test yes = "$GCC"; then + # Check if gcc -print-prog-name=ld gives a path. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +printf %s "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return, which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD=$ac_prog + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test yes = "$with_gnu_ld"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +printf %s "checking for GNU ld... " >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +printf %s "checking for non-GNU ld... " >&6; } +fi +if test ${lt_cv_path_LD+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 no != "$with_gnu_ld" && break + ;; + *) + test yes != "$with_gnu_ld" && break + ;; + esac + fi + done + IFS=$lt_save_ifs +else + lt_cv_path_LD=$LD # Let the user override the test with a path. +fi ;; +esac +fi + +LD=$lt_cv_path_LD +if test -n "$LD"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 +printf "%s\n" "$LD" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +printf %s "checking if the linker ($LD) is GNU ld... " >&6; } +if test ${lt_cv_prog_gnu_ld+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) # 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 ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5 +printf "%s\n" "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +printf %s "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if test ${lt_cv_path_NM+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty + case $build_os in + mingw*) lt_bad_file=conftest.nm/nofile ;; + *) lt_bad_file=/dev/null ;; + esac + case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in + *$lt_bad_file* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break 2 + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break 2 + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS=$lt_save_ifs + done + : ${lt_cv_path_NM=no} +fi ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +printf "%s\n" "$lt_cv_path_NM" >&6; } +if test no != "$lt_cv_path_NM"; then + NM=$lt_cv_path_NM +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + if test -n "$ac_tool_prefix"; then + for ac_prog in dumpbin "link -dump" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_DUMPBIN+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +printf "%s\n" "$DUMPBIN" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in dumpbin "link -dump" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_DUMPBIN+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +printf "%s\n" "$ac_ct_DUMPBIN" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + case `$DUMPBIN -symbols -headers /dev/null 2>&1 | $SED '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols -headers" + ;; + *) + DUMPBIN=: + ;; + esac + fi + + if test : != "$DUMPBIN"; then + NM=$DUMPBIN + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +printf %s "checking the name lister ($NM) interface... " >&6; } +if test ${lt_cv_nm_interface+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +printf "%s\n" "$lt_cv_nm_interface" >&6; } + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +printf %s "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +printf "%s\n" "no, using $LN_S" >&6; } +fi + +# find the maximum length of command line arguments +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +printf %s "checking the maximum length of command line arguments... " >&6; } +if test ${lt_cv_sys_max_cmd_len+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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* | cegcc*) + # 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; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + 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; + ;; + + bitrig* | darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) + # 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 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + 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" && \ + test undefined != "$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 + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test X`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test 17 != "$i" # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + 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 + ;; +esac +fi + +if test -n "$lt_cv_sys_max_cmd_len"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +printf "%s\n" "$lt_cv_sys_max_cmd_len" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5 +printf "%s\n" "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# 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 + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 +printf %s "checking how to convert $build file names to $host format... " >&6; } +if test ${lt_cv_to_host_file_cmd+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac + ;; +esac +fi + +to_host_file_cmd=$lt_cv_to_host_file_cmd +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 +printf "%s\n" "$lt_cv_to_host_file_cmd" >&6; } + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 +printf %s "checking how to convert $build file names to toolchain format... " >&6; } +if test ${lt_cv_to_tool_file_cmd+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) #assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac + ;; +esac +fi + +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 +printf "%s\n" "$lt_cv_to_tool_file_cmd" >&6; } + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +printf %s "checking for $LD option to reload object files... " >&6; } +if test ${lt_cv_ld_reload_flag+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) lt_cv_ld_reload_flag='-r' ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +printf "%s\n" "$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 + cygwin* | mingw* | pw32* | cegcc*) + if test yes != "$GCC"; then + reload_cmds=false + fi + ;; + darwin*) + if test yes = "$GCC"; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}file", so it can be a program name with args. +set dummy ${ac_tool_prefix}file; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_FILECMD+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$FILECMD"; then + ac_cv_prog_FILECMD="$FILECMD" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_FILECMD="${ac_tool_prefix}file" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +FILECMD=$ac_cv_prog_FILECMD +if test -n "$FILECMD"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FILECMD" >&5 +printf "%s\n" "$FILECMD" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_FILECMD"; then + ac_ct_FILECMD=$FILECMD + # Extract the first word of "file", so it can be a program name with args. +set dummy file; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_FILECMD+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$ac_ct_FILECMD"; then + ac_cv_prog_ac_ct_FILECMD="$ac_ct_FILECMD" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_FILECMD="file" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_FILECMD=$ac_cv_prog_ac_ct_FILECMD +if test -n "$ac_ct_FILECMD"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_FILECMD" >&5 +printf "%s\n" "$ac_ct_FILECMD" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_FILECMD" = x; then + FILECMD=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + FILECMD=$ac_ct_FILECMD + fi +else + FILECMD="$ac_cv_prog_FILECMD" +fi + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_OBJDUMP+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +printf "%s\n" "$OBJDUMP" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_OBJDUMP+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +printf "%s\n" "$ac_ct_OBJDUMP" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +printf %s "checking how to recognize dependent libraries... " >&6; } +if test ${lt_cv_deplibs_check_method+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 +# that 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 +aix[4-9]*) + 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='$FILECMD -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 + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly* | midnightbsd*) + 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=$FILECMD + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=$FILECMD + 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])(-bit)?( [LM]SB)? 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 glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + 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=$FILECMD + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd* | bitrig*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; 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 + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + 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 + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +os2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +printf "%s\n" "$lt_cv_deplibs_check_method" >&6; } + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` + fi + ;; + esac +fi + +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 test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_DLLTOOL+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 +printf "%s\n" "$DLLTOOL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_DLLTOOL+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 +printf "%s\n" "$ac_ct_DLLTOOL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DLLTOOL=$ac_ct_DLLTOOL + fi +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + +test -z "$DLLTOOL" && DLLTOOL=dlltool + + + + + + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 +printf %s "checking how to associate runtime and link libraries... " >&6; } +if test ${lt_cv_sharedlib_from_linklib_cmd+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh; + # decide which one to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd=$ECHO + ;; +esac + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 +printf "%s\n" "$lt_cv_sharedlib_from_linklib_cmd" >&6; } +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + + + + + + + +if test -n "$ac_tool_prefix"; then + for ac_prog in ar + 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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_AR+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="$ac_tool_prefix$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +printf "%s\n" "$AR" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$AR" && break + done +fi +if test -z "$AR"; then + ac_ct_AR=$AR + for ac_prog in ar +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_AR+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +printf "%s\n" "$ac_ct_AR" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$ac_ct_AR" && break +done + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +fi + +: ${AR=ar} + + + + + + +# Use ARFLAGS variable as AR's operation code to sync the variable naming with +# Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have +# higher priority because thats what people were doing historically (setting +# ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS +# variable obsoleted/removed. + +test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr} +lt_ar_flags=$AR_FLAGS + + + + + + +# Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override +# by AR_FLAGS because that was never working and AR_FLAGS is about to die. + + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 +printf %s "checking for archiver @FILE support... " >&6; } +if test ${lt_cv_ar_at_file+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) lt_cv_ar_at_file=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test 0 -eq "$ac_status"; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test 0 -ne "$ac_status"; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 +printf "%s\n" "$lt_cv_ar_at_file" >&6; } + +if test no = "$lt_cv_ar_at_file"; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_STRIP+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +printf "%s\n" "$STRIP" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_STRIP+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +printf "%s\n" "$ac_ct_STRIP" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_RANLIB+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +printf "%s\n" "$RANLIB" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_RANLIB+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +printf "%s\n" "$ac_ct_RANLIB" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# 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 + bitrig* | openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# 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 for command to grab the raw symbol name followed by C symbol from nm. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +printf %s "checking command to parse $NM output from $compiler object... " >&6; } +if test ${lt_cv_sys_global_symbol_pipe+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) +# 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]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test ia64 = "$host_cpu"; then + symcode='[ABCDEGRST]' + 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 + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Gets list of data symbols to import. + lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'" + # Adjust the below global symbol transforms to fixup imported variables. + lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" + lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" + lt_c_name_lib_hook="\ + -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ + -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" +else + # Disable hooks by default. + lt_cv_sys_global_symbol_to_import= + lt_cdecl_hook= + lt_c_name_hook= + lt_c_name_lib_hook= +fi + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="$SED -n"\ +$lt_cdecl_hook\ +" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="$SED -n"\ +$lt_c_name_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" + +# Transform an extracted symbol line into symbol name with lib prefix and +# symbol address. +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\ +$lt_c_name_lib_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" + +# 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 + +# Try without a prefix underscore, 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. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function, + # D for any global variable and I for any imported variable. + # Also find C++ and __fastcall symbols from MSVC++ or ICC, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ +" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ +" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ +" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ +" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="$SED -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | $SED '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5 + if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && 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 <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined __osf__ +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS=conftstm.$ac_objext + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest$ac_exeext; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_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 -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test yes = "$pipe_works"; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + ;; +esac +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 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +printf "%s\n" "failed" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +printf "%s\n" "ok" >&6; } +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 +printf %s "checking for sysroot... " >&6; } + +# Check whether --with-sysroot was given. +if test ${with_sysroot+y} +then : + withval=$with_sysroot; +else case e in #( + e) with_sysroot=no ;; +esac +fi + + +lt_sysroot= +case $with_sysroot in #( + yes) + if test yes = "$GCC"; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 +printf "%s\n" "$with_sysroot" >&6; } + as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 + ;; +esac + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 +printf "%s\n" "${lt_sysroot:-no}" >&6; } + + + + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 +printf %s "checking for a working dd... " >&6; } +if test ${ac_cv_path_lt_DD+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +: ${lt_DD:=$DD} +if test -z "$lt_DD"; then + ac_path_lt_DD_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in dd + do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_lt_DD="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_lt_DD" || continue +if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: +fi + $ac_path_lt_DD_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_lt_DD"; then + : + fi +else + ac_cv_path_lt_DD=$lt_DD +fi + +rm -f conftest.i conftest2.i conftest.out ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 +printf "%s\n" "$ac_cv_path_lt_DD" >&6; } + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 +printf %s "checking how to truncate binary pipes... " >&6; } +if test ${lt_cv_truncate_bin+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +lt_cv_truncate_bin= +if "$ac_cv_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" +fi +rm -f conftest.i conftest2.i conftest.out +test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 +printf "%s\n" "$lt_cv_truncate_bin" >&6; } + + + + + + + +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in $*""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} + +# Check whether --enable-libtool-lock was given. +if test ${enable_libtool_lock+y} +then : + enableval=$enable_libtool_lock; +fi + +test no = "$enable_libtool_lock" || 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 what ABI is being produced by ac_compile, and set mode + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `$FILECMD conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE=32 + ;; + *ELF-64*) + HPUX_IA64_MODE=64 + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test yes = "$lt_cv_prog_gnu_ld"; then + case `$FILECMD conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `$FILECMD 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* + ;; + +mips64*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + emul=elf + case `$FILECMD conftest.$ac_objext` in + *32-bit*) + emul="${emul}32" + ;; + *64-bit*) + emul="${emul}64" + ;; + esac + case `$FILECMD conftest.$ac_objext` in + *MSB*) + emul="${emul}btsmip" + ;; + *LSB*) + emul="${emul}ltsmip" + ;; + esac + case `$FILECMD conftest.$ac_objext` in + *N32*) + emul="${emul}n32" + ;; + esac + LD="${LD-ld} -m $emul" + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. Note that the listed cases only cover the + # situations where additional linker options are needed (such as when + # doing 32-bit compilation for a host where ld defaults to 64-bit, or + # vice versa); the common cases where no linker options are needed do + # not appear in the list. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `$FILECMD conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + case `$FILECMD conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*linux*) + LD="${LD-ld} -m elf32lppclinux" + ;; + 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*) + 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" + ;; + powerpcle-*linux*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + 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" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +printf %s "checking whether the C compiler needs -belf... " >&6; } +if test ${lt_cv_cc_needs_belf+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + lt_cv_cc_needs_belf=yes +else case e in #( + e) lt_cv_cc_needs_belf=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + 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 + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +printf "%s\n" "$lt_cv_cc_needs_belf" >&6; } + if test yes != "$lt_cv_cc_needs_belf"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS=$SAVE_CFLAGS + fi + ;; +*-*solaris*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `$FILECMD conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*|x86_64-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD=${LD-ld}_sol2 + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks=$enable_libtool_lock + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. +set dummy ${ac_tool_prefix}mt; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_MANIFEST_TOOL+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$MANIFEST_TOOL"; then + ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL +if test -n "$MANIFEST_TOOL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 +printf "%s\n" "$MANIFEST_TOOL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_MANIFEST_TOOL"; then + ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL + # Extract the first word of "mt", so it can be a program name with args. +set dummy mt; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_MANIFEST_TOOL+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$ac_ct_MANIFEST_TOOL"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL +if test -n "$ac_ct_MANIFEST_TOOL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 +printf "%s\n" "$ac_ct_MANIFEST_TOOL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_MANIFEST_TOOL" = x; then + MANIFEST_TOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL + fi +else + MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" +fi + +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 +printf %s "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } +if test ${lt_cv_path_mainfest_tool+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&5 + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest* ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 +printf "%s\n" "$lt_cv_path_mainfest_tool" >&6; } +if test yes != "$lt_cv_path_mainfest_tool"; then + MANIFEST_TOOL=: +fi + + + + + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_DSYMUTIL+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +printf "%s\n" "$DSYMUTIL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_DSYMUTIL+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +printf "%s\n" "$ac_ct_DSYMUTIL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_NMEDIT+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +printf "%s\n" "$NMEDIT" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_NMEDIT+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +printf "%s\n" "$ac_ct_NMEDIT" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_LIPO+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +printf "%s\n" "$LIPO" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_LIPO+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_LIPO="lipo" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +printf "%s\n" "$ac_ct_LIPO" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_OTOOL+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +printf "%s\n" "$OTOOL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_OTOOL+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL="otool" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +printf "%s\n" "$ac_ct_OTOOL" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_OTOOL64+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +printf "%s\n" "$OTOOL64" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_OTOOL64+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +printf "%s\n" "$ac_ct_OTOOL64" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +printf %s "checking for -single_module linker flag... " >&6; } +if test ${lt_cv_apple_cc_single_mod+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) lt_cv_apple_cc_single_mod=no + if test -z "$LT_MULTI_MODULE"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&5 + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test 0 = "$_lt_result"; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +printf "%s\n" "$lt_cv_apple_cc_single_mod" >&6; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +printf %s "checking for -exported_symbols_list linker flag... " >&6; } +if test ${lt_cv_ld_exported_symbols_list+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + lt_cv_ld_exported_symbols_list=yes +else case e in #( + e) lt_cv_ld_exported_symbols_list=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +printf "%s\n" "$lt_cv_ld_exported_symbols_list" >&6; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 +printf %s "checking for -force_load linker flag... " >&6; } +if test ${lt_cv_ld_force_load+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 + echo "$AR $AR_FLAGS libconftest.a conftest.o" >&5 + $AR $AR_FLAGS libconftest.a conftest.o 2>&5 + echo "$RANLIB libconftest.a" >&5 + $RANLIB libconftest.a 2>&5 + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&5 + elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&5 + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 +printf "%s\n" "$lt_cv_ld_force_load" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + darwin*) + case $MACOSX_DEPLOYMENT_TARGET,$host in + 10.[012],*|,*powerpc*-darwin[5-8]*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + *) + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test yes = "$lt_cv_apple_cc_single_mod"; then + _lt_dar_single_mod='$single_module' + fi + if test yes = "$lt_cv_ld_exported_symbols_list"; then + _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' + fi + if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + +# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x$2 in + x) + ;; + *:) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" + ;; + x:*) + eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" + ;; + *) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" + ;; + esac +} + +ac_header= ac_cache= +for ac_item in $ac_header_c_list +do + if test $ac_cache; then + ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" + if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then + printf "%s\n" "#define $ac_item 1" >> confdefs.h + fi + ac_header= ac_cache= + elif test $ac_header; then + ac_cache=$ac_item + else + ac_header=$ac_item + fi +done + + + + + + + + +if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes +then : + +printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = xyes +then : + printf "%s\n" "#define HAVE_DLFCN_H 1" >>confdefs.h + +fi + + + + + +# Set options +# Check whether --enable-static was given. +if test ${enable_static+y} +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 case e in #( + e) enable_static=no ;; +esac +fi + + + + + + + + + + + enable_dlopen=no + + + enable_win32_dll=no + + + # Check whether --enable-shared was given. +if test ${enable_shared+y} +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 case e in #( + e) enable_shared=yes ;; +esac +fi + + + + + + + + + + + +# Check whether --with-pic was given. +if test ${with_pic+y} +then : + withval=$with_pic; lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for lt_pkg in $withval; do + IFS=$lt_save_ifs + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS=$lt_save_ifs + ;; + esac +else case e in #( + e) pic_mode=default ;; +esac +fi + + + + + + + + + # Check whether --enable-fast-install was given. +if test ${enable_fast_install+y} +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 case e in #( + e) enable_fast_install=yes ;; +esac +fi + + + + + + + + + shared_archive_member_spec= +case $host,$enable_shared in +power*-*-aix[5-9]*,yes) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 +printf %s "checking which variant of shared library versioning to provide... " >&6; } + +# Check whether --with-aix-soname was given. +if test ${with_aix_soname+y} +then : + withval=$with_aix_soname; case $withval in + aix|svr4|both) + ;; + *) + as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 + ;; + esac + lt_cv_with_aix_soname=$with_aix_soname +else case e in #( + e) if test ${lt_cv_with_aix_soname+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) lt_cv_with_aix_soname=aix ;; +esac +fi + + with_aix_soname=$lt_cv_with_aix_soname ;; +esac +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 +printf "%s\n" "$with_aix_soname" >&6; } + if test aix != "$with_aix_soname"; then + # For the AIX way of multilib, we name the shared archive member + # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', + # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. + # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, + # the AIX toolchain works better with OBJECT_MODE set (default 32). + if test 64 = "${OBJECT_MODE-32}"; then + shared_archive_member_spec=shr_64 + else + shared_archive_member_spec=shr + fi + fi + ;; +*) + with_aix_soname=aix + ;; +esac + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS=$ltmain + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +printf %s "checking for objdir... " >&6; } +if test ${lt_cv_objdir+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +printf "%s\n" "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +printf "%s\n" "#define LT_OBJDIR \"$lt_cv_objdir/\"" >>confdefs.h + + + + +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 set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a '.a' archive for static linking (except MSVC and +# ICC, which need '.lib'). +libext=a + +with_gnu_ld=$lt_cv_prog_gnu_ld + +old_CC=$CC +old_CFLAGS=$CFLAGS + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +func_cc_basename $compiler +cc_basename=$func_cc_basename_result + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +printf %s "checking for ${ac_tool_prefix}file... " >&6; } +if test ${lt_cv_path_MAGIC_CMD+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 <<_LT_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 + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS=$lt_save_ifs + MAGIC_CMD=$lt_save_MAGIC_CMD + ;; +esac ;; +esac +fi + +MAGIC_CMD=$lt_cv_path_MAGIC_CMD +if test -n "$MAGIC_CMD"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +printf "%s\n" "$MAGIC_CMD" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +printf %s "checking for file... " >&6; } +if test ${lt_cv_path_MAGIC_CMD+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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 <<_LT_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 + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS=$lt_save_ifs + MAGIC_CMD=$lt_save_MAGIC_CMD + ;; +esac ;; +esac +fi + +MAGIC_CMD=$lt_cv_path_MAGIC_CMD +if test -n "$MAGIC_CMD"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +printf "%s\n" "$MAGIC_CMD" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +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 the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$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 -r conftest* + + +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test yes = "$GCC"; then + case $cc_basename in + nvcc*) + lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; + *) + lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; + esac + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +printf %s "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if test ${lt_cv_prog_compiler_rtti_exceptions+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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" ## exclude from sc_useless_quotes_in_assignment + # 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:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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* + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +printf "%s\n" "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; 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= + + + if test yes = "$GCC"; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + lt_prog_compiler_pic='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # 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' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # 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' + case $host_os in + os2*) + lt_prog_compiler_static='$wl-static' + ;; + esac + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + 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 + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + lt_prog_compiler_wl='-Xlinker ' + if test -n "$lt_prog_compiler_pic"; then + lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" + fi + ;; + 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 ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + case $cc_basename in + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + esac + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # 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' + case $host_os in + os2*) + lt_prog_compiler_static='$wl-static' + ;; + esac + ;; + + 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' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + # old Intel for x86_64, which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # flang / f18. f95 an alias for gfortran or flang on Debian + flang* | f18* | f95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # 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' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | $SED 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) + # 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='' + ;; + *Sun\ F* | *Sun*Fortran*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Intel*\ [CF]*Compiler*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + *Portland\ Group*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + 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* | sunf77* | sunf90* | sunf95*) + 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 + +case $host_os in + # For platforms that do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +printf %s "checking for $compiler option to produce PIC... " >&6; } +if test ${lt_cv_prog_compiler_pic+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) lt_cv_prog_compiler_pic=$lt_prog_compiler_pic ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 +printf "%s\n" "$lt_cv_prog_compiler_pic" >&6; } +lt_prog_compiler_pic=$lt_cv_prog_compiler_pic + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if test ${lt_cv_prog_compiler_pic_works+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) lt_cv_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" ## exclude from sc_useless_quotes_in_assignment + # 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:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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_pic_works=yes + fi + fi + $RM conftest* + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +printf "%s\n" "$lt_cv_prog_compiler_pic_works" >&6; } + +if test yes = "$lt_cv_prog_compiler_pic_works"; 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 + + + + + + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if test ${lt_cv_prog_compiler_static_works+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) lt_cv_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 "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS=$save_LDFLAGS + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +printf "%s\n" "$lt_cv_prog_compiler_static_works" >&6; } + +if test yes = "$lt_cv_prog_compiler_static_works"; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test ${lt_cv_prog_compiler_c_o+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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 .. + $RM -r conftest + $RM conftest* + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test ${lt_cv_prog_compiler_c_o+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) 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:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $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 "$_lt_compiler_boilerplate" | $SED '/^$/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 .. + $RM -r conftest + $RM conftest* + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links=nottested +if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then + # do not overwrite the value of need_locks provided by the user + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +printf %s "checking if we can lock with hard links... " >&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 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +printf "%s\n" "$hard_links" >&6; } + if test no = "$hard_links"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 +printf "%s\n" "$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 + + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +printf %s "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # 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_|_GLOBAL__F[ID]_.*' + # 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. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++ or Intel C++ Compiler. + if test yes != "$GCC"; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) + with_gnu_ld=yes + ;; + openbsd* | bitrig*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu | gnu*) + link_all_deplibs=no + ;; + esac + + ld_shlibs=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test yes = "$with_gnu_ld"; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; + *\ \(GNU\ Binutils\)\ [3-9]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test yes = "$lt_use_gnu_ld_interface"; 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 | $SED -e 's/([^)]\+)\s\+//' 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [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 + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test ia64 != "$host_cpu"; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, 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 install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + 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 + ;; + esac + ;; + + 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* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + export_dynamic_flag_spec='$wl--export-all-symbols' + 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/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + + 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, use it as + # is; otherwise, prepend EXPORTS... + archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; 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 + ;; + + haiku*) + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + link_all_deplibs=yes + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + shrext_cmds=.dll + archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + enable_shared_with_static_runtimes=yes + file_list_spec='@' + ;; + + 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* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test linux-dietlibc = "$host_os"; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test no = "$tmp_diet" + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + 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; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # 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; func_echo_all \"$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' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + nagfor*) # NAGFOR 5.3 + tmp_sharedflag='-Wl,-shared' ;; + xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + compiler_needs_object=yes + ;; + 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; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + + if test yes = "$supports_anon_versioning"; 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 + + case $cc_basename in + tcc*) + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + export_dynamic_flag_spec='-rdynamic' + ;; + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test yes = "$supports_anon_versioning"; 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~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + 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 $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $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 <<_LT_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. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $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 cannot +*** 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 + ;; + *) + # 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. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + 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 + ;; + + 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 $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $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 no = "$ld_shlibs"; 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 yes = "$GCC" && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test ia64 = "$host_cpu"; 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 GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX 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") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | 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 + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then + aix_use_runtimelinking=yes + break + fi + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + 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_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='$wl-f,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # traditional, no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + hardcode_direct=no + hardcode_direct_absolute=no + ;; + esac + + if test yes = "$GCC"; 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 yes = "$aix_use_runtimelinking"; then + shared_flag="$shared_flag "'$wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; 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 yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + fi + fi + + export_dynamic_flag_spec='$wl-bexpall' + # 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,yes = "$with_aix_soname,$aix_use_runtimelinking"; 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. + if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + if test ${lt_cv_aix_libpath_+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_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 "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=/usr/lib:/lib + fi + ;; +esac +fi + + aix_libpath=$lt_cv_aix_libpath_ +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 -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; 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. + if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + if test ${lt_cv_aix_libpath_+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_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 "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=/usr/lib:/lib + fi + ;; +esac +fi + + aix_libpath=$lt_cv_aix_libpath_ +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' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + fi + archive_cmds_need_lc=yes + archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + 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 + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++ or Intel C++ Compiler. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl* | icl*) + # Native MSVC or ICC + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + always_export_symbols=yes + file_list_spec='@' + # 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 $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, )='true' + enable_shared_with_static_runtimes=yes + exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + old_postinstall_cmds='chmod 644 $oldlib' + postlink_cmds='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC and ICC wrapper + 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 `func_echo_all "$deplibs" | $SED '\''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' + enable_shared_with_static_runtimes=yes + ;; + esac + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + if test yes = "$lt_cv_ld_force_load"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec='' + fi + link_all_deplibs=yes + allow_undefined_flag=$_lt_dar_allow_undefined + case $cc_basename in + ifort*|nagfor*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test yes = "$_lt_dar_can_shared"; then + output_verbose_link_cmd=func_echo_all + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" + archive_expsym_cmds="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" + module_expsym_cmds="$SED -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=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* | midnightbsd*) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test yes = "$GCC"; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$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 "x$output_objdir/$soname" = "x$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 yes,no = "$GCC,$with_gnu_ld"; then + archive_cmds='$CC -shared $pic_flag $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 no = "$with_gnu_ld"; then + hardcode_libdir_flag_spec='$wl+b $wl$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=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 yes,no = "$GCC,$with_gnu_ld"; 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 $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared $pic_flag $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' + ;; + *) + + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 +printf %s "checking if $CC understands -b... " >&6; } +if test ${lt_cv_prog_compiler__b+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) lt_cv_prog_compiler__b=no + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -b" + 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 "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler__b=yes + fi + else + lt_cv_prog_compiler__b=yes + fi + fi + $RM -r conftest* + LDFLAGS=$save_LDFLAGS + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 +printf "%s\n" "$lt_cv_prog_compiler__b" >&6; } + +if test yes = "$lt_cv_prog_compiler__b"; then + archive_cmds='$CC -b $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 + + ;; + esac + fi + if test no = "$with_gnu_ld"; then + hardcode_libdir_flag_spec='$wl+b $wl$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=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 yes = "$GCC"; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 +printf %s "checking whether the $host_os linker accepts -exported_symbol... " >&6; } +if test ${lt_cv_irix_exported_symbol+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo (void) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + lt_cv_irix_exported_symbol=yes +else case e in #( + e) lt_cv_irix_exported_symbol=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 +printf "%s\n" "$lt_cv_irix_exported_symbol" >&6; } + if test yes = "$lt_cv_irix_exported_symbol"; then + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' + fi + link_all_deplibs=no + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + linux*) + case $cc_basename in + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + ld_shlibs=yes + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + ;; + esac + ;; + + netbsd* | netbsdelf*-gnu) + 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 + ;; + + *nto* | *qnx*) + ;; + + openbsd* | bitrig*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; 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 + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='$wl-rpath,$libdir' + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + shrext_cmds=.dll + archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + enable_shared_with_static_runtimes=yes + file_list_spec='@' + ;; + + osf3*) + if test yes = "$GCC"; 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" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test yes = "$GCC"; then + allow_undefined_flag=' $wl-expect_unresolved $wl\*' + archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$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='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-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; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_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 + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test yes = "$GCC"; then + wlarc='$wl' + archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $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 $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + 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' + ;; + *) + wlarc='$wl' + archive_cmds='$CC -G$allow_undefined_flag -h $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 -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + 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 yes = "$GCC"; 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 sequent = "$host_vendor"; 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 yes = "$GCC"; 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 CANNOT 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='$wl-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='$wl-Bexport' + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; 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 + ;; + + 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 + + if test sni = "$host_vendor"; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='$wl-Blargedynsym' + ;; + esac + fi + fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +printf "%s\n" "$ld_shlibs" >&6; } +test no = "$ld_shlibs" && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# 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 yes,yes = "$GCC,$enable_shared"; 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. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +printf %s "checking whether -lc should be explicitly linked in... " >&6; } +if test ${lt_cv_archive_cmds_need_lc+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 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\":${as_lineno-$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=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 +printf "%s\n" "$lt_cv_archive_cmds_need_lc" >&6; } + archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +printf %s "checking dynamic linker characteristics... " >&6; } + +if test yes = "$GCC"; then + case $host_os in + darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; + *) lt_awk_arg='/^libraries:/' ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; + *) lt_sed_strip_eq='s|=/|/|g' ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # 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 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # 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` + # ...but if some path component already ends with the multilib dir we assume + # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). + case "$lt_multi_os_dir; $lt_search_path_spec " in + "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) + lt_multi_os_dir= + ;; + esac + 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" + elif test -n "$lt_multi_os_dir"; then + 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; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's|/\([A-Za-z]:\)|\1|g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +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" +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 # correct to gnu/linux during the next big refactor + 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' + ;; + +aix[4-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test ia64 = "$host_cpu"; 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 + # Using Import Files as archive members, it is possible to support + # filename-based versioning of shared library archives on AIX. While + # this would work for both with and without runtime linking, it will + # prevent static linking of such archives. So we do filename-based + # shared library versioning with .so extension only, which is used + # when both runtime linking and shared linking is enabled. + # Unfortunately, runtime linking may impact performance, so we do + # not want this to be the default eventually. Also, we use the + # versioned .so libs for executables only if there is the -brtl + # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. + # To allow for filename-based versioning support, we need to create + # libNAME.so.V as an archive file, containing: + # *) an Import File, referring to the versioned filename of the + # archive as well as the shared archive member, telling the + # bitwidth (32 or 64) of that shared object, and providing the + # list of exported symbols of that shared object, eventually + # decorated with the 'weak' keyword + # *) the shared object with the F_LOADONLY flag set, to really avoid + # it being seen by the linker. + # At run time we better use the real file rather than another symlink, + # but for link time we create the symlink libNAME.so -> libNAME.so.V + + case $with_aix_soname,$aix_use_runtimelinking in + # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + aix,yes) # traditional libtool + dynamic_linker='AIX unversionable lib.so' + # 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' + ;; + aix,no) # traditional AIX only + dynamic_linker='AIX lib.a(lib.so.V)' + # 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' + ;; + svr4,*) # full svr4 only + dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,yes) # both, prefer svr4 + dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # unpreferred sharedlib libNAME.a needs extra handling + postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' + postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,no) # both, prefer aix + dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling + postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' + postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' + ;; + esac + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + m68k) + 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=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $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' + ;; + esac + ;; + +beos*) + library_names_spec='$libname$shared_ext' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux # correct to gnu/linux during the next big refactor + 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* | cegcc*) + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + 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~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + 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="$sys_lib_search_path_spec /usr/lib/w32api" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + ;; + 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 + dynamic_linker='Win32 ld.exe' + ;; + + *,cl* | *,icl*) + # Native MSVC or ICC + libname_spec='$name' + soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + library_names_spec='$libname.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec=$LIB + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + 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 + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # 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' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC and ICC wrapper + library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # 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$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 # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly* | midnightbsd*) + # 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[23].*) 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$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + 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 + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + 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=LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + 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 32 = "$HPUX_IA64_MODE"; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + sys_lib_dlsearch_path_spec=/usr/lib/hpux32 + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + sys_lib_dlsearch_path_spec=/usr/lib/hpux64 + fi + ;; + 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' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + 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 yes = "$lt_cv_prog_gnu_ld"; then + version_type=linux # correct to gnu/linux during the next big refactor + 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 + ;; + +linux*android*) + version_type=none # Android doesn't support versioned libraries. + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext' + soname_spec='$libname$release$shared_ext' + finish_cmds= + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + + # 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 + + dynamic_linker='Android linker' + # Don't embed -rpath directories since the linker doesn't support them. + hardcode_libdir_flag_spec='-L$libdir' + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + 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 + + # Some binutils ld are patched to set DT_RUNPATH + if test ${lt_cv_shlibpath_overrides_runpath+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null +then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + ;; +esac +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # 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 + + # Ideally, we could use ldconfig to report *all* directores which are + # searched for libraries, however this is still not possible. Aside from not + # being certain /sbin/ldconfig is available, command + # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, + # even though it is searched at run-time. Try to do the best guess by + # appending ld.so.conf contents (and includes) 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;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $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' + ;; + +netbsdelf*-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 + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_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 # correct to gnu/linux during the next big refactor + 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=qnx + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd* | bitrig*) + version_type=sunos + sys_lib_dlsearch_path_spec=/usr/lib + need_lib_prefix=no + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + need_version=no + else + need_version=yes + fi + 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 + shlibpath_overrides_runpath=yes + ;; + +os2*) + libname_spec='$name' + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + # OS/2 can only load a DLL with a base name of 8 characters or less. + soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; + v=$($ECHO $release$versuffix | tr -d .-); + n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); + $ECHO $n$v`$shared_ext' + library_names_spec='${libname}_dll.$libext' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=BEGINLIBPATH + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + 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~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + ;; + +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 # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=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 yes = "$with_gnu_ld"; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + 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 + 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 # correct to gnu/linux during the next big refactor + 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=sco + 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 + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test yes = "$with_gnu_ld"; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + 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' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + 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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +printf "%s\n" "$dynamic_linker" >&6; } +test no = "$dynamic_linker" && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test yes = "$GCC"; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then + sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec +fi + +if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then + sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec +fi + +# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... +configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec + +# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code +func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" + +# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool +configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +printf %s "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test yes = "$hardcode_automatic"; then + + # We can hardcode non-existent directories. + if test no != "$hardcode_direct" && + # 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 no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && + test no != "$hardcode_minus_L"; 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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +printf "%s\n" "$hardcode_action" >&6; } + +if test relink = "$hardcode_action" || + test yes = "$inherit_rpath"; then + # Fast installation is not supported + enable_fast_install=no +elif test yes = "$shlibpath_overrides_runpath" || + test no = "$enable_shared"; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test yes != "$enable_dlopen"; 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* | cegcc*) + 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 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +printf %s "checking for dlopen in -ldl... " >&6; } +if test ${ac_cv_lib_dl_dlopen+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (void); +int +main (void) +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_dl_dlopen=yes +else case e in #( + e) ac_cv_lib_dl_dlopen=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes +then : + lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl +else case e in #( + e) + lt_cv_dlopen=dyld + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; +esac +fi + + ;; + + tpf*) + # Don't try to run any link tests for TPF. We know it's impossible + # because TPF is a cross-compiler, and we know how we open DSOs. + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + lt_cv_dlopen_self=no + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = xyes +then : + lt_cv_dlopen=shl_load +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +printf %s "checking for shl_load in -ldld... " >&6; } +if test ${ac_cv_lib_dld_shl_load+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (void); +int +main (void) +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_dld_shl_load=yes +else case e in #( + e) ac_cv_lib_dld_shl_load=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +printf "%s\n" "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = xyes +then : + lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld +else case e in #( + e) ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = xyes +then : + lt_cv_dlopen=dlopen +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +printf %s "checking for dlopen in -ldl... " >&6; } +if test ${ac_cv_lib_dl_dlopen+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (void); +int +main (void) +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_dl_dlopen=yes +else case e in #( + e) ac_cv_lib_dl_dlopen=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes +then : + lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +printf %s "checking for dlopen in -lsvld... " >&6; } +if test ${ac_cv_lib_svld_dlopen+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (void); +int +main (void) +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_svld_dlopen=yes +else case e in #( + e) ac_cv_lib_svld_dlopen=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +printf "%s\n" "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = xyes +then : + lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +printf %s "checking for dld_link in -ldld... " >&6; } +if test ${ac_cv_lib_dld_dld_link+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (void); +int +main (void) +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_dld_dld_link=yes +else case e in #( + e) ac_cv_lib_dld_dld_link=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +printf "%s\n" "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = xyes +then : + lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld +fi + + ;; +esac +fi + + ;; +esac +fi + + ;; +esac +fi + + ;; +esac +fi + + ;; +esac +fi + + ;; + esac + + if test no = "$lt_cv_dlopen"; then + enable_dlopen=no + else + enable_dlopen=yes + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS=$CPPFLAGS + test yes = "$ac_cv_header_dlfcn_h" && 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" + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +printf %s "checking whether a program can dlopen itself... " >&6; } +if test ${lt_cv_dlopen_self+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test yes = "$cross_compiling"; 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 <<_LT_EOF +#line $LINENO "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 + +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 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; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && 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* + + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +printf "%s\n" "$lt_cv_dlopen_self" >&6; } + + if test yes = "$lt_cv_dlopen_self"; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +printf %s "checking whether a statically linked program can dlopen itself... " >&6; } +if test ${lt_cv_dlopen_self_static+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test yes = "$cross_compiling"; 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 <<_LT_EOF +#line $LINENO "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 + +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 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; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && 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* + + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +printf "%s\n" "$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 + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +printf %s "checking whether stripping libraries is possible... " >&6; } +if test -z "$STRIP"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +else + if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + old_striplib="$STRIP --strip-debug" + striplib="$STRIP --strip-unneeded" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + case $host_os in + darwin*) + # FIXME - insert some real tests, host_os isn't really good enough + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ;; + freebsd*) + if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then + old_striplib="$STRIP --strip-debug" + striplib="$STRIP --strip-unneeded" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + fi + ;; + *) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ;; + esac + fi +fi + + + + + + + + + + + + + # Report what library types will actually be built + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +printf %s "checking if libtool supports shared libraries... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +printf "%s\n" "$can_build_shared" >&6; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +printf %s "checking whether to build shared libraries... " >&6; } + test no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + fi + ;; + esac + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +printf "%s\n" "$enable_shared" >&6; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +printf %s "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test yes = "$enable_shared" || enable_static=yes + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +printf "%s\n" "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC=$lt_save_CC + + + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + + +if (test "$USE_MAINTAINER_MODE" = "yes"); then + # Extract the first word of "lcov", so it can be a program name with args. +set dummy lcov; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_enable_coverage+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$enable_coverage"; then + ac_cv_prog_enable_coverage="$enable_coverage" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_enable_coverage="yes" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_enable_coverage" && ac_cv_prog_enable_coverage="no" +fi ;; +esac +fi +enable_coverage=$ac_cv_prog_enable_coverage +if test -n "$enable_coverage"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_coverage" >&5 +printf "%s\n" "$enable_coverage" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + # Extract the first word of "dbus-run-session", so it can be a program name with args. +set dummy dbus-run-session; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_enable_dbus_run_session+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$enable_dbus_run_session"; then + ac_cv_prog_enable_dbus_run_session="$enable_dbus_run_session" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_enable_dbus_run_session="yes" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +enable_dbus_run_session=$ac_cv_prog_enable_dbus_run_session +if test -n "$enable_dbus_run_session"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_dbus_run_session" >&5 +printf "%s\n" "$enable_dbus_run_session" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + # Extract the first word of "valgrind", so it can be a program name with args. +set dummy valgrind; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_enable_valgrind+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$enable_valgrind"; then + ac_cv_prog_enable_valgrind="$enable_valgrind" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_enable_valgrind="yes" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +enable_valgrind=$ac_cv_prog_enable_valgrind +if test -n "$enable_valgrind"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_valgrind" >&5 +printf "%s\n" "$enable_valgrind" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + ac_fn_c_check_header_compile "$LINENO" "valgrind/memcheck.h" "ac_cv_header_valgrind_memcheck_h" "$ac_includes_default" +if test "x$ac_cv_header_valgrind_memcheck_h" = xyes +then : + printf "%s\n" "#define HAVE_VALGRIND_MEMCHECK_H 1" >>confdefs.h + +fi + +fi + if test "${enable_coverage}" = "yes"; then + COVERAGE_TRUE= + COVERAGE_FALSE='#' +else + COVERAGE_TRUE='#' + COVERAGE_FALSE= +fi + + if test "${enable_dbus_run_session}" = "yes"; then + DBUS_RUN_SESSION_TRUE= + DBUS_RUN_SESSION_FALSE='#' +else + DBUS_RUN_SESSION_TRUE='#' + DBUS_RUN_SESSION_FALSE= +fi + + + + misc_cflags="" + misc_ldflags="" + # Check whether --enable-optimization was given. +if test ${enable_optimization+y} +then : + enableval=$enable_optimization; + if (test "${enableval}" = "no"); then + misc_cflags="$misc_cflags -O0" + fi + +fi + + # Check whether --enable-asan was given. +if test ${enable_asan+y} +then : + enableval=$enable_asan; + save_LIBS=$LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _init in -lasan" >&5 +printf %s "checking for _init in -lasan... " >&6; } +if test ${ac_cv_lib_asan__init+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS +LIBS="-lasan $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char _init (void); +int +main (void) +{ +return _init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_asan__init=yes +else case e in #( + e) ac_cv_lib_asan__init=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_asan__init" >&5 +printf "%s\n" "$ac_cv_lib_asan__init" >&6; } +if test "x$ac_cv_lib_asan__init" = xyes +then : + printf "%s\n" "#define HAVE_LIBASAN 1" >>confdefs.h + + LIBS="-lasan $LIBS" + +fi + + LIBS=$save_LIBS + if (test "${enableval}" = "yes" && + test "${ac_cv_lib_asan__init}" = "yes" && + test "${ac_cv_prog_cc_asan}" = "yes"); then + misc_cflags="$misc_cflags -fsanitize=address"; + misc_ldflags="$misc_ldflags -fsanitize=address" + ASAN_LIB=${ac_cv_lib_asan__init} + + fi + +fi + + # Check whether --enable-lsan was given. +if test ${enable_lsan+y} +then : + enableval=$enable_lsan; + save_LIBS=$LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _init in -llsan" >&5 +printf %s "checking for _init in -llsan... " >&6; } +if test ${ac_cv_lib_lsan__init+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS +LIBS="-llsan $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char _init (void); +int +main (void) +{ +return _init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_lsan__init=yes +else case e in #( + e) ac_cv_lib_lsan__init=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lsan__init" >&5 +printf "%s\n" "$ac_cv_lib_lsan__init" >&6; } +if test "x$ac_cv_lib_lsan__init" = xyes +then : + printf "%s\n" "#define HAVE_LIBLSAN 1" >>confdefs.h + + LIBS="-llsan $LIBS" + +fi + + LIBS=$save_LIBS + if (test "${enableval}" = "yes" && + test "${ac_cv_lib_lsan__init}" = "yes" && + test "${ac_cv_prog_cc_lsan}" = "yes"); then + misc_cflags="$misc_cflags -fsanitize=leak"; + misc_ldflags="$misc_ldflags -fsanitize=leak" + ASAN_LIB=${ac_cv_lib_lsan__init} + + fi + +fi + + # Check whether --enable-ubsan was given. +if test ${enable_ubsan+y} +then : + enableval=$enable_ubsan; + save_LIBS=$LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _init in -lubsan" >&5 +printf %s "checking for _init in -lubsan... " >&6; } +if test ${ac_cv_lib_ubsan__init+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS +LIBS="-lubsan $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char _init (void); +int +main (void) +{ +return _init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_ubsan__init=yes +else case e in #( + e) ac_cv_lib_ubsan__init=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ubsan__init" >&5 +printf "%s\n" "$ac_cv_lib_ubsan__init" >&6; } +if test "x$ac_cv_lib_ubsan__init" = xyes +then : + printf "%s\n" "#define HAVE_LIBUBSAN 1" >>confdefs.h + + LIBS="-lubsan $LIBS" + +fi + + LIBS=$save_LIBS + if (test "${enableval}" = "yes" && + test "${ac_cv_lib_ubsan__init}" = "yes" && + test "${ac_cv_prog_cc_ubsan}" = "yes"); then + misc_cflags="$misc_cflags -fsanitize=undefined"; + misc_ldflags="$misc_ldflags -fsanitize=undefined"; + fi + +fi + + # Check whether --enable-debug was given. +if test ${enable_debug+y} +then : + enableval=$enable_debug; + if (test "${enableval}" = "yes" && + test "${ac_cv_prog_cc_g}" = "yes"); then + misc_cflags="$misc_cflags -g" + fi + +fi + + # Check whether --enable-pie was given. +if test ${enable_pie+y} +then : + enableval=$enable_pie; + if (test "${enableval}" = "yes" && + test "${ac_cv_prog_cc_pie}" = "yes"); then + misc_cflags="$misc_cflags -fPIC" + misc_ldflags="$misc_ldflags -pie -Wl,-z,now" + fi + +fi + + if (test "$enable_coverage" = "yes"); then + misc_cflags="$misc_cflags --coverage" + misc_ldflags="$misc_ldflags --coverage" + fi + misc_cflags="$misc_cflags -ffunction-sections -fdata-sections" + misc_ldflags="$misc_ldflags -Wl,--gc-sections" + MISC_CFLAGS=$misc_cflags + + MISC_LDFLAGS=$misc_ldflags + + + + if test "${enable_valgrind}" = "yes" && + test "$ASAN_LIB" != "yes" && test "LSAN_LIB" != "yes"; then + VALGRIND_TRUE= + VALGRIND_FALSE='#' +else + VALGRIND_TRUE='#' + VALGRIND_FALSE= +fi + + +# Check whether --enable-threads was given. +if test ${enable_threads+y} +then : + enableval=$enable_threads; enable_threads=${enableval} +fi + + +ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero" +if test "x$ac_cv_func_explicit_bzero" = xyes +then : + printf "%s\n" "#define HAVE_EXPLICIT_BZERO 1" >>confdefs.h + +fi + + +ac_fn_c_check_func "$LINENO" "getrandom" "ac_cv_func_getrandom" +if test "x$ac_cv_func_getrandom" = xyes +then : + printf "%s\n" "#define HAVE_GETRANDOM 1" >>confdefs.h + +fi + + +ac_fn_c_check_func "$LINENO" "rawmemchr" "ac_cv_func_rawmemchr" +if test "x$ac_cv_func_rawmemchr" = xyes +then : + printf "%s\n" "#define HAVE_RAWMEMCHR 1" >>confdefs.h + +fi + + +ac_fn_c_check_func "$LINENO" "signalfd" "ac_cv_func_signalfd" +if test "x$ac_cv_func_signalfd" = xyes +then : + dummy=yes +else case e in #( + e) as_fn_error $? "signalfd support is required" "$LINENO" 5 ;; +esac +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +printf %s "checking for clock_gettime in -lrt... " >&6; } +if test ${ac_cv_lib_rt_clock_gettime+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS +LIBS="-lrt $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char clock_gettime (void); +int +main (void) +{ +return clock_gettime (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_rt_clock_gettime=yes +else case e in #( + e) ac_cv_lib_rt_clock_gettime=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +printf "%s\n" "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes +then : + dummy=yes +else case e in #( + e) as_fn_error $? "realtime clock support is required" "$LINENO" 5 ;; +esac +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 +printf %s "checking for pthread_create in -lpthread... " >&6; } +if test ${ac_cv_lib_pthread_pthread_create+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_create (void); +int +main (void) +{ +return pthread_create (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_pthread_pthread_create=yes +else case e in #( + e) ac_cv_lib_pthread_pthread_create=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 +printf "%s\n" "$ac_cv_lib_pthread_pthread_create" >&6; } +if test "x$ac_cv_lib_pthread_pthread_create" = xyes +then : + dummy=yes +else case e in #( + e) as_fn_error $? "posix thread support is required" "$LINENO" 5 ;; +esac +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +printf %s "checking for dlopen in -ldl... " >&6; } +if test ${ac_cv_lib_dl_dlopen+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (void); +int +main (void) +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_dl_dlopen=yes +else case e in #( + e) ac_cv_lib_dl_dlopen=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes +then : + dummy=yes +else case e in #( + e) as_fn_error $? "dynamic linking loader is required" "$LINENO" 5 ;; +esac +fi + + +ac_fn_c_check_header_compile "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default" +if test "x$ac_cv_header_string_h" = xyes +then : + printf "%s\n" "#define HAVE_STRING_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "linux/types.h" "ac_cv_header_linux_types_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_types_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_TYPES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "linux/if_alg.h" "ac_cv_header_linux_if_alg_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_if_alg_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_IF_ALG_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "linux/uinput.h" "ac_cv_header_linux_uinput_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_uinput_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_UINPUT_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "linux/uhid.h" "ac_cv_header_linux_uhid_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_uhid_h" = xyes +then : + printf "%s\n" "#define HAVE_LINUX_UHID_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "sys/random.h" "ac_cv_header_sys_random_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_random_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_RANDOM_H 1" >>confdefs.h + +fi + + +# basename may be only available in libgen.h with the POSIX behavior, +# not desired here +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 +printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } +if test ${ac_cv_c_undeclared_builtin_options+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_save_CFLAGS=$CFLAGS + ac_cv_c_undeclared_builtin_options='cannot detect' + for ac_arg in '' -fno-builtin; do + CFLAGS="$ac_save_CFLAGS $ac_arg" + # This test program should *not* compile successfully. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +(void) strchr; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + +else case e in #( + e) # This test program should compile successfully. + # No library function is consistently available on + # freestanding implementations, so test against a dummy + # declaration. Include always-available headers on the + # off chance that they somehow elicit warnings. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <float.h> +#include <limits.h> +#include <stdarg.h> +#include <stddef.h> +extern void ac_decl (int, char *); + +int +main (void) +{ +(void) ac_decl (0, (char *) 0); + (void) ac_decl; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + if test x"$ac_arg" = x +then : + ac_cv_c_undeclared_builtin_options='none needed' +else case e in #( + e) ac_cv_c_undeclared_builtin_options=$ac_arg ;; +esac +fi + break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + done + CFLAGS=$ac_save_CFLAGS + ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 +printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; } + case $ac_cv_c_undeclared_builtin_options in #( + 'cannot detect') : + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "cannot make $CC report undeclared builtins +See 'config.log' for more details" "$LINENO" 5; } ;; #( + 'none needed') : + ac_c_undeclared_builtin_options='' ;; #( + *) : + ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;; +esac + +ac_fn_check_decl "$LINENO" "basename" "ac_cv_have_decl_basename" "#define _GNU_SOURCE 1 + #include <string.h> + +" "$ac_c_undeclared_builtin_options" "CFLAGS" +if test "x$ac_cv_have_decl_basename" = xyes +then : + ac_have_decl=1 +else case e in #( + e) ac_have_decl=0 ;; +esac +fi +printf "%s\n" "#define HAVE_DECL_BASENAME $ac_have_decl" >>confdefs.h +if test $ac_have_decl = 1 +then : + +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: GNU basename extension not found" >&5 +printf "%s\n" "$as_me: WARNING: GNU basename extension not found" >&2;} ;; +esac +fi + + + + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for glib-2.0 >= 2.28" >&5 +printf %s "checking for glib-2.0 >= 2.28... " >&6; } + +if test -n "$GLIB_CFLAGS"; then + pkg_cv_GLIB_CFLAGS="$GLIB_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.28\""; } >&5 + ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.28") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GLIB_CFLAGS=`$PKG_CONFIG --cflags "glib-2.0 >= 2.28" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$GLIB_LIBS"; then + pkg_cv_GLIB_LIBS="$GLIB_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.28\""; } >&5 + ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.28") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GLIB_LIBS=`$PKG_CONFIG --libs "glib-2.0 >= 2.28" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + GLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "glib-2.0 >= 2.28" 2>&1` + else + GLIB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "glib-2.0 >= 2.28" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$GLIB_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (glib-2.0 >= 2.28) were not met: + +$GLIB_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables GLIB_CFLAGS +and GLIB_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "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. + +Alternatively, you may set the environment variables GLIB_CFLAGS +and GLIB_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See 'config.log' for more details" "$LINENO" 5; } +else + GLIB_CFLAGS=$pkg_cv_GLIB_CFLAGS + GLIB_LIBS=$pkg_cv_GLIB_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + +if (test "${enable_threads}" = "yes"); then + +printf "%s\n" "#define NEED_THREADS 1" >>confdefs.h + + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gthread-2.0 >= 2.16" >&5 +printf %s "checking for gthread-2.0 >= 2.16... " >&6; } + +if test -n "$GTHREAD_CFLAGS"; then + pkg_cv_GTHREAD_CFLAGS="$GTHREAD_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gthread-2.0 >= 2.16\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gthread-2.0 >= 2.16") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GTHREAD_CFLAGS=`$PKG_CONFIG --cflags "gthread-2.0 >= 2.16" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$GTHREAD_LIBS"; then + pkg_cv_GTHREAD_LIBS="$GTHREAD_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gthread-2.0 >= 2.16\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gthread-2.0 >= 2.16") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GTHREAD_LIBS=`$PKG_CONFIG --libs "gthread-2.0 >= 2.16" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + GTHREAD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gthread-2.0 >= 2.16" 2>&1` + else + GTHREAD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gthread-2.0 >= 2.16" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$GTHREAD_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (gthread-2.0 >= 2.16) were not met: + +$GTHREAD_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables GTHREAD_CFLAGS +and GTHREAD_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "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. + +Alternatively, you may set the environment variables GTHREAD_CFLAGS +and GTHREAD_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See 'config.log' for more details" "$LINENO" 5; } +else + GTHREAD_CFLAGS=$pkg_cv_GTHREAD_CFLAGS + GTHREAD_LIBS=$pkg_cv_GTHREAD_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS" + GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS" +fi + + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dbus-1 >= 1.10" >&5 +printf %s "checking for dbus-1 >= 1.10... " >&6; } + +if test -n "$DBUS_CFLAGS"; then + pkg_cv_DBUS_CFLAGS="$DBUS_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"dbus-1 >= 1.10\""; } >&5 + ($PKG_CONFIG --exists --print-errors "dbus-1 >= 1.10") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_DBUS_CFLAGS=`$PKG_CONFIG --cflags "dbus-1 >= 1.10" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$DBUS_LIBS"; then + pkg_cv_DBUS_LIBS="$DBUS_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"dbus-1 >= 1.10\""; } >&5 + ($PKG_CONFIG --exists --print-errors "dbus-1 >= 1.10") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_DBUS_LIBS=`$PKG_CONFIG --libs "dbus-1 >= 1.10" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + DBUS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "dbus-1 >= 1.10" 2>&1` + else + DBUS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "dbus-1 >= 1.10" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$DBUS_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (dbus-1 >= 1.10) were not met: + +$DBUS_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables DBUS_CFLAGS +and DBUS_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "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. + +Alternatively, you may set the environment variables DBUS_CFLAGS +and DBUS_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See 'config.log' for more details" "$LINENO" 5; } +else + DBUS_CFLAGS=$pkg_cv_DBUS_CFLAGS + DBUS_LIBS=$pkg_cv_DBUS_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + + +# Check whether --with-dbusconfdir was given. +if test ${with_dbusconfdir+y} +then : + withval=$with_dbusconfdir; path_dbusconfdir=${withval} +fi + +if (test -z "${path_dbusconfdir}"); then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking D-Bus configuration directory" >&5 +printf %s "checking D-Bus configuration directory... " >&6; } + path_dbusconfdir="`$PKG_CONFIG --variable=datadir dbus-1`" + if (test -z "${path_dbusconfdir}"); then + as_fn_error $? "D-Bus configuration directory is required" "$LINENO" 5 + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${path_dbusconfdir}" >&5 +printf "%s\n" "${path_dbusconfdir}" >&6; } +fi +DBUS_CONFDIR=${path_dbusconfdir} + + + +# Check whether --with-dbussystembusdir was given. +if test ${with_dbussystembusdir+y} +then : + withval=$with_dbussystembusdir; path_dbussystembusdir=${withval} +fi + +if (test -z "${path_dbussystembusdir}"); then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking D-Bus system bus services dir" >&5 +printf %s "checking D-Bus system bus services dir... " >&6; } + path_dbussystembusdir="`$PKG_CONFIG --variable=system_bus_services_dir dbus-1`" + if (test -z "${path_dbussystembusdir}"); then + as_fn_error $? "D-Bus system bus services directory is required" "$LINENO" 5 + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${path_dbussystembusdir}" >&5 +printf "%s\n" "${path_dbussystembusdir}" >&6; } +fi +DBUS_SYSTEMBUSDIR=${path_dbussystembusdir} + + + +# Check whether --with-dbussessionbusdir was given. +if test ${with_dbussessionbusdir+y} +then : + withval=$with_dbussessionbusdir; path_dbussessionbusdir=${withval} +fi + +if (test -z "${path_dbussessionbusdir}"); then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking D-Bus session bus services dir" >&5 +printf %s "checking D-Bus session bus services dir... " >&6; } + path_dbussessionbusdir="`$PKG_CONFIG --variable=session_bus_services_dir dbus-1`" + if (test -z "${path_dbussessionbusdir}"); then + as_fn_error $? "D-Bus session bus services directory is required" "$LINENO" 5 + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${path_dbussessionbusdir}" >&5 +printf "%s\n" "${path_dbussessionbusdir}" >&6; } +fi +DBUS_SESSIONBUSDIR=${path_dbussessionbusdir} + + + +# Check whether --with-zsh-completion-dir was given. +if test ${with_zsh_completion_dir+y} +then : + withval=$with_zsh_completion_dir; path_zshcompletiondir=${withval} +else case e in #( + e) path_zshcompletiondir="yes" ;; +esac +fi + + +if (test "${path_zshcompletiondir}" = "yes"); then + path_zshcompletiondir="$datarootdir/zsh/site-functions" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${path_zshcompletiondir}" >&5 +printf "%s\n" "${path_zshcompletiondir}" >&6; } +fi +ZSH_COMPLETIONDIR=${path_zshcompletiondir} + + if test "${path_zshcompletiondir}" != "no"; then + ZSH_COMPLETIONS_TRUE= + ZSH_COMPLETIONS_FALSE='#' +else + ZSH_COMPLETIONS_TRUE='#' + ZSH_COMPLETIONS_FALSE= +fi + + +# Check whether --enable-backtrace was given. +if test ${enable_backtrace+y} +then : + enableval=$enable_backtrace; enable_backtrace=${enableval} +fi + + +if (test "${enable_backtrace}" = "yes"); then + ac_fn_c_check_header_compile "$LINENO" "elfutils/libdwfl.h" "ac_cv_header_elfutils_libdwfl_h" "$ac_includes_default" +if test "x$ac_cv_header_elfutils_libdwfl_h" = xyes +then : + dummy=yes +else case e in #( + e) as_fn_error $? "elfutils support is required" "$LINENO" 5 ;; +esac +fi + + +printf "%s\n" "#define HAVE_BACKTRACE_SUPPORT 1" >>confdefs.h + + BACKTRACE_CFLAGS="" + BACKTRACE_LIBS="-ldw" + + +fi + +# Check whether --enable-library was given. +if test ${enable_library+y} +then : + enableval=$enable_library; enable_library=${enableval} +fi + + if test "${enable_library}" = "yes"; then + LIBRARY_TRUE= + LIBRARY_FALSE='#' +else + LIBRARY_TRUE='#' + LIBRARY_FALSE= +fi + + +# Check whether --enable-test was given. +if test ${enable_test+y} +then : + enableval=$enable_test; enable_test=${enableval} +fi + + if test "${enable_test}" = "yes"; then + TEST_TRUE= + TEST_FALSE='#' +else + TEST_TRUE='#' + TEST_FALSE= +fi + + +# Check whether --enable-nfc was given. +if test ${enable_nfc+y} +then : + enableval=$enable_nfc; enable_nfc=${enableval} +fi + + if test "${enable_nfc}" = "yes"; then + NFC_TRUE= + NFC_FALSE='#' +else + NFC_TRUE='#' + NFC_FALSE= +fi + + +# Check whether --enable-sap was given. +if test ${enable_sap+y} +then : + enableval=$enable_sap; enable_sap=${enableval} +fi + + if test "${enable_sap}" = "yes"; then + SAP_TRUE= + SAP_FALSE='#' +else + SAP_TRUE='#' + SAP_FALSE= +fi + + +# Check whether --enable-a2dp was given. +if test ${enable_a2dp+y} +then : + enableval=$enable_a2dp; enable_a2dp=${enableval} +fi + + if test "${enable_a2dp}" != "no"; then + A2DP_TRUE= + A2DP_FALSE='#' +else + A2DP_TRUE='#' + A2DP_FALSE= +fi + + +# Check whether --enable-avrcp was given. +if test ${enable_avrcp+y} +then : + enableval=$enable_avrcp; enable_avrcp=${enableval} +fi + + if test "${enable_avrcp}" != "no"; then + AVRCP_TRUE= + AVRCP_FALSE='#' +else + AVRCP_TRUE='#' + AVRCP_FALSE= +fi + + +# Check whether --enable-network was given. +if test ${enable_network+y} +then : + enableval=$enable_network; enable_network=${enableval} +fi + + if test "${enable_network}" != "no"; then + NETWORK_TRUE= + NETWORK_FALSE='#' +else + NETWORK_TRUE='#' + NETWORK_FALSE= +fi + + +# Check whether --enable-hid was given. +if test ${enable_hid+y} +then : + enableval=$enable_hid; enable_hid=${enableval} +fi + + if test "${enable_hid}" != "no"; then + HID_TRUE= + HID_FALSE='#' +else + HID_TRUE='#' + HID_FALSE= +fi + + +# Check whether --enable-hog was given. +if test ${enable_hog+y} +then : + enableval=$enable_hog; enable_hog=${enableval} +fi + + if test "${enable_hog}" != "no"; then + HOG_TRUE= + HOG_FALSE='#' +else + HOG_TRUE='#' + HOG_FALSE= +fi + + +# Check whether --enable-health was given. +if test ${enable_health+y} +then : + enableval=$enable_health; enable_health=${enableval} +fi + + if test "${enable_health}" = "yes"; then + HEALTH_TRUE= + HEALTH_FALSE='#' +else + HEALTH_TRUE='#' + HEALTH_FALSE= +fi + + +# Check whether --enable-bap was given. +if test ${enable_bap+y} +then : + enableval=$enable_bap; enable_bap=${enableval} +fi + + if test "${enable_bap}" != "no"; then + BAP_TRUE= + BAP_FALSE='#' +else + BAP_TRUE='#' + BAP_FALSE= +fi + + +# Check whether --enable-bass was given. +if test ${enable_bass+y} +then : + enableval=$enable_bass; enable_bass=${enableval} +fi + + if test "${enable_bass}" != "no"; then + BASS_TRUE= + BASS_FALSE='#' +else + BASS_TRUE='#' + BASS_FALSE= +fi + + +# Check whether --enable-mcp was given. +if test ${enable_mcp+y} +then : + enableval=$enable_mcp; enable_mcp=${enableval} +fi + + if test "${enable_mcp}" != "no"; then + MCP_TRUE= + MCP_FALSE='#' +else + MCP_TRUE='#' + MCP_FALSE= +fi + + +# Check whether --enable-ccp was given. +if test ${enable_ccp+y} +then : + enableval=$enable_ccp; enable_ccp=${enableval} +fi + + if test "${enable_ccp}" != "no"; then + CCP_TRUE= + CCP_FALSE='#' +else + CCP_TRUE='#' + CCP_FALSE= +fi + + +# Check whether --enable-vcp was given. +if test ${enable_vcp+y} +then : + enableval=$enable_vcp; enable_vcp=${enableval} +fi + + if test "${enable_vcp}" != "no"; then + VCP_TRUE= + VCP_FALSE='#' +else + VCP_TRUE='#' + VCP_FALSE= +fi + + +# Check whether --enable-micp was given. +if test ${enable_micp+y} +then : + enableval=$enable_micp; enable_micp=${enableval} +fi + + if test "${enable_micp}" != "no"; then + MICP_TRUE= + MICP_FALSE='#' +else + MICP_TRUE='#' + MICP_FALSE= +fi + + +# Check whether --enable-csip was given. +if test ${enable_csip+y} +then : + enableval=$enable_csip; enable_csip=${enableval} +fi + + if test "${enable_csip}" != "no"; then + CSIP_TRUE= + CSIP_FALSE='#' +else + CSIP_TRUE='#' + CSIP_FALSE= +fi + + +# Check whether --enable-asha was given. +if test ${enable_asha+y} +then : + enableval=$enable_asha; enable_asha=${enableval} +fi + + if test "${enable_asha}" != "no"; then + ASHA_TRUE= + ASHA_FALSE='#' +else + ASHA_TRUE='#' + ASHA_FALSE= +fi + + +# Check whether --enable-tools was given. +if test ${enable_tools+y} +then : + enableval=$enable_tools; enable_tools=${enableval} +fi + + if test "${enable_tools}" != "no"; then + TOOLS_TRUE= + TOOLS_FALSE='#' +else + TOOLS_TRUE='#' + TOOLS_FALSE= +fi + + +# Check whether --enable-monitor was given. +if test ${enable_monitor+y} +then : + enableval=$enable_monitor; enable_monitor=${enableval} +fi + + if test "${enable_monitor}" != "no"; then + MONITOR_TRUE= + MONITOR_FALSE='#' +else + MONITOR_TRUE='#' + MONITOR_FALSE= +fi + + +# Check whether --enable-udev was given. +if test ${enable_udev+y} +then : + enableval=$enable_udev; enable_udev=${enableval} +fi + +if (test "${enable_udev}" != "no"); then + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libudev >= 196" >&5 +printf %s "checking for libudev >= 196... " >&6; } + +if test -n "$UDEV_CFLAGS"; then + pkg_cv_UDEV_CFLAGS="$UDEV_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libudev >= 196\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libudev >= 196") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_UDEV_CFLAGS=`$PKG_CONFIG --cflags "libudev >= 196" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$UDEV_LIBS"; then + pkg_cv_UDEV_LIBS="$UDEV_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libudev >= 196\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libudev >= 196") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_UDEV_LIBS=`$PKG_CONFIG --libs "libudev >= 196" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + UDEV_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libudev >= 196" 2>&1` + else + UDEV_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libudev >= 196" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$UDEV_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (libudev >= 196) were not met: + +$UDEV_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables UDEV_CFLAGS +and UDEV_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "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. + +Alternatively, you may set the environment variables UDEV_CFLAGS +and UDEV_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See 'config.log' for more details" "$LINENO" 5; } +else + UDEV_CFLAGS=$pkg_cv_UDEV_CFLAGS + UDEV_LIBS=$pkg_cv_UDEV_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + +printf "%s\n" "#define HAVE_UDEV 1" >>confdefs.h + +fi + + +# Check whether --with-udevdir was given. +if test ${with_udevdir+y} +then : + withval=$with_udevdir; path_udevdir=${withval} +fi + +if (test "${enable_udev}" != "no" && test -z "${path_udevdir}"); then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking udev directory" >&5 +printf %s "checking udev directory... " >&6; } + path_udevdir="`$PKG_CONFIG --variable=udevdir udev`" + if (test -z "${path_udevdir}"); then + as_fn_error $? "udev directory is required" "$LINENO" 5 + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${path_udevdir}" >&5 +printf "%s\n" "${path_udevdir}" >&6; } +fi +UDEV_DIR=${path_udevdir} + + +# Check whether --enable-cups was given. +if test ${enable_cups+y} +then : + enableval=$enable_cups; enable_cups=${enableval} +fi + + if test "${enable_cups}" != "no"; then + CUPS_TRUE= + CUPS_FALSE='#' +else + CUPS_TRUE='#' + CUPS_FALSE= +fi + +if (test "${enable_cups}" != "no"); then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking cups directory" >&5 +printf %s "checking cups directory... " >&6; } + cups_serverbin=`$PKG_CONFIG cups --variable=cups_serverbin` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${cups_serverbin}" >&5 +printf "%s\n" "${cups_serverbin}" >&6; } +fi + if test "${cups_serverbin}" != ""; then + CUPS_SERVERBIN_TRUE= + CUPS_SERVERBIN_FALSE='#' +else + CUPS_SERVERBIN_TRUE='#' + CUPS_SERVERBIN_FALSE= +fi + +if test "${cups_serverbin}" != "" +then : + + CUPS_SERVERBIN=${cups_serverbin} + + +fi + +# Check whether --enable-mesh was given. +if test ${enable_mesh+y} +then : + enableval=$enable_mesh; enable_mesh=${enableval} +fi + + if test "${enable_mesh}" = "yes"; then + MESH_TRUE= + MESH_FALSE='#' +else + MESH_TRUE='#' + MESH_FALSE= +fi + + +if (test "${enable_mesh}" = "yes"); then + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for json-c >= 0.13" >&5 +printf %s "checking for json-c >= 0.13... " >&6; } + +if test -n "$JSONC_CFLAGS"; then + pkg_cv_JSONC_CFLAGS="$JSONC_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"json-c >= 0.13\""; } >&5 + ($PKG_CONFIG --exists --print-errors "json-c >= 0.13") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_JSONC_CFLAGS=`$PKG_CONFIG --cflags "json-c >= 0.13" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$JSONC_LIBS"; then + pkg_cv_JSONC_LIBS="$JSONC_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"json-c >= 0.13\""; } >&5 + ($PKG_CONFIG --exists --print-errors "json-c >= 0.13") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_JSONC_LIBS=`$PKG_CONFIG --libs "json-c >= 0.13" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + JSONC_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "json-c >= 0.13" 2>&1` + else + JSONC_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "json-c >= 0.13" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$JSONC_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (json-c >= 0.13) were not met: + +$JSONC_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables JSONC_CFLAGS +and JSONC_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "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. + +Alternatively, you may set the environment variables JSONC_CFLAGS +and JSONC_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See 'config.log' for more details" "$LINENO" 5; } +else + JSONC_CFLAGS=$pkg_cv_JSONC_CFLAGS + JSONC_LIBS=$pkg_cv_JSONC_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi +fi + +# Check whether --enable-midi was given. +if test ${enable_midi+y} +then : + enableval=$enable_midi; enable_midi=${enableval} +fi + + if test "${enable_midi}" = "yes"; then + MIDI_TRUE= + MIDI_FALSE='#' +else + MIDI_TRUE='#' + MIDI_FALSE= +fi + + +if (test "${enable_midi}" = "yes"); then + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for alsa" >&5 +printf %s "checking for alsa... " >&6; } + +if test -n "$ALSA_CFLAGS"; then + pkg_cv_ALSA_CFLAGS="$ALSA_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"alsa\""; } >&5 + ($PKG_CONFIG --exists --print-errors "alsa") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_ALSA_CFLAGS=`$PKG_CONFIG --cflags "alsa" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$ALSA_LIBS"; then + pkg_cv_ALSA_LIBS="$ALSA_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"alsa\""; } >&5 + ($PKG_CONFIG --exists --print-errors "alsa") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_ALSA_LIBS=`$PKG_CONFIG --libs "alsa" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + ALSA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "alsa" 2>&1` + else + ALSA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "alsa" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$ALSA_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (alsa) were not met: + +$ALSA_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables ALSA_CFLAGS +and ALSA_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "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. + +Alternatively, you may set the environment variables ALSA_CFLAGS +and ALSA_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See 'config.log' for more details" "$LINENO" 5; } +else + ALSA_CFLAGS=$pkg_cv_ALSA_CFLAGS + ALSA_LIBS=$pkg_cv_ALSA_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi +fi + +# Check whether --enable-obex was given. +if test ${enable_obex+y} +then : + enableval=$enable_obex; enable_obex=${enableval} +fi + +if (test "${enable_obex}" != "no"); then + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libical" >&5 +printf %s "checking for libical... " >&6; } + +if test -n "$ICAL_CFLAGS"; then + pkg_cv_ICAL_CFLAGS="$ICAL_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libical\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libical") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_ICAL_CFLAGS=`$PKG_CONFIG --cflags "libical" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$ICAL_LIBS"; then + pkg_cv_ICAL_LIBS="$ICAL_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libical\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libical") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_ICAL_LIBS=`$PKG_CONFIG --libs "libical" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + ICAL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libical" 2>&1` + else + ICAL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libical" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$ICAL_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (libical) were not met: + +$ICAL_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables ICAL_CFLAGS +and ICAL_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "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. + +Alternatively, you may set the environment variables ICAL_CFLAGS +and ICAL_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See 'config.log' for more details" "$LINENO" 5; } +else + ICAL_CFLAGS=$pkg_cv_ICAL_CFLAGS + ICAL_LIBS=$pkg_cv_ICAL_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi +fi + if test "${enable_obex}" != "no"; then + OBEX_TRUE= + OBEX_FALSE='#' +else + OBEX_TRUE='#' + OBEX_FALSE= +fi + + +# Check whether --enable-btpclient was given. +if test ${enable_btpclient+y} +then : + enableval=$enable_btpclient; enable_btpclient=${enableval} +fi + + if test "${enable_btpclient}" = "yes"; then + BTPCLIENT_TRUE= + BTPCLIENT_FALSE='#' +else + BTPCLIENT_TRUE='#' + BTPCLIENT_FALSE= +fi + + +# Check whether --enable-external_ell was given. +if test ${enable_external_ell+y} +then : + enableval=$enable_external_ell; enable_external_ell=${enableval} +fi + +if (test "${enable_external_ell}" = "yes"); then + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ell >= 0.39" >&5 +printf %s "checking for ell >= 0.39... " >&6; } + +if test -n "$ELL_CFLAGS"; then + pkg_cv_ELL_CFLAGS="$ELL_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ell >= 0.39\""; } >&5 + ($PKG_CONFIG --exists --print-errors "ell >= 0.39") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_ELL_CFLAGS=`$PKG_CONFIG --cflags "ell >= 0.39" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$ELL_LIBS"; then + pkg_cv_ELL_LIBS="$ELL_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ell >= 0.39\""; } >&5 + ($PKG_CONFIG --exists --print-errors "ell >= 0.39") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_ELL_LIBS=`$PKG_CONFIG --libs "ell >= 0.39" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + ELL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "ell >= 0.39" 2>&1` + else + ELL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "ell >= 0.39" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$ELL_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (ell >= 0.39) were not met: + +$ELL_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables ELL_CFLAGS +and ELL_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "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. + +Alternatively, you may set the environment variables ELL_CFLAGS +and ELL_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See 'config.log' for more details" "$LINENO" 5; } +else + ELL_CFLAGS=$pkg_cv_ELL_CFLAGS + ELL_LIBS=$pkg_cv_ELL_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi +fi +if (test "${enable_external_ell}" != "yes" && + (test "${enable_btpclient}" = "yes" || test "${enable_mesh}" = "yes")); then + if (test ! -f ${srcdir}/ell/ell.h) && + (test ! -f ${srcdir}/../ell/ell/ell.h); then + as_fn_error $? "ELL source is required or use --enable-external-ell" "$LINENO" 5 + fi +fi + if test "${enable_external_ell}" = "yes" || + (test "${enable_btpclient}" != "yes" && + test "${enable_mesh}" != "yes"); then + EXTERNAL_ELL_TRUE= + EXTERNAL_ELL_FALSE='#' +else + EXTERNAL_ELL_TRUE='#' + EXTERNAL_ELL_FALSE= +fi + + if test "${enable_btpclient}" = "yes" || + test "${enable_mesh}" = "yes"; then + LIBSHARED_ELL_TRUE= + LIBSHARED_ELL_FALSE='#' +else + LIBSHARED_ELL_TRUE='#' + LIBSHARED_ELL_FALSE= +fi + + +# Check whether --enable-client was given. +if test ${enable_client+y} +then : + enableval=$enable_client; enable_client=${enableval} +fi + + if test "${enable_client}" != "no"; then + CLIENT_TRUE= + CLIENT_FALSE='#' +else + CLIENT_TRUE='#' + CLIENT_FALSE= +fi + + +if (test "${enable_client}" != "no" || test "${enable_mesh}" = "yes"); then + for ac_header in readline/readline.h +do : + ac_fn_c_check_header_compile "$LINENO" "readline/readline.h" "ac_cv_header_readline_readline_h" "$ac_includes_default" +if test "x$ac_cv_header_readline_readline_h" = xyes +then : + printf "%s\n" "#define HAVE_READLINE_READLINE_H 1" >>confdefs.h + enable_readline=yes +else case e in #( + e) as_fn_error $? "readline header files are required" "$LINENO" 5 ;; +esac +fi + +done +fi + if test "${enable_readline}" = "yes"; then + READLINE_TRUE= + READLINE_FALSE='#' +else + READLINE_TRUE='#' + READLINE_FALSE= +fi + + +# Check whether --enable-systemd was given. +if test ${enable_systemd+y} +then : + enableval=$enable_systemd; enable_systemd=${enableval} +fi + + if test "${enable_systemd}" != "no"; then + SYSTEMD_TRUE= + SYSTEMD_FALSE='#' +else + SYSTEMD_TRUE='#' + SYSTEMD_FALSE= +fi + + + +# Check whether --with-systemdsystemunitdir was given. +if test ${with_systemdsystemunitdir+y} +then : + withval=$with_systemdsystemunitdir; path_systemunitdir=${withval} +fi + +if (test "${enable_systemd}" != "no" && test -z "${path_systemunitdir}"); then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking systemd system unit dir" >&5 +printf %s "checking systemd system unit dir... " >&6; } + path_systemunitdir="`$PKG_CONFIG --variable=systemdsystemunitdir systemd`" + if (test -z "${path_systemunitdir}"); then + as_fn_error $? "systemd system unit directory is required" "$LINENO" 5 + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${path_systemunitdir}" >&5 +printf "%s\n" "${path_systemunitdir}" >&6; } +fi +SYSTEMD_SYSTEMUNITDIR=${path_systemunitdir} + + + +# Check whether --with-systemduserunitdir was given. +if test ${with_systemduserunitdir+y} +then : + withval=$with_systemduserunitdir; path_userunitdir=${withval} +fi + +if (test "${enable_systemd}" != "no" && test -z "${path_userunitdir}"); then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking systemd user unit dir" >&5 +printf %s "checking systemd user unit dir... " >&6; } + path_userunitdir="`$PKG_CONFIG --variable=systemduserunitdir systemd`" + if (test -z "${path_userunitdir}"); then + as_fn_error $? "systemd user unit directory is required" "$LINENO" 5 + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${path_userunitdir}" >&5 +printf "%s\n" "${path_userunitdir}" >&6; } +fi +SYSTEMD_USERUNITDIR=${path_userunitdir} + + +# Check whether --enable-datafiles was given. +if test ${enable_datafiles+y} +then : + enableval=$enable_datafiles; enable_datafiles=${enableval} +fi + + if test "${enable_datafiles}" != "no"; then + DATAFILES_TRUE= + DATAFILES_FALSE='#' +else + DATAFILES_TRUE='#' + DATAFILES_FALSE= +fi + + +# Check whether --enable-manpages was given. +if test ${enable_manpages+y} +then : + enableval=$enable_manpages; enable_manpages=${enableval} +fi + +if (test "${enable_manpages}" != "no"); then + for ac_prog in rst2man rst2man.py +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_RST2MAN+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -n "$RST2MAN"; then + ac_cv_prog_RST2MAN="$RST2MAN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_RST2MAN="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi ;; +esac +fi +RST2MAN=$ac_cv_prog_RST2MAN +if test -n "$RST2MAN"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RST2MAN" >&5 +printf "%s\n" "$RST2MAN" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$RST2MAN" && break +done +test -n "$RST2MAN" || RST2MAN=""no"" + + if (test "${RST2MAN}" = "no" ); then + as_fn_error $? "rst2man is required" "$LINENO" 5 + fi +fi + if test "${enable_manpages}" != "no"; then + MANPAGES_TRUE= + MANPAGES_FALSE='#' +else + MANPAGES_TRUE='#' + MANPAGES_FALSE= +fi + + if test "${enable_manpages}" != "no" && + test "${RST2MAN}" != "no"; then + RUN_RST2MAN_TRUE= + RUN_RST2MAN_FALSE='#' +else + RUN_RST2MAN_TRUE='#' + RUN_RST2MAN_FALSE= +fi + + +# Check whether --enable-testing was given. +if test ${enable_testing+y} +then : + enableval=$enable_testing; enable_testing=${enableval} +fi + + if test "${enable_testing}" = "yes"; then + TESTING_TRUE= + TESTING_FALSE='#' +else + TESTING_TRUE='#' + TESTING_FALSE= +fi + + +# Check whether --enable-experimental was given. +if test ${enable_experimental+y} +then : + enableval=$enable_experimental; enable_experimental=${enableval} +fi + + if test "${enable_experimental}" = "yes"; then + EXPERIMENTAL_TRUE= + EXPERIMENTAL_FALSE='#' +else + EXPERIMENTAL_TRUE='#' + EXPERIMENTAL_FALSE= +fi + + +# Check whether --enable-deprecated was given. +if test ${enable_deprecated+y} +then : + enableval=$enable_deprecated; enable_deprecated=${enableval} +fi + + if test "${enable_deprecated}" = "yes"; then + DEPRECATED_TRUE= + DEPRECATED_FALSE='#' +else + DEPRECATED_TRUE='#' + DEPRECATED_FALSE= +fi + + +# Check whether --enable-external-plugins was given. +if test ${enable_external_plugins+y} +then : + enableval=$enable_external_plugins; enable_external_plugins=${enableval} +fi + + if test "${enable_external_plugins}" = "yes"; then + EXTERNAL_PLUGINS_TRUE= + EXTERNAL_PLUGINS_FALSE='#' +else + EXTERNAL_PLUGINS_TRUE='#' + EXTERNAL_PLUGINS_FALSE= +fi + +if (test "${enable_external_plugins}" = "yes"); then + +printf "%s\n" "#define EXTERNAL_PLUGINS 1" >>confdefs.h + +else + +printf "%s\n" "#define EXTERNAL_PLUGINS 0" >>confdefs.h + +fi + +# Check whether --enable-sixaxis was given. +if test ${enable_sixaxis+y} +then : + enableval=$enable_sixaxis; enable_sixaxis=${enableval} +fi + + if test "${enable_sixaxis}" = "yes" && + test "${enable_udev}" != "no"; then + SIXAXIS_TRUE= + SIXAXIS_FALSE='#' +else + SIXAXIS_TRUE='#' + SIXAXIS_FALSE= +fi + + +# Check whether --enable-hid2hci was given. +if test ${enable_hid2hci+y} +then : + enableval=$enable_hid2hci; enable_hid2hci=${enableval} +fi + + if test "${enable_hid2hci}" = "yes" && + test "${enable_udev}" != "no"; then + HID2HCI_TRUE= + HID2HCI_FALSE='#' +else + HID2HCI_TRUE='#' + HID2HCI_FALSE= +fi + + +# Check whether --enable-logger was given. +if test ${enable_logger+y} +then : + enableval=$enable_logger; enable_logger=${enableval} +fi + + if test "${enable_logger}" = "yes"; then + LOGGER_TRUE= + LOGGER_FALSE='#' +else + LOGGER_TRUE='#' + LOGGER_FALSE= +fi + + +# Check whether --enable-admin was given. +if test ${enable_admin+y} +then : + enableval=$enable_admin; enable_admin=${enableval} +fi + + if test "${enable_admin}" = "yes"; then + ADMIN_TRUE= + ADMIN_FALSE='#' +else + ADMIN_TRUE='#' + ADMIN_FALSE= +fi + + +if (test "${prefix}" = "NONE"); then + if (test "$localstatedir" = '${prefix}/var'); then + localstatedir='/var' + + fi + + prefix="${ac_default_prefix}" +fi + +if (test "${exec_prefix}" = "NONE"); then + # exec_prefix defaults to prefix, although our manual handling of the + # latter (above) confuses autoconf. Manually set the exec_prefix. + exec_prefix="${prefix}" +fi + +# Expand any variables containing relative references like ${prefix} and co. +# +# Otherwise we'll end up with literal references in the final binaries or +# manuals, which is not something we really want. +# +pkgbindir="${bindir}" +if (test "$bindir" = '${exec_prefix}/bin'); then + pkgbindir="${exec_prefix}/bin" +else + pkgbindir="${bindir}" +fi +PKGBINDIR="${pkgbindir}" + + +if (test "$libexecdir" = '${exec_prefix}/libexec'); then + pkglibexecdir="${exec_prefix}/libexec/bluetooth" +else + pkglibexecdir="${libexecdir}/bluetooth" +fi +PKGLIBEXECDIR="${pkglibexecdir}" + + +if (test "$localstatedir" = '${prefix}/var'); then + storagedir="${prefix}/var/lib/bluetooth" +else + storagedir="${localstatedir}/lib/bluetooth" +fi + +printf "%s\n" "#define STORAGEDIR \"${storagedir}\"" >>confdefs.h + + +if (test "$sysconfdir" = '${prefix}/etc'); then + configdir="${prefix}/etc/bluetooth" +else + configdir="${sysconfdir}/bluetooth" +fi + +printf "%s\n" "#define CONFIGDIR \"${configdir}\"" >>confdefs.h + +CONFIGDIR="${configdir}" + + + +printf "%s\n" "#define MESH_STORAGEDIR \"${storagedir}/mesh\"" >>confdefs.h + +MESH_STORAGEDIR="${storagedir}/mesh" + + +# Check whether --enable-android was given. +if test ${enable_android+y} +then : + enableval=$enable_android; enable_android=${enableval} +fi + + if test "${enable_android}" = "yes"; then + ANDROID_TRUE= + ANDROID_FALSE='#' +else + ANDROID_TRUE='#' + ANDROID_FALSE= +fi + + +if (test "${enable_android}" = "yes"); then + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sbc >= 1.2" >&5 +printf %s "checking for sbc >= 1.2... " >&6; } + +if test -n "$SBC_CFLAGS"; then + pkg_cv_SBC_CFLAGS="$SBC_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sbc >= 1.2\""; } >&5 + ($PKG_CONFIG --exists --print-errors "sbc >= 1.2") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_SBC_CFLAGS=`$PKG_CONFIG --cflags "sbc >= 1.2" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$SBC_LIBS"; then + pkg_cv_SBC_LIBS="$SBC_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sbc >= 1.2\""; } >&5 + ($PKG_CONFIG --exists --print-errors "sbc >= 1.2") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_SBC_LIBS=`$PKG_CONFIG --libs "sbc >= 1.2" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + SBC_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "sbc >= 1.2" 2>&1` + else + SBC_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "sbc >= 1.2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$SBC_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (sbc >= 1.2) were not met: + +$SBC_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables SBC_CFLAGS +and SBC_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "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. + +Alternatively, you may set the environment variables SBC_CFLAGS +and SBC_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See 'config.log' for more details" "$LINENO" 5; } +else + SBC_CFLAGS=$pkg_cv_SBC_CFLAGS + SBC_LIBS=$pkg_cv_SBC_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi +fi + +if (test "${enable_android}" = "yes"); then + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for speexdsp >= 1.2" >&5 +printf %s "checking for speexdsp >= 1.2... " >&6; } + +if test -n "$SPEEXDSP_CFLAGS"; then + pkg_cv_SPEEXDSP_CFLAGS="$SPEEXDSP_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"speexdsp >= 1.2\""; } >&5 + ($PKG_CONFIG --exists --print-errors "speexdsp >= 1.2") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_SPEEXDSP_CFLAGS=`$PKG_CONFIG --cflags "speexdsp >= 1.2" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$SPEEXDSP_LIBS"; then + pkg_cv_SPEEXDSP_LIBS="$SPEEXDSP_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"speexdsp >= 1.2\""; } >&5 + ($PKG_CONFIG --exists --print-errors "speexdsp >= 1.2") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_SPEEXDSP_LIBS=`$PKG_CONFIG --libs "speexdsp >= 1.2" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + SPEEXDSP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "speexdsp >= 1.2" 2>&1` + else + SPEEXDSP_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "speexdsp >= 1.2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$SPEEXDSP_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (speexdsp >= 1.2) were not met: + +$SPEEXDSP_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables SPEEXDSP_CFLAGS +and SPEEXDSP_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "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. + +Alternatively, you may set the environment variables SPEEXDSP_CFLAGS +and SPEEXDSP_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See 'config.log' for more details" "$LINENO" 5; } +else + SPEEXDSP_CFLAGS=$pkg_cv_SPEEXDSP_CFLAGS + SPEEXDSP_LIBS=$pkg_cv_SPEEXDSP_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi +fi + + +printf "%s\n" "#define ANDROID_STORAGEDIR \"${storagedir}/android\"" >>confdefs.h + + + +# Check whether --with-phonebook was given. +if test ${with_phonebook+y} +then : + withval=$with_phonebook; plugin_phonebook=${withval} +fi + +if (test -z "${plugin_phonebook}"); then + plugin_phonebook=dummy +fi + +if (test "${plugin_phonebook}" = "ebook"); then + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libebook-1.2 >= 3.3" >&5 +printf %s "checking for libebook-1.2 >= 3.3... " >&6; } + +if test -n "$LIBEBOOK_CFLAGS"; then + pkg_cv_LIBEBOOK_CFLAGS="$LIBEBOOK_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libebook-1.2 >= 3.3\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libebook-1.2 >= 3.3") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBEBOOK_CFLAGS=`$PKG_CONFIG --cflags "libebook-1.2 >= 3.3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$LIBEBOOK_LIBS"; then + pkg_cv_LIBEBOOK_LIBS="$LIBEBOOK_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libebook-1.2 >= 3.3\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libebook-1.2 >= 3.3") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBEBOOK_LIBS=`$PKG_CONFIG --libs "libebook-1.2 >= 3.3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + LIBEBOOK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libebook-1.2 >= 3.3" 2>&1` + else + LIBEBOOK_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libebook-1.2 >= 3.3" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$LIBEBOOK_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (libebook-1.2 >= 3.3) were not met: + +$LIBEBOOK_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables LIBEBOOK_CFLAGS +and LIBEBOOK_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "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. + +Alternatively, you may set the environment variables LIBEBOOK_CFLAGS +and LIBEBOOK_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See 'config.log' for more details" "$LINENO" 5; } +else + LIBEBOOK_CFLAGS=$pkg_cv_LIBEBOOK_CFLAGS + LIBEBOOK_LIBS=$pkg_cv_LIBEBOOK_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libedataserver-1.2 >= 3.3" >&5 +printf %s "checking for libedataserver-1.2 >= 3.3... " >&6; } + +if test -n "$LIBEDATESERVER_CFLAGS"; then + pkg_cv_LIBEDATESERVER_CFLAGS="$LIBEDATESERVER_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libedataserver-1.2 >= 3.3\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libedataserver-1.2 >= 3.3") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBEDATESERVER_CFLAGS=`$PKG_CONFIG --cflags "libedataserver-1.2 >= 3.3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$LIBEDATESERVER_LIBS"; then + pkg_cv_LIBEDATESERVER_LIBS="$LIBEDATESERVER_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libedataserver-1.2 >= 3.3\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libedataserver-1.2 >= 3.3") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBEDATESERVER_LIBS=`$PKG_CONFIG --libs "libedataserver-1.2 >= 3.3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + LIBEDATESERVER_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libedataserver-1.2 >= 3.3" 2>&1` + else + LIBEDATESERVER_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libedataserver-1.2 >= 3.3" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$LIBEDATESERVER_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (libedataserver-1.2 >= 3.3) were not met: + +$LIBEDATESERVER_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables LIBEDATESERVER_CFLAGS +and LIBEDATESERVER_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "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. + +Alternatively, you may set the environment variables LIBEDATESERVER_CFLAGS +and LIBEDATESERVER_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See 'config.log' for more details" "$LINENO" 5; } +else + LIBEDATESERVER_CFLAGS=$pkg_cv_LIBEDATESERVER_CFLAGS + LIBEDATESERVER_LIBS=$pkg_cv_LIBEDATESERVER_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +fi +fi +PLUGIN_PHONEBOOK=${plugin_phonebook} + + +ac_config_files="$ac_config_files lib/bluez.pc Makefile mesh/bluetooth-meshd.rst mesh/bluetooth-mesh.service obexd/src/obex.service obexd/src/org.bluez.obex.service src/bluetoothd.rst src/bluetooth.service tools/bluetooth-logger.service tools/mpris-proxy.service" + +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_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; 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+y} || &/ + 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 + if test "x$cache_file" != "x/dev/null"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +printf "%s\n" "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +printf "%s\n" "$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= +U= +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=`printf "%s\n" "$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. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 +printf %s "checking that generated files are newer than configure... " >&6; } + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 +printf "%s\n" "done" >&6; } + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error $? "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${COVERAGE_TRUE}" && test -z "${COVERAGE_FALSE}"; then + as_fn_error $? "conditional \"COVERAGE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DBUS_RUN_SESSION_TRUE}" && test -z "${DBUS_RUN_SESSION_FALSE}"; then + as_fn_error $? "conditional \"DBUS_RUN_SESSION\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${VALGRIND_TRUE}" && test -z "${VALGRIND_FALSE}"; then + as_fn_error $? "conditional \"VALGRIND\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ZSH_COMPLETIONS_TRUE}" && test -z "${ZSH_COMPLETIONS_FALSE}"; then + as_fn_error $? "conditional \"ZSH_COMPLETIONS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${LIBRARY_TRUE}" && test -z "${LIBRARY_FALSE}"; then + as_fn_error $? "conditional \"LIBRARY\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${TEST_TRUE}" && test -z "${TEST_FALSE}"; then + as_fn_error $? "conditional \"TEST\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${NFC_TRUE}" && test -z "${NFC_FALSE}"; then + as_fn_error $? "conditional \"NFC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${SAP_TRUE}" && test -z "${SAP_FALSE}"; then + as_fn_error $? "conditional \"SAP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${A2DP_TRUE}" && test -z "${A2DP_FALSE}"; then + as_fn_error $? "conditional \"A2DP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${AVRCP_TRUE}" && test -z "${AVRCP_FALSE}"; then + as_fn_error $? "conditional \"AVRCP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${NETWORK_TRUE}" && test -z "${NETWORK_FALSE}"; then + as_fn_error $? "conditional \"NETWORK\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HID_TRUE}" && test -z "${HID_FALSE}"; then + as_fn_error $? "conditional \"HID\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HOG_TRUE}" && test -z "${HOG_FALSE}"; then + as_fn_error $? "conditional \"HOG\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HEALTH_TRUE}" && test -z "${HEALTH_FALSE}"; then + as_fn_error $? "conditional \"HEALTH\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BAP_TRUE}" && test -z "${BAP_FALSE}"; then + as_fn_error $? "conditional \"BAP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BASS_TRUE}" && test -z "${BASS_FALSE}"; then + as_fn_error $? "conditional \"BASS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${MCP_TRUE}" && test -z "${MCP_FALSE}"; then + as_fn_error $? "conditional \"MCP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${CCP_TRUE}" && test -z "${CCP_FALSE}"; then + as_fn_error $? "conditional \"CCP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${VCP_TRUE}" && test -z "${VCP_FALSE}"; then + as_fn_error $? "conditional \"VCP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${MICP_TRUE}" && test -z "${MICP_FALSE}"; then + as_fn_error $? "conditional \"MICP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${CSIP_TRUE}" && test -z "${CSIP_FALSE}"; then + as_fn_error $? "conditional \"CSIP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ASHA_TRUE}" && test -z "${ASHA_FALSE}"; then + as_fn_error $? "conditional \"ASHA\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${TOOLS_TRUE}" && test -z "${TOOLS_FALSE}"; then + as_fn_error $? "conditional \"TOOLS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${MONITOR_TRUE}" && test -z "${MONITOR_FALSE}"; then + as_fn_error $? "conditional \"MONITOR\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${CUPS_TRUE}" && test -z "${CUPS_FALSE}"; then + as_fn_error $? "conditional \"CUPS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${CUPS_SERVERBIN_TRUE}" && test -z "${CUPS_SERVERBIN_FALSE}"; then + as_fn_error $? "conditional \"CUPS_SERVERBIN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${MESH_TRUE}" && test -z "${MESH_FALSE}"; then + as_fn_error $? "conditional \"MESH\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${MIDI_TRUE}" && test -z "${MIDI_FALSE}"; then + as_fn_error $? "conditional \"MIDI\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${OBEX_TRUE}" && test -z "${OBEX_FALSE}"; then + as_fn_error $? "conditional \"OBEX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BTPCLIENT_TRUE}" && test -z "${BTPCLIENT_FALSE}"; then + as_fn_error $? "conditional \"BTPCLIENT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${EXTERNAL_ELL_TRUE}" && test -z "${EXTERNAL_ELL_FALSE}"; then + as_fn_error $? "conditional \"EXTERNAL_ELL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${LIBSHARED_ELL_TRUE}" && test -z "${LIBSHARED_ELL_FALSE}"; then + as_fn_error $? "conditional \"LIBSHARED_ELL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${CLIENT_TRUE}" && test -z "${CLIENT_FALSE}"; then + as_fn_error $? "conditional \"CLIENT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${READLINE_TRUE}" && test -z "${READLINE_FALSE}"; then + as_fn_error $? "conditional \"READLINE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${SYSTEMD_TRUE}" && test -z "${SYSTEMD_FALSE}"; then + as_fn_error $? "conditional \"SYSTEMD\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DATAFILES_TRUE}" && test -z "${DATAFILES_FALSE}"; then + as_fn_error $? "conditional \"DATAFILES\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${MANPAGES_TRUE}" && test -z "${MANPAGES_FALSE}"; then + as_fn_error $? "conditional \"MANPAGES\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${RUN_RST2MAN_TRUE}" && test -z "${RUN_RST2MAN_FALSE}"; then + as_fn_error $? "conditional \"RUN_RST2MAN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${TESTING_TRUE}" && test -z "${TESTING_FALSE}"; then + as_fn_error $? "conditional \"TESTING\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${EXPERIMENTAL_TRUE}" && test -z "${EXPERIMENTAL_FALSE}"; then + as_fn_error $? "conditional \"EXPERIMENTAL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DEPRECATED_TRUE}" && test -z "${DEPRECATED_FALSE}"; then + as_fn_error $? "conditional \"DEPRECATED\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${EXTERNAL_PLUGINS_TRUE}" && test -z "${EXTERNAL_PLUGINS_FALSE}"; then + as_fn_error $? "conditional \"EXTERNAL_PLUGINS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${SIXAXIS_TRUE}" && test -z "${SIXAXIS_FALSE}"; then + as_fn_error $? "conditional \"SIXAXIS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HID2HCI_TRUE}" && test -z "${HID2HCI_FALSE}"; then + as_fn_error $? "conditional \"HID2HCI\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${LOGGER_TRUE}" && test -z "${LOGGER_FALSE}"; then + as_fn_error $? "conditional \"LOGGER\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ADMIN_TRUE}" && test -z "${ADMIN_FALSE}"; then + as_fn_error $? "conditional \"ADMIN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ANDROID_TRUE}" && test -z "${ANDROID_FALSE}"; then + as_fn_error $? "conditional \"ANDROID\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $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} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else case e in #( + e) case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac ;; +esac +fi + + + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. +as_nl=' +' +export as_nl +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi +if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi + +# The user is always right. +if ${PATH_SEPARATOR+false} :; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + 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 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + printf "%s\n" "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else case e in #( + e) as_fn_append () + { + eval $1=\$$1\$2 + } ;; +esac +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else case e in #( + e) as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } ;; +esac +fi # as_fn_arith + + +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 + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# 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 + + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + +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 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + 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 -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`printf "%s\n" "$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 || +printf "%s\n" 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" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" +as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated + +# Sed expression to map a string onto a valid variable name. +as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" +as_tr_sh="eval sed '$as_sed_sh'" # deprecated + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=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 bluez $as_me 5.79, which was +generated by GNU Autoconf 2.72. 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 + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# 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_write_fail=1 +ac_cs_usage="\ +'$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + 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 the package provider." + +_ACEOF +ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` +ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config='$ac_cs_config_escaped' +ac_cs_version="\\ +bluez config.status 5.79 +configured by $0, generated by GNU Autoconf 2.72, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2023 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' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +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=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + 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 ) + printf "%s\n" "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + printf "%s\n" "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: '$1' +Try '$0 --help' for more information.";; + --help | --hel | -h ) + printf "%s\n" "$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. + -*) as_fn_error $? "unrecognized option: '$1' +Try '$0 --help' for more information." ;; + + *) as_fn_append 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 || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + printf "%s\n" "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" + + +# 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 + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' +lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +FILECMD='`$ECHO "$FILECMD" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' +want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' +DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' +sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +lt_ar_flags='`$ECHO "$lt_ar_flags" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' +nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' +lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' +lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' +configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in SHELL \ +ECHO \ +PATH_SEPARATOR \ +SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +FILECMD \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +file_magic_glob \ +want_nocaseglob \ +DLLTOOL \ +sharedlib_from_linklib_cmd \ +AR \ +archiver_list_spec \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_import \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +lt_cv_nm_interface \ +nm_file_list_spec \ +lt_cv_truncate_bin \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_pic \ +lt_prog_compiler_wl \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +MANIFEST_TOOL \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_separator \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +install_override_mode \ +finish_eval \ +old_striplib \ +striplib; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postlink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +configure_time_dlsearch_path \ +configure_time_lt_sys_library_path; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +ac_aux_dir='$ac_aux_dir' + +# See if we are running on zsh, and set the options that allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + RM='$RM' + ofile='$ofile' + + + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# 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" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "lib/bluez.pc") CONFIG_FILES="$CONFIG_FILES lib/bluez.pc" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "mesh/bluetooth-meshd.rst") CONFIG_FILES="$CONFIG_FILES mesh/bluetooth-meshd.rst" ;; + "mesh/bluetooth-mesh.service") CONFIG_FILES="$CONFIG_FILES mesh/bluetooth-mesh.service" ;; + "obexd/src/obex.service") CONFIG_FILES="$CONFIG_FILES obexd/src/obex.service" ;; + "obexd/src/org.bluez.obex.service") CONFIG_FILES="$CONFIG_FILES obexd/src/org.bluez.obex.service" ;; + "src/bluetoothd.rst") CONFIG_FILES="$CONFIG_FILES src/bluetoothd.rst" ;; + "src/bluetooth.service") CONFIG_FILES="$CONFIG_FILES src/bluetooth.service" ;; + "tools/bluetooth-logger.service") CONFIG_FILES="$CONFIG_FILES tools/bluetooth-logger.service" ;; + "tools/mpris-proxy.service") CONFIG_FILES="$CONFIG_FILES tools/mpris-proxy.service" ;; + + *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; + 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+y} || CONFIG_FILES=$config_files + test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers + test ${CONFIG_COMMANDS+y} || 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= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with './config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' <conf$$subs.awk | sed ' +/^[^""]/{ + N + s/\n// +} +' >>$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries 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[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with './config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script 'defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' <confdefs.h | sed ' +s/'"$ac_delim"'/"\\\ +"/g' >>$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # 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. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; + :[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="$ac_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 || + as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append 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 '` + printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +printf "%s\n" "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`printf "%s\n" "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + 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 || +printf "%s\n" 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"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`printf "%s\n" "$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 || ac_write_fail=1 +# 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= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + 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 || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;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 +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +printf "%s\n" "$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 "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + printf "%s\n" "/* $configure_input */" >&1 \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + printf "%s\n" "/* $configure_input */" >&1 \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +# 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 || +printf "%s\n" 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) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +printf "%s\n" "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + # TODO: see whether this extra hack can be removed once we start + # requiring Autoconf 2.70 or later. + case $CONFIG_FILES in #( + *\'*) : + eval set x "$CONFIG_FILES" ;; #( + *) : + set x $CONFIG_FILES ;; #( + *) : + ;; +esac + shift + # Used to flag and report bootstrapping failures. + am_rc=0 + for am_mf + do + # Strip MF so we end up with the name of the file. + am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile which includes + # dependency-tracking related rules and includes. + # Grep'ing the whole file directly is not great: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ + || continue + am_dirpart=`$as_dirname -- "$am_mf" || +$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$am_mf" : 'X\(//\)[^/]' \| \ + X"$am_mf" : 'X\(//\)$' \| \ + X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X"$am_mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + am_filepart=`$as_basename -- "$am_mf" || +$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ + X"$am_mf" : 'X\(//\)$' \| \ + X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X/"$am_mf" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { echo "$as_me:$LINENO: cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles" >&5 + (cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } || am_rc=$? + done + if test $am_rc -ne 0; then + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} +as_fn_error $? "Something went wrong bootstrapping makefile fragments + for automatic dependency tracking. If GNU make was not used, consider + re-running the configure script with MAKE=\"gmake\" (or whatever is + necessary). You can also try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking). +See 'config.log' for more details" "$LINENO" 5; } + fi + { am_dirpart=; unset am_dirpart;} + { am_filepart=; unset am_filepart;} + { am_mf=; unset am_mf;} + { am_rc=; unset am_rc;} + rm -f conftest-deps.mk +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options that allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST + fi + + cfgfile=${ofile}T + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL +# Generated automatically by $as_me ($PACKAGE) $VERSION +# NOTE: Changes made to this file will be lost: look at ltmain.sh. + +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit, 1996 + +# Copyright (C) 2014 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. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program or library that is built +# using GNU Libtool, you may include this file under the same +# distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +# The names of the tagged configurations supported by this script. +available_tags='' + +# Configured defaults for sys_lib_dlsearch_path munging. +: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} + +# ### BEGIN LIBTOOL CONFIG + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# Shared archive member basename,for filename based shared library versioning on AIX. +shared_archive_member_spec=$shared_archive_member_spec + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The PATH separator for the build system. +PATH_SEPARATOR=$lt_PATH_SEPARATOR + +# 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 + +# 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//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# convert \$build file names to \$host format. +to_host_file_cmd=$lt_cv_to_host_file_cmd + +# convert \$build files to toolchain format. +to_tool_file_cmd=$lt_cv_to_tool_file_cmd + +# A file(cmd) program that detects file types. +FILECMD=$lt_FILECMD + +# An object symbol dumper. +OBJDUMP=$lt_OBJDUMP + +# 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 + +# How to find potential files when deplibs_check_method = "file_magic". +file_magic_glob=$lt_file_magic_glob + +# Find potential files using nocaseglob when deplibs_check_method = "file_magic". +want_nocaseglob=$lt_want_nocaseglob + +# DLL creation program. +DLLTOOL=$lt_DLLTOOL + +# Command to associate shared and link libraries. +sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd + +# The archiver. +AR=$lt_AR + +# Flags to create an archive (by configure). +lt_ar_flags=$lt_ar_flags + +# Flags to create an archive. +AR_FLAGS=\${ARFLAGS-"\$lt_ar_flags"} + +# How to feed a file listing to the archiver. +archiver_list_spec=$lt_archiver_list_spec + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# 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 into a list of symbols to manually relocate. +global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import + +# 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 + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# The name lister interface. +nm_interface=$lt_lt_cv_nm_interface + +# Specify filename containing input files for \$NM. +nm_file_list_spec=$lt_nm_file_list_spec + +# The root where to search for dependent libraries,and where our libraries should be installed. +lt_sysroot=$lt_sysroot + +# Command to truncate a binary pipe. +lt_truncate_bin=$lt_lt_cv_truncate_bin + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Manifest tool. +MANIFEST_TOOL=$lt_MANIFEST_TOOL + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# 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 + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# 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 + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Detected run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path + +# Explicit LT_SYS_LIBRARY_PATH set during ./configure time. +configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path + +# 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 + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# 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 + +# 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 + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# 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 a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# 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 + +# 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 DIR/libNAME\$shared_ext during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \$shlibpath_var if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# 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 + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# 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 + +# 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 + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# ### END LIBTOOL CONFIG + +_LT_EOF + + cat <<'_LT_EOF' >> "$cfgfile" + +# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE + +# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x$2 in + x) + ;; + *:) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" + ;; + x:*) + eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" + ;; + *) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" + ;; + esac +} + + +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in $*""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} + + +# ### END FUNCTIONS SHARED WITH CONFIGURE + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_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 set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + + +ltmain=$ac_aux_dir/ltmain.sh + + + # 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" + + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# 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 || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + diff --git a/configure.ac b/configure.ac index f9f0faf573cad78a60235d2d6ea5fa5ed91b5441..01f0f2ba04c06faf06563e6f2e8b87c11f016b7e 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 AC_PREREQ(2.60) -AC_INIT(bluez, 5.66) +AC_INIT(bluez, 5.79) AM_INIT_AUTOMAKE([foreign subdir-objects color-tests silent-rules tar-pax no-dist-gzip dist-xz]) @@ -32,8 +32,8 @@ AC_PROG_MKDIR_P m4_define([_LT_AC_TAGCONFIG], []) m4_ifdef([AC_LIBTOOL_TAGS], [AC_LIBTOOL_TAGS([])]) -AC_DISABLE_STATIC -AC_PROG_LIBTOOL +LT_PREREQ(2.2) +LT_INIT([disable-static]) if (test "$USE_MAINTAINER_MODE" = "yes"); then AC_CHECK_PROG(enable_coverage, [lcov], [yes], [no]) @@ -70,32 +70,34 @@ AC_CHECK_LIB(pthread, pthread_create, dummy=yes, AC_CHECK_LIB(dl, dlopen, dummy=yes, AC_MSG_ERROR(dynamic linking loader is required)) -AC_CHECK_HEADERS(linux/types.h linux/if_alg.h linux/uinput.h linux/uhid.h sys/random.h) +AC_CHECK_HEADERS(string.h linux/types.h linux/if_alg.h linux/uinput.h linux/uhid.h sys/random.h) -PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.28, dummy=yes, - AC_MSG_ERROR(GLib >= 2.28 is required)) -AC_SUBST(GLIB_CFLAGS) -AC_SUBST(GLIB_LIBS) +# basename may be only available in libgen.h with the POSIX behavior, +# not desired here +AC_CHECK_DECLS([basename], [], + AC_MSG_WARN([GNU basename extension not found]), + [#define _GNU_SOURCE 1 + #include <string.h> + ]) + + +PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.28) if (test "${enable_threads}" = "yes"); then AC_DEFINE(NEED_THREADS, 1, [Define if threading support is required]) - PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes, - AC_MSG_ERROR(GThread >= 2.16 is required)) + PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16) GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS" GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS" fi -PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.6, dummy=yes, - AC_MSG_ERROR(D-Bus >= 1.6 is required)) -AC_SUBST(DBUS_CFLAGS) -AC_SUBST(DBUS_LIBS) +PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.10) AC_ARG_WITH([dbusconfdir], AS_HELP_STRING([--with-dbusconfdir=DIR], [path to D-Bus configuration directory]), [path_dbusconfdir=${withval}]) if (test -z "${path_dbusconfdir}"); then AC_MSG_CHECKING([D-Bus configuration directory]) - path_dbusconfdir="`$PKG_CONFIG --variable=sysconfdir dbus-1`" + path_dbusconfdir="`$PKG_CONFIG --variable=datadir dbus-1`" if (test -z "${path_dbusconfdir}"); then AC_MSG_ERROR([D-Bus configuration directory is required]) fi @@ -199,14 +201,34 @@ AC_ARG_ENABLE(bap, AS_HELP_STRING([--disable-bap], [disable BAP profile]), [enable_bap=${enableval}]) AM_CONDITIONAL(BAP, test "${enable_bap}" != "no") +AC_ARG_ENABLE(bass, AS_HELP_STRING([--disable-bass], + [disable BASS service]), [enable_bass=${enableval}]) +AM_CONDITIONAL(BASS, test "${enable_bass}" != "no") + AC_ARG_ENABLE(mcp, AS_HELP_STRING([--disable-mcp], [disable MCP profile]), [enable_mcp=${enableval}]) AM_CONDITIONAL(MCP, test "${enable_mcp}" != "no") +AC_ARG_ENABLE(ccp, AS_HELP_STRING([--disable-ccp], + [disable CCP profile]), [enable_ccp=${enableval}]) +AM_CONDITIONAL(CCP, test "${enable_ccp}" != "no") + AC_ARG_ENABLE(vcp, AS_HELP_STRING([--disable-vcp], [disable VCP profile]), [enable_vcp=${enableval}]) AM_CONDITIONAL(VCP, test "${enable_vcp}" != "no") +AC_ARG_ENABLE(micp, AS_HELP_STRING([--disable-micp], + [disable MICP profile]), [enable_micp=${enableval}]) +AM_CONDITIONAL(MICP, test "${enable_micp}" != "no") + +AC_ARG_ENABLE(csip, AS_HELP_STRING([--disable-csip], + [disable CSIP profile]), [enable_csip=${enableval}]) +AM_CONDITIONAL(CSIP, test "${enable_csip}" != "no") + +AC_ARG_ENABLE(asha, AS_HELP_STRING([--disable-asha], + [disable ASHA support]), [enable_asha=${enableval}]) +AM_CONDITIONAL(ASHA, test "${enable_asha}" != "no") + AC_ARG_ENABLE(tools, AS_HELP_STRING([--disable-tools], [disable Bluetooth tools]), [enable_tools=${enableval}]) AM_CONDITIONAL(TOOLS, test "${enable_tools}" != "no") @@ -217,16 +239,10 @@ AM_CONDITIONAL(MONITOR, test "${enable_monitor}" != "no") AC_ARG_ENABLE(udev, AS_HELP_STRING([--disable-udev], [disable udev device support]), [enable_udev=${enableval}]) -if (test "${enable_tools}" != "no" && test "${enable_udev}" != "no"); then - PKG_CHECK_MODULES(UDEV, libudev >= 172, dummy=yes, - AC_MSG_ERROR(libudev >= 172 is required)) - AC_SUBST(UDEV_CFLAGS) - AC_SUBST(UDEV_LIBS) - AC_CHECK_LIB(udev, udev_hwdb_new, - AC_DEFINE(HAVE_UDEV_HWDB_NEW, 1, - [Define to 1 if you have the udev_hwdb_new() function.])) +if (test "${enable_udev}" != "no"); then + PKG_CHECK_MODULES(UDEV, libudev >= 196) + AC_DEFINE(HAVE_UDEV, 1, [Define to 1 if udev is required]) fi -AM_CONDITIONAL(UDEV, test "${enable_udev}" != "no") AC_ARG_WITH([udevdir], AS_HELP_STRING([--with-udevdir=DIR], [path to udev directory]), [path_udevdir=${withval}]) @@ -243,16 +259,22 @@ AC_SUBST(UDEV_DIR, [${path_udevdir}]) AC_ARG_ENABLE(cups, AS_HELP_STRING([--disable-cups], [disable CUPS printer support]), [enable_cups=${enableval}]) AM_CONDITIONAL(CUPS, test "${enable_cups}" != "no") +if (test "${enable_cups}" != "no"); then + AC_MSG_CHECKING([cups directory]) + cups_serverbin=`$PKG_CONFIG cups --variable=cups_serverbin` + AC_MSG_RESULT([${cups_serverbin}]) +fi +AM_CONDITIONAL(CUPS_SERVERBIN, test "${cups_serverbin}" != "") +AS_IF([test "${cups_serverbin}" != ""],[ + AC_SUBST(CUPS_SERVERBIN, ${cups_serverbin}) +]) AC_ARG_ENABLE(mesh, AS_HELP_STRING([--enable-mesh], [enable Mesh profile support]), [enable_mesh=${enableval}]) AM_CONDITIONAL(MESH, test "${enable_mesh}" = "yes") if (test "${enable_mesh}" = "yes"); then - PKG_CHECK_MODULES(JSONC, json-c >= 0.13, dummy=yes, - AC_MSG_ERROR(json-c >= 0.13 is required)) - AC_SUBST(JSON_CFLAGS) - AC_SUBST(JSON_LIBS) + PKG_CHECK_MODULES(JSONC, json-c >= 0.13) fi AC_ARG_ENABLE(midi, AS_HELP_STRING([--enable-midi], @@ -260,19 +282,13 @@ AC_ARG_ENABLE(midi, AS_HELP_STRING([--enable-midi], AM_CONDITIONAL(MIDI, test "${enable_midi}" = "yes") if (test "${enable_midi}" = "yes"); then - PKG_CHECK_MODULES(ALSA, alsa, dummy=yes, - AC_MSG_ERROR(ALSA lib is required for MIDI support)) - AC_SUBST(ALSA_CFLAGS) - AC_SUBST(ALSA_LIBS) + PKG_CHECK_MODULES(ALSA, alsa) fi AC_ARG_ENABLE(obex, AS_HELP_STRING([--disable-obex], [disable OBEX profile support]), [enable_obex=${enableval}]) if (test "${enable_obex}" != "no"); then - PKG_CHECK_MODULES(ICAL, libical, dummy=yes, - AC_MSG_ERROR(libical is required)) - AC_SUBST(ICAL_CFLAGS) - AC_SUBST(ICAL_LIBS) + PKG_CHECK_MODULES(ICAL, libical) fi AM_CONDITIONAL(OBEX, test "${enable_obex}" != "no") @@ -284,10 +300,14 @@ AC_ARG_ENABLE([external_ell], AS_HELP_STRING([--enable-external-ell], [enable external Embedded Linux library]), [enable_external_ell=${enableval}]) if (test "${enable_external_ell}" = "yes"); then - PKG_CHECK_MODULES(ELL, ell >= 0.39, dummy=yes, - AC_MSG_ERROR(Embedded Linux library >= 0.39 is required)) - AC_SUBST(ELL_CFLAGS) - AC_SUBST(ELL_LIBS) + PKG_CHECK_MODULES(ELL, ell >= 0.39) +fi +if (test "${enable_external_ell}" != "yes" && + (test "${enable_btpclient}" = "yes" || test "${enable_mesh}" = "yes")); then + if (test ! -f ${srcdir}/ell/ell.h) && + (test ! -f ${srcdir}/../ell/ell/ell.h); then + AC_MSG_ERROR(ELL source is required or use --enable-external-ell) + fi fi AM_CONDITIONAL(EXTERNAL_ELL, test "${enable_external_ell}" = "yes" || (test "${enable_btpclient}" != "yes" && @@ -370,6 +390,16 @@ AC_ARG_ENABLE(deprecated, AS_HELP_STRING([--enable-deprecated], [enable_deprecated=${enableval}]) AM_CONDITIONAL(DEPRECATED, test "${enable_deprecated}" = "yes") +AC_ARG_ENABLE(external-plugins, AS_HELP_STRING([--enable-external-plugins], + [enable support for external plugins]), + [enable_external_plugins=${enableval}]) +AM_CONDITIONAL(EXTERNAL_PLUGINS, test "${enable_external_plugins}" = "yes") +if (test "${enable_external_plugins}" = "yes"); then + AC_DEFINE(EXTERNAL_PLUGINS, 1, [Define if external plugin support is required]) +else + AC_DEFINE(EXTERNAL_PLUGINS, 0, [Define if external plugin support is required]) +fi + AC_ARG_ENABLE(sixaxis, AS_HELP_STRING([--enable-sixaxis], [enable sixaxis plugin]), [enable_sixaxis=${enableval}]) AM_CONDITIONAL(SIXAXIS, test "${enable_sixaxis}" = "yes" && @@ -397,6 +427,32 @@ if (test "${prefix}" = "NONE"); then prefix="${ac_default_prefix}" fi +if (test "${exec_prefix}" = "NONE"); then + # exec_prefix defaults to prefix, although our manual handling of the + # latter (above) confuses autoconf. Manually set the exec_prefix. + exec_prefix="${prefix}" +fi + +# Expand any variables containing relative references like ${prefix} and co. +# +# Otherwise we'll end up with literal references in the final binaries or +# manuals, which is not something we really want. +# +pkgbindir="${bindir}" +if (test "$bindir" = '${exec_prefix}/bin'); then + pkgbindir="${exec_prefix}/bin" +else + pkgbindir="${bindir}" +fi +AC_SUBST(PKGBINDIR, "${pkgbindir}") + +if (test "$libexecdir" = '${exec_prefix}/libexec'); then + pkglibexecdir="${exec_prefix}/libexec/bluetooth" +else + pkglibexecdir="${libexecdir}/bluetooth" +fi +AC_SUBST(PKGLIBEXECDIR, "${pkglibexecdir}") + if (test "$localstatedir" = '${prefix}/var'); then storagedir="${prefix}/var/lib/bluetooth" else @@ -424,17 +480,11 @@ AC_ARG_ENABLE(android, AS_HELP_STRING([--enable-android], AM_CONDITIONAL(ANDROID, test "${enable_android}" = "yes") if (test "${enable_android}" = "yes"); then - PKG_CHECK_MODULES(SBC, sbc >= 1.2, dummy=yes, - AC_MSG_ERROR(SBC library >= 1.2 is required)) - AC_SUBST(SBC_CFLAGS) - AC_SUBST(SBC_LIBS) + PKG_CHECK_MODULES(SBC, sbc >= 1.2) fi if (test "${enable_android}" = "yes"); then - PKG_CHECK_MODULES(SPEEXDSP, speexdsp >= 1.2, dummy=yes, - AC_MSG_ERROR(SPEEXDSP library >= 1.2 is required)) - AC_SUBST(SPEEXDSP_CFLAGS) - AC_SUBST(SPEEXDSP_LIBS) + PKG_CHECK_MODULES(SPEEXDSP, speexdsp >= 1.2) fi AC_DEFINE_UNQUOTED(ANDROID_STORAGEDIR, "${storagedir}/android", @@ -448,17 +498,21 @@ if (test -z "${plugin_phonebook}"); then fi if (test "${plugin_phonebook}" = "ebook"); then - PKG_CHECK_MODULES(LIBEBOOK, [libebook-1.2 >= 3.3], dummy=yes, - AC_MSG_ERROR(libebook >= 3.3 is required)) - AC_SUBST(LIBEBOOK_CFLAGS) - AC_SUBST(LIBEBOOK_LIBS) - PKG_CHECK_MODULES(LIBEDATESERVER, [libedataserver-1.2 >= 3.3], - dummy=yes, - AC_MSG_ERROR(libedataserver >= 3.3 is required)) - AC_SUBST(LIBEDATESERVER_CFLAGS) - AC_SUBST(LIBEDATESERVER_LIBS) + PKG_CHECK_MODULES(LIBEBOOK, libebook-1.2 >= 3.3) + PKG_CHECK_MODULES(LIBEDATESERVER, libedataserver-1.2 >= 3.3) fi AC_SUBST(PLUGIN_PHONEBOOK, [${plugin_phonebook}]) -AC_CONFIG_FILES(Makefile src/bluetoothd.rst lib/bluez.pc mesh/bluetooth-meshd.rst) +AC_CONFIG_FILES( + lib/bluez.pc + Makefile + mesh/bluetooth-meshd.rst + mesh/bluetooth-mesh.service + obexd/src/obex.service + obexd/src/org.bluez.obex.service + src/bluetoothd.rst + src/bluetooth.service + tools/bluetooth-logger.service + tools/mpris-proxy.service +) AC_OUTPUT diff --git a/debian/NEWS b/debian/NEWS deleted file mode 100644 index 07d854f1be7fca2015e4bc72d0c0f2a14e5ba96b..0000000000000000000000000000000000000000 --- a/debian/NEWS +++ /dev/null @@ -1,167 +0,0 @@ -bluez-utils (4.40-1) unstable; urgency=low - - This version includes a new hid2hci program which expects the vendor ID and - product ID of the device to be switched to HID/HCI mode, this means the - switching is no longer done in init script but via udev rules for supported - devices. Adding new devices can be done by dropping rules into - /etc/udev/rules.d/ similar to ones found in - /lib/udev/rules.d/62-bluez-hid2hci.rules or by manually running hid2hci, see - hid2hci(8) manpage for further information. - - This version also ships a simple commandline agent (bluetooth-agent) to do - pairing on the command line - - -- Filippo Giunchedi <filippo@debian.org> Fri, 22 May 2009 15:21:35 +0200 - -bluez-utils (3.36-3) unstable; urgency=low - - This version includes an new d-bus policy with updated access control. - As a result of this, only users of netdev group or which are in front of the - computer (i.e. match the at_console="true" rule) are able to communicate - with hcid via dbus. See also #510644. - - -- Filippo Giunchedi <filippo@debian.org> Thu, 08 Jan 2009 18:35:38 +0100 - -bluez-utils (3.30-2) unstable; urgency=low - - This upstream version switches the service infrastructure from external - processes to shared objects. Services (i.e. audio) are started automatically - and do not require a .service file in /etc/bluetooth/. audio.service will be - removed automatically by the upgrade unless modified. - - -- Filippo Giunchedi <filippo@debian.org> Mon, 14 Apr 2008 17:34:21 +0200 - -bluez-utils (3.7-1) unstable; urgency=low - - This version reverts the /etc/bluetooth/passkeys infrastructure as agents for - passkeys are not supposed to be system-wide. - A bluez-passkey-gnome is provided as a passkey agent, plus there's a example - passkey-agent in /usr/share/doc/bluez-utils/examples/passkey-agent.c - - -- Filippo Giunchedi <filippo@debian.org> Sat, 7 Oct 2006 11:43:09 +0200 - -bluez-utils (3.1-3) unstable; urgency=low - - This version includes a new management for outgoing passkey (PIN) requests - while the incoming passkeys defaults to 1234 in /etc/bluetooth/hcid.conf. - See README.Debian for further informations. - - -- Filippo Giunchedi <filippo@debian.org> Wed, 26 Jul 2006 11:37:14 +0200 - -bluez-utils (3.1-1) unstable; urgency=low - - This new upstream version removes the need for external pin helper, pin - requests are handled via dbus. The default pin (or now-called "passkey") is - set to 1234 for backward compatibility. - - Also, udev rules for pcmcia card are included along with - /lib/udev/bluetooth.sh (setserial required) in the bluez-pcmcia-support. - - -- Filippo Giunchedi <filippo@debian.org> Wed, 26 Jul 2006 11:37:02 +0200 - -bluez-utils (2.24-1) unstable; urgency=low - - This version moves /etc/{init.d,default}/bluez-utils to - /etc/{init.d,default}/bluetooth for LSB compilance. - If local modifications are detected the new files will be installed with - the ".dpkg-new" suffix - - -- Filippo Giunchedi <filippo@debian.org> Wed, 7 Jun 2006 13:57:35 +0200 - -bluez-utils (2.19-1) unstable; urgency=high - - * Includes new D-BUS support: sends signals for inquiry results and - remote name resolves. - - * Also adds support for device-specific SDP records. - - -- Edd Dumbill <ejad@debian.org> Fri, 19 Aug 2005 01:12:02 +0100 - -bluez-utils (2.9-1) unstable; urgency=low - - * This release improves input device support: EPoX keyboards and - their new HID presenters should now work correctly in report - protocol mode. - - -- Edd Dumbill <ejad@debian.org> Sun, 8 Aug 2004 15:19:24 +0100 - -bluez-utils (2.8-1) unstable; urgency=low - - * Users of dongles with HID proxy capability (this is where the dongle - pretends to be a keyboard and mouse until it is switched into Bluetooth - mode, allowing Bluetooth input devices to be used in BIOS etc.) are - now supported. The switch is made as part of the bluez-utils init - script. - - -- Edd Dumbill <ejad@debian.org> Mon, 14 Jun 2004 14:24:12 +0100 - -bluez-utils (2.7-1) experimental; urgency=low - - * Upstream has merged bluez-pan with this package. You should - remove the /etc/init.d/bluez-pan script, and use - /etc/default/bluez-utils to configure dund and pand, although - for the moment the old /etc/default/bluez-pan is also read. - - * This source package now has Bluetooth printing support, which - is built into the bluez-cups binary package. - - * DBUS support has been enabled in this build. To use it, add - 'dbus_pin_helper' into the options section, and comment out - the pin_helper. DBUS-aware pin helpers such as that in - bluez-pin will now be used. - - * Bluetooth HID devices (eg, mouse, keyboard) are now supported - for Linux 2.6.6 or better running the hidp patch from bluez.org. - If running these, set HIDD_ENABLED to 1 in /etc/default/bluez-utils - to enable support, then run hidd --connect <bdaddr> to connect - to your keyboard or mouse. - - -- Edd Dumbill <ejad@debian.org> Wed, 26 May 2004 12:43:08 +0100 - -bluez-utils (2.6-1) experimental; urgency=low - - * Upstream has merged bluez-sdp with this package. The sdp tools - are now in this package. You should remove the /etc/init.d/bluez-sdp - script. - - * All tools from /sbin now live in /usr/sbin: hciattach hciconfig - hcid l2ping. - - -- Edd Dumbill <ejad@debian.org> Thu, 6 May 2004 11:58:16 +0100 - -bluez-utils (2.4-4) unstable; urgency=high - - * If you still use the old 'bluepin' PIN assistant: note it has moved - from /bin/ to /usr/bin/. You will need to update your hcid.conf - accordingly. Even better, install bluez-pin and use the helper from - there instead. - * hcitool has also moved to /usr/bin, and l2ping to /sbin. - - -- Edd Dumbill <ejad@debian.org> Wed, 15 Jan 2004 18:37:32 +0000 - -bluez-utils (2.4-3) unstable; urgency=low - - * If you're using devfsd and a recent Linux kernel (2.4.22 or later, or - 2.6.x), remove the file /etc/devfs/devices.d/bluez and run update-devfsd. - This will stop your system complaining when devfsd is started. This - package no longer installs that file, but you must remove it yourself. - If you need it in future, you can find it in /usr/share/doc/bluez-utils. - - -- Edd Dumbill <ejad@debian.org> Wed, 14 Jan 2004 21:14:35 +0000 - -bluez-utils (2.4-1) unstable; urgency=low - - * The rfcomm program has changed slightly: you now need a "bind yes" - in each entry in /etc/bluetooth/rfcomm.conf to ensure they are bound - at startup time. See man rfcomm for more details. - - -- Edd Dumbill <ejad@debian.org> Thu, 1 Jan 2004 18:38:35 +0100 - -bluez-utils (2.3-2) unstable; urgency=low - - * This package now depends on a new PIN helper bluez-pin. If you are - upgrading this package and want to use the new helper instead of the - default one (highly recommended) then alter your pin_helper line in - /etc/bluetooth/hcid.conf to specify /usr/bin/bluez-pin. - - -- Edd Dumbill <ejad@debian.org> Thu, 28 Aug 2003 12:38:35 +0100 diff --git a/debian/apertis/copyright b/debian/apertis/copyright index d6d7a5e3e6ed9214d460280b5e5bab7713a70308..5e2907c09b87789fc59afa3c5cbef0681e8b1088 100644 --- a/debian/apertis/copyright +++ b/debian/apertis/copyright @@ -1,6 +1,6 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Files: * doc/* mesh/* tools/mesh-gatt/* tools/mesh/* +Files: * client/* Copyright: 2008-2015, Intel Corporation. License: GPL-2+ @@ -13,8 +13,54 @@ Files: Makefile.am Copyright: no-info-found License: GPL-2 -Files: android/* -Copyright: 2011-2022, Intel Corporation. +Files: Makefile.in +Copyright: 1987-2021, Free Software Foundation, Inc. +License: GPL-2 + +Files: aclocal.m4 +Copyright: 1996-2021, Free Software Foundation, Inc. +License: (FSFULLR or GPL-2) with Libtool exception + +Files: android/a2dp-sink.c + android/a2dp-sink.h + android/a2dp.c + android/a2dp.h + android/audio-msg.h + android/avrcp-lib.c + android/avrcp-lib.h + android/avrcp.c + android/avrcp.h + android/bluetooth.c + android/bluetooth.h + android/bluetoothd-snoop.c + android/gatt.c + android/gatt.h + android/hal-msg.h + android/handsfree-client.c + android/handsfree-client.h + android/handsfree.c + android/handsfree.h + android/health.h + android/hidhost.c + android/hidhost.h + android/ipc-common.h + android/ipc-tester.c + android/ipc.c + android/ipc.h + android/main.c + android/map-client.c + android/map-client.h + android/pan.c + android/pan.h + android/sco-msg.h + android/sco.h + android/socket.c + android/socket.h + android/system-emulator.c + android/test-ipc.c + android/tester-main.h + android/utils.h +Copyright: 2011-2023, Intel Corporation. License: LGPL-2.1 Files: android/audio_utils/* @@ -35,7 +81,7 @@ Copyright: 2006-2011, Nokia Corporation License: GPL-2 Files: android/avdtptest.c -Copyright: 2011-2015, Intel Corporation +Copyright: 2011-2015, 2023, Intel Corporation License: GPL-2 Files: android/bluetoothd-wrapper.c @@ -80,13 +126,17 @@ Copyright: 2013, 2014, Intel Corporation License: Apache-2.0 Files: android/compat/* -Copyright: 1987-2011, Free Software Foundation, Inc. +Copyright: 1987-2021, Free Software Foundation, Inc. License: GPL-2 Files: android/compat/wordexp.h Copyright: 1991-2013, Free Software Foundation, Inc. License: LGPL-2.1 +Files: android/cutils/* +Copyright: 2011-2023, Intel Corporation. +License: LGPL-2.1 + Files: android/hal-audio-aptx.c Copyright: 2014, Tieto Poland License: Apache-2.0 @@ -102,7 +152,7 @@ License: LGPL-2.1 Files: android/log.c android/sco.c -Copyright: 2008-2016, 2020, 2022, Intel Corporation. +Copyright: 2008-2016, 2020, 2022-2024, Intel Corporation. License: GPL-2 Files: android/system/* @@ -118,59 +168,107 @@ Files: attrib/att-database.h Copyright: 2012, Texas Instruments Corporation License: GPL-2 -Files: attrib/gatttool.h - attrib/interactive.c - attrib/utils.c -Copyright: 2007-2011, Nokia Corporation -License: GPL-2 - Files: btio/* -Copyright: 2006-2011, Nokia Corporation +Copyright: 2023, 2024, NXP + 2006-2011, Nokia Corporation 2004-2011, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 -Files: client/* -Copyright: 2008-2016, 2020, 2022, Intel Corporation. -License: GPL-2 - Files: client/admin.c client/admin.h Copyright: 2021, Google LLC License: GPL-2+ Files: client/adv_monitor.c - client/adv_monitor.h +Copyright: 2024, NXP + 2020, Google LLC +License: GPL-2 + +Files: client/adv_monitor.h Copyright: 2020, Google LLC License: GPL-2 +Files: client/advertising.c + client/advertising.h + client/agent.c + client/agent.h + client/display.c + client/display.h + client/gatt.h + client/mgmt.c + client/mgmt.h + client/player.h + client/print.c + client/print.h +Copyright: 2008-2016, 2020, 2022-2024, Intel Corporation. +License: GPL-2 + +Files: client/assistant.c + client/assistant.h +Copyright: 2023, 2024, NXP +License: GPL-2 + +Files: client/bluetoothctl.1 + client/bluetoothctl.rst +Copyright: Free use of this software is granted under the terms of the GNU +License: LGPL + +Files: client/gatt.c + client/main.c + client/player.c +Copyright: 2023, 2024, NXP + 2012, 2014, 2020, 2022, Intel Corporation. +License: GPL-2 + +Files: compile + depcomp + missing + test-driver +Copyright: 1996-2021, Free Software Foundation, Inc. +License: GPL-2+ with Autoconf-data exception + +Files: configure +Copyright: 1992-1996, 1998-2017, 2020-2023, Free Software Foundation +License: FSFUL + Files: debian/* -Copyright: Edd Dumbill <edd@usefulinc.com> - Andrea Veri <andrea.veri89@gmail.com> - Filippo Giunchedi <filippo@debian.org> - Baptiste Mille-Mathias <baptiste.millemathias@gmail.com> - Mario Limonciello <mario_limonciello@dell.com> - Scott James Remnant <scott@ubuntu.com> - Nobuhiro Iwamatsu <iwamatsu@debian.org> +Copyright: Scott James Remnant <scott@ubuntu.com> + Nobuhiro Iwamatsu <iwamatsu@debian.org> + Mario Limonciello <mario_limonciello@dell.com> + Filippo Giunchedi <filippo@debian.org> + Edd Dumbill <edd@usefulinc.com> + Baptiste Mille-Mathias <baptiste.millemathias@gmail.com> + Andrea Veri <andrea.veri89@gmail.com> License: GPL-2+ Files: debian/control -Copyright: Edd Dumbill <edd@usefulinc.com> - Andrea Veri <andrea.veri89@gmail.com> - Filippo Giunchedi <filippo@debian.org> - Baptiste Mille-Mathias <baptiste.millemathias@gmail.com> - Mario Limonciello <mario_limonciello@dell.com> - Scott James Remnant <scott@ubuntu.com> - Nobuhiro Iwamatsu <iwamatsu@debian.org> +Copyright: Scott James Remnant <scott@ubuntu.com> + Nobuhiro Iwamatsu <iwamatsu@debian.org> + Mario Limonciello <mario_limonciello@dell.com> + Filippo Giunchedi <filippo@debian.org> + Edd Dumbill <edd@usefulinc.com> + Baptiste Mille-Mathias <baptiste.millemathias@gmail.com> + Andrea Veri <andrea.veri89@gmail.com> License: GPL -Files: debian/patches/Change-shebang-from-usr-bin-python-to-usr-bin-python.patch -Copyright: Edd Dumbill <edd@usefulinc.com> - Andrea Veri <andrea.veri89@gmail.com> - Filippo Giunchedi <filippo@debian.org> - Baptiste Mille-Mathias <baptiste.millemathias@gmail.com> - Mario Limonciello <mario_limonciello@dell.com> - Scott James Remnant <scott@ubuntu.com> - Nobuhiro Iwamatsu <iwamatsu@debian.org> +Files: ell/* +Copyright: 2011-2021, Intel Corporation +License: LGPL-2.1 + +Files: ell/dbus-client.c + ell/dbus-client.h +Copyright: 2017, Codecoup + 2011-2014, Intel Corporation +License: LGPL-2.1 + +Files: ell/ecc-external.c +Copyright: 2013, Kenneth MacKay +License: BSD-2-clause + +Files: ell/utf8.c + ell/utf8.h +Copyright: 2024, Cruise, LLC + 2011-2014, Intel Corporation License: LGPL-2.1 Files: emulator/* @@ -180,27 +278,45 @@ License: LGPL-2.1 Files: emulator/b1ee.c emulator/hfp.c -Copyright: 2009-2012, Intel Corporation +Copyright: 2007-2012, Intel Corporation 2004-2010, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 +Files: emulator/btdev.c + emulator/bthost.c + emulator/bthost.h +Copyright: 2023, 2024, NXP + 2011-2014, Intel Corporation + 2002-2010, Marcel Holtmann <marcel@holtmann.org> +License: LGPL-2.1 + Files: emulator/hciemu.c emulator/hciemu.h -Copyright: 2011-2022, Intel Corporation. +Copyright: 2011-2023, Intel Corporation. License: LGPL-2.1 Files: emulator/smp.c -Copyright: 2013, 2014, 2016, 2018, 2019, Intel Corporation +Copyright: 2011-2021, Intel Corporation License: LGPL-2.1 Files: gdbus/* Copyright: 2002-2012, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 +Files: gdbus/client.c + gdbus/gdbus.h +Copyright: 2024, NXP + 2004-2011, Marcel Holtmann <marcel@holtmann.org> +License: GPL-2 + Files: gobex/* -Copyright: 2008-2016, 2020, 2022, Intel Corporation. +Copyright: 2008-2016, 2020, 2022-2024, Intel Corporation. License: GPL-2 +Files: install-sh +Copyright: 1994, X Consortium +License: X11 + Files: lib/* Copyright: 2002-2010, Marcel Holtmann <marcel@holtmann.org> 2002, 2003, Maxim Krasnyansky <maxk@qualcomm.com> @@ -213,6 +329,13 @@ Copyright: 2012, Intel Corporation. 2010-2012, Code Aurora Forum. License: GPL-2 +Files: lib/bluetooth.h +Copyright: 2023, NXP + 2002-2010, Marcel Holtmann <marcel@holtmann.org> + 2002, 2003, Maxim Krasnyansky <maxk@qualcomm.com> + 2000, 2001, Qualcomm Incorporated +License: GPL-2 + Files: lib/bnep.h lib/rfcomm.h lib/sco.h @@ -226,7 +349,7 @@ Copyright: 2002-2012, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 Files: lib/iso.h -Copyright: 2008-2016, 2020, 2022, Intel Corporation. +Copyright: 2008-2016, 2020, 2022-2024, Intel Corporation. License: GPL-2 Files: lib/l2cap.h @@ -238,7 +361,6 @@ License: GPL-2 Files: lib/mgmt.h lib/uuid.c - lib/uuid.h Copyright: 2006-2011, Nokia Corporation 2004-2011, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 @@ -252,57 +374,18 @@ Copyright: 2002-2010, Marcel Holtmann <marcel@holtmann.org> 2001, 2002, Nokia Corporation License: GPL-2 -Files: mesh/agent.c - mesh/agent.h - mesh/appkey.c - mesh/appkey.h - mesh/cfgmod-server.c - mesh/cfgmod.h - mesh/crypto.c - mesh/crypto.h - mesh/dbus.c - mesh/dbus.h - mesh/error.h - mesh/friend.c - mesh/friend.h - mesh/keyring.c - mesh/keyring.h - mesh/main.c - mesh/manager.c - mesh/manager.h - mesh/mesh-config-json.c - mesh/mesh-config.h - mesh/mesh-defs.h - mesh/mesh-io-api.h - mesh/mesh-io-generic.c - mesh/mesh-io-generic.h - mesh/mesh-io-mgmt.c - mesh/mesh-io-mgmt.h - mesh/mesh-io-unit.c - mesh/mesh-io-unit.h - mesh/mesh-io.c - mesh/mesh-io.h - mesh/mesh.c - mesh/mesh.h - mesh/model.c - mesh/model.h - mesh/net-keys.c - mesh/net-keys.h - mesh/net.c - mesh/net.h - mesh/node.c - mesh/node.h - mesh/pb-adv.c - mesh/pb-adv.h - mesh/prov-acceptor.c - mesh/prov-initiator.c - mesh/prov.h - mesh/provision.h - mesh/rpl.c - mesh/rpl.h - mesh/util.c - mesh/util.h -Copyright: 2011-2022, Intel Corporation. +Files: lib/uuid.h +Copyright: 2023, 2024, NXP + 2006-2011, Nokia Corporation + 2004-2011, Marcel Holtmann <marcel@holtmann.org> +License: GPL-2 + +Files: ltmain.sh +Copyright: 1996-2019, 2021, 2022, Free Software Foundation, Inc. +License: (Expat or GPL-2+) with Libtool exception + +Files: mesh/* +Copyright: 2011-2023, Intel Corporation. License: LGPL-2.1 Files: mesh/mesh-mgmt.c @@ -310,6 +393,13 @@ Files: mesh/mesh-mgmt.c Copyright: 2019, SILVAIR sp. z o.o. License: LGPL-2.1 +Files: mesh/prv-beacon.h + mesh/prvbeac-server.c + mesh/remprv-server.c + mesh/remprv.h +Copyright: 2023, Intel Corporation. +License: LGPL-2.1+ + Files: monitor/* Copyright: 2011-2014, Intel Corporation 2002-2010, Marcel Holtmann <marcel@holtmann.org> @@ -326,6 +416,14 @@ Files: monitor/a2dp.h Copyright: 2015, Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl> License: LGPL-2.1 +Files: monitor/att.c + monitor/bt.h + monitor/packet.c +Copyright: 2023, 2024, NXP + 2011-2014, Intel Corporation + 2002-2010, Marcel Holtmann <marcel@holtmann.org> +License: LGPL-2.1 + Files: monitor/jlink.c monitor/jlink.h Copyright: 2018, Codecoup @@ -338,11 +436,22 @@ Copyright: 2011-2014, Intel Corporation License: LGPL-2.1+ Files: monitor/tty.h -Copyright: 2013, 2014, 2016, 2018, 2019, Intel Corporation +Copyright: 2011-2021, Intel Corporation License: LGPL-2.1 Files: obexd/* -Copyright: 2011-2015, Intel Corporation +Copyright: 2002-2012, Marcel Holtmann <marcel@holtmann.org> +License: GPL-2 + +Files: obexd/client/* +Copyright: 2011-2015, 2023, Intel Corporation +License: GPL-2 + +Files: obexd/client/bip-common.c + obexd/client/bip-common.h + obexd/client/bip.c + obexd/client/bip.h +Copyright: 2024, Collabora Ltd. License: GPL-2 Files: obexd/client/driver.c @@ -369,8 +478,8 @@ Files: obexd/client/pbap.c obexd/client/pbap.h obexd/client/sync.c obexd/client/sync.h -Copyright: 2007-2010, Marcel Holtmann <marcel@holtmann.org> - 2007-2010, Intel Corporation +Copyright: 2007-2012, Intel Corporation + 2004-2010, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 Files: obexd/client/session.c @@ -382,13 +491,6 @@ Copyright: 2011, 2012, BMW Car IT GmbH. License: GPL-2 Files: obexd/plugins/* -Copyright: 2007-2011, Nokia Corporation -License: GPL-2 - -Files: obexd/plugins/bluetooth.c - obexd/plugins/ftp.c - obexd/plugins/opp.c - obexd/plugins/pcsuite.c Copyright: 2006-2011, Nokia Corporation 2004-2011, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 @@ -396,7 +498,7 @@ License: GPL-2 Files: obexd/plugins/filesystem.c obexd/plugins/pbap.c obexd/plugins/phonebook-dummy.c -Copyright: 2009-2012, Intel Corporation +Copyright: 2007-2012, Intel Corporation 2004-2010, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 @@ -416,25 +518,19 @@ Copyright: 2021, Dylan Van Assche <me@dylanvanassche.be> 2007-2021, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 -Files: obexd/plugins/syncevolution.c -Copyright: 2007-2010, Marcel Holtmann <marcel@holtmann.org> - 2007-2010, Intel Corporation -License: GPL-2 - Files: obexd/plugins/vcard.c obexd/plugins/vcard.h -Copyright: 2008-2016, 2020, 2022, Intel Corporation. -License: GPL-2 - -Files: obexd/src/* -Copyright: 2002-2012, Marcel Holtmann <marcel@holtmann.org> +Copyright: 2008-2016, 2020, 2022-2024, Intel Corporation. License: GPL-2 Files: obexd/src/manager.h - obexd/src/map_ap.h Copyright: 2007-2011, Nokia Corporation License: GPL-2 +Files: obexd/src/map_ap.h +Copyright: 2010, 2011, Nokia Corporation +License: GPL-2 + Files: obexd/src/obex-priv.h obexd/src/obex.c obexd/src/obex.h @@ -445,11 +541,11 @@ Copyright: 2006-2011, Nokia Corporation License: GPL-2 Files: peripheral/* -Copyright: 2011-2022, Intel Corporation. +Copyright: 2011-2023, Intel Corporation. License: LGPL-2.1 Files: plugins/* -Copyright: 2011, 2012, David Herrmann <dh.herrmann@googlemail.com> +Copyright: 2002-2012, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 Files: plugins/admin.c @@ -460,20 +556,12 @@ Files: plugins/autopair.c Copyright: 2012, 2014, 2015, Google Inc. License: GPL-2 -Files: plugins/external-dummy.c -Copyright: no-info-found -License: GPL-2 - -Files: plugins/hostname.c -Copyright: 2002-2012, Marcel Holtmann <marcel@holtmann.org> -License: GPL-2 - Files: plugins/neard.c Copyright: 2012, 2013, Tieto Poland License: GPL-2 Files: plugins/policy.c -Copyright: 2008-2016, 2020, 2022, Intel Corporation. +Copyright: 2008-2016, 2020, 2022-2024, Intel Corporation. License: GPL-2 Files: plugins/sixaxis.c @@ -482,6 +570,10 @@ Copyright: 2013, Szymon Janc <szymon.janc@gmail.com> 2009, 2017, Bastien Nocera <hadess@hadess.net> License: GPL-2 +Files: plugins/wiimote.c +Copyright: 2011, 2012, David Herrmann <dh.herrmann@googlemail.com> +License: GPL-2 + Files: profiles/* Copyright: 2002-2012, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 @@ -499,12 +591,16 @@ License: LGPL-2.1 Files: profiles/audio/a2dp.c profiles/audio/a2dp.h - profiles/audio/media.c Copyright: 2011, BMW Car IT GmbH. 2006-2010, Nokia Corporation 2004-2010, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 +Files: profiles/audio/asha.c + profiles/audio/asha.h +Copyright: 2024, Asymptotic Inc. +License: GPL-2 + Files: profiles/audio/avctp.c profiles/audio/avrcp.c profiles/audio/control.c @@ -514,9 +610,35 @@ Copyright: 2011, Texas Instruments, Inc. License: GPL-2 Files: profiles/audio/bap.c +Copyright: 2023, 2024, NXP + 2012, 2014, 2020, 2022, Intel Corporation. +License: GPL-2 + +Files: profiles/audio/bap.h + profiles/audio/bass.h +Copyright: 2023, 2024, NXP +License: GPL-2 + +Files: profiles/audio/bass.c +Copyright: 2023, 2024, NXP +License: LGPL-2.1 + +Files: profiles/audio/ccp.c + profiles/audio/csip.c profiles/audio/mcp.c profiles/audio/vcp.c -Copyright: 2008-2016, 2020, 2022, Intel Corporation. +Copyright: 2008-2016, 2020, 2022-2024, Intel Corporation. +License: GPL-2 + +Files: profiles/audio/media.c +Copyright: 2023, NXP + 2011, BMW Car IT GmbH. + 2006, 2007, Nokia Corporation + 2004-2009, Marcel Holtmann <marcel@holtmann.org> +License: GPL-2 + +Files: profiles/audio/micp.c +Copyright: 2023, NXP Semiconductors. License: GPL-2 Files: profiles/audio/player.c @@ -533,8 +655,14 @@ Copyright: 2009, Joao Paulo Rechi Vita 2004-2010, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 +Files: profiles/audio/transport.c +Copyright: 2023, 2024, NXP + 2006-2011, Nokia Corporation + 2004-2011, Marcel Holtmann <marcel@holtmann.org> +License: GPL-2 + Files: profiles/battery/* -Copyright: 2011-2022, Intel Corporation. +Copyright: 2011-2023, Intel Corporation. License: LGPL-2.1 Files: profiles/battery/battery.c @@ -544,6 +672,10 @@ Copyright: 2017, Red Hat Inc. License: GPL-2 Files: profiles/deviceinfo/* +Copyright: 2011-2023, Intel Corporation. +License: LGPL-2.1 + +Files: profiles/deviceinfo/deviceinfo.c Copyright: 2015, Google Inc. 2012, Texas Instruments, Inc. License: GPL-2 @@ -552,10 +684,6 @@ Files: profiles/deviceinfo/dis.c Copyright: 2012, Texas Instruments, Inc. License: GPL-2 -Files: profiles/deviceinfo/dis.h -Copyright: 2011-2022, Intel Corporation. -License: LGPL-2.1 - Files: profiles/gap/* Copyright: 2014, Google Inc. 2012, Instituto Nokia de Tecnologia - INdT @@ -586,7 +714,7 @@ Copyright: 2014, Intel Corporation. License: GPL-2 Files: profiles/input/hog-lib.h -Copyright: 2011-2022, Intel Corporation. +Copyright: 2011-2023, Intel Corporation. License: LGPL-2.1 Files: profiles/input/hog.c @@ -601,8 +729,7 @@ Copyright: 2013, Szymon Janc <szymon.janc@gmail.com> 2009, 2017, Bastien Nocera <hadess@hadess.net> License: GPL-2 -Files: profiles/input/suspend-dummy.c - profiles/input/suspend-none.c +Files: profiles/input/suspend-none.c profiles/input/suspend.h Copyright: 2012, Nordic Semiconductor Inc. 2012, Instituto Nokia de Tecnologia - INdT @@ -643,20 +770,18 @@ Copyright: 2012, Nordic Semiconductor Inc. License: GPL-2 Files: profiles/scanparam/scpp.h -Copyright: 2011-2022, Intel Corporation. +Copyright: 2011-2023, Intel Corporation. License: LGPL-2.1 Files: src/* -Copyright: 2002-2012, Marcel Holtmann <marcel@holtmann.org> -License: GPL-2 +Copyright: 2011-2023, Intel Corporation. +License: LGPL-2.1 Files: src/adapter.c src/adapter.h src/agent.c src/agent.h src/dbus-common.h - src/device.c - src/device.h src/eir.c src/eir.h src/storage.c @@ -678,6 +803,27 @@ Files: src/advertising.c Copyright: 2012, 2014, 2015, Google Inc. License: GPL-2 +Files: src/backtrace.c + src/backtrace.h + src/log.c + src/log.h + src/oui.c + src/oui.h + src/plugin.c + src/plugin.h + src/rfkill.c + src/sdp-client.c + src/sdp-client.h + src/sdp-xml.c + src/sdp-xml.h + src/storage.h + src/textfile.c + src/textfile.h + src/uuid-helper.c + src/uuid-helper.h +Copyright: 2002-2012, Marcel Holtmann <marcel@holtmann.org> +License: GPL-2 + Files: src/battery.c src/battery.h Copyright: 2020, Google LLC @@ -696,6 +842,13 @@ Copyright: 2006-2010, Nokia Corporation 2004-2010, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 +Files: src/device.c + src/device.h +Copyright: 2023, 2024, NXP + 2006-2011, Nokia Corporation + 2004-2011, Marcel Holtmann <marcel@holtmann.org> +License: GPL-2 + Files: src/error.c src/error.h Copyright: 2007, 2008, Fabien Chevalier <fabchevalier@free.fr> @@ -705,7 +858,7 @@ License: GPL-2 Files: src/profile.c src/profile.h -Copyright: 2008-2016, 2020, 2022, Intel Corporation. +Copyright: 2008-2016, 2020, 2022-2024, Intel Corporation. License: GPL-2 Files: src/sdpd-database.c @@ -724,29 +877,50 @@ Files: src/service.c Copyright: 2012, 2013, BMW Car IT GmbH. License: GPL-2 -Files: src/settings.c - src/settings.h -Copyright: 2011-2022, Intel Corporation. -License: LGPL-2.1 - -Files: src/shared/* -Copyright: 2011-2022, Intel Corporation. -License: LGPL-2.1 +Files: src/set.c + src/set.h +Copyright: 2011-2015, 2023, Intel Corporation +License: GPL-2 Files: src/shared/ad.c src/shared/ad.h - src/shared/att-types.h src/shared/att.c src/shared/att.h src/shared/gatt-client.c src/shared/gatt-client.h src/shared/gatt-helpers.c src/shared/gatt-helpers.h - src/shared/gatt-server.c src/shared/gatt-server.h Copyright: 2014, 2015, Google Inc. License: LGPL-2.1 +Files: src/shared/asha.c + src/shared/asha.h +Copyright: 2024, Asymptotic Inc. +License: LGPL-2.1 + +Files: src/shared/att-types.h + src/shared/gatt-server.c +Copyright: 2023, NXP + 2014, Google Inc. +License: LGPL-2.1 + +Files: src/shared/bap-defs.h + src/shared/bap.c + src/shared/bap.h + src/shared/lc3.h + src/shared/shell.c + src/shared/util.c + src/shared/util.h +Copyright: 2023, 2024, NXP + 2012-2014, 2017, 2022, Intel Corporation. +License: LGPL-2.1 + +Files: src/shared/bass.c + src/shared/bass.h +Copyright: 2023, 2024, NXP +License: LGPL-2.1 + Files: src/shared/ecc.c src/shared/ecc.h Copyright: 2013, Kenneth MacKay @@ -756,7 +930,7 @@ Files: src/shared/hci-crypto.c src/shared/hci-crypto.h src/shared/mainloop-ell.c src/shared/mainloop-glib.c -Copyright: 2013, 2014, 2016, 2018, 2019, Intel Corporation +Copyright: 2011-2021, Intel Corporation License: LGPL-2.1 Files: src/shared/mainloop.c @@ -765,6 +939,11 @@ Copyright: 2011-2014, Intel Corporation 2002-2010, Marcel Holtmann <marcel@holtmann.org> License: LGPL-2.1 +Files: src/shared/micp.c + src/shared/micp.h +Copyright: 2023, NXP Semiconductors. +License: LGPL-2.1 + Files: test/* Copyright: no-info-found License: LGPL-2.1 @@ -774,7 +953,32 @@ Copyright: 2010, 2011, ST-Ericsson SA """ License: LGPL-2.1 Files: tools/* -Copyright: 2008-2016, 2020, 2022, Intel Corporation. +Copyright: 2011-2023, Intel Corporation. +License: LGPL-2.1 + +Files: tools/3dsp.c + tools/bluemoon.c + tools/bluetooth-player.c + tools/bnep-tester.c + tools/btmgmt.c + tools/btpclientctl.c + tools/check-selftest.c + tools/create-image.c + tools/gap-tester.c + tools/hci-tester.c + tools/hciattach_bcm43xx.c + tools/hciattach_intel.c + tools/l2cap-tester.c + tools/mesh-tester.c + tools/mgmt-tester.c + tools/obex-client-tool.c + tools/obex-server-tool.c + tools/obexctl.c + tools/rfcomm-tester.c + tools/sco-tester.c + tools/smp-tester.c + tools/userchan-tester.c +Copyright: 2008-2016, 2020, 2022-2024, Intel Corporation. License: GPL-2 Files: tools/advtest.c @@ -788,7 +992,7 @@ Files: tools/advtest.c tools/eddystone.c tools/ibeacon.c tools/oobtest.c -Copyright: 2009-2012, Intel Corporation +Copyright: 2007-2012, Intel Corporation 2004-2010, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 @@ -799,7 +1003,6 @@ Copyright: 2018, Pali Rohár <pali.rohar@gmail.com> License: GPL-2 Files: tools/avtest.c - tools/btiotest.c Copyright: 2006-2011, Nokia Corporation 2004-2011, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 @@ -811,7 +1014,7 @@ Files: tools/bcmfw.c tools/nokfw.c tools/rtlfw.c tools/seq2bseq.c -Copyright: 2011-2015, Intel Corporation +Copyright: 2011-2015, 2023, Intel Corporation License: GPL-2 Files: tools/bdaddr.c @@ -831,23 +1034,18 @@ Files: tools/btgatt-client.c Copyright: 2012, 2014, 2015, Google Inc. License: GPL-2 +Files: tools/btiotest.c +Copyright: 2023, 2024, NXP + 2006-2011, Nokia Corporation + 2004-2011, Marcel Holtmann <marcel@holtmann.org> +License: GPL-2 + Files: tools/btmon-logger.c Copyright: 2017, 2018, Codecoup 2011-2014, Intel Corporation 2002-2010, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 -Files: tools/btpclient.c - tools/ioctl-tester.c - tools/iso-tester.c - tools/isotest.c - tools/mesh-cfgclient.c - tools/mesh-cfgtest.c - tools/meshctl.c - tools/test-runner.c -Copyright: 2011-2022, Intel Corporation. -License: LGPL-2.1 - Files: tools/gatt-service.c Copyright: 2010, 2014, Instituto Nokia de Tecnologia - INdT License: GPL-2 @@ -890,51 +1088,16 @@ Copyright: 2009-2011, Kay Sievers <kay.sievers@vrfy.org> 2003-2010, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 -Files: tools/mesh-gatt/config-client.c - tools/mesh-gatt/config-server.c - tools/mesh-gatt/crypto.c - tools/mesh-gatt/crypto.h - tools/mesh-gatt/gatt.c - tools/mesh-gatt/gatt.h - tools/mesh-gatt/keys.h - tools/mesh-gatt/mesh-net.h - tools/mesh-gatt/net.c - tools/mesh-gatt/net.h - tools/mesh-gatt/node.c - tools/mesh-gatt/node.h - tools/mesh-gatt/onoff-model.c - tools/mesh-gatt/onoff-model.h - tools/mesh-gatt/prov-db.c - tools/mesh-gatt/prov-db.h - tools/mesh-gatt/prov.c - tools/mesh-gatt/prov.h - tools/mesh-gatt/util.c - tools/mesh-gatt/util.h -Copyright: 2011-2022, Intel Corporation. +Files: tools/iso-tester.c + tools/isotest.c +Copyright: 2023, 2024, NXP + 2012-2014, 2017, 2022, Intel Corporation. License: LGPL-2.1 -Files: tools/mesh/agent.c - tools/mesh/agent.h - tools/mesh/cfgcli.c - tools/mesh/cfgcli.h - tools/mesh/config-model.h - tools/mesh/keys.c - tools/mesh/keys.h - tools/mesh/mesh-db.c - tools/mesh/mesh-db.h - tools/mesh/model.h - tools/mesh/remote.c - tools/mesh/remote.h - tools/mesh/util.c - tools/mesh/util.h -Copyright: 2011-2022, Intel Corporation. +Files: tools/missing.h +Copyright: 2024, Khem Raj <raj.khem@gmail.com> License: LGPL-2.1 -Files: tools/parse_companies.pl - tools/update_compids.sh -Copyright: no-info-found -License: GPL-2 - Files: tools/parser/* Copyright: 2002-2012, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 @@ -942,7 +1105,7 @@ License: GPL-2 Files: tools/parser/amp.c tools/parser/avrcp.c tools/parser/smp.c -Copyright: 2008-2016, 2020, 2022, Intel Corporation. +Copyright: 2008-2016, 2020, 2022-2024, Intel Corporation. License: GPL-2 Files: tools/parser/att.c @@ -988,7 +1151,16 @@ Copyright: 2002-2010, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 Files: unit/* -Copyright: 2008-2016, 2020, 2022, Intel Corporation. +Copyright: 2008-2016, 2020, 2022-2024, Intel Corporation. +License: GPL-2 + +Files: unit/test-bap.c +Copyright: 2023, 2024, NXP + 2012, 2014, 2020, 2022, Intel Corporation. +License: GPL-2 + +Files: unit/test-bass.c +Copyright: 2023, 2024, NXP License: GPL-2 Files: unit/test-crc.c @@ -996,7 +1168,7 @@ Files: unit/test-crc.c unit/test-eir.c unit/test-gdbus-client.c unit/test-uuid.c -Copyright: 2011-2015, Intel Corporation +Copyright: 2011-2015, 2023, Intel Corporation License: GPL-2 Files: unit/test-ecc.c @@ -1013,7 +1185,12 @@ Copyright: 2013, Intel Corporation. License: GPL-2 Files: unit/test-mesh-crypto.c -Copyright: 2011-2022, Intel Corporation. +Copyright: 2011-2023, Intel Corporation. +License: LGPL-2.1 + +Files: unit/test-micp.c + unit/test-vcp.c +Copyright: 2023, NXP Semiconductors. License: LGPL-2.1 Files: unit/test-midi.c @@ -1025,6 +1202,6 @@ Files: unit/test-textfile.c Copyright: 2002-2012, Marcel Holtmann <marcel@holtmann.org> License: GPL-2 -Files: INSTALL README doc/mgmt-api.txt mesh/bluetooth-meshd.rst.in monitor/btmon.rst src/bluetoothd.rst.in tools/bdaddr.rst tools/btattach.rst tools/ciptool.rst tools/hciattach.rst tools/hciconfig.rst tools/hcidump.rst tools/hcitool.rst tools/hid2hci.rst tools/isotest.rst tools/l2ping.rst tools/rctest.rst tools/rfcomm.rst tools/sdptool.rst +Files: INSTALL doc/hci.7 doc/hci.rst doc/l2cap.7 doc/l2cap.rst doc/rfcomm.7 doc/rfcomm.rst mesh/bluetooth-meshd.rst.in monitor/btmon.1 monitor/btmon.rst src/bluetoothd.8 src/bluetoothd.rst src/bluetoothd.rst.in tools/bdaddr.1 tools/bdaddr.rst tools/btattach.1 tools/btattach.rst tools/btmgmt.1 tools/btmgmt.rst tools/ciptool.1 tools/ciptool.rst tools/hciattach.1 tools/hciattach.rst tools/hciconfig.1 tools/hciconfig.rst tools/hcidump.1 tools/hcidump.rst tools/hcitool.1 tools/hcitool.rst tools/hid2hci.1 tools/hid2hci.rst tools/isotest.1 tools/isotest.rst tools/l2ping.1 tools/l2ping.rst tools/rctest.1 tools/rctest.rst tools/rfcomm.1 tools/rfcomm.rst tools/sdptool.1 tools/sdptool.rst Copyright: 2008-2015, Intel Corporation. License: GPL-2+ diff --git a/debian/bluez-mesh.maintscript b/debian/bluez-mesh.maintscript new file mode 100644 index 0000000000000000000000000000000000000000..d2da684eba6c72d59db256842ed72327bff9f1bf --- /dev/null +++ b/debian/bluez-mesh.maintscript @@ -0,0 +1 @@ +rm_conffile /etc/dbus-1/system.d/bluetooth-mesh.conf 4.86-1~ diff --git a/debian/bluez-meshd.install b/debian/bluez-meshd.install index 6d144e7f9bc9c89a4b35db98a7ab27ee1178e1ac..a8dee87924d4d45dccbccd6d2142ed510ec5f08a 100644 --- a/debian/bluez-meshd.install +++ b/debian/bluez-meshd.install @@ -1,7 +1,8 @@ -etc/dbus-1/system.d/bluetooth-mesh.conf -lib/systemd/system/bluetooth-mesh.service +usr/share/dbus-1/system.d/bluetooth-mesh.conf +${env:deb_systemdsystemunitdir}/bluetooth-mesh.service usr/bin/mesh-cfgclient usr/bin/mesh-cfgtest usr/bin/meshctl usr/libexec/bluetooth/bluetooth-meshd usr/share/dbus-1/system-services/org.bluez.mesh.service +etc/bluetooth/mesh-main.conf diff --git a/debian/bluez-obexd.install b/debian/bluez-obexd.install index 3ea53a4d656a1f95965c21aade44778c02585b94..4f81fc79d5608034609a55d61a602b11d10955ab 100644 --- a/debian/bluez-obexd.install +++ b/debian/bluez-obexd.install @@ -1,3 +1,4 @@ usr/libexec/bluetooth/obexd usr/share/dbus-1/services/org.bluez.obex.service +usr/lib/systemd/user/dbus-org.bluez.obex.service usr/lib/systemd/user/obex.service diff --git a/debian/bluez.install b/debian/bluez.install index 7d9ec8d87e86ab9992dfe44a3505e09212166459..681c50f8675637793bddf208f214969ebaecf1f2 100644 --- a/debian/bluez.install +++ b/debian/bluez.install @@ -1,13 +1,13 @@ -src/main.conf etc/bluetooth -profiles/input/input.conf etc/bluetooth -profiles/network/network.conf etc/bluetooth +etc/bluetooth/input.conf +etc/bluetooth/main.conf +etc/bluetooth/network.conf usr/libexec/bluetooth/bluetoothd usr/bin/bluetoothctl usr/bin/bluemoon usr/bin/btattach usr/bin/btmon usr/bin/hciattach -usr/bin/hciconfig bin/ +usr/bin/hciconfig usr/bin/hcitool usr/bin/sdptool usr/bin/rctest @@ -20,12 +20,14 @@ usr/bin/rctest usr/bin/mpris-proxy tools/btmgmt usr/bin tools/obexctl usr/bin -lib/udev/hid2hci -lib/udev/rules.d/97-hid2hci.rules +${env:deb_udevdir}/hid2hci +${env:deb_udevdir}/rules.d/97-hid2hci.rules attrib/gatttool usr/bin #-- for systemd -lib/systemd/system/bluetooth.service -etc/dbus-1/system.d/bluetooth.conf +${env:deb_systemdsystemunitdir}/bluetooth.service +usr/lib/systemd/user/mpris-proxy.service +usr/share/dbus-1/system.d/bluetooth.conf usr/share/dbus-1/system-services/org.bluez.service debian/apparmor.d/* /etc/apparmor.d/ usr/share/zsh/site-functions/_bluetoothctl +debian/source_bluez.py usr/share/apport/package-hooks diff --git a/debian/bluez.maintscript b/debian/bluez.maintscript index 43676be4292049007490548196a131722a3484b0..b722edc21f56e6c64421cc3e221cb2de87d597c1 100644 --- a/debian/bluez.maintscript +++ b/debian/bluez.maintscript @@ -8,3 +8,4 @@ rm_conffile /etc/bluetooth/audio.conf 5.21-2~ bluez rm_conffile /etc/bluetooth/proximity.conf 5.50-1~ bluez mv_conffile /etc/dbus-1/system.d/bluez-hcid.conf /etc/dbus-1/system.d/bluetooth.conf 3.7-1 bluez mv_conffile /etc/modprobe.d/bluez /etc/modprobe.d/bluez.conf 4.42-1 bluez +rm_conffile /etc/dbus-1/system.d/bluetooth.conf 4.86-1~ bluez diff --git a/debian/bluez.manpages b/debian/bluez.manpages index 0f95d4a939af5999edc724cf55d3e9bdff8f584d..839e691e321a94bbc8f85e578782369b967986c5 100644 --- a/debian/bluez.manpages +++ b/debian/bluez.manpages @@ -9,14 +9,69 @@ debian/tmp/usr/share/man/man1/l2ping.1 debian/tmp/usr/share/man/man1/rctest.1 debian/tmp/usr/share/man/man1/rfcomm.1 debian/tmp/usr/share/man/man1/sdptool.1 +debian/tmp/usr/share/man/man1/bluetoothctl-assistant.1 +debian/tmp/usr/share/man/man1/bluetoothctl-mgmt.1 +debian/tmp/usr/share/man/man1/bluetoothctl-monitor.1 +debian/tmp/usr/share/man/man1/bluetoothctl-admin.1 +debian/tmp/usr/share/man/man1/bluetoothctl-advertise.1 +debian/tmp/usr/share/man/man1/bluetoothctl-endpoint.1 +debian/tmp/usr/share/man/man1/bluetoothctl-gatt.1 +debian/tmp/usr/share/man/man1/bluetoothctl-player.1 +debian/tmp/usr/share/man/man1/bluetoothctl-scan.1 +debian/tmp/usr/share/man/man1/bluetoothctl-transport.1 +debian/tmp/usr/share/man/man1/btmgmt.1 debian/tmp/usr/share/man/man8/bluetoothd.8 debian/tmp/usr/share/man/man8/bluetooth-meshd.8 +debian/tmp/usr/share/man/man5/org.bluez.Adapter.5 +debian/tmp/usr/share/man/man5/org.bluez.AdminPolicySet.5 +debian/tmp/usr/share/man/man5/org.bluez.AdminPolicyStatus.5 +debian/tmp/usr/share/man/man5/org.bluez.AdvertisementMonitor.5 +debian/tmp/usr/share/man/man5/org.bluez.AdvertisementMonitorManager.5 +debian/tmp/usr/share/man/man5/org.bluez.Agent.5 +debian/tmp/usr/share/man/man5/org.bluez.AgentManager.5 +debian/tmp/usr/share/man/man5/org.bluez.Battery.5 +debian/tmp/usr/share/man/man5/org.bluez.BatteryProvider.5 +debian/tmp/usr/share/man/man5/org.bluez.BatteryProviderManager.5 +debian/tmp/usr/share/man/man5/org.bluez.Device.5 +debian/tmp/usr/share/man/man5/org.bluez.DeviceSet.5 +debian/tmp/usr/share/man/man5/org.bluez.GattCharacteristic.5 +debian/tmp/usr/share/man/man5/org.bluez.GattDescriptor.5 +debian/tmp/usr/share/man/man5/org.bluez.GattManager.5 +debian/tmp/usr/share/man/man5/org.bluez.GattProfile.5 +debian/tmp/usr/share/man/man5/org.bluez.GattService.5 +debian/tmp/usr/share/man/man5/org.bluez.Input.5 +debian/tmp/usr/share/man/man5/org.bluez.LEAdvertisement.5 +debian/tmp/usr/share/man/man5/org.bluez.LEAdvertisingManager.5 +debian/tmp/usr/share/man/man5/org.bluez.Media.5 +debian/tmp/usr/share/man/man5/org.bluez.MediaAssistant.5 +debian/tmp/usr/share/man/man5/org.bluez.MediaControl.5 +debian/tmp/usr/share/man/man5/org.bluez.MediaEndpoint.5 +debian/tmp/usr/share/man/man5/org.bluez.MediaFolder.5 +debian/tmp/usr/share/man/man5/org.bluez.MediaItem.5 +debian/tmp/usr/share/man/man5/org.bluez.MediaPlayer.5 +debian/tmp/usr/share/man/man5/org.bluez.MediaTransport.5 +debian/tmp/usr/share/man/man5/org.bluez.Network.5 +debian/tmp/usr/share/man/man5/org.bluez.NetworkServer.5 +debian/tmp/usr/share/man/man5/org.bluez.Profile.5 +debian/tmp/usr/share/man/man5/org.bluez.ProfileManager.5 +debian/tmp/usr/share/man/man5/org.bluez.obex.Agent.5 +debian/tmp/usr/share/man/man5/org.bluez.obex.AgentManager.5 +debian/tmp/usr/share/man/man5/org.bluez.obex.Client.5 +debian/tmp/usr/share/man/man5/org.bluez.obex.FileTransfer.5 +debian/tmp/usr/share/man/man5/org.bluez.obex.Image.5 +debian/tmp/usr/share/man/man5/org.bluez.obex.Message.5 +debian/tmp/usr/share/man/man5/org.bluez.obex.MessageAccess.5 +debian/tmp/usr/share/man/man5/org.bluez.obex.ObjectPush.5 +debian/tmp/usr/share/man/man5/org.bluez.obex.PhonebookAccess.5 +debian/tmp/usr/share/man/man5/org.bluez.obex.Session.5 +debian/tmp/usr/share/man/man5/org.bluez.obex.Synchronization.5 +debian/tmp/usr/share/man/man5/org.bluez.obex.Transfer.5 debian/manpages/l2test.1 debian/manpages/btmon.1 -debian/manpages/bluetoothctl.1 debian/manpages/gatttool.1 debian/manpages/bluemoon.1 debian/manpages/hex2hcd.1 debian/manpages/mpris-proxy.1 debian/manpages/btmgmt.1 debian/manpages/obexctl.1 +debian/tmp/usr/share/man/man1/bluetoothctl.1 diff --git a/debian/changelog b/debian/changelog index 8cb94f694e8574fe988afadf611c52d0e6be2877..db49557961e30c05c53d3141d778f22ef9dbcb6c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,148 @@ +bluez (5.79-1+apertis1) apertis; urgency=medium + + * Sync from debian/trixie. + * Remaining Apertis specific changes: + - Replace libreadline-dev by libeditreadline-dev in Build-Deps + - Add patch to make bluez compatible with libeditreadline + - Install AppArmor rules + - Create tmpfile for bluez data storage + - Set car class of device + + -- Dylan Aïssi <dylan.aissi@collabora.com> Mon, 10 Mar 2025 16:56:55 +0100 + +bluez (5.79-1) unstable; urgency=medium + + [ Jeremy BÃcha ] + * Add apport hook + * Drop obsolete Pre-Depends + * debian/rules: minor cleanup + * Use ebook phonebook plugin + * autopkgtest: update syntax for Python 3.12 + * Add patches from Ubuntu + - 0002-hostname-handle-chassis-type-handset.patch + - lp1759836.patch + - raspi-bcm43xx-load-firmware.patch + - raspi-bcm43xx-3wire.patch + - raspi-cypress-305-bdaddr.patch + - ubuntu_error_restart.patch + + [ Nobuhiro Iwamatsu ] + * New upstream version 5.79 + (Closes: #1086526, #1031599, #1083183) + * d/patches: Drop raspi-cypress-305-bdaddr.patch. + * Install newly added files. + + -- Nobuhiro Iwamatsu <iwamatsu@debian.org> Mon, 04 Nov 2024 07:19:59 +0900 + +bluez (5.77-1) unstable; urgency=medium + + * Update to 5.77. (Closes: #1070269) + + -- Nobuhiro Iwamatsu <iwamatsu@debian.org> Fri, 16 Aug 2024 15:46:59 +0900 + +bluez (5.73-1.1) unstable; urgency=medium + + * tests: don't fail on output to stderr (Closes: #1071147) + * tests: mark the test as superficial as it doesn't test anything now + + -- Paul Gevers <elbrus@debian.org> Sun, 28 Jul 2024 17:14:24 +0200 + +bluez (5.73-1) unstable; urgency=medium + + * Update to 5.73. (Closes: #1060795, #1060242) + * d/patches: + - Drop allow-using-obexd-without-systemd-in-the-user-sessio.patch. + - Drop change_path_of_hogsuspend.patch. + - Update org.bluez.obex.service.in.patch. + - Drop Change-shebang-from-usr-bin-python-to-usr-bin-python.patch + - Update work-around-Logitech-diNovo-Edge-keyboard-firmware-i.patch. + (Closes: #1060393) + * d//libbluetooth*.install: + - Drop sixaxis.[a|so] from libbluetooth*.install. + * d/bluez-meshd.install: Install mesh-main.conf. + * d/bluez.install: Change install path of config files. + * d/bluez.manpages: Change install path of manpages. + * d/bluez-obexd.install: Install dbus-org.bluez.obex.service. + * d/control: + - Change from pkg-config to pkgconf with libbluetooth-dev. + - Add systemd-dev only with Build-Depends. (Closes: #1060516) + - Bumped Standards-Version to 4.7.0. + * d/tests: + - Add simple testsuite from Ubuntu. (Closes: #1060395) + * d/libbluetooth3.symbols: Update + * d/copyright: + - Drop unprovided source files. + + -- Nobuhiro Iwamatsu <iwamatsu@debian.org> Wed, 10 Apr 2024 20:25:04 +0900 + +bluez (5.71-1) unstable; urgency=medium + + * Update to 5.71. + * d/patches: Drop input.conf-Change-default-of-ClassicBondedOnly.patch. + * Update d/bluez.manpages. + + -- Nobuhiro Iwamatsu <iwamatsu@debian.org> Wed, 03 Jan 2024 02:43:51 +0900 + +bluez (5.70-1.1) unstable; urgency=medium + + * Non-maintainer upload. + * Upload to unstable. + + -- Salvatore Bonaccorso <carnil@debian.org> Fri, 15 Dec 2023 20:57:14 +0100 + +bluez (5.70-1.1~exp0) experimental; urgency=medium + + * Non-maintainer upload. + + [ Helmut Grohne ] + * Fix FTBFS when systemd.pc changes systemdsystemunitdir (Closes: #1052983) + + [ Chris Hofstaedtler ] + * Defer udev file placement to udev's pkg-config data (Closes: #1056996) + * Install hciconfig into /usr/bin instead of /bin + + [ Salvatore Bonaccorso ] + * input.conf: Change default of ClassicBondedOnly (CVE-2023-45866) + (Closes: #1057914) + + -- Salvatore Bonaccorso <carnil@debian.org> Thu, 14 Dec 2023 22:32:44 +0100 + +bluez (5.70-1) unstable; urgency=medium + + * Update to 5.70. + * d/clean: Add debian/tmp-source. (Closes: #1044111) + + -- Nobuhiro Iwamatsu <iwamatsu@debian.org> Tue, 24 Oct 2023 15:17:00 +0900 + +bluez (5.69-1) unstable; urgency=medium + + * Update to 5.69. + * Update d/patches/Fix-typo.patch. + * Update d/bluez.manpages. + + -- Nobuhiro Iwamatsu <iwamatsu@debian.org> Mon, 28 Aug 2023 09:38:44 +0900 + +bluez (5.68-2) unstable; urgency=medium + + * d/rules: export DEB_CFLAGS_MAINT_APPEND + * d/patches: Add Add-HCI_TO_STR-macro-for-FIRMWARE_DIR.patch (Closes: #1036546) + + -- Nobuhiro Iwamatsu <iwamatsu@debian.org> Sun, 06 Aug 2023 08:42:46 +0900 + +bluez (5.68-1) unstable; urgency=medium + + * Update to 5.68. + * d/patches/obex-Use-GLib-helper-function-to-manipulate-paths.patch: Update. + * d/control: Drop lsb-base from Depends of bluez. + * Update d/patches/Fix-typo.patch. + * Install dbus policy in /usr instead of /etc. + * d/control: Remove unnecessary Conflicts and Replace. + * d/NEWS: Remove it. + * d/rules: Override FIRMWARE_DIR to /lib/firmware. (Closes: #1036546) + Thanks to undef <debian@undef.tools>. + + -- Nobuhiro Iwamatsu <iwamatsu@debian.org> Sun, 06 Aug 2023 07:02:04 +0900 + bluez (5.66-1+deb12u2+apertis1) apertis; urgency=medium * Merge updates from debian/bookworm. diff --git a/debian/clean b/debian/clean new file mode 100644 index 0000000000000000000000000000000000000000..c8914829d2f82c67d88bb8739a577315393714f3 --- /dev/null +++ b/debian/clean @@ -0,0 +1 @@ +debian/tmp-source/ diff --git a/debian/control b/debian/control index da5fa72f01a3bf342f696a9ea4fe276f1d0f1e0d..38a0dfe43f3c3c311b5e8b7dee0a8ffad34e39ac 100644 --- a/debian/control +++ b/debian/control @@ -8,6 +8,7 @@ Build-Depends: debhelper-compat (= 13), flex, bison, libdbus-1-dev (>= 1.6), + libebook1.2-dev [!i386 !alpha !m68k !ppc64 !sh4 !x32], libglib2.0-dev, libdw-dev, libudev-dev, @@ -17,10 +18,11 @@ Build-Depends: debhelper-compat (= 13), libell-dev (>= 0.39), libjson-c-dev (>= 0.13), python3-docutils, + python3-pygments, udev, check <!nocheck>, - systemd -Standards-Version: 4.6.1 + systemd-dev, +Standards-Version: 4.7.0 Rules-Requires-Root: no Vcs-Browser: https://salsa.debian.org/bluetooth-team/bluez Vcs-Git: https://salsa.debian.org/bluetooth-team/bluez.git @@ -32,9 +34,6 @@ Multi-Arch: same Section: libs Depends: ${shlibs:Depends}, ${misc:Depends} -Pre-Depends: ${misc:Pre-Depends} -Conflicts: libsdp2 (<= 1.5-2) -Replaces: libsdp2 (<= 1.5-2) Description: Library to use the BlueZ Linux Bluetooth stack BlueZ is the official Linux Bluetooth protocol stack. It is an Open Source project distributed under GNU General Public License (GPL). @@ -46,12 +45,8 @@ Section: libdevel Depends: libbluetooth3 (= ${binary:Version}), libc6-dev | libc-dev, ${misc:Depends} -Suggests: pkg-config -Conflicts: libbluetooth-dev, - libsdp2-dev (<= 1.5.2), - bluez-pan +Suggests: pkgconf Provides: libbluetooth3-dev -Replaces: libsdp2-dev (<= 1.5.2) Description: Development files for using the BlueZ Linux Bluetooth library BlueZ is the official Linux Bluetooth protocol stack. It is an Open Source project distributed under GNU General Public License (GPL). @@ -77,19 +72,8 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, kmod, udev, - lsb-base, default-dbus-system-bus | dbus-system-bus -Pre-Depends: ${misc:Pre-Depends} Suggests: pulseaudio-module-bluetooth -Breaks: udev (<< 170-1) -Conflicts: bluez-utils (<= 3.36-3), - bluez-audio (<= 3.36-3) -Replaces: bluez-input, - bluez-network, - bluez-serial, - bluez-utils (<= 3.36-3), - bluez-audio (<= 3.36-3), - udev (<< 170-1) Description: Bluetooth tools and daemons This package contains tools and system daemons for using Bluetooth devices. . @@ -113,10 +97,6 @@ Architecture: linux-any Depends: ${shlibs:Depends}, ${misc:Depends} Recommends: dbus-user-session -Conflicts: obexd-server, - obexd-client -Replaces: obexd-server, - obexd-client Description: bluez obex daemon This package contains a OBEX(OBject EXchange) daemon. . diff --git a/debian/copyright b/debian/copyright index f479ca16ef0c20d9c084a9abe14da3fa745c0cdb..cde7985b9bd4be7291c0c59bb9519b0c83675e50 100644 --- a/debian/copyright +++ b/debian/copyright @@ -517,7 +517,6 @@ Files: emulator/b1ee.c obexd/plugins/filesystem.c obexd/plugins/pbap.c obexd/plugins/phonebook-dummy.c - obexd/plugins/syncevolution.c tools/advtest.c tools/amptest.c tools/btattach.c @@ -634,7 +633,6 @@ Files: attrib/gatttool.h attrib/utils.c obexd/plugins/mas.c obexd/plugins/messages-dummy.c - obexd/plugins/messages-tracker.c obexd/plugins/messages.h obexd/plugins/phonebook-tracker.c obexd/src/manager.h @@ -703,7 +701,7 @@ Copyright: 2012-2013, BMW Car IT GmbH. 2013, BMW Car IT GmbH. License: GPL-2+ -Files: profiles/input/suspend-dummy.c +Files: profiles/input/suspend-none.c profiles/input/suspend.h profiles/scanparam/scan.c diff --git a/debian/libbluetooth-dev.install b/debian/libbluetooth-dev.install index 1c715306d60847b919bb609f873750029881c4f9..814707f8abb5ff81b18894b7514afcb3fe3c1f12 100644 --- a/debian/libbluetooth-dev.install +++ b/debian/libbluetooth-dev.install @@ -2,4 +2,3 @@ usr/include/bluetooth usr/lib/*/libbluetooth.a usr/lib/*/libbluetooth.so usr/lib/*/pkgconfig -usr/lib/*/bluetooth/plugins/sixaxis.a diff --git a/debian/libbluetooth-dev.manpages b/debian/libbluetooth-dev.manpages new file mode 100644 index 0000000000000000000000000000000000000000..201e5c07d9ab2f6420114fd65952a5a4b06b282a --- /dev/null +++ b/debian/libbluetooth-dev.manpages @@ -0,0 +1,3 @@ +debian/tmp/usr/share/man/man7/rfcomm.7 +debian/tmp/usr/share/man/man7/l2cap.7 +debian/tmp/usr/share/man/man7/hci.7 diff --git a/debian/libbluetooth3.install b/debian/libbluetooth3.install index 38461b60288cc02f6fdbb20d6378ac09d9f05648..70a2f0b012337de9547386db188d1d78d3f6f48a 100644 --- a/debian/libbluetooth3.install +++ b/debian/libbluetooth3.install @@ -1,3 +1,2 @@ usr/lib/*/libbluetooth.so.3 usr/lib/*/libbluetooth.so.3.* -usr/lib/*/bluetooth/plugins/sixaxis.so diff --git a/debian/libbluetooth3.symbols b/debian/libbluetooth3.symbols index d892e5fda27432f5b1fbbae604eaf4a65ee2fd7f..2272ab39d2dfa5b172be4dac7b9f33e40e134e92 100644 --- a/debian/libbluetooth3.symbols +++ b/debian/libbluetooth3.symbols @@ -217,5 +217,3 @@ libbluetooth.so.3 libbluetooth3 #MINVER# sdp_uuid_to_uuid128@Base 4.91 str2ba@Base 4.91 strtoba@Base 4.91 -sixaxis.so libbluetooth3 #MINVER# - bluetooth_plugin_desc@Base 5.20 diff --git a/debian/patches/0002-hostname-handle-chassis-type-handset.patch b/debian/patches/0002-hostname-handle-chassis-type-handset.patch new file mode 100644 index 0000000000000000000000000000000000000000..f10ae0827ffa36a634bc747f3b97ee750bfaefda --- /dev/null +++ b/debian/patches/0002-hostname-handle-chassis-type-handset.patch @@ -0,0 +1,51 @@ +From: Simon Fels <simon.fels@canonical.com> +Date: Mon, 12 Oct 2015 07:32:36 +0200 +Subject: [PATCH 2/4] hostname: handle chassis type handset + +This also corrects the link to the definition of the base class of +device field. +--- + plugins/hostname.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/plugins/hostname.c b/plugins/hostname.c +index 51707f0..b343c5a 100644 +--- a/plugins/hostname.c ++++ b/plugins/hostname.c +@@ -29,10 +29,11 @@ + #include "src/adapter.h" + #include "src/log.h" + +-/* http://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm */ ++/* https://www.bluetooth.org/en-us/specification/assigned-numbers/baseband */ + + #define MAJOR_CLASS_MISCELLANEOUS 0x00 + #define MAJOR_CLASS_COMPUTER 0x01 ++#define MAJOR_CLASS_PHONE 0x02 + + #define MINOR_CLASS_UNCATEGORIZED 0x00 + #define MINOR_CLASS_DESKTOP 0x01 +@@ -43,6 +44,8 @@ + #define MINOR_CLASS_WEARABLE 0x06 + #define MINOR_CLASS_TABLET 0x07 + ++#define MINOR_CLASS_SMARTPHONE 0x3 ++ + static uint8_t major_class = MAJOR_CLASS_MISCELLANEOUS; + static uint8_t minor_class = MINOR_CLASS_UNCATEGORIZED; + +@@ -117,8 +120,14 @@ static const struct { + { "desktop", MAJOR_CLASS_COMPUTER, MINOR_CLASS_DESKTOP }, + { "server", MAJOR_CLASS_COMPUTER, MINOR_CLASS_SERVER }, + { "laptop", MAJOR_CLASS_COMPUTER, MINOR_CLASS_LAPTOP }, ++#if 0 ++ // NOTE: Until we have support for more chassis types in ++ // hostnamed like 'phone' we keep handset separated and ++ // take it for the phone role. + { "handset", MAJOR_CLASS_COMPUTER, MINOR_CLASS_HANDHELD }, ++#endif + { "tablet", MAJOR_CLASS_COMPUTER, MINOR_CLASS_TABLET }, ++ { "handset", MAJOR_CLASS_PHONE, MINOR_CLASS_SMARTPHONE }, + { } + }; + diff --git a/debian/patches/Add-HCI_TO_STR-macro-for-FIRMWARE_DIR.patch b/debian/patches/Add-HCI_TO_STR-macro-for-FIRMWARE_DIR.patch new file mode 100644 index 0000000000000000000000000000000000000000..644be065a6d6c65affbd2e912e9d91d5cb7a9bbc --- /dev/null +++ b/debian/patches/Add-HCI_TO_STR-macro-for-FIRMWARE_DIR.patch @@ -0,0 +1,85 @@ +From 0a8a015f567993d31c963a01adc9932142cf0340 Mon Sep 17 00:00:00 2001 +From: Nobuhiro Iwamatsu <iwamatsu@debian.org> +Date: Sun, 6 Aug 2023 08:34:28 +0900 +Subject: [PATCH] Add HCI_TO_STR macro for FIRMWARE_DIR +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If the macro specified with -D is string, it cannot be expanded and an error +will occur. This adds HCI_TO_STR macro that expands as string and wraps it +when expanding FIRMWARE_DIR. + +``` +tools/hciattach_bcm43xx.c: In function ‘bcm43xx_init’: +<command-line>: error: expected expression before ‘/’ token +tools/hciattach_bcm43xx.c:352:34: note: in expansion of macro ‘FIRMWARE_DIR’ + 352 | if (bcm43xx_locate_patch(FIRMWARE_DIR, chip_name, fw_path)) { + | ^~~~~~~~~~~~ +``` + +Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@debian.org> +--- + tools/hciattach.h | 4 ++++ + tools/hciattach_bcm43xx.c | 2 +- + tools/hciattach_qualcomm.c | 2 +- + tools/hciattach_tialt.c | 2 +- + 4 files changed, 7 insertions(+), 3 deletions(-) + +diff --git a/tools/hciattach.h b/tools/hciattach.h +index dfa4c1e7a..ad4fb70b2 100644 +--- a/tools/hciattach.h ++++ b/tools/hciattach.h +@@ -42,6 +42,10 @@ + + #ifndef FIRMWARE_DIR + #define FIRMWARE_DIR "/etc/firmware" ++#define HCI_TO_STR(x) (x) ++#else ++#define __HCI_TO_STR(x) (#x) ++#define HCI_TO_STR(x) __HCI_TO_STR(x) + #endif + + int read_hci_event(int fd, unsigned char *buf, int size); +diff --git a/tools/hciattach_bcm43xx.c b/tools/hciattach_bcm43xx.c +index b89fc1b50..9df246800 100644 +--- a/tools/hciattach_bcm43xx.c ++++ b/tools/hciattach_bcm43xx.c +@@ -349,7 +349,7 @@ int bcm43xx_init(int fd, int def_speed, int speed, struct termios *ti, + if (bcm43xx_read_local_name(fd, chip_name, sizeof(chip_name))) + return -1; + +- if (bcm43xx_locate_patch(FIRMWARE_DIR, chip_name, fw_path)) { ++ if (bcm43xx_locate_patch(HCI_TO_STR(FIRMWARE_DIR), chip_name, fw_path)) { + fprintf(stderr, "Patch not found, continue anyway\n"); + } else { + if (bcm43xx_set_speed(fd, ti, speed)) +diff --git a/tools/hciattach_qualcomm.c b/tools/hciattach_qualcomm.c +index d751f42b1..33e742c00 100644 +--- a/tools/hciattach_qualcomm.c ++++ b/tools/hciattach_qualcomm.c +@@ -219,7 +219,7 @@ int qualcomm_init(int fd, int speed, struct termios *ti, const char *bdaddr) + } while (resp[3] != 0 && resp[4] != 2); + + snprintf(fw, sizeof(fw), "%s/%c%c%c%c%c%c_%c%c%c%c.bin", +- FIRMWARE_DIR, ++ HCI_TO_STR(FIRMWARE_DIR), + resp[18], resp[19], resp[20], resp[21], + resp[22], resp[23], + resp[32], resp[33], resp[34], resp[35]); +diff --git a/tools/hciattach_tialt.c b/tools/hciattach_tialt.c +index bf6e84923..69f6b3ee5 100644 +--- a/tools/hciattach_tialt.c ++++ b/tools/hciattach_tialt.c +@@ -222,7 +222,7 @@ int texasalt_init(int fd, int speed, struct termios *ti) + brf_chip); + + sprintf(fw, "%s/%s.bin", +- FIRMWARE_DIR, ++ HCI_TO_STR(FIRMWARE_DIR), + (brf_chip > 7) ? "unknown" : c_brf_chip[brf_chip]); + texas_load_firmware(fd, fw); + +-- +2.40.1 + diff --git a/debian/patches/CVE-2023-27349.patch b/debian/patches/CVE-2023-27349.patch deleted file mode 100644 index 60d5cc7ac76176f99b6d3ca07df77216635f551c..0000000000000000000000000000000000000000 --- a/debian/patches/CVE-2023-27349.patch +++ /dev/null @@ -1,42 +0,0 @@ -From f54299a850676d92c3dafd83e9174fcfe420ccc9 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> -Date: Wed, 22 Mar 2023 11:34:24 -0700 -Subject: avrcp: Fix crash while handling unsupported events - -The following crash can be observed if the remote peer send and -unsupported event: - -ERROR: AddressSanitizer: heap-use-after-free on address 0x60b000148f11 - at pc 0x559644552088 bp 0x7ffe28b3c7b0 sp 0x7ffe28b3c7a0 - WRITE of size 1 at 0x60b000148f11 thread T0 - #0 0x559644552087 in avrcp_handle_event profiles/audio/avrcp.c:3907 - #1 0x559644536c22 in control_response profiles/audio/avctp.c:939 - #2 0x5596445379ab in session_cb profiles/audio/avctp.c:1108 - #3 0x7fbcb3e51c43 in g_main_context_dispatch (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x55c43) - #4 0x7fbcb3ea66c7 (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0xaa6c7) - #5 0x7fbcb3e512b2 in g_main_loop_run (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x552b2) - #6 0x559644754ab6 in mainloop_run src/shared/mainloop-glib.c:66 - #7 0x559644755606 in mainloop_run_with_signal src/shared/mainloop-notify.c:188 - #8 0x5596445bb963 in main src/main.c:1289 - #9 0x7fbcb3bafd8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 - #10 0x7fbcb3bafe3f in __libc_start_main_impl ../csu/libc-start.c:392 - #11 0x5596444e8224 in _start (/usr/local/libexec/bluetooth/bluetoothd+0xf0224) ---- - profiles/audio/avrcp.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- bluez-5.66.orig/profiles/audio/avrcp.c -+++ bluez-5.66/profiles/audio/avrcp.c -@@ -3901,6 +3901,12 @@ static gboolean avrcp_handle_event(struc - case AVRCP_EVENT_UIDS_CHANGED: - avrcp_uids_changed(session, pdu); - break; -+ default: -+ if (event > AVRCP_EVENT_LAST) { -+ warn("Unsupported event: %u", event); -+ return FALSE; -+ } -+ break; - } - - session->registered_events |= (1 << event); diff --git a/debian/patches/CVE-2023-50229_CVE-2023-50230.patch b/debian/patches/CVE-2023-50229_CVE-2023-50230.patch deleted file mode 100644 index e18f80b9fcb4ab2cf1bcce0494987c538f1dc126..0000000000000000000000000000000000000000 --- a/debian/patches/CVE-2023-50229_CVE-2023-50230.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 5ab5352531a9cc7058cce569607f3a6831464443 Mon Sep 17 00:00:00 2001 -From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> -Date: Tue, 19 Sep 2023 12:14:01 -0700 -Subject: [PATCH] pbap: Fix not checking Primary/Secundary Counter length - -Primary/Secundary Counters are supposed to be 16 bytes values, if the -server has implemented them incorrectly it may lead to the following -crash: - -================================================================= -==31860==ERROR: AddressSanitizer: heap-buffer-overflow on address -0x607000001878 at pc 0x7f95a1575638 bp 0x7fff58c6bb80 sp 0x7fff58c6b328 - - READ of size 48 at 0x607000001878 thread T0 - #0 0x7f95a1575637 in MemcmpInterceptorCommon(void*, int (*)(void const*, void const*, unsigned long), void const*, void const*, unsigned long) ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:860 - #1 0x7f95a1575ba6 in __interceptor_memcmp ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:892 - #2 0x7f95a1575ba6 in __interceptor_memcmp ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:887 - #3 0x564df69c77a0 in read_version obexd/client/pbap.c:288 - #4 0x564df69c77a0 in read_return_apparam obexd/client/pbap.c:352 - #5 0x564df69c77a0 in phonebook_size_callback obexd/client/pbap.c:374 - #6 0x564df69bea3c in session_terminate_transfer obexd/client/session.c:921 - #7 0x564df69d56b0 in get_xfer_progress_first obexd/client/transfer.c:729 - #8 0x564df698b9ee in handle_response gobex/gobex.c:1140 - #9 0x564df698cdea in incoming_data gobex/gobex.c:1385 - #10 0x7f95a12fdc43 in g_main_context_dispatch (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x55c43) - #11 0x7f95a13526c7 (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0xaa6c7) - #12 0x7f95a12fd2b2 in g_main_loop_run (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x552b2) - #13 0x564df6977d41 in main obexd/src/main.c:307 - #14 0x7f95a10a7d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 - #15 0x7f95a10a7e3f in __libc_start_main_impl ../csu/libc-start.c:392 - #16 0x564df6978704 in _start (/usr/local/libexec/bluetooth/obexd+0x8b704) - 0x607000001878 is located 0 bytes to the right of 72-byte region [0x607000001830,0x607000001878) - - allocated by thread T0 here: - #0 0x7f95a1595a37 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154 - #1 0x564df69c8b6a in pbap_probe obexd/client/pbap.c:1259 ---- - obexd/client/pbap.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - ---- bluez-5.66.orig/obexd/client/pbap.c -+++ bluez-5.66/obexd/client/pbap.c -@@ -285,7 +285,7 @@ static void read_version(struct pbap_dat - data = value; - } - -- if (memcmp(pbap->primary, data, len)) { -+ if (len == sizeof(pbap->primary) && memcmp(pbap->primary, data, len)) { - memcpy(pbap->primary, data, len); - g_dbus_emit_property_changed(conn, - obc_session_get_path(pbap->session), -@@ -299,7 +299,8 @@ static void read_version(struct pbap_dat - data = value; - } - -- if (memcmp(pbap->secondary, data, len)) { -+ if (len == sizeof(pbap->secondary) && -+ memcmp(pbap->secondary, data, len)) { - memcpy(pbap->secondary, data, len); - g_dbus_emit_property_changed(conn, - obc_session_get_path(pbap->session), diff --git a/debian/patches/Change-shebang-from-usr-bin-python-to-usr-bin-python.patch b/debian/patches/Change-shebang-from-usr-bin-python-to-usr-bin-python.patch deleted file mode 100644 index 8729318fc63cfd2387df292b28daafc8e5d933bc..0000000000000000000000000000000000000000 --- a/debian/patches/Change-shebang-from-usr-bin-python-to-usr-bin-python.patch +++ /dev/null @@ -1,342 +0,0 @@ -From 8e96de127ff1ef03af947e542283ff0b1999cf19 Mon Sep 17 00:00:00 2001 -From: Nobuhiro Iwamatsu <iwamatsu@debian.org> -Date: Wed, 28 Jul 2021 21:55:12 +0900 -Subject: [PATCH] Change shebang from /usr/bin/python to /usr/bin/python3 - -Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@debian.org> ---- - test/example-adv-monitor | 2 +- - test/example-advertisement | 2 +- - test/example-endpoint | 2 +- - test/example-player | 2 +- - test/exchange-business-cards | 2 +- - test/ftp-client | 2 +- - test/get-managed-objects | 2 +- - test/get-obex-capabilities | 2 +- - test/list-devices | 2 +- - test/list-folders | 2 +- - test/map-client | 2 +- - test/monitor-bluetooth | 2 +- - test/opp-client | 2 +- - test/pbap-client | 2 +- - test/simple-agent | 2 +- - test/simple-endpoint | 2 +- - test/simple-obex-agent | 2 +- - test/simple-player | 2 +- - test/test-adapter | 2 +- - test/test-device | 2 +- - test/test-discovery | 2 +- - test/test-gatt-profile | 2 +- - test/test-health | 2 +- - test/test-health-sink | 2 +- - test/test-hfp | 2 +- - test/test-manager | 2 +- - test/test-nap | 2 +- - test/test-network | 2 +- - test/test-profile | 2 +- - test/test-sap-server | 2 +- - 30 files changed, 30 insertions(+), 30 deletions(-) - -diff --git a/test/example-adv-monitor b/test/example-adv-monitor -index a405fc7b0..7f586e7b6 100644 ---- a/test/example-adv-monitor -+++ b/test/example-adv-monitor -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - import argparse -diff --git a/test/example-advertisement b/test/example-advertisement -index 5f022ee67..9d232a525 100755 ---- a/test/example-advertisement -+++ b/test/example-advertisement -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import print_function -diff --git a/test/example-endpoint b/test/example-endpoint -index 16651c683..8fe0161ff 100644 ---- a/test/example-endpoint -+++ b/test/example-endpoint -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/example-player b/test/example-player -index 1497d1107..481d91805 100644 ---- a/test/example-player -+++ b/test/example-player -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import print_function -diff --git a/test/exchange-business-cards b/test/exchange-business-cards -index 9a3aa29fb..6cfd4b2fc 100755 ---- a/test/exchange-business-cards -+++ b/test/exchange-business-cards -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - import sys -diff --git a/test/ftp-client b/test/ftp-client -index ef756ab2b..f6081b911 100755 ---- a/test/ftp-client -+++ b/test/ftp-client -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/get-managed-objects b/test/get-managed-objects -index 5125ee524..0166b34bf 100755 ---- a/test/get-managed-objects -+++ b/test/get-managed-objects -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/get-obex-capabilities b/test/get-obex-capabilities -index a7980a442..339b57df7 100755 ---- a/test/get-obex-capabilities -+++ b/test/get-obex-capabilities -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - import sys -diff --git a/test/list-devices b/test/list-devices -index b112556c3..f700b0d33 100755 ---- a/test/list-devices -+++ b/test/list-devices -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/list-folders b/test/list-folders -index b4e3f100b..15a0c2087 100755 ---- a/test/list-folders -+++ b/test/list-folders -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - import sys -diff --git a/test/map-client b/test/map-client -index a2d96ae5f..05ad6e8bf 100755 ---- a/test/map-client -+++ b/test/map-client -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/monitor-bluetooth b/test/monitor-bluetooth -index a3977e206..7ca236f89 100755 ---- a/test/monitor-bluetooth -+++ b/test/monitor-bluetooth -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/opp-client b/test/opp-client -index 4f00a41c0..32ec55f61 100755 ---- a/test/opp-client -+++ b/test/opp-client -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/pbap-client b/test/pbap-client -index e6cafdd30..979c3932d 100755 ---- a/test/pbap-client -+++ b/test/pbap-client -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/simple-agent b/test/simple-agent -index 4fdaff1eb..a176b15c2 100755 ---- a/test/simple-agent -+++ b/test/simple-agent -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/simple-endpoint b/test/simple-endpoint -index 59ca189ce..21f687df0 100755 ---- a/test/simple-endpoint -+++ b/test/simple-endpoint -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/simple-obex-agent b/test/simple-obex-agent -index 064f6d30b..08514afaf 100755 ---- a/test/simple-obex-agent -+++ b/test/simple-obex-agent -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/simple-player b/test/simple-player -index 92682844d..67310b1c9 100755 ---- a/test/simple-player -+++ b/test/simple-player -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import print_function -diff --git a/test/test-adapter b/test/test-adapter -index a216140ba..9d0a1584e 100755 ---- a/test/test-adapter -+++ b/test/test-adapter -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/test-device b/test/test-device -index a1e508166..be3abb38f 100755 ---- a/test/test-device -+++ b/test/test-device -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/test-discovery b/test/test-discovery -index eccc7c7e3..97b3c2236 100755 ---- a/test/test-discovery -+++ b/test/test-discovery -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/test-gatt-profile b/test/test-gatt-profile -index a973ae14e..352bec2f8 100755 ---- a/test/test-gatt-profile -+++ b/test/test-gatt-profile -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/test-health b/test/test-health -index d6b437ed8..45011edde 100755 ---- a/test/test-health -+++ b/test/test-health -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/test-health-sink b/test/test-health-sink -index 57665d2ba..305ab6c82 100755 ---- a/test/test-health-sink -+++ b/test/test-health-sink -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/test-hfp b/test/test-hfp -index 11e328e54..3898b07a8 100755 ---- a/test/test-hfp -+++ b/test/test-hfp -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/test-manager b/test/test-manager -index 3fa7205a0..34d4549f9 100755 ---- a/test/test-manager -+++ b/test/test-manager -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/test-nap b/test/test-nap -index d5c757b79..f270ca417 100755 ---- a/test/test-nap -+++ b/test/test-nap -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/test-network b/test/test-network -index acc7dff65..c3487ec37 100755 ---- a/test/test-network -+++ b/test/test-network -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/test-profile b/test/test-profile -index af1e23f76..e6448da98 100755 ---- a/test/test-profile -+++ b/test/test-profile -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals -diff --git a/test/test-sap-server b/test/test-sap-server -index ddb1efe9b..353f58e4c 100755 ---- a/test/test-sap-server -+++ b/test/test-sap-server -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # SPDX-License-Identifier: LGPL-2.1-or-later - - from __future__ import absolute_import, print_function, unicode_literals --- -2.32.0 - diff --git a/debian/patches/Fix-typo.patch b/debian/patches/Fix-typo.patch index 4034bd9ce9f9b870ccd976ea8c33e2cd092b4de1..09aad794dc8f458515217d565248dea716d769aa 100644 --- a/debian/patches/Fix-typo.patch +++ b/debian/patches/Fix-typo.patch @@ -1,6 +1,6 @@ -From 940f5fede5165f199072bf2fa462ab1302d8e233 Mon Sep 17 00:00:00 2001 +From b217d211de1e529659255f50e2388e1b2d95db3a Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu <iwamatsu@debian.org> -Date: Fri, 18 Nov 2022 08:24:30 +0900 +Date: Mon, 28 Aug 2023 09:25:33 +0900 Subject: [PATCH] Fix typo This commit fixes following typo: @@ -32,17 +32,19 @@ This commit fixes following typo: Unexpexted -> Unexpected Supressing -> Suppressing wich -> which - -Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@debian.org> + Falg -> Flag + preffered -> preferred Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@debian.org> --- android/tester-main.c | 6 +++--- attrib/att.c | 2 +- + client/mgmt.c | 4 ++-- emulator/btdev.c | 2 +- lib/bluetooth.c | 2 +- + lib/hci.h | 10 +++++----- mesh/net.c | 2 +- - monitor/att.c | 2 +- + monitor/att.c | 8 ++++---- monitor/avctp.c | 6 +++--- monitor/ll.c | 2 +- obexd/plugins/bluetooth.c | 2 +- @@ -53,22 +55,23 @@ Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@debian.org> profiles/gap/gas.c | 2 +- profiles/health/mcap.c | 2 +- profiles/midi/midi.c | 2 +- - src/adapter.c | 6 +++--- + src/adapter.c | 10 +++++----- src/profile.c | 4 ++-- + src/shared/bap.c | 4 ++-- src/shared/util.c | 2 +- - tools/btmgmt.c | 4 ++-- + tools/btattach.rst | 2 +- tools/btpclient.c | 4 ++-- tools/ciptool.c | 2 +- tools/l2cap-tester.c | 2 +- tools/l2test.c | 6 +++--- - tools/mgmt-tester.c | 4 ++-- + tools/mgmt-tester.c | 2 +- tools/parser/att.c | 2 +- tools/parser/avrcp.c | 10 +++++----- tools/parser/hci.c | 6 +++--- tools/parser/l2cap.c | 4 ++-- tools/parser/smp.c | 4 ++-- tools/rctest.c | 6 +++--- - 31 files changed, 54 insertions(+), 54 deletions(-) + 34 files changed, 66 insertions(+), 66 deletions(-) diff --git a/android/tester-main.c b/android/tester-main.c index 317c1de06..f9503a294 100644 @@ -111,11 +114,33 @@ index fa53c90aa..bf98fe2d8 100644 case ATT_ECODE_ABORTED: return "The operation was aborted"; default: +diff --git a/client/mgmt.c b/client/mgmt.c +index c056d018a..96992baea 100644 +--- a/client/mgmt.c ++++ b/client/mgmt.c +@@ -5876,7 +5876,7 @@ static const struct bt_shell_menu mgmt_menu = { + { "ssp", "<on/off>", + cmd_ssp, "Toggle SSP mode" }, + { "sc", "<on/off/only>", +- cmd_sc, "Toogle SC support" }, ++ cmd_sc, "Toggle SC support" }, + { "hs", "<on/off>", + cmd_hs, "Toggle HS support" }, + { "le", "<on/off>", +@@ -5938,7 +5938,7 @@ static const struct bt_shell_menu mgmt_menu = { + { "ext-config", "<on/off>", + cmd_ext_config, "External configuration" }, + { "debug-keys", "<on/off>", +- cmd_debug_keys, "Toogle debug keys" }, ++ cmd_debug_keys, "Toggle debug keys" }, + { "conn-info", "[-t type] <remote address>", + cmd_conn_info, "Get connection information" }, + { "io-cap", "<cap>", diff --git a/emulator/btdev.c b/emulator/btdev.c -index 549f93645..2257e8330 100644 +index 58414bd74..fb2d4620d 100644 --- a/emulator/btdev.c +++ b/emulator/btdev.c -@@ -241,7 +241,7 @@ struct inquiry_data { +@@ -249,7 +249,7 @@ struct inquiry_data { int iter; }; @@ -137,11 +162,46 @@ index 84e40c819..ccfd0254c 100644 case 423: return "ENERGOUS CORPORATION"; case 424: +diff --git a/lib/hci.h b/lib/hci.h +index 50f385c1e..30ac1e216 100644 +--- a/lib/hci.h ++++ b/lib/hci.h +@@ -473,8 +473,8 @@ typedef struct { + #define OCF_SETUP_SYNC_CONN 0x0028 + typedef struct { + uint16_t handle; +- uint32_t tx_bandwith; +- uint32_t rx_bandwith; ++ uint32_t tx_bandwidth; ++ uint32_t rx_bandwidth; + uint16_t max_latency; + uint16_t voice_setting; + uint8_t retrans_effort; +@@ -485,8 +485,8 @@ typedef struct { + #define OCF_ACCEPT_SYNC_CONN_REQ 0x0029 + typedef struct { + bdaddr_t bdaddr; +- uint32_t tx_bandwith; +- uint32_t rx_bandwith; ++ uint32_t tx_bandwidth; ++ uint32_t rx_bandwidth; + uint16_t max_latency; + uint16_t voice_setting; + uint8_t retrans_effort; +@@ -1864,7 +1864,7 @@ typedef struct { + #define EVT_FLUSH_OCCURRED 0x11 + typedef struct { + uint16_t handle; +-} __attribute__ ((packed)) evt_flush_occured; ++} __attribute__ ((packed)) evt_flush_occurred; + #define EVT_FLUSH_OCCURRED_SIZE 2 + + #define EVT_ROLE_CHANGE 0x12 diff --git a/mesh/net.c b/mesh/net.c -index 1d27289bf..10bc9ecf7 100644 +index 05ca48326..be5bc1152 100644 --- a/mesh/net.c +++ b/mesh/net.c -@@ -1031,7 +1031,7 @@ static bool msg_in_cache(struct mesh_net *net, uint16_t src, uint32_t seq, +@@ -1058,7 +1058,7 @@ static bool msg_in_cache(struct mesh_net *net, uint16_t src, uint32_t seq, msg = l_queue_find(net->msg_cache, match_cache, &tst); if (msg) { @@ -151,10 +211,23 @@ index 1d27289bf..10bc9ecf7 100644 return true; } diff --git a/monitor/att.c b/monitor/att.c -index efd840d51..3a8aeb063 100644 +index 0e12ee352..80ba93cbc 100644 --- a/monitor/att.c +++ b/monitor/att.c -@@ -1827,7 +1827,7 @@ static void print_vcs_flag(const struct l2cap_frame *frame) +@@ -1049,9 +1049,9 @@ static bool print_prefer_framing(const struct l2cap_frame *frame) + } + + static const struct bitfield_data prefer_phy_table[] = { +- { 0, "LE 1M PHY preffered (0x01)" }, +- { 1, "LE 2M PHY preffered (0x02)" }, +- { 2, "LE Codec PHY preffered (0x04)" }, ++ { 0, "LE 1M PHY preferred (0x01)" }, ++ { 1, "LE 2M PHY preferred (0x02)" }, ++ { 2, "LE Codec PHY preferred (0x04)" }, + { } + }; + +@@ -2204,7 +2204,7 @@ static void print_vcs_flag(const struct l2cap_frame *frame) print_text(COLOR_ERROR, "Volume Flag: invalid size"); goto done; } @@ -193,7 +266,7 @@ index fb2628282..7a8c124ab 100644 break; case AVRCP_EVENT_BATT_STATUS_CHANGED: diff --git a/monitor/ll.c b/monitor/ll.c -index f588d5e99..db2354991 100644 +index feeb13e92..8352d0a74 100644 --- a/monitor/ll.c +++ b/monitor/ll.c @@ -256,7 +256,7 @@ static void data_packet(const void *data, uint8_t size, bool padded) @@ -232,12 +305,12 @@ index f5a9d9ae8..f3707d104 100644 if (ret < 0) { error("backup: cmd = %s", obj->cmd); diff --git a/obexd/src/manager.c b/obexd/src/manager.c -index 01741fe62..dae2d3ecb 100644 +index 73fd6b9af..458a74f96 100644 --- a/obexd/src/manager.c +++ b/obexd/src/manager.c -@@ -39,7 +39,7 @@ - #define SESSION_INTERFACE OBEXD_SERVICE ".Session1" +@@ -40,7 +40,7 @@ #define AGENT_INTERFACE OBEXD_SERVICE ".Agent1" + #define OBEX_ERROR_REJECT "org.bluez.obex.Error.Rejected" -#define TIMEOUT 60*1000 /* Timeout for user response (miliseconds) */ +#define TIMEOUT 60*1000 /* Timeout for user response (milliseconds) */ @@ -306,10 +379,10 @@ index 5d2bac3d9..1601b99d6 100644 if (phase2_delay > 61*1000) { diff --git a/profiles/midi/midi.c b/profiles/midi/midi.c -index 40064df3a..4c660da47 100644 +index bab309bca..0976842e8 100644 --- a/profiles/midi/midi.c +++ b/profiles/midi/midi.c -@@ -318,7 +318,7 @@ static int midi_accept(struct btd_service *service) +@@ -319,7 +319,7 @@ static int midi_accept(struct btd_service *service) err = snd_seq_client_id(midi->seq_handle); if (err < 0) { @@ -319,10 +392,10 @@ index 40064df3a..4c660da47 100644 } midi->seq_client_id = err; diff --git a/src/adapter.c b/src/adapter.c -index 8fb2acdc8..711487a14 100644 +index 5ebfc4752..0d0b17135 100644 --- a/src/adapter.c +++ b/src/adapter.c -@@ -4196,7 +4196,7 @@ static void set_privacy_complete(uint8_t status, uint16_t length, +@@ -4215,7 +4215,7 @@ static void set_privacy_complete(uint8_t status, uint16_t length, return; } @@ -331,7 +404,7 @@ index 8fb2acdc8..711487a14 100644 } static int set_privacy(struct btd_adapter *adapter, uint8_t privacy) -@@ -5538,7 +5538,7 @@ void adapter_auto_connect_add(struct btd_adapter *adapter, +@@ -5557,7 +5557,7 @@ void adapter_auto_connect_add(struct btd_adapter *adapter, bdaddr_type = btd_device_get_bdaddr_type(device); if (bdaddr_type == BDADDR_BREDR) { @@ -340,7 +413,7 @@ index 8fb2acdc8..711487a14 100644 return; } -@@ -5651,7 +5651,7 @@ void adapter_auto_connect_remove(struct btd_adapter *adapter, +@@ -5670,7 +5670,7 @@ void adapter_auto_connect_remove(struct btd_adapter *adapter, bdaddr_type = btd_device_get_bdaddr_type(device); if (bdaddr_type == BDADDR_BREDR) { @@ -349,11 +422,29 @@ index 8fb2acdc8..711487a14 100644 return; } +@@ -10205,7 +10205,7 @@ static void read_info_complete(uint8_t status, uint16_t length, + case BT_MODE_BREDR: + if (!(adapter->supported_settings & MGMT_SETTING_BREDR)) { + btd_error(adapter->dev_id, +- "Ignoring adapter withouth BR/EDR support"); ++ "Ignoring adapter without BR/EDR support"); + goto failed; + } + +@@ -10219,7 +10219,7 @@ static void read_info_complete(uint8_t status, uint16_t length, + case BT_MODE_LE: + if (!(adapter->supported_settings & MGMT_SETTING_LE)) { + btd_error(adapter->dev_id, +- "Ignoring adapter withouth LE support"); ++ "Ignoring adapter without LE support"); + goto failed; + } + diff --git a/src/profile.c b/src/profile.c -index e1bebf1ee..5b651ce7b 100644 +index ea188f36b..d1c3e4e81 100644 --- a/src/profile.c +++ b/src/profile.c -@@ -1250,7 +1250,7 @@ static void ext_confirm(GIOChannel *io, gpointer user_data) +@@ -1256,7 +1256,7 @@ static void ext_confirm(GIOChannel *io, gpointer user_data) DBG("incoming connect from %s", addr); if (!btd_adapter_is_uuid_allowed(adapter_find(&src), uuid)) { @@ -362,7 +453,7 @@ index e1bebf1ee..5b651ce7b 100644 return; } -@@ -1292,7 +1292,7 @@ static void ext_direct_connect(GIOChannel *io, GError *err, gpointer user_data) +@@ -1298,7 +1298,7 @@ static void ext_direct_connect(GIOChannel *io, GError *err, gpointer user_data) } if (!btd_adapter_is_uuid_allowed(adapter_find(&src), uuid)) { @@ -371,11 +462,33 @@ index e1bebf1ee..5b651ce7b 100644 return; } +diff --git a/src/shared/bap.c b/src/shared/bap.c +index 1c43680c2..139e589c0 100644 +--- a/src/shared/bap.c ++++ b/src/shared/bap.c +@@ -858,7 +858,7 @@ static void stream_notify_config(struct bt_bap_stream *stream) + status->id = ep->id; + status->state = ep->state; + +- /* Initialize preffered settings if not set */ ++ /* Initialize preferred settings if not set */ + if (!lpac->qos.phy) + lpac->qos.phy = 0x02; + +@@ -880,7 +880,7 @@ static void stream_notify_config(struct bt_bap_stream *stream) + if (!lpac->qos.ppd_max) + lpac->qos.ppd_max = lpac->qos.pd_max; + +- /* TODO:Add support for setting preffered settings on bt_bap_pac */ ++ /* TODO:Add support for setting preferred settings on bt_bap_pac */ + config = (void *)status->params; + config->framing = lpac->qos.framing; + config->phy = lpac->qos.phy; diff --git a/src/shared/util.c b/src/shared/util.c -index 0a0308cb0..9eee200d4 100644 +index e9c1c18f5..e8931a3d8 100644 --- a/src/shared/util.c +++ b/src/shared/util.c -@@ -246,7 +246,7 @@ static const struct { +@@ -583,7 +583,7 @@ static const struct { { 0x111d, "Imaging Referenced Objects" }, { 0x111e, "Handsfree" }, { 0x111f, "Handsfree Audio Gateway" }, @@ -384,28 +497,19 @@ index 0a0308cb0..9eee200d4 100644 { 0x1121, "Reflected UI" }, { 0x1122, "Basic Printing" }, { 0x1123, "Printing Status" }, -diff --git a/tools/btmgmt.c b/tools/btmgmt.c -index 29f86091f..866d65afe 100644 ---- a/tools/btmgmt.c -+++ b/tools/btmgmt.c -@@ -5895,7 +5895,7 @@ static const struct bt_shell_menu main_menu = { - { "ssp", "<on/off>", - cmd_ssp, "Toggle SSP mode" }, - { "sc", "<on/off/only>", -- cmd_sc, "Toogle SC support" }, -+ cmd_sc, "Toggle SC support" }, - { "hs", "<on/off>", - cmd_hs, "Toggle HS support" }, - { "le", "<on/off>", -@@ -5957,7 +5957,7 @@ static const struct bt_shell_menu main_menu = { - { "ext-config", "<on/off>", - cmd_ext_config, "External configuration" }, - { "debug-keys", "<on/off>", -- cmd_debug_keys, "Toogle debug keys" }, -+ cmd_debug_keys, "Toggle debug keys" }, - { "conn-info", "[-t type] <remote address>", - cmd_conn_info, "Get connection information" }, - { "io-cap", "<cap>", +diff --git a/tools/btattach.rst b/tools/btattach.rst +index 787d5c49e..d4f3f7f0c 100644 +--- a/tools/btattach.rst ++++ b/tools/btattach.rst +@@ -60,7 +60,7 @@ OPTIONS + + * - qca + +--S baudrate, --speed baudrate Specify wich baudrate to use ++-S baudrate, --speed baudrate Specify which baudrate to use + + -N, --noflowctl Disable flow control + diff --git a/tools/btpclient.c b/tools/btpclient.c index bdfff5df8..f4eea093a 100644 --- a/tools/btpclient.c @@ -442,10 +546,10 @@ index 0d6272da9..4ba33f87e 100644 } diff --git a/tools/l2cap-tester.c b/tools/l2cap-tester.c -index 3f0464013..c3a30628a 100644 +index 141dd570c..ab70da478 100644 --- a/tools/l2cap-tester.c +++ b/tools/l2cap-tester.c -@@ -1909,7 +1909,7 @@ static void test_getpeername_not_connected(const void *test_data) +@@ -2096,7 +2096,7 @@ static void test_getpeername_not_connected(const void *test_data) } if (errno != ENOTCONN) { @@ -455,10 +559,10 @@ index 3f0464013..c3a30628a 100644 tester_test_failed(); goto done; diff --git a/tools/l2test.c b/tools/l2test.c -index 5aae4b687..4baaba5e0 100644 +index 011a68c37..50340cdfb 100644 --- a/tools/l2test.c +++ b/tools/l2test.c -@@ -902,7 +902,7 @@ static void recv_mode(int sk) +@@ -922,7 +922,7 @@ static void recv_mode(int sk) /* Check sequence */ sq = get_le32(buf); if (seq != sq) { @@ -467,7 +571,7 @@ index 5aae4b687..4baaba5e0 100644 seq = sq; } seq++; -@@ -910,14 +910,14 @@ static void recv_mode(int sk) +@@ -930,14 +930,14 @@ static void recv_mode(int sk) /* Check length */ l = get_le16(buf + 4); if (len != l) { @@ -485,10 +589,10 @@ index 5aae4b687..4baaba5e0 100644 total += len; diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c -index a56c38173..29df74007 100644 +index 7dfd1b0c7..343fe4055 100644 --- a/tools/mgmt-tester.c +++ b/tools/mgmt-tester.c -@@ -14015,10 +14015,10 @@ int main(int argc, char *argv[]) +@@ -14268,7 +14268,7 @@ int main(int argc, char *argv[]) test_bredrle50("Set PHY 2m Success", &set_phy_2m_success, NULL, test_command_generic); @@ -496,10 +600,6 @@ index a56c38173..29df74007 100644 + test_bredrle50("Set PHY coded Success", &set_phy_coded_success, NULL, test_command_generic); -- test_bredrle50("Set PHY 1m 2m coded Succcess", &set_phy_all_success, -+ test_bredrle50("Set PHY 1m 2m coded Success", &set_phy_all_success, - NULL, test_command_generic); - test_bredrle50("Set PHY 2m tx success", &set_phy_2m_tx_success, diff --git a/tools/parser/att.c b/tools/parser/att.c index bef583a1a..fe1165bdd 100644 @@ -669,5 +769,5 @@ index d31180880..1eb781218 100644 #endif total += r; -- -2.36.1 +2.40.1 diff --git a/debian/patches/allow-using-obexd-without-systemd-in-the-user-sessio.patch b/debian/patches/allow-using-obexd-without-systemd-in-the-user-sessio.patch deleted file mode 100644 index 24af69b0f7be940c7eb100d1b50f8e891c54e9ff..0000000000000000000000000000000000000000 --- a/debian/patches/allow-using-obexd-without-systemd-in-the-user-sessio.patch +++ /dev/null @@ -1,57 +0,0 @@ -http://www.spinics.net/lists/linux-bluetooth/msg38490.html - -From 3027cb7141fb65cf3eeda69c688db8c4045e2d3f Mon Sep 17 00:00:00 2001 -From: Giovanni Campagna <gcampagna-cNUdlRotFMnNLxjTenLetw@public.gmane.org> -Date: Sat, 12 Oct 2013 17:45:25 +0200 -Subject: [PATCH] Allow using obexd without systemd in the user session - -Not all sessions run systemd --user (actually, the majority -doesn't), so the dbus daemon must be able to spawn obexd -directly, and to do so it needs the full path of the daemon. ---- - Makefile.obexd | 4 ++-- - obexd/src/org.bluez.obex.service | 4 ---- - obexd/src/org.bluez.obex.service.in | 4 ++++ - 3 files changed, 6 insertions(+), 6 deletions(-) - delete mode 100644 obexd/src/org.bluez.obex.service - create mode 100644 obexd/src/org.bluez.obex.service.in - -diff --git a/obexd/src/org.bluez.obex.service b/obexd/src/org.bluez.obex.service -deleted file mode 100644 -index a538088..0000000 ---- a/obexd/src/org.bluez.obex.service -+++ /dev/null -@@ -1,4 +0,0 @@ --[D-BUS Service] --Name=org.bluez.obex --Exec=/bin/false --SystemdService=dbus-org.bluez.obex.service -diff --git a/obexd/src/org.bluez.obex.service.in b/obexd/src/org.bluez.obex.service.in -new file mode 100644 -index 0000000..9c815f2 ---- /dev/null -+++ b/obexd/src/org.bluez.obex.service.in -@@ -0,0 +1,4 @@ -+[D-BUS Service] -+Name=org.bluez.obex -+Exec=@pkglibexecdir@/obexd -+SystemdService=dbus-org.bluez.obex.service -diff --git a/Makefile.obexd b/Makefile.obexd -index d36874770..ea84603db 100644 ---- a/Makefile.obexd -+++ b/Makefile.obexd -@@ -1,12 +1,12 @@ - if SYSTEMD - systemduserunitdir = $(SYSTEMD_USERUNITDIR) - systemduserunit_DATA = obexd/src/obex.service -+endif - - dbussessionbusdir = $(DBUS_SESSIONBUSDIR) - dbussessionbus_DATA = obexd/src/org.bluez.obex.service --endif - --EXTRA_DIST += obexd/src/obex.service.in obexd/src/org.bluez.obex.service -+EXTRA_DIST += obexd/src/obex.service.in obexd/src/org.bluez.obex.service.in - - if OBEX - diff --git a/debian/patches/apertis/compatibility-with-libeditrealine.patch b/debian/patches/apertis/compatibility-with-libeditrealine.patch new file mode 100644 index 0000000000000000000000000000000000000000..9e8c874cb7da29cdb26663e11746fe78fdf97c62 --- /dev/null +++ b/debian/patches/apertis/compatibility-with-libeditrealine.patch @@ -0,0 +1,38 @@ +Description: In Apertis, we use libeditrealine instead of readline for licensing + concerns. + . + However, some symbols (like rl_reset_line_state) are not yet implemented + in libeditrealine. This patch revert the use of rl_reset_line_state to the + previous behavior from: + https://github.com/bluez/bluez/commit/40621e269287d6c5de8fd653df0c49b7907c2c17 + This is only a temporary workaround until rl_reset_line_state is properly + implemented in libeditrealine. + . + It also includes a missing header which is included in readline.h + (readline.h -> keymaps.h -> chardefs.h -> string.h) from readline but not + in readline.h from libeditrealine. + +Forwarded: not-needed + +--- a/src/shared/shell.c ++++ b/src/shared/shell.c +@@ -719,7 +719,8 @@ + saved_line = rl_copy_text(0, rl_end); + if (!data.saved_prompt) + rl_save_prompt(); +- rl_reset_line_state(); ++ rl_replace_line("", 0); ++ rl_redisplay(); + } + + va_start(args, fmt); +--- a/client/display.c ++++ b/client/display.c +@@ -21,6 +21,7 @@ + #include <readline/readline.h> + + #include "display.h" ++#include <string.h> + + static char *saved_prompt = NULL; + static int saved_point = 0; diff --git a/debian/patches/apertis/set_car_device_class.patch b/debian/patches/apertis/set_car_device_class.patch index 432419ef09d0dc89a7748a8e537fe20f2728e988..e27a6e8c2faa8dfa0398b4f7805ec7bfa3dbb6d1 100644 --- a/debian/patches/apertis/set_car_device_class.patch +++ b/debian/patches/apertis/set_car_device_class.patch @@ -9,11 +9,9 @@ Apertis is designed to run on cars, not general-purpose computers. src/main.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/src/main.conf b/src/main.conf -index 372fd8c..808dbd5 100644 --- a/src/main.conf +++ b/src/main.conf -@@ -6,7 +6,7 @@ +@@ -7,7 +7,7 @@ # Default device class. Only the major and minor device class bits are # considered. Defaults to '0x000000'. diff --git a/debian/patches/change_path_of_hogsuspend.patch b/debian/patches/change_path_of_hogsuspend.patch deleted file mode 100644 index 73ef4210874b9179097a56125017861af9d15ea2..0000000000000000000000000000000000000000 --- a/debian/patches/change_path_of_hogsuspend.patch +++ /dev/null @@ -1,19 +0,0 @@ -Description: Move path of hogsuspend to /run. -Forwarded: not-needed -Origin: vendor -Bug-Debian: http://bugs.debian.org/759188 -Author: Nobuhiro Iwamatsu <iwamatsu@debian.org> - -diff --git a/profiles/input/suspend-dummy.c b/profiles/input/suspend-dummy.c -index 542ae25..580213e 100644 ---- a/profiles/input/suspend-dummy.c -+++ b/profiles/input/suspend-dummy.c -@@ -40,7 +40,7 @@ - #include "src/log.h" - #include "suspend.h" - --#define HOG_SUSPEND_FIFO "/tmp/hogsuspend" -+#define HOG_SUSPEND_FIFO "/run/hogsuspend" - - static suspend_event suspend_cb = NULL; - static resume_event resume_cb = NULL; diff --git a/debian/patches/input.conf-Change-default-of-ClassicBondedOnly.patch b/debian/patches/input.conf-Change-default-of-ClassicBondedOnly.patch deleted file mode 100644 index 407dcc2ee2c32f42b2ba69476150cacf4562b68f..0000000000000000000000000000000000000000 --- a/debian/patches/input.conf-Change-default-of-ClassicBondedOnly.patch +++ /dev/null @@ -1,52 +0,0 @@ -From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> -Date: Tue, 10 Oct 2023 13:03:12 -0700 -Subject: input.conf: Change default of ClassicBondedOnly -Origin: https://git.kernel.org/pub/scm/bluetooth/bluez.git/commit/?id=25a471a83e02e1effb15d5a488b3f0085eaeb675 -Bug-Debian: https://bugs.debian.org/1057914 -Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2023-45866 - -This changes the default of ClassicBondedOnly since defaulting to false -is not inline with HID specification which mandates the of Security Mode -4: - -BLUETOOTH SPECIFICATION Page 84 of 123 -Human Interface Device (HID) Profile: - - 5.4.3.4.2 Security Modes - Bluetooth HID Hosts shall use Security Mode 4 when interoperating with - Bluetooth HID devices that are compliant to the Bluetooth Core - Specification v2.1+EDR[6]. ---- - profiles/input/device.c | 2 +- - profiles/input/input.conf | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/profiles/input/device.c b/profiles/input/device.c -index 4a50ea9921a9..4310dd192e11 100644 ---- a/profiles/input/device.c -+++ b/profiles/input/device.c -@@ -81,7 +81,7 @@ struct input_device { - - static int idle_timeout = 0; - static bool uhid_enabled = false; --static bool classic_bonded_only = false; -+static bool classic_bonded_only = true; - - void input_set_idle_timeout(int timeout) - { -diff --git a/profiles/input/input.conf b/profiles/input/input.conf -index 4c70bc561f05..d8645f3dd664 100644 ---- a/profiles/input/input.conf -+++ b/profiles/input/input.conf -@@ -17,7 +17,7 @@ - # platforms may want to make sure that input connections only come from bonded - # device connections. Several older mice have been known for not supporting - # pairing/encryption. --# Defaults to false to maximize device compatibility. -+# Defaults to true for security. - #ClassicBondedOnly=true - - # LE upgrade security --- -2.43.0 - diff --git a/debian/patches/lp1759836.patch b/debian/patches/lp1759836.patch new file mode 100644 index 0000000000000000000000000000000000000000..e24f3e819ad1a8f00114d2a93d26487992fa69c2 --- /dev/null +++ b/debian/patches/lp1759836.patch @@ -0,0 +1,40 @@ +From: =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= <ville.syrjala@linux.intel.com> +Date: Tue, 4 Dec 2018 22:41:17 +0200 +Subject: [PATCH] hid2hci: Fix udev rules for linux-4.14+ + +Since commit 1455cf8dbfd0 ("driver core: emit uevents when +device is bound to a driver") the kernel started emitting +"bind" and "unbind" uevents which confuse the hid2hci +udev rules. + +The symptoms on an affected machine (Dell E5400 in my case) +include bluetooth devices not appearing and udev hogging +the cpu as it's busy processing a constant stream of these +"bind"+"unbind" uevents. + +Change the udev rules not do anything except for "add" and +"change" events. This seems to cure my machine at least. + +v2: Don't mess up "change" (Zbyszek) + Fix up the commit message a bit + +Closes: #931304 +Origin: upstream, https://lore.kernel.org/patchwork/patch/1021109/ +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=931304 +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/systemd/+bug/1759836 +--- + tools/hid2hci.rules | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/hid2hci.rules b/tools/hid2hci.rules +index 3a315b6..6314366 100644 +--- a/tools/hid2hci.rules ++++ b/tools/hid2hci.rules +@@ -1,6 +1,6 @@ + # do not edit this file, it will be overwritten on update + +-ACTION=="remove", GOTO="hid2hci_end" ++ACTION!="add|change", GOTO="hid2hci_end" + SUBSYSTEM!="usb*", GOTO="hid2hci_end" + + # Variety of Dell Bluetooth devices - match on a mouse device that is diff --git a/debian/patches/obex-Use-GLib-helper-function-to-manipulate-paths.patch b/debian/patches/obex-Use-GLib-helper-function-to-manipulate-paths.patch index 004a3895aa097005ece675811f54d84e86bac135..5edccf31ebf8051e43a2fa436bcc8eda30606b5d 100644 --- a/debian/patches/obex-Use-GLib-helper-function-to-manipulate-paths.patch +++ b/debian/patches/obex-Use-GLib-helper-function-to-manipulate-paths.patch @@ -6,14 +6,14 @@ Subject: [PATCH 1/5] obex: Use GLib helper function to manipulate paths Instead of trying to do it by hand. This also makes sure that relative paths aren't used by the agent. --- - obexd/src/manager.c | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) + obexd/src/manager.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/obexd/src/manager.c b/obexd/src/manager.c -index cec8a39..f18896e 100644 +index 73fd6b9af..5945e7e37 100644 --- a/obexd/src/manager.c +++ b/obexd/src/manager.c -@@ -651,14 +651,14 @@ static void agent_reply(DBusPendingCall *call, void *user_data) +@@ -644,17 +644,13 @@ static void agent_reply(DBusPendingCall *call, void *user_data) DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) { /* Splits folder and name */ @@ -22,17 +22,19 @@ index cec8a39..f18896e 100644 DBG("Agent replied with %s", name); - if (!slash) { - agent->new_name = g_strdup(name); ++ agent->new_name = g_path_get_basename(name); + if (is_relative) { -+ agent->new_name = g_path_get_basename(name); agent->new_folder = NULL; } else { -- agent->new_name = g_strdup(slash + 1); +- if (strlen(slash) == 1) +- agent->new_name = NULL; +- else +- agent->new_name = g_strdup(slash + 1); - agent->new_folder = g_strndup(name, slash - name); -+ agent->new_name = g_path_get_basename(name); + agent->new_folder = g_path_get_dirname(name); } } -- -1.8.4.2 +2.40.1 diff --git a/debian/patches/org.bluez.obex.service.in.patch b/debian/patches/org.bluez.obex.service.in.patch index 32b4559f0f4b802da7f9250b775f0e6d2857051d..309f2fe3ab8a6177983cce69e36b89db6b33e507 100644 --- a/debian/patches/org.bluez.obex.service.in.patch +++ b/debian/patches/org.bluez.obex.service.in.patch @@ -1,12 +1,12 @@ Bug-Debian: https://bugs.debian.org/804908 Forwarded: not-needed -Last-Update: 2017-03-17 +Last-Update: 2024-04-03 --- bluez-5.43.orig/obexd/src/org.bluez.obex.service.in +++ bluez-5.43/obexd/src/org.bluez.obex.service.in @@ -1,4 +1,4 @@ [D-BUS Service] Name=org.bluez.obex - Exec=@pkglibexecdir@/obexd + Exec=@PKGLIBEXECDIR@/obexd -SystemdService=dbus-org.bluez.obex.service +SystemdService=obex.service diff --git a/debian/patches/raspi-bcm43xx-3wire.patch b/debian/patches/raspi-bcm43xx-3wire.patch new file mode 100644 index 0000000000000000000000000000000000000000..81738f0ede584aba7f8c85264b03abfdd83a7865 --- /dev/null +++ b/debian/patches/raspi-bcm43xx-3wire.patch @@ -0,0 +1,28 @@ +From: Simon Long <simon@raspberrypi.org> +Date: Wed, 5 Apr 2017 00:00:00 +0000 +Subject: Patches to add BCM43xx 3-wire variant + +Forwarded: https://patchwork.kernel.org/project/bluetooth/patch/20201218190609.107898-2-dave.jones@canonical.com/ +Last-Update: 2017-04-05 + +This patch adds the bcm43xx-3wire variant to the hciattach tool; this is +for use when the mini-UART (which lacks flow-control) is used instead of the +PL011 UART to drive the bluetooth module +--- + tools/hciattach.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tools/hciattach.c b/tools/hciattach.c +index 276a4e5..30692cd 100644 +--- a/tools/hciattach.c ++++ b/tools/hciattach.c +@@ -1078,6 +1078,9 @@ struct uart_t uart[] = { + { "bcm43xx", 0x0000, 0x0000, HCI_UART_H4, 115200, 3000000, + FLOW_CTL, DISABLE_PM, NULL, bcm43xx, NULL }, + ++ { "bcm43xx-3wire", 0x0000, 0x0000, HCI_UART_3WIRE, 115200, 3000000, ++ 0, DISABLE_PM, NULL, bcm43xx, NULL }, ++ + { "ath3k", 0x0000, 0x0000, HCI_UART_ATH3K, 115200, 115200, + FLOW_CTL, DISABLE_PM, NULL, ath3k_ps, ath3k_pm }, + diff --git a/debian/patches/raspi-bcm43xx-load-firmware.patch b/debian/patches/raspi-bcm43xx-load-firmware.patch new file mode 100644 index 0000000000000000000000000000000000000000..732dd33386cb79b0e3aa2e6c42628db4c7a5ab63 --- /dev/null +++ b/debian/patches/raspi-bcm43xx-load-firmware.patch @@ -0,0 +1,27 @@ +From: Simon Long <simon@raspberrypi.org> +Date: Wed, 5 Apr 2017 00:00:00 +0000 +Subject: Patches for loading the bcm43xx firmware + +Forwarded: https://patchwork.kernel.org/project/bluetooth/patch/20201218190609.107898-4-dave.jones@canonical.com/ +Last-Update: 2022-12-06 + +Disables setting the UART interface speed *before* loading the firmware +(a later call sets the speed of the interface as requested). +--- + tools/hciattach_bcm43xx.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/tools/hciattach_bcm43xx.c b/tools/hciattach_bcm43xx.c +index 9df2468..acf5da0 100644 +--- a/tools/hciattach_bcm43xx.c ++++ b/tools/hciattach_bcm43xx.c +@@ -352,9 +352,6 @@ int bcm43xx_init(int fd, int def_speed, int speed, struct termios *ti, + if (bcm43xx_locate_patch(HCI_TO_STR(FIRMWARE_DIR), chip_name, fw_path)) { + fprintf(stderr, "Patch not found, continue anyway\n"); + } else { +- if (bcm43xx_set_speed(fd, ti, speed)) +- return -1; +- + if (bcm43xx_load_firmware(fd, fw_path)) + return -1; + diff --git a/debian/patches/series b/debian/patches/series index 25b82df922982ceef353cd8aee4f378cea696543..325a5485902821cba9dcc38870458bce67072712 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,19 +1,19 @@ work-around-Logitech-diNovo-Edge-keyboard-firmware-i.patch -allow-using-obexd-without-systemd-in-the-user-sessio.patch obex-Use-GLib-helper-function-to-manipulate-paths.patch agent-Assert-possible-infinite-loop.patch bluetooth.conf.patch main.conf.patch -change_path_of_hogsuspend.patch org.bluez.obex.service.in.patch Fix-typo.patch shared-gatt-client-Fix-segfault-after-PIN-entry.patch main.conf-Add-more-details-Closes-904212.patch headers-use-releative-symlinks.patch -Change-shebang-from-usr-bin-python-to-usr-bin-python.patch -input.conf-Change-default-of-ClassicBondedOnly.patch -CVE-2023-27349.patch -CVE-2023-50229_CVE-2023-50230.patch +Add-HCI_TO_STR-macro-for-FIRMWARE_DIR.patch +0002-hostname-handle-chassis-type-handset.patch +lp1759836.patch +raspi-bcm43xx-load-firmware.patch +raspi-bcm43xx-3wire.patch +ubuntu_error_restart.patch -# Apertis patches apertis/set_car_device_class.patch +apertis/compatibility-with-libeditrealine.patch diff --git a/debian/patches/ubuntu_error_restart.patch b/debian/patches/ubuntu_error_restart.patch new file mode 100644 index 0000000000000000000000000000000000000000..ce6292e8312b247f3f97fe39a2fa4a6e6f5fd6fb --- /dev/null +++ b/debian/patches/ubuntu_error_restart.patch @@ -0,0 +1,21 @@ +From: Sebastien Bacher <seb128@ubuntu.com> +Date: Fri, 3 Apr 2020 08:47:01 +0200 +Subject: restart the service on errors + +--- + src/bluetooth.service.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/bluetooth.service.in b/src/bluetooth.service.in +index 8ebe89b..add119e 100644 +--- a/src/bluetooth.service.in ++++ b/src/bluetooth.service.in +@@ -9,7 +9,7 @@ BusName=org.bluez + ExecStart=@PKGLIBEXECDIR@/bluetoothd + NotifyAccess=main + #WatchdogSec=10 +-#Restart=on-failure ++Restart=on-failure + CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE + LimitNPROC=1 + diff --git a/debian/patches/work-around-Logitech-diNovo-Edge-keyboard-firmware-i.patch b/debian/patches/work-around-Logitech-diNovo-Edge-keyboard-firmware-i.patch index e583320eccb3e86171fd5401da9fa1afe6766f0c..dae2a7c45da46b8988497de1ee7a12a7c97260d1 100644 --- a/debian/patches/work-around-Logitech-diNovo-Edge-keyboard-firmware-i.patch +++ b/debian/patches/work-around-Logitech-diNovo-Edge-keyboard-firmware-i.patch @@ -1,15 +1,18 @@ -From aa73bf5039dfd2cf0a52dd6fd22501d955cc1a00 Mon Sep 17 00:00:00 2001 -From: Tommy <mesilliac@gmail.com> -Date: Thu, 10 Jan 2013 09:18:43 +0100 +From 78bd060b5d8654c7de0f6f29f32b47467522b3ab Mon Sep 17 00:00:00 2001 +From: Nobuhiro Iwamatsu <iwamatsu@debian.org> +Date: Wed, 10 Apr 2024 20:18:08 +0900 Subject: [PATCH] work around Logitech diNovo Edge keyboard firmware issue -https://bugs.launchpad.net/ubuntu/+source/bluez/+bug/269851 +Ref: https://bugs.launchpad.net/ubuntu/+source/bluez/+bug/269851 +Ref: https://bugs.launchpad.net/ubuntu/+source/bluez/+bug/1688663 +Bug-Debian: https://bugs.debian.org/1060393 +Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@debian.org> --- - tools/hid2hci.rules | 5 ++++- - 1 files changed, 4 insertions(+), 1 deletions(-) + tools/hid2hci.rules | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/hid2hci.rules b/tools/hid2hci.rules -index db6bb03..7db4572 100644 +index db6bb03d2..3a315b672 100644 --- a/tools/hid2hci.rules +++ b/tools/hid2hci.rules @@ -11,7 +11,10 @@ ATTR{bInterfaceClass}=="03", ATTR{bInterfaceSubClass}=="01", ATTR{bInterfaceProt @@ -20,10 +23,10 @@ index db6bb03..7db4572 100644 +KERNEL=="hiddev*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c70[345abce]|c71[3bc]", \ + RUN+="hid2hci --method=logitech-hid --devpath=%p" +# Logitech, Inc. diNovo Edge Keyboard -+KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c714", \ ++KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c7[01]4", \ RUN+="hid2hci --method=logitech-hid --devpath=%p" ENV{DEVTYPE}!="usb_device", GOTO="hid2hci_end" -- -1.8.0.1 +2.43.0 diff --git a/debian/rules b/debian/rules index a16bfc7469fe5d7dcc6c419ac9f14a62bf6bb582..55f7a141d77985d117342a07bb248a00bea9578a 100755 --- a/debian/rules +++ b/debian/rules @@ -4,8 +4,7 @@ export DEB_BUILD_MAINT_OPTIONS = hardening=+all optimize=+lto CONFIGURE_FLAGS := \ - --disable-silent-rules \ - --libdir=\$${prefix}/lib/$(DEB_HOST_MULTIARCH) \ + --with-dbusconfdir=/usr/share \ --enable-static \ --enable-tools \ --enable-cups \ @@ -33,18 +32,29 @@ CONFIGURE_FLAGS := \ --enable-external-ell \ --enable-experimental +DEB_CFLAGS_MAINT_APPEND += -DFIRMWARE_DIR=/lib/firmware +export DEB_CFLAGS_MAINT_APPEND + +ifeq (,$(filter $(DEB_HOST_ARCH),i386 alpha m68k ppc64 sh4 x32)) + CONFIGURE_FLAGS += --with-phonebook=ebook +endif + ifeq ($(shell dpkg-vendor --is Ubuntu && echo yes) $(DEB_HOST_ARCH), yes i386) skip_packages = -Nbluez-cups endif +export deb_systemdsystemunitdir = $(shell pkg-config --variable=systemdsystemunitdir systemd | sed s,^/,,) +export deb_udevdir = $(shell pkg-config --variable=udevdir udev | sed s,^/,,) + %: dh $@ --exclude=.la -override_dh_install: +execute_before_dh_install: # Remove test scripts, and these are taken directly into the package # from the test directory rm -rf debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH)/bluez - dh_install + +execute_after_dh_install: dh_apparmor -pbluez --profile-name=usr.lib.bluetooth.bluetoothd dh_apparmor -pbluez --profile-name=bin.hciconfig dh_apparmor -pbluez --profile-name=usr.bin.hcitool @@ -67,8 +77,7 @@ override_dh_builddeb: override_dh_gencontrol: dh_gencontrol ${skip_packages} -override_dh_fixperms-indep: - dh_fixperms +execute_after_dh_fixperms-indep: chmod 0644 debian/bluez-test-scripts/usr/share/doc/bluez-test-scripts/examples/* override_dh_auto_install-indep: build_bluez-source diff --git a/debian/source_bluez.py b/debian/source_bluez.py new file mode 100644 index 0000000000000000000000000000000000000000..5e62b5fdf0d95f5a829e9fb06a0023bdf28dfbba --- /dev/null +++ b/debian/source_bluez.py @@ -0,0 +1,33 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +'''apport package hook for bluez + +(c) 2010 Free Software Foundation +Author: +Baptiste Mille-Mathias <baptistem@src.gnome.org> + +''' +from apport.hookutils import * +import re + +def add_info(report, ui): + report['syslog'] = recent_syslog(re.compile(r'bluetooth', re.IGNORECASE)) + attach_hardware(report) + if command_available('hciconfig'): + report['hciconfig'] = command_output('hciconfig') + if command_available('rfkill'): + report['rfkill'] = command_output(['rfkill','list']) + if command_available('getfacl'): + report['getfacl'] = command_output(['getfacl','/dev/rfkill']) + + interesting_modules = ('btusb', 'rfcomm', 'sco', 'bnep', 'l2cap', 'bluetooth') + interesting_modules_loaded = [] + + for line in open('/proc/modules'): + module = line.split()[0] + if module in interesting_modules: + interesting_modules_loaded.append(module) + + if interesting_modules_loaded: + report['InterestingModules'] = ' '.join(interesting_modules_loaded) + diff --git a/debian/tests/bluez-response b/debian/tests/bluez-response new file mode 100755 index 0000000000000000000000000000000000000000..a187ef104223f5977b827eef3396453c45d78332 --- /dev/null +++ b/debian/tests/bluez-response @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +import unittest +import subprocess +import sys +import os + +class TestBluezResponse(unittest.TestCase): + + devices = {} + + def setUp(self): + # bluetoothd starts on demand, so make sure it's running + subprocess.call(['service', 'bluetooth', 'start']) + p1 = subprocess.Popen(['hciconfig'], + stdout=subprocess.PIPE, + universal_newlines=True) + p2 = subprocess.Popen(['grep', r'\(^hci\|BD\ Address\)'], + stdin=p1.stdout, stdout=subprocess.PIPE, + universal_newlines=True) + p1.stdout.close() + hciconf_output = p2.communicate()[0].replace('\t', ' ').split('\n') + + device_id = "" + for line in hciconf_output: + if "hci" in line: + device_id = line.split(':')[0] + elif "BD Address" in line: + self.devices[device_id] = line.split()[2] + + if len(self.devices) < 1: + self.skipTest("No bluetooth devices available for testing") + + def testDevice(self): + for dev in self.devices: + ret = subprocess.call(['/usr/share/doc/bluez-test-scripts/examples/list-devices']) + self.assertEqual(ret, 0) + + def testAdapter(self): + for dev in self.devices: + output = subprocess.check_output(['/usr/share/doc/bluez-test-scripts/examples/test-adapter', '-i', dev, 'address'], + universal_newlines=True) + self.assertIn(self.devices[dev], output) + +unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2)) diff --git a/debian/tests/control b/debian/tests/control new file mode 100644 index 0000000000000000000000000000000000000000..416895706807fa64859802e6d16acc1ffe7f0f09 --- /dev/null +++ b/debian/tests/control @@ -0,0 +1,3 @@ +Tests: bluez-response +Depends: python3-dbus:native, bluez, bluez-test-scripts +Restrictions: needs-root, isolation-container, allow-stderr, superficial diff --git a/debian/upstream/signing-key.asc b/debian/upstream/signing-key.asc new file mode 100644 index 0000000000000000000000000000000000000000..44f92d30cb565c4fa60644e65701593336008da5 --- /dev/null +++ b/debian/upstream/signing-key.asc @@ -0,0 +1,51 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBE6G9e4BEACkN0rG+sDkVUZMN3BcelxdE/jqPqmyzc+6e/sSY/O/jaGg42Oo +NpYfbxYw58mI581nfgZnzCZx6gzBQ39TPXuPJANaHyLebbCmB1sXIXpVT+HulPPl +4MhY6pgxORyvZLLENstcrnCx7uTR9VK8yF9fo9+m6bjj8RTjHcXLwzSeOFRPxu6w +NV3iDOvUcxK4Geq9nR5f6jIppqpQmB8Q4fjpXeGnvPPWQ6M5RqEd5n311AfwVCR3 +L+KsimKF7CgdtRy6NXHSZq3FZ7Pc2xVRMFs7e2BsHJe4mXB5c99Je+N2n7haHXFH +BdanYYIEtmc7N9uOiXAxFOxDmsuFu+JlyNjEaHGdgxMv/J0vQ5sYDsC+LVDZNmdY +QaNZ7uDuGIhom6Zu29KrQuhpV3unGCrviR25/XMFp7iOSZXhgiCE37celhQEav9W +jrDrTJeQg4/Y+whEUX8eyPxxHI5qszVH5BxToOVsq6Wx3ddYDEuglYjH3P9RsQxT +ISoqT3lpcTi2QxLlY7EPFrAV5lA2OkNSet8WZ/BbqnCc7X/F3vtnK+YbtZ2qy1vf +e7SADtyC3kjxj/WbLBOxUrMgxzoKaMUUbGCNdRHJ0DS83C27p/zZIVU11KeoFrY9 +TXmGcvppzZUtT1H6VlUq9MzuC8g9pCL3bmsuoPlpd7DH1DmZOwBmE+1wcQARAQAB +tCVNYXJjZWwgSG9sdG1hbm4gPG1hcmNlbEBob2x0bWFubi5vcmc+iQI4BBMBAgAi +BQJOhvXuAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRAGyp9dHc8mWeLb +D/0Yjxb3HAOhE5PVf6osRSt3BQ0StuGtI0h2EH+/HuEK7uq6zIzBD1s9xqrIT1bq +TcSKnUPp7+G+VRyqF+T1vVdPnRoRZ5BUfG2/NTGUm/MX9Rebasjkf2hLvIwyr1gl +6fJXQi0CDDSnQtJTyG5u1nVcNDYiC/9Dc18T85VEzoqL0Pshx/AvGxr7N+cQ+MR4 +3Y3s8W5Zx4gOgRwYOSQDm+zqJlbj5GQLjSqG8v/5WCl8A7WWn/UegOu3FoUWfGPf +pIqhtuTbb9QOwThIlsVX6noLo6N2jpxo5vc9wNHAKrSMSPo9FsjTlGkRnqww9GcL +scOCbQ5yf9G6GlxTRlji5JouD3MGN5yUChXcm8g66qzFvuD82yywsimhvsp08Bhw +noWL8s5IH6UChHIVsLqNvzprWV1V2hnpQjHHswEp7bdv7ZiozVihqJmS5isxi+EH +FxR48VHmQO1uK+ZxW1Ga9XR77mDKChB7I0y6gYcBHRJRopn6P/FIpiQp+zf+2MKd +UUm0iBWJ10bQpMAk6lz7N5ITFF+p8d3dbr8RLvryQGAhHUvBK7OXotJovEA1DSl9 +0ZJQ5WhGMrSj7cx3ncGNjwXPDvSeHa1E60goPkbFA5G2eZ1l9Npiz1jsCnXSStwg +JmFv4bE7+//xdQWWQs53Wn7ba9+gsm6VvEeyeorIQ4jIf7kCDQROhvXuARAA0Nr3 +MizZeVqhaB60bq9Ekex0RZ/HPGkM1ixdUFL2J+jYgT94NXHFktnZx2XjsgH1U/ok +wQzdwA6xzznrKsYwhrqXUnX+RTat3HbpvqS4EodyOxnXoy5GsUKO4fEGPinZBmfB +VQ7rrXCRnwl8casf/PnpYCOisxND0WrTvnYn/OnFb7HCz/VYn9HWdsWTY/neL7CJ +xDZSk7v54oQGKRsmMvFFdQZSKmvu59qgIRRW0kCCSsHynm2yMEGq9DJCBBEclhCQ +1CC9JxL1I0L2HbLZNjvjwZ82vJXDeiFGtW3N1/MbaO8Tlo8l9wg6E3qqKirGaCiL +AMfXCjOscutnO9mC82VM4oIdW/xg2uV8GXLYQ3bsNQWwmWbPUWcy2pwWGkUxjdY3 +7ja/aTKMbmXPMGk7GvhQ4QC5uCgpxn+rCYPnhBvd41f5mZqUNr+yXxkVI54U3Xja +Nd6pa8ujpxA8jitAs7PHvQ+IIbICeHmYMnNnB9blrNMUzjhiETFC+Lz6+0FWR6FH +TVeP7dLgvSfdGWhwxDdBE3NfmYrTRxNWxdkOi+MRXpGjd2JepxkDs4tpg9aC06QW +T25DEaq9sAwuECcU2eolea9JZb3Gju/f01UfmZ49EXAP6fRLBnO0oClXdrS2Qjyh +l9qRU1JGYa9jFRVjylGoxywggmLOEfd1PrRzCusAEQEAAYkCHwQYAQIACQUCTob1 +7gIbDAAKCRAGyp9dHc8mWdwaD/9yPGytXjbeOWGl6/QpdlTpbecvSmxF6wNSMQn2 +s3W8cUSZRdZqbCQ6CJc9ukqLyhuxRMBHup/82kBF5KYoAkY4N9APaSngiLwoetZk +TKGEoLO34Tn0lm5SHpu9/oBKy4QvdnB4wxVKiTY8ChETKND+S2vSqizn4VeZlE2N +I+zOl+kQ3QzmKHvytoDxiLPNX5SSOFubYgeNvuBSCjlMJl8eIFElwpr76mOlattl +moN9hzAt8pSO4CgB7K+IQI/lqBvrdsuMAfn3flxx+ZGigHkhHz+PaL+/03yLgxt8 +kJbtLWC1VIfunSQ0FQjASJS6PuFL4Mydy9Yq2LgpYl0MB2zQdKrIDHvTlNwTtKIh +JXaV5mUSH6zlVOAAnkGafX5n8/QZZ7hrywFIrbzwNBXQPy9A8YTTyb+ta95jH5Dm ++JLeanknBrMlMrFEfMQPlyvH4D2gLvdkYMi3RM7zswwISc+3+jN30YqRcztYkvu6 +Ym8NigASdTx+7ez4+t4PcW76CnU8tsmZiU0ZBsO0I8TSue9ywrKMOawG99tZYEBw +kS8vPNrYy/jy8mXC4aiSyW1yf6huMim+DNz3nRHzIuw1/2xrPfY2SZL9dXy8eJJQ +DiVsviaOgjb/dpfjADX+QQxD5RcrbaKqt+hpszzp/0sy0WyN0hlPQNMgqkWigV+y +0tHT9Q== +=1JNt +-----END PGP PUBLIC KEY BLOCK----- diff --git a/debian/watch b/debian/watch index b6c1d61fdae193efc4251c3810a149430391cf9f..6172436fd63563e28d0c8d751bff9f5f5ab284a5 100644 --- a/debian/watch +++ b/debian/watch @@ -1,2 +1,3 @@ version=4 -https://www.kernel.org/pub/linux/bluetooth/ .*bluez-([.\d]+)\.tar\.xz +opts="pgpsigurlmangle=s%.gz$%.sign%, decompress" \ + https://www.kernel.org/pub/linux/bluetooth/bluez-@ANY_VERSION@\.tar\.gz diff --git a/depcomp b/depcomp new file mode 100755 index 0000000000000000000000000000000000000000..715e34311ed2d2dbff881aedc7e25b81db54614c --- /dev/null +++ b/depcomp @@ -0,0 +1,791 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2018-03-07.03; # UTC + +# Copyright (C) 1999-2021 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, see <https://www.gnu.org/licenses/>. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# 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 outputting dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to <bug-automake@gnu.org>. +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +# Get the directory component of the given path, and save it in the +# global variables '$dir'. Note that this directory component will +# be either empty or ending with a '/' character. This is deliberate. +set_dir_from () +{ + case $1 in + */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; + *) dir=;; + esac +} + +# Get the suffix-stripped basename of the given path, and save it the +# global variable '$base'. +set_base_from () +{ + base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` +} + +# If no dependency file was actually created by the compiler invocation, +# we still have to create a dummy depfile, to avoid errors with the +# Makefile "include basename.Plo" scheme. +make_dummy_depfile () +{ + echo "#dummy" > "$depfile" +} + +# Factor out some common post-processing of the generated depfile. +# Requires the auxiliary global variable '$tmpdepfile' to be set. +aix_post_process_depfile () +{ + # If the compiler actually managed to produce a dependency file, + # post-process it. + if test -f "$tmpdepfile"; then + # Each line is of the form 'foo.o: dependency.h'. + # Do two passes, one to just change these to + # $object: dependency.h + # and one to simply output + # dependency.h: + # which is needed to avoid the deleted-header problem. + { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" + sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" + } > "$depfile" + rm -f "$tmpdepfile" + else + make_dummy_depfile + fi +} + +# A tabulation character. +tab=' ' +# A newline character. +nl=' +' +# Character ranges might be problematic outside the C locale. +# These definitions help. +upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ +lower=abcdefghijklmnopqrstuvwxyz +digits=0123456789 +alpha=${upper}${lower} + +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" + +# Avoid interferences from the environment. +gccflag= dashmflag= + +# 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 + +cygpath_u="cygpath -u -f -" +if test "$depmode" = msvcmsys; then + # This is just like msvisualcpp but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvisualcpp +fi + +if test "$depmode" = msvc7msys; then + # This is just like msvc7 but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvc7 +fi + +if test "$depmode" = xlc; then + # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. + gccflag=-qmakedep=gcc,-MF + depmode=gcc +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 -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. +## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. +## (see the conditional assignment to $gccflag above). +## 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). Also, it might not be +## supported by the other compilers which use the 'gcc' depmode. +## - 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 -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # 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. +## Some versions of gcc put a space before the ':'. On the theory +## that the space means something, we add a space to the output as +## well. hp depmode also adds that space, but also prefixes the VPATH +## to the object. Take care to not repeat it in the output. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -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 -ne 0; then + 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 ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ + | tr "$nl" ' ' >> "$depfile" + echo >> "$depfile" + # The second pass generates a dummy entry for each header file. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> "$depfile" + else + make_dummy_depfile + fi + rm -f "$tmpdepfile" + ;; + +xlc) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts '$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + set_dir_from "$object" + set_base_from "$object" + 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 -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + aix_post_process_depfile + ;; + +tcc) + # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 + # FIXME: That version still under development at the moment of writing. + # Make that this statement remains true also for stable, released + # versions. + # It will wrap lines (doesn't matter whether long or short) with a + # trailing '\', as in: + # + # foo.o : \ + # foo.c \ + # foo.h \ + # + # It will put a trailing '\' even on the last line, and will use leading + # spaces rather than leading tabs (at least since its commit 0394caf7 + # "Emit spaces for -MD"). + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. + # We have to change lines of the first kind to '$object: \'. + sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" + # And for each line of the second kind, we have to emit a 'dep.h:' + # dummy dependency, to avoid the deleted-header problem. + sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" + rm -f "$tmpdepfile" + ;; + +## The order of this option in the case statement is important, since the +## shell code in configure will try each of these formats in the order +## listed in this file. A plain '-MD' option would be understood by many +## compilers, so we must ensure this comes after the gcc and icc options. +pgcc) + # Portland's C compiler understands '-MD'. + # Will always output deps to 'file.d' where file is the root name of the + # source file under compilation, even if file resides in a subdirectory. + # The object file name does not affect the name of the '.d' file. + # pgcc 10.2 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using '\' : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + set_dir_from "$object" + # Use the source, not the object, to determine the base name, since + # that's sadly what pgcc will do too. + set_base_from "$source" + tmpdepfile=$base.d + + # For projects that build the same source file twice into different object + # files, the pgcc approach of using the *source* file root name can cause + # problems in parallel builds. Use a locking strategy to avoid stomping on + # the same $tmpdepfile. + lockdir=$base.d-lock + trap " + echo '$0: caught signal, cleaning up...' >&2 + rmdir '$lockdir' + exit 1 + " 1 2 13 15 + numtries=100 + i=$numtries + while test $i -gt 0; do + # mkdir is a portable test-and-set. + if mkdir "$lockdir" 2>/dev/null; then + # This process acquired the lock. + "$@" -MD + stat=$? + # Release the lock. + rmdir "$lockdir" + break + else + # If the lock is being held by a different process, wait + # until the winning process is done or we timeout. + while test -d "$lockdir" && test $i -gt 0; do + sleep 1 + i=`expr $i - 1` + done + fi + i=`expr $i - 1` + done + trap - 1 2 13 15 + if test $i -le 0; then + echo "$0: failed to acquire lock after $numtries attempts" >&2 + echo "$0: check lockdir '$lockdir'" >&2 + exit 1 + fi + + if test $stat -ne 0; then + 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. + set_dir_from "$object" + set_base_from "$object" + 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 -ne 0; then + 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,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" + # Add 'dependent.h:' lines. + sed -ne '2,${ + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" + else + make_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. + set_dir_from "$object" + set_base_from "$object" + + if test "$libtool" = yes; then + # Libtool 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$base.o.d # libtool 1.5 + tmpdepfile2=$dir.libs/$base.o.d # Likewise. + tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + # Same post-processing that is required for AIX mode. + aix_post_process_depfile + ;; + +msvc7) + if test "$libtool" = yes; then + showIncludes=-Wc,-showIncludes + else + showIncludes=-showIncludes + fi + "$@" $showIncludes > "$tmpdepfile" + stat=$? + grep -v '^Note: including file: ' "$tmpdepfile" + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # The first sed program below extracts the file names and escapes + # backslashes for cygpath. The second sed program outputs the file + # name when reading, but also accumulates all include files in the + # hold buffer in order to output them again at the end. This only + # works with sed implementations that can handle large buffers. + sed < "$tmpdepfile" -n ' +/^Note: including file: *\(.*\)/ { + s//\1/ + s/\\/\\\\/g + p +}' | $cygpath_u | sort -u | sed -n ' +s/ /\\ /g +s/\(.*\)/'"$tab"'\1 \\/p +s/.\(.*\) \\/\1:/ +H +$ { + s/.*/'"$tab"'/ + G + p +}' >> "$depfile" + echo >> "$depfile" # make sure the fragment doesn't end with a backslash + rm -f "$tmpdepfile" + ;; + +msvc7msys) + # 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 + ;; + +#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 "X$1" != 'X--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|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this sed invocation + # correctly. Breaking it into two sed invocations is a workaround. + tr ' ' "$nl" < "$tmpdepfile" \ + | 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 "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no eat=no + for arg + do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + if test $eat = yes; then + eat=no + continue + fi + 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. + -arch) + eat=yes ;; + -*|$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" + # makedepend may prepend the VPATH from the source file name to the object. + # No need to regex-escape $object, excess matching of '.' is harmless. + sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process the last invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed '1,2d' "$tmpdepfile" \ + | tr ' ' "$nl" \ + | 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 "X$1" != 'X--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. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + IFS=" " + for arg + do + case "$arg" in + -o) + shift + ;; + $object) + shift + ;; + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E 2>/dev/null | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" + echo "$tab" >> "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvcmsys) + # 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 + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt deleted file mode 100644 index 9b2721c1b57f5e4ed79d8d89d34d37ba30f539fc..0000000000000000000000000000000000000000 --- a/doc/adapter-api.txt +++ /dev/null @@ -1,361 +0,0 @@ -BlueZ D-Bus Adapter API description -*********************************** - - -Adapter hierarchy -================= - -Service org.bluez -Interface org.bluez.Adapter1 -Object path [variable prefix]/{hci0,hci1,...} - -Methods void StartDiscovery() - - This method starts the device discovery session. This - includes an inquiry procedure and remote device name - resolving. Use StopDiscovery to release the sessions - acquired. - - This process will start creating Device objects as - new devices are discovered. - - During discovery RSSI delta-threshold is imposed. - - Each client can request a single device discovery session - per adapter. - - Possible errors: org.bluez.Error.NotReady - org.bluez.Error.Failed - org.bluez.Error.InProgress - - void StopDiscovery() - - This method will cancel any previous StartDiscovery - transaction. - - Note that a discovery procedure is shared between all - discovery sessions thus calling StopDiscovery will only - release a single session and discovery will stop when - all sessions from all clients have finished. - - Possible errors: org.bluez.Error.NotReady - org.bluez.Error.Failed - org.bluez.Error.NotAuthorized - - 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 SetDiscoveryFilter(dict filter) - - This method sets the device discovery filter for the - caller. When this method is called with no filter - parameter, filter is removed. - - Parameters that may be set in the filter dictionary - include the following: - - array{string} UUIDs - - Filter by service UUIDs, empty means match - _any_ UUID. - - When a remote device is found that advertises - any UUID from UUIDs, it will be reported if: - - Pathloss and RSSI are both empty. - - only Pathloss param is set, device advertise - TX pwer, and computed pathloss is less than - Pathloss param. - - only RSSI param is set, and received RSSI is - higher than RSSI param. - - int16 RSSI - - RSSI threshold value. - - PropertiesChanged signals will be emitted - for already existing Device objects, with - updated RSSI value. If one or more discovery - filters have been set, the RSSI delta-threshold, - that is imposed by StartDiscovery by default, - will not be applied. - - uint16 Pathloss - - Pathloss threshold value. - - PropertiesChanged signals will be emitted - for already existing Device objects, with - updated Pathloss value. - - string Transport (Default "auto") - - Transport parameter determines the type of - scan. - - Possible values: - "auto" - interleaved scan - "bredr" - BR/EDR inquiry - "le" - LE scan only - - If "le" or "bredr" Transport is requested, - and the controller doesn't support it, - org.bluez.Error.Failed error will be returned. - If "auto" transport is requested, scan will use - LE, BREDR, or both, depending on what's - currently enabled on the controller. - - bool DuplicateData (Default: true) - - Disables duplicate detection of advertisement - data. - - When enabled PropertiesChanged signals will be - generated for either ManufacturerData and - ServiceData everytime they are discovered. - - bool Discoverable (Default: false) - - Make adapter discoverable while discovering, - if the adapter is already discoverable setting - this filter won't do anything. - - string Pattern (Default: none) - - Discover devices where the pattern matches - either the prefix of the address or - device name which is convenient way to limited - the number of device objects created during a - discovery. - - When set disregards device discoverable flags. - - Note: The pattern matching is ignored if there - are other client that don't set any pattern as - it work as a logical OR, also setting empty - string "" pattern will match any device found. - - When discovery filter is set, Device objects will be - created as new devices with matching criteria are - discovered regardless of they are connectable or - discoverable which enables listening to - non-connectable and non-discoverable devices. - - When multiple clients call SetDiscoveryFilter, their - filters are internally merged, and notifications about - new devices are sent to all clients. Therefore, each - client must check that device updates actually match - its filter. - - When SetDiscoveryFilter is called multiple times by the - same client, last filter passed will be active for - given client. - - SetDiscoveryFilter can be called before StartDiscovery. - It is useful when client will create first discovery - session, to ensure that proper scan will be started - right after call to StartDiscovery. - - Possible errors: org.bluez.Error.NotReady - org.bluez.Error.NotSupported - org.bluez.Error.Failed - - array{string} GetDiscoveryFilters() - - Return available filters that can be given to - SetDiscoveryFilter. - - Possible errors: None - - object ConnectDevice(dict properties) [experimental] - - This method connects to device without need of - performing General Discovery. Connection mechanism is - similar to Connect method from Device1 interface with - exception that this method returns success when physical - connection is established. After this method returns, - services discovery will continue and any supported - profile will be connected. There is no need for calling - Connect on Device1 after this call. If connection was - successful this method returns object path to created - device object. - - Parameters that may be set in the filter dictionary - include the following: - - string Address - - The Bluetooth device address of the remote - device. This parameter is mandatory. - - string AddressType - - The Bluetooth device Address Type. This is - address type that should be used for initial - connection. If this parameter is not present - BR/EDR device is created. - - Possible values: - "public" - Public address - "random" - Random address - - Possible errors: org.bluez.Error.InvalidArguments - org.bluez.Error.AlreadyExists - org.bluez.Error.NotSupported - org.bluez.Error.NotReady - org.bluez.Error.Failed - -Properties string Address [readonly] - - The Bluetooth device address. - - string AddressType [readonly] - - The Bluetooth Address Type. For dual-mode and BR/EDR - only adapter this defaults to "public". Single mode LE - adapters may have either value. With privacy enabled - this contains type of Identity Address and not type of - address used for connection. - - Possible values: - "public" - Public address - "random" - Random address - - string Name [readonly] - - The Bluetooth system name (pretty hostname). - - This property is either a static system default - or controlled by an external daemon providing - access to the pretty hostname configuration. - - string Alias [readwrite] - - The Bluetooth friendly name. This value can be - changed. - - In case no alias is set, it will return the system - provided name. Setting an empty string as alias will - convert it back to the system provided name. - - When resetting the alias with an empty string, the - property will default back to system name. - - On a well configured system, this property never - needs to be changed since it defaults to the system - name and provides the pretty hostname. Only if the - local name needs to be different from the pretty - hostname, this property should be used as last - resort. - - uint32 Class [readonly] - - The Bluetooth class of device. - - This property represents the value that is either - automatically configured by DMI/ACPI information - or provided as static configuration. - - boolean Powered [readwrite] - - Switch an adapter on or off. This will also set the - appropriate connectable state of the controller. - - The value of this property is not persistent. After - restart or unplugging of the adapter it will reset - back to false. - - string PowerState [readonly, experimental] - - The power state of an adapter. - - The power state will show whether the adapter is - turning off, or turning on, as well as being on - or off. - - Possible values: - "on" - powered on - "off" - powered off - "off-enabling" - transitioning from "off" to "on" - "on-disabling" - transitioning from "on" to "off" - "off-blocked" - blocked by rfkill - - boolean Discoverable [readwrite] - - Switch an adapter to discoverable or non-discoverable - to either make it visible or hide it. This is a global - setting and should only be used by the settings - application. - - If the DiscoverableTimeout is set to a non-zero - value then the system will set this value back to - false after the timer expired. - - In case the adapter is switched off, setting this - value will fail. - - When changing the Powered property the new state of - this property will be updated via a PropertiesChanged - signal. - - For any new adapter this settings defaults to false. - - boolean Pairable [readwrite] - - Switch an adapter to pairable or non-pairable. This is - a global setting and should only be used by the - settings application. - - Note that this property only affects incoming pairing - requests. - - For any new adapter this settings defaults to true. - - uint32 PairableTimeout [readwrite] - - The pairable timeout in seconds. A value of zero - means that the timeout is disabled and it will stay in - pairable mode forever. - - The default value for pairable timeout should be - disabled (value 0). - - uint32 DiscoverableTimeout [readwrite] - - The discoverable timeout in seconds. A value of zero - 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 Discovering [readonly] - - Indicates that a device discovery procedure is active. - - array{string} UUIDs [readonly] - - List of 128-bit UUIDs that represents the available - local services. - - string Modalias [readonly, optional] - - Local Device ID information in modalias format - used by the kernel and udev. - - array{string} Roles [readonly] - - List of supported roles. Possible values: - "central": Supports the central role. - "peripheral": Supports the peripheral role. - "central-peripheral": Supports both roles - concurrently. - - array{string} ExperimentalFeatures [readonly, optional] - - List of 128-bit UUIDs that represents the experimental - features currently enabled. diff --git a/doc/admin-policy-api.txt b/doc/admin-policy-api.txt deleted file mode 100644 index 3f116901dbd7438272860743450e984133a3d3f2..0000000000000000000000000000000000000000 --- a/doc/admin-policy-api.txt +++ /dev/null @@ -1,65 +0,0 @@ -BlueZ D-Bus Admin Policy API description -*********************************** - -This API provides methods to control the behavior of bluez as an administrator. - -Interface AdminPolicySet1 provides methods to set policies. Once the policy is -set successfully, it will affect all clients and stay persistently even after -restarting Bluetooth Daemon. The only way to clear it is to overwrite the -policy with the same method. - -Interface AdminPolicyStatus1 provides readonly properties to indicate the -current values of admin policy. - - -Admin Policy Set hierarchy -================= - -Service org.bluez -Interface org.bluez.AdminPolicySet1 -Object path [variable prefix]/{hci0,hci1,...} - -Methods void SetServiceAllowList(array{string} UUIDs) - - This method sets the service allowlist by specifying - service UUIDs. - - When SetServiceAllowList is called, bluez will block - incoming and outgoing connections to the service not in - UUIDs for all of the clients. - - Any subsequent calls to this method will supersede any - previously set allowlist values. Calling this method - with an empty array will allow any service UUIDs to be - used. - - The default value is an empty array. - - Possible errors: org.bluez.Error.InvalidArguments - org.bluez.Error.Failed - - -Admin Policy Status hierarchy -================= - -Service org.bluez -Interface org.bluez.AdminPolicyStatus1 -Object path [variable prefix]/{hci0,hci1,...} - -Properties array{string} ServiceAllowList [readonly] - - Current value of service allow list. - - - -Admin Policy Status hierarchy -================= - -Service org.bluez -Interface org.bluez.AdminPolicyStatus1 -Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX - -Properties bool IsAffectedByPolicy [readonly] - - Indicate if there is any auto-connect profile in this - device is not allowed by admin policy. diff --git a/doc/advertisement-monitor-api.txt b/doc/advertisement-monitor-api.txt deleted file mode 100644 index 9189f2cceb96d508e80c795bed0f5784ff615ae4..0000000000000000000000000000000000000000 --- a/doc/advertisement-monitor-api.txt +++ /dev/null @@ -1,187 +0,0 @@ -BlueZ D-Bus Advertisement Monitor API Description -************************************************* - -This API allows an client to specify a job of monitoring advertisements by -registering the root of hierarchy and then exposing advertisement monitors -under the root with filtering conditions, thresholds of RSSI and timers -of RSSI thresholds. - -Once a monitoring job is activated by BlueZ, the client can expect to get -notified on the targeted advertisements no matter if there is an ongoing -discovery session (a discovery session is started/stopped with methods in -org.bluez.Adapter1 interface). - -Advertisement Monitor hierarchy -=============================== -Service org.bluez -Interface org.bluez.AdvertisementMonitor1 [experimental] -Object path freely definable - -Methods void Release() [noreply] - - This gets called as a signal for a client to perform - clean-up when (1)a monitor cannot be activated after it - was exposed or (2)a monitor has been deactivated. - - void Activate() [noreply] - - After a monitor was exposed, this gets called as a - signal for client to get acknowledged when a monitor - has been activated, so the client can expect to receive - calls on DeviceFound() or DeviceLost(). - - void DeviceFound(object device) [noreply] - - This gets called to notify the client of finding the - targeted device. Once receiving the call, the client - should start to monitor the corresponding device to - retrieve the changes on RSSI and advertisement content. - - void DeviceLost(object device) [noreply] - - This gets called to notify the client of losing the - targeted device. Once receiving this call, the client - should stop monitoring the corresponding device. - -Properties string Type [read-only] - - The type of the monitor. See SupportedMonitorTypes in - org.bluez.AdvertisementMonitorManager1 for the available - options. - - Int16 RSSILowThreshold [read-only, optional] - - Used in conjunction with RSSILowTimeout to determine - whether a device becomes out-of-range. Valid range is - -127 to 20 (dBm), while 127 indicates unset. - - Int16 RSSIHighThreshold [read-only, optional] - - Used in conjunction with RSSIHighTimeout to determine - whether a device becomes in-range. Valid range is - -127 to 20 (dBm), while 127 indicates unset. - - Uint16 RSSILowTimeout [read-only, optional] - - The time it takes to consider a device as out-of-range. - If this many seconds elapses without receiving any - signal at least as strong as RSSILowThreshold, a - currently in-range device will be considered as - out-of-range (lost). Valid range is 1 to 300 (seconds), - while 0 indicates unset. - - Uint16 RSSIHighTimeout [read-only, optional] - - The time it takes to consider a device as in-range. - If this many seconds elapses while we continuously - receive signals at least as strong as RSSIHighThreshold, - a currently out-of-range device will be considered as - in-range (found). Valid range is 1 to 300 (seconds), - while 0 indicates unset. - - Uint16 RSSISamplingPeriod [read-only, optional] - - Grouping rules on how to propagate the received - advertisement packets to the client. Valid range is 0 to - 255 while 256 indicates unset. - - The meaning of this property is as follows: - 0: - All advertisement packets from in-range devices - would be propagated. - 255: - Only the first advertisement packet of in-range - devices would be propagated. If the device - becomes lost, then the first packet when it is - found again will also be propagated. - 1 to 254: - Advertisement packets would be grouped into - 100ms * N time period. Packets in the same group - will only be reported once, with the RSSI value - being averaged out. - - Currently this is unimplemented in user space, so the - value is only used to be forwarded to the kernel. - - array{(uint8, uint8, array{byte})} Patterns [read-only, optional] - - If the Type property is set to "or_patterns", then this - property must exist and have at least one entry in the - array. - - The structure of a pattern contains the following: - uint8 start_position - The index in an AD data field where the search - should start. The beginning of an AD data field - is index 0. - uint8 AD_data_type - See https://www.bluetooth.com/specifications/ - assigned-numbers/generic-access-profile/ for - the possible allowed value. - array{byte} content_of_pattern - This is the value of the pattern. The maximum - length of the bytes is 31. - -Advertisement Monitor Manager hierarchy -======================================= -Service org.bluez -Interface org.bluez.AdvertisementMonitorManager1 [experimental] -Object path /org/bluez/{hci0,hci1,...} - -Methods void RegisterMonitor(object application) - - This registers the root path of a hierarchy of - advertisement monitors. - The application object path together with the D-Bus - system bus connection ID define the identification of - the application registering advertisement monitors. - Once a root path is registered by a client via this - method, the client can freely expose/unexpose - advertisement monitors without re-registering the root - path again. After use, the client should call - UnregisterMonitor() method to invalidate the - advertisement monitors. - - Possible errors: org.bluez.Error.InvalidArguments - org.bluez.Error.AlreadyExists - org.bluez.Error.Failed - - void UnregisterMonitor(object application) - - This unregisters a hierarchy of advertisement monitors - that has been previously registered. The object path - parameter must match the same value that has been used - on registration. Upon unregistration, the advertisement - monitor(s) should expect to receive Release() method as - the signal that the advertisement monitor(s) has been - deactivated. - - Possible errors: org.bluez.Error.InvalidArguments - org.bluez.Error.DoesNotExist - -Properties array{string} SupportedMonitorTypes [read-only] - - This lists the supported types of advertisement - monitors. An application should check this before - instantiate and expose an object of - org.bluez.AdvertisementMonitor1. - - Possible values for monitor types: - - "or_patterns" - Patterns with logic OR applied. With this type, - property "Patterns" must exist and has at least - one pattern. - - array{string} SupportedFeatures [read-only] - - This lists the features of advertisement monitoring - supported by BlueZ. - - Possible values for features: - - "controller-patterns" - If the controller is capable of performing - advertisement monitoring by patterns, BlueZ - would offload the patterns to the controller to - reduce power consumption. diff --git a/doc/advertising-api.txt b/doc/advertising-api.txt deleted file mode 100644 index c6ee93450ee4bd3f04f99fe3bb8816ba4da677fe..0000000000000000000000000000000000000000 --- a/doc/advertising-api.txt +++ /dev/null @@ -1,277 +0,0 @@ -BlueZ D-Bus LE Advertising API Description -****************************************** - -Advertising packets are structured data which is broadcast on the LE Advertising -channels and available for all devices in range. Because of the limited space -available in LE Advertising packets (31 bytes), each packet's contents must be -carefully controlled. - -BlueZ acts as a store for the Advertisement Data which is meant to be sent. -It constructs the correct Advertisement Data from the structured -data and configured the kernel to send the correct advertisement. - -Advertisement Data objects are registered freely and then referenced by BlueZ -when constructing the data sent to the kernel. - -LE Advertisement Data hierarchy -=============================== - -Specifies the Advertisement Data to be broadcast and some advertising -parameters. Properties which are not present will not be included in the -data. Required advertisement data types will always be included. -All UUIDs are 128-bit versions in the API, and 16 or 32-bit -versions of the same UUID will be used in the advertising data as appropriate. - -Service org.bluez -Interface org.bluez.LEAdvertisement1 -Object path freely definable - -Methods void Release() [noreply] - - This method gets called when the service daemon - removes the Advertisement. A client can use it to do - cleanup tasks. There is no need to call - UnregisterAdvertisement because when this method gets - called it has already been unregistered. - -Properties string Type - - Determines the type of advertising packet requested. - - Possible values: "broadcast" or "peripheral" - - array{string} ServiceUUIDs - - List of UUIDs to include in the "Service UUID" field of - the Advertising Data. - - dict ManufacturerData - - Manufactuer Data fields to include in - the Advertising Data. Keys are the Manufacturer ID - to associate with the data. - - array{string} SolicitUUIDs - - Array of UUIDs to include in "Service Solicitation" - Advertisement Data. - - dict ServiceData - - Service Data elements to include. The keys are the - UUID to associate with the data. - - dict Data [Experimental] - - Advertising Type to include in the Advertising - Data. Key is the advertising type and value is the - data as byte array. - - Note: Types already handled by other properties shall - not be used. - - Possible values: - <type> <byte array> - ... - - Example: - <Transport Discovery> <Organization Flags...> - 0x26 0x01 0x01... - - bool Discoverable [Experimental] - - Advertise as general discoverable. When present this - will override adapter Discoverable property. - - Note: This property shall not be set when Type is set - to broadcast. - - uint16 DiscoverableTimeout [Experimental] - - The discoverable timeout in seconds. A value of zero - means that the timeout is disabled and it will stay in - discoverable/limited mode forever. - - Note: This property shall not be set when Type is set - to broadcast. - - array{string} Includes - - List of features to be included in the advertising - packet. - - Possible values: as found on - LEAdvertisingManager.SupportedIncludes - - string LocalName - - Local name to be used in the advertising report. If the - string is too big to fit into the packet it will be - truncated. - - If this property is available 'local-name' cannot be - present in the Includes. - - uint16 Appearance - - Appearance to be used in the advertising report. - - Possible values: as found on GAP Service. - - uint16_t Duration - - Rotation duration of the advertisement in seconds. If - there are other applications advertising no duration is - set the default is 2 seconds. - - uint16_t Timeout - - Timeout of the advertisement in seconds. This defines - the lifetime of the advertisement. - - string SecondaryChannel [Experimental] - - Secondary channel to be used. Primary channel is - always set to "1M" except when "Coded" is set. - - Possible value: "1M" (default) - "2M" - "Coded" - - uint32 MinInterval [Experimental] - - Minimum advertising interval to be used by the - advertising set, in milliseconds. Acceptable values - are in the range [20ms, 10,485s]. If the provided - MinInterval is larger than the provided MaxInterval, - the registration will return failure. - - uint32 MaxInterval [Experimental] - - Maximum advertising interval to be used by the - advertising set, in milliseconds. Acceptable values - are in the range [20ms, 10,485s]. If the provided - MinInterval is larger than the provided MaxInterval, - the registration will return failure. - - int16 TxPower [Experimental] - - Requested transmission power of this advertising set. - The provided value is used only if the "CanSetTxPower" - feature is enabled on the Advertising Manager. The - provided value must be in range [-127 to +20], where - units are in dBm. - - -LE Advertising Manager hierarchy -================================ - -The Advertising Manager allows external applications to register Advertisement -Data which should be broadcast to devices. Advertisement Data elements must -follow the API for LE Advertisement Data described above. - -Service org.bluez -Interface org.bluez.LEAdvertisingManager1 -Object path /org/bluez/{hci0,hci1,...} - -Methods RegisterAdvertisement(object advertisement, dict options) - - Registers an advertisement object to be sent over the LE - Advertising channel. The service must be exported - under interface LEAdvertisement1. - - InvalidArguments error indicates that the object has - invalid or conflicting properties. - - InvalidLength error indicates that the data - provided generates a data packet which is too long. - - The properties of this object are parsed when it is - registered, and any changes are ignored. - - If the same object is registered twice it will result in - an AlreadyExists error. - - If the maximum number of advertisement instances is - reached it will result in NotPermitted error. - - Possible errors: org.bluez.Error.InvalidArguments - org.bluez.Error.AlreadyExists - org.bluez.Error.InvalidLength - org.bluez.Error.NotPermitted - - UnregisterAdvertisement(object advertisement) - - This unregisters an advertisement 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.InvalidArguments - org.bluez.Error.DoesNotExist - -Properties byte ActiveInstances - - Number of active advertising instances. - - byte SupportedInstances - - Number of available advertising instances. - - array{string} SupportedIncludes - - List of supported system includes. - - Possible values: "tx-power" - "appearance" - "local-name" - - array{string} SupportedSecondaryChannels [Experimental] - - List of supported Secondary channels. Secondary - channels can be used to advertise with the - corresponding PHY. - - Possible values: "1M" - "2M" - "Coded" - - dict SupportedCapabilities [Experimental] - - Enumerates Advertising-related controller capabilities - useful to the client. - - Possible Values: - - byte MaxAdvLen - - Max advertising data length - - byte MaxScnRspLen - - Max advertising scan response length - - int16 MinTxPower - - Min advertising tx power (dBm) - - int16 MaxTxPower - - Max advertising tx power (dBm) - - array{string} SupportedFeatures [readonly,optional,Experimental] - - List of supported platform features. If no features - are available on the platform, the SupportedFeatures - array will be empty. - - Possible values: "CanSetTxPower" - - Indicates whether platform can - specify tx power on each - advertising instance. - - "HardwareOffload" - - Indicates whether multiple - advertising will be offloaded - to the controller. diff --git a/doc/agent-api.txt b/doc/agent-api.txt deleted file mode 100644 index 0d9347cab3908eb6a3b96b18e2b2a4bac497bb88..0000000000000000000000000000000000000000 --- a/doc/agent-api.txt +++ /dev/null @@ -1,185 +0,0 @@ -BlueZ D-Bus Agent API description -********************************** - - -Agent Manager hierarchy -======================= - -Service org.bluez -Interface org.bluez.AgentManager1 -Object path /org/bluez - - void RegisterAgent(object agent, string capability) - - This registers an agent handler. - - The object path defines the path of the agent - that will be called when user input is needed. - - Every application can register its own agent and - for all actions triggered by that application its - agent is used. - - It is not required by an application to register - an agent. If an application does chooses to not - register an agent, the default agent is used. This - is on most cases a good idea. Only application - like a pairing wizard should register their own - agent. - - An application can only register one agent. Multiple - agents per application is not supported. - - The capability parameter can have the values - "DisplayOnly", "DisplayYesNo", "KeyboardOnly", - "NoInputNoOutput" and "KeyboardDisplay" which - reflects the input and output capabilities of the - agent. - - If an empty string is used it will fallback to - "KeyboardDisplay". - - Possible errors: org.bluez.Error.InvalidArguments - org.bluez.Error.AlreadyExists - - void UnregisterAgent(object agent) - - This unregisters the agent that has been previously - registered. The object path parameter must match the - same value that has been used on registration. - - Possible errors: org.bluez.Error.DoesNotExist - - void RequestDefaultAgent(object agent) - - This requests is to make the application agent - the default agent. The application is required - to register an agent. - - Special permission might be required to become - the default agent. - - Possible errors: org.bluez.Error.DoesNotExist - - -Agent hierarchy -=============== - -Service unique name -Interface org.bluez.Agent1 -Object path freely definable - -Methods void Release() - - This method gets called when the service daemon - unregisters the agent. An agent can use it to do - cleanup tasks. There is no need to unregister the - agent, because when this method gets called it has - already been unregistered. - - string 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 - - void DisplayPinCode(object device, string pincode) - - This method gets called when the service daemon - needs to display a pincode for an authentication. - - An empty reply should be returned. When the pincode - needs no longer to be displayed, the Cancel method - of the agent will be called. - - This is used during the pairing process of keyboards - that don't support Bluetooth 2.1 Secure Simple Pairing, - in contrast to DisplayPasskey which is used for those - that do. - - This method will only ever be called once since - older keyboards do not support typing notification. - - Note that the PIN will always be a 6-digit number, - zero-padded to 6 digits. This is for harmony with - the later specification. - - Possible errors: org.bluez.Error.Rejected - org.bluez.Error.Canceled - - uint32 RequestPasskey(object device) - - This method gets called when the service daemon - 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, - uint16 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. - - Note that the passkey will always be a 6-digit number, - so the display should be zero-padded at the start if - the value contains less than 6 digits. - - void RequestConfirmation(object device, uint32 passkey) - - This method gets called when the service daemon - 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. - - Note that the passkey will always be a 6-digit number, - so the display should be zero-padded at the start if - the value contains less than 6 digits. - - Possible errors: org.bluez.Error.Rejected - org.bluez.Error.Canceled - - void RequestAuthorization(object device) - - This method gets called to request the user to - authorize an incoming pairing attempt which - would in other circumstances trigger the just-works - model, or when the user plugged in a device that - implements cable pairing. In the latter case, the - device would not be connected to the adapter via - Bluetooth yet. - - Possible errors: org.bluez.Error.Rejected - org.bluez.Error.Canceled - - void AuthorizeService(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 Cancel() - - This method gets called to indicate that the agent - request failed before a reply was returned. diff --git a/doc/battery-api.txt b/doc/battery-api.txt deleted file mode 100644 index 9a6b4fd3931da87632664ae5e870cd432b35c855..0000000000000000000000000000000000000000 --- a/doc/battery-api.txt +++ /dev/null @@ -1,69 +0,0 @@ -BlueZ D-Bus Battery API description -*********************************** - - -Battery hierarchy -================= - -Service org.bluez -Interface org.bluez.Battery1 -Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX - -Properties byte Percentage [readonly] - - The percentage of battery left as an unsigned 8-bit integer. - - string Source [readonly, optional, experimental] - - Describes where the battery information comes from - This property is informational only and may be useful - for debugging purposes. - Providers from BatteryProvider1 may make use of this - property to indicate where the battery report comes from - (e.g. "HFP 1.7", "HID", or the profile UUID). - - -Battery Provider Manager hierarchy -================================== -A battery provider starts by registering itself as a battery provider with the -RegisterBatteryProvider method passing an object path as the provider ID. Then, -it can start exposing org.bluez.BatteryProvider1 objects having the path -starting with the given provider ID. It can also remove objects at any time. -The objects and their properties exposed by battery providers will be reflected -on org.bluez.Battery1 interface. - -BlueZ will stop monitoring these exposed and removed objects after -UnregisterBatteryProvider is called for that provider ID. - -Service org.bluez -Interface org.bluez.BatteryProviderManager1 [experimental] -Object path /org/bluez/{hci0,hci1,...} - -Methods void RegisterBatteryProvider(object provider) - - This registers a battery provider. A registered - battery provider can then expose objects with - org.bluez.BatteryProvider1 interface described below. - - void UnregisterBatteryProvider(object provider) - - This unregisters a battery provider. After - unregistration, the BatteryProvider1 objects provided - by this client are ignored by BlueZ. - - -Battery Provider hierarchy -========================== - -Service <client D-Bus address> -Interface org.bluez.BatteryProvider1 [experimental] -Object path {provider_root}/{unique battery object path} - -Properties Objects provided on this interface contain the same properties - as org.bluez.Battery1 interface. Additionally, this interface - needs to have the Device property indicating the object path - of the device this battery provides. - - object Device [readonly] - - The object path of the device that has this battery. diff --git a/doc/ci.config b/doc/ci.config deleted file mode 100644 index 31e49ba969b20189378e3fb51e51b3f01867bd8b..0000000000000000000000000000000000000000 --- a/doc/ci.config +++ /dev/null @@ -1,122 +0,0 @@ -############################################################# -# # -# This config file is for testing bluetooth build only. # -# # -############################################################# - -CONFIG_VIRTIO=y -CONFIG_VIRTIO_PCI=y - -CONFIG_NET=y -CONFIG_INET=y - -CONFIG_NET_9P=y -CONFIG_NET_9P_VIRTIO=y - -CONFIG_9P_FS=y -CONFIG_9P_FS_POSIX_ACL=y - -CONFIG_GPIOLIB=y - -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_PCI=y -CONFIG_SERIAL_8250_NR_UARTS=4 - -CONFIG_SERIAL_DEV_BUS=y - -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_TMPFS_XATTR=y - -CONFIG_DEVTMPFS=y -CONFIG_DEBUG_FS=y - -CONFIG_MMC=y - -CONFIG_RPMSG=y -CONFIG_QCOM_WCNSS_CTRL=y - -CONFIG_PCMCIA=y - -CONFIG_ISDN_CAPI=y - -CONFIG_6LOWPAN=y - -CONFIG_LEDS_CLASS=y - -CONFIG_USB=y - -CONFIG_BT=y -CONFIG_BT_BREDR=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=y -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_HIDP=y -CONFIG_BT_LE=y -CONFIG_BT_MSFTEXT=y -CONFIG_BT_HS=y -CONFIG_BT_CMTP=y -CONFIG_BT_6LOWPAN=y -CONFIG_BT_LEDS=y -CONFIG_BT_FEATURE_DEBUG=y - -CONFIG_BT_HCIVHCI=y - -CONFIG_BT_HCIBTUSB=y -CONFIG_BT_HCIBTUSB_AUTOSUSPEND=y -CONFIG_BT_HCIBTUSB_MTK=y -CONFIG_BT_HCIBCM203X=y -CONFIG_BT_HCIBPA10X=y -CONFIG_BT_MRVL=y -CONFIG_BT_ATH3K=y - -CONFIG_BT_HCIUART=y -CONFIG_BT_HCIUART_SERDEV=y -CONFIG_BT_HCIUART_H4=y -CONFIG_BT_HCIUART_BCSP=y -CONFIG_BT_HCIUART_ATH3K=y -CONFIG_BT_HCIUART_AG6XX=y -CONFIG_BT_HCIUART_NOKIA=y -CONFIG_BT_HCIUART_LL=y -CONFIG_BT_HCIUART_3WIRE=y -CONFIG_BT_HCIUART_INTEL=y -CONFIG_BT_HCIUART_BCM=y -CONFIG_BT_HCIUART_RTL=y -CONFIG_BT_HCIUART_QCA=y -CONFIG_BT_HCIUART_MRVL=y -CONFIG_BT_MTKUART=y - -CONFIG_BT_HCIBFUSB=y - -CONFIG_BT_HCIBTSDIO=y -CONFIG_BT_MRVL_SDIO=y -CONFIG_BT_MTKSDIO=y - -CONFIG_BT_HCIDTL1=y -CONFIG_BT_HCIBT3C=y -CONFIG_BT_HCIBLUECARD=y - -CONFIG_BT_QCOMSMD=y - -CONFIG_BT_VIRTIO=y - -CONFIG_CRYPTO_CMAC=y -CONFIG_CRYPTO_USER_API=y -CONFIG_CRYPTO_USER_API_HASH=y -CONFIG_CRYPTO_USER_API_SKCIPHER=y - -CONFIG_UNIX=y - -CONFIG_UHID=y - -CONFIG_LOCKDEP_SUPPORT=y -CONFIG_DEBUG_SPINLOCK=y -CONFIG_DEBUG_LOCK_ALLOC=y -CONFIG_PROVE_LOCKING=y -CONFIG_LOCKDEP=y -CONFIG_DEBUG_MUTEXES=y - -CONFIG_OF=y diff --git a/doc/coding-style.txt b/doc/coding-style.txt deleted file mode 100644 index e73158840ff6da6f2748c61c7c61afa7776c3a89..0000000000000000000000000000000000000000 --- a/doc/coding-style.txt +++ /dev/null @@ -1,279 +0,0 @@ -BlueZ coding style -****************** - -Every project has its coding style, and BlueZ is not an exception. This -document describes the preferred coding style for BlueZ code, in order to keep -some level of consistency among developers so that code can be easily -understood and maintained. - -First of all, BlueZ coding style must follow every rule for Linux kernel -(https://www.kernel.org/doc/Documentation/process/coding-style.rst). There also -exists a tool named checkpatch.pl to help you check the compliance with it. -Just type "checkpatch.pl --no-tree patch_name" to check your patch. In theory, -you need to clean up all the warnings and errors except this one: "ERROR: -Missing Signed-off-by: line(s)". BlueZ does not used Signed-Off lines, so -including them is actually an error. In certain circumstances one can ignore -the 80 character per line limit. This is generally only allowed if the -alternative would make the code even less readable. - -Besides the kernel coding style above, BlueZ has special flavors for its own. -Some of them are mandatory (marked as 'M'), while some others are optional -(marked as 'O'), but generally preferred. - -M1: Blank line before and after an if/while/do/for statement -============================================================ - -There should be a blank line before if statement unless the if is nested and -not preceded by an expression or variable declaration. - -Example: -1) -a = 1; -if (b) { // wrong - -2) -a = 1 - -if (b) { -} -a = 2; // wrong - -3) -if (a) { - if (b) // correct - -4) -b = 2; - -if (a) { // correct - -} - -b = 3; - -The only exception to this rule applies when a variable is being checked for -errors as such: - -err = stat(filename, &st); -if (err || !S_ISDIR(st.st_mode)) - return; - -M2: Multiple line comment -========================= - -If your comment has more than one line, please start it from the second line. - -Example: -/* - * first line comment // correct - * ... - * last line comment - */ - - -M3: Space before and after operator -=================================== - -There should be a space before and after each operator. - -Example: -a + b; // correct - - -M4: Wrap long lines -=================== - -If your condition in if, while, for statement or a function declaration is too -long to fit in one line, the new line needs to be indented not aligned with the -body. - -Example: -1) -if ((adapter->supported_settings & MGMT_SETTING_SSP) && - !(adapter->current_settings & MGMT_SETTING_SSP)) // wrong - -2) -if ((adapter->supported_settings & MGMT_SETTING_SSP) && - !(adapter->current_settings & MGMT_SETTING_SSP)) - -3) -void btd_adapter_register_pin_cb(struct btd_adapter *adapter, - btd_adapter_pin_cb_t cb) // wrong - -4) -void btd_adapter_register_pin_cb(struct btd_adapter *adapter, - btd_adapter_pin_cb_t cb) - -The referred style for line wrapping is to indent as far as possible to the -right without hitting the 80 columns limit. - -M5: Space when doing type casting -================================= - -There should be a space between new type and variable. - -Example: -1) -a = (int *)b; // wrong -2) -a = (int *) b; // correct - - -M6: Don't initialize variable unnecessarily -=========================================== - -When declaring a variable, try not to initialize it unless necessary. - -Example: -int i = 1; // wrong - -for (i = 0; i < 3; i++) { -} - -M7: Follow the order of include header elements -=============================================== - -When writing an include header the various elements should be in the following -order: - - #includes - - forward declarations - - #defines - - enums - - typedefs - - function declarations and inline function definitions - -M8: Internal headers must not use include guards -================================================ - -Any time when creating a new header file with non-public API, that header -must not contain include guards. - -M9: Naming of enums -=================== - -Enums must have a descriptive name. The enum type should be small caps and -it should not be typedef-ed. Enum contents should be in CAPITAL letters and -prefixed by the enum type name. - -Example: - -enum animal_type { - ANIMAL_TYPE_FOUR_LEGS, - ANIMAL_TYPE_EIGHT_LEGS, - ANIMAL_TYPE_TWO_LEGS, -}; - -If the enum contents have values (e.g. from specification) the formatting -should be as follows: - -enum animal_type { - ANIMAL_TYPE_FOUR_LEGS = 4, - ANIMAL_TYPE_EIGHT_LEGS = 8, - ANIMAL_TYPE_TWO_LEGS = 2, -}; - -M10: Enum as switch variable -============================ - -If the variable of a switch is an enum, you must include all values in -switch body even if providing default. This is enforced by compiler option -enabling extra warning in such case. The reason for this is to ensure that if -later on enum is modified and one forget to change the switch accordingly, the -compiler will complain the new added type hasn't been handled. - -Example: - -enum animal_type { - ANIMAL_TYPE_FOUR_LEGS = 4, - ANIMAL_TYPE_EIGHT_LEGS = 8, - ANIMAL_TYPE_TWO_LEGS = 2, -}; - -enum animal_type t; - -switch (t) { // OK -case ANIMAL_TYPE_FOUR_LEGS: - ... - break; -case ANIMAL_TYPE_EIGHT_LEGS: - ... - break; -case ANIMAL_TYPE_TWO_LEGS: - ... - break; -default: - break; -} - -switch (t) { // Wrong -case ANIMAL_TYPE_FOUR_LEGS: - ... - break; -case ANIMAL_TYPE_TWO_LEGS: - ... - break; -default: - break; -} - -However if the enum comes from an external header file outside BlueZ, such as -Android headers, we cannot make any assumption of how the enum is defined and -this rule might not apply. - -M11: Always use parenthesis with sizeof -======================================= - -The expression argument to the sizeof operator should always be in -parenthesis, too. - -Example: -1) -memset(stuff, 0, sizeof(*stuff)); - -2) -memset(stuff, 0, sizeof *stuff); // Wrong - -M12: Use void if function has no parameters -=========================================== - -A function with no parameters must use void in the parameter list. - -Example: -1) -void foo(void) -{ -} - -2) -void foo() // Wrong -{ -} - -O1: Try to avoid complex if body -================================ - -It's better not to have a complicated statement for if. You may judge its -contrary condition and return | break | continue | goto ASAP. - -Example: -1) -if (device) { // worse - memset(&eir_data, 0, sizeof(eir_data)); - if (eir_len > 0) - eir_parse(&eir_data, ev->eir, eir_len); - ... -} else { - error("Unable to get device object for %s", addr); - return; -} - -2) -if (!device) { - error("Unable to get device object for %s", addr); - return; -} - -memset(&eir_data, 0, sizeof(eir_data)); -if (eir_len > 0) - eir_parse(&eir_data, ev->eir, eir_len); -... diff --git a/doc/device-api.txt b/doc/device-api.txt deleted file mode 100644 index 628accb8a572f3984835e5997d306685aebdd8a5..0000000000000000000000000000000000000000 --- a/doc/device-api.txt +++ /dev/null @@ -1,283 +0,0 @@ -BlueZ D-Bus Device API description -********************************** - - -Device hierarchy -================ - -Service org.bluez -Interface org.bluez.Device1 -Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX - -Methods void Connect() - - This is a generic method to connect any profiles - the remote device supports that can be connected - to and have been flagged as auto-connectable on - our side. If only subset of profiles is already - connected it will try to connect currently disconnected - ones. - - If at least one profile was connected successfully this - method will indicate success. - - For dual-mode devices only one bearer is connected at - time, the conditions are in the following order: - - 1. Connect the disconnected bearer if already - connected. - - 2. Connect first the bonded bearer. If no - bearers are bonded or both are skip and check - latest seen bearer. - - 3. Connect last seen bearer, in case the - timestamps are the same BR/EDR takes - precedence. - - Possible errors: org.bluez.Error.NotReady - org.bluez.Error.Failed - org.bluez.Error.InProgress - org.bluez.Error.AlreadyConnected - - void Disconnect() - - This method gracefully disconnects all connected - profiles and then terminates low-level ACL connection. - - ACL connection will be terminated even if some profiles - were not disconnected properly e.g. due to misbehaving - device. - - This method can be also used to cancel a preceding - Connect call before a reply to it has been received. - - For non-trusted devices connected over LE bearer calling - this method will disable incoming connections until - Connect method is called again. - - Possible errors: org.bluez.Error.NotConnected - - void ConnectProfile(string uuid) - - This method connects a specific profile of this - device. The UUID provided is the remote service - UUID for the profile. - - Possible errors: org.bluez.Error.Failed - org.bluez.Error.InProgress - org.bluez.Error.InvalidArguments - org.bluez.Error.NotAvailable - org.bluez.Error.NotReady - - void DisconnectProfile(string uuid) - - This method disconnects a specific profile of - this device. The profile needs to be registered - client profile. - - There is no connection tracking for a profile, so - as long as the profile is registered this will always - succeed. - - Possible errors: org.bluez.Error.Failed - org.bluez.Error.InProgress - org.bluez.Error.InvalidArguments - org.bluez.Error.NotSupported - - void Pair() - - This method will connect to the remote device, - initiate pairing and then retrieve all SDP records - (or GATT primary services). - - If the application has registered its own agent, - then that specific agent will be used. Otherwise - it will use the default agent. - - Only for applications like a pairing wizard it - would make sense to have its own agent. In almost - all other cases the default agent will handle - this just fine. - - In case there is no application agent and also - no default agent present, this method will fail. - - Possible errors: org.bluez.Error.InvalidArguments - org.bluez.Error.Failed - org.bluez.Error.AlreadyExists - org.bluez.Error.AuthenticationCanceled - org.bluez.Error.AuthenticationFailed - org.bluez.Error.AuthenticationRejected - org.bluez.Error.AuthenticationTimeout - org.bluez.Error.ConnectionAttemptFailed - - void CancelPairing() - - This method can be used to cancel a pairing - operation initiated by the Pair method. - - Possible errors: org.bluez.Error.DoesNotExist - org.bluez.Error.Failed - -Properties string Address [readonly] - - The Bluetooth device address of the remote device. - - string AddressType [readonly] - - The Bluetooth device Address Type. For dual-mode and - BR/EDR only devices this defaults to "public". Single - mode LE devices may have either value. If remote device - uses privacy than before pairing this represents address - type used for connection and Identity Address after - pairing. - - Possible values: - "public" - Public address - "random" - Random address - - string Name [readonly, optional] - - The Bluetooth remote name. This value can not be - changed. Use the Alias property instead. - - This value is only present for completeness. It is - better to always use the Alias property when - displaying the devices name. - - If the Alias property is unset, it will reflect - this value which makes it more convenient. - - string Icon [readonly, optional] - - Proposed icon name according to the freedesktop.org - icon naming specification. - - uint32 Class [readonly, optional] - - The Bluetooth class of device of the remote device. - - uint16 Appearance [readonly, optional] - - External appearance of device, as found on GAP service. - - array{string} UUIDs [readonly, optional] - - List of 128-bit UUIDs that represents the available - remote services. - - boolean Paired [readonly] - - Indicates if the remote device is paired. Paired means - the pairing process where devices exchange the - information to establish an encrypted connection has - been completed. - - boolean Bonded [readonly] - - Indicates if the remote device is bonded. Bonded means - the information exchanged on pairing process has been - stored and will be persisted. - - boolean Connected [readonly] - - Indicates if the remote device is currently connected. - A PropertiesChanged 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. - - boolean Blocked [readwrite] - - If set to true any incoming connections from the - device will be immediately rejected. Any device - drivers will also be removed and no new ones will - be probed as long as the device is blocked. - - boolean WakeAllowed [readwrite] - - If set to true this device will be allowed to wake the - host from system suspend. - - 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 resetting the alias with an empty string, the - property will default back to the remote name. - - object Adapter [readonly] - - The object path of the adapter the device belongs to. - - boolean LegacyPairing [readonly] - - Set to true if the device only supports the pre-2.1 - pairing mechanism. This property is useful during - device discovery to anticipate whether legacy or - simple pairing will occur if pairing is initiated. - - Note that this property can exhibit false-positives - in the case of Bluetooth 2.1 (or newer) devices that - have disabled Extended Inquiry Response support. - - string Modalias [readonly, optional] - - Remote Device ID information in modalias format - used by the kernel and udev. - - int16 RSSI [readonly, optional] - - Received Signal Strength Indicator of the remote - device (inquiry or advertising). - - int16 TxPower [readonly, optional] - - Advertised transmitted power level (inquiry or - advertising). - - dict ManufacturerData [readonly, optional] - - Manufacturer specific advertisement data. Keys are - 16 bits Manufacturer ID followed by its byte array - value. - - dict ServiceData [readonly, optional] - - Service advertisement data. Keys are the UUIDs in - string format followed by its byte array value. - - bool ServicesResolved [readonly] - - Indicate whether or not service discovery has been - resolved. - - array{byte} AdvertisingFlags [readonly, experimental] - - The Advertising Data Flags of the remote device. - - dict AdvertisingData [readonly, experimental] - - The Advertising Data of the remote device. Keys are - are 8 bits AD Type followed by data as byte array. - - Note: Only types considered safe to be handled by - application are exposed. - - Possible values: - <type> <byte array> - ... - - Example: - <Transport Discovery> <Organization Flags...> - 0x26 0x01 0x01... diff --git a/doc/errors.txt b/doc/errors.txt deleted file mode 100644 index 047610c741de12961e6e7a5b023b08c54f16b9c5..0000000000000000000000000000000000000000 --- a/doc/errors.txt +++ /dev/null @@ -1,233 +0,0 @@ -D-Bus Method Return Error Codes -=============================== - -The motivation of having detailed error is to provide context-based failure -reasons along with D-Bus method return so that D-Bus clients can build metrics -and optimize their application based on these failure reasons. For instance, a -client can build retry mechanism for a connection failure or improve the -bottleneck of use scenario based on actionable metrics. - -These error codes are context-based but not necessarily tied to interface or -method calls. For instance, if a pairing request failed due to connection -failure, connection error would be attached to the method return of Pair(). - -BR/EDR connection already connected -=================================== - errno: EALREADY, EISCONN - - Either the profile is already connected or ACL connection is in place. - -BR/EDR connection page timeout -============================== - errno: EHOSTDOWN - - Failed due to page timeout. - -BR/EDR connection profile unavailable -===================================== - errno: ENOPROTOOPT - - Failed to find connectable services or the target service. - -BR/EDR connection SDP search -============================ - errno: none - - Failed to complete the SDP search. - -BR/EDR connection create socket -=============================== - errno: EIO - - Failed to create or connect to BT IO socket. This can also indicate - hardware failure in the controller. - -BR/EDR connection invalid arguments -=================================== - errno: EHOSTUNREACH - - Failed due to invalid arguments. - -BR/EDR connection not powered -============================= - errno: EHOSTUNREACH - - Failed due to adapter not powered. - -BR/EDR connection not supported -=============================== - errno: EOPNOTSUPP, EPROTONOSUPPORT - - Failed due to unsupported state transition of L2CAP channel or other - features either by the local host or the remote. - -BR/EDR connection bad socket -============================ - errno: EBADFD - - Failed due to the socket is in bad state. - -BR/EDR connection memory allocation -=================================== - errno: ENOMEM - - Failed to allocate memory in either host stack or controller. - -BR/EDR connection busy -====================== - errno: EBUSY - - Failed due to other ongoing operations, such as pairing, busy L2CAP - channel or the operation disallowed by the controller. - -BR/EDR connection concurrent connection limit -============================================= - errno: EMLINK - - Failed due to reaching the concurrent connection limit to a device. - -BR/EDR connection timeout -========================= - errno: ETIMEDOUT - - Failed due to connection timeout - -BR/EDR connection refused -========================= - errno: ECONNREFUSED - - Refused by the remote device due to limited resource, security reason - or unacceptable address type. - -BR/EDR connection aborted by remote -=================================== - errno: ECONNRESET - - Terminated by the remote device due to limited resource or power off. - -BR/EDR connection aborted by local -================================== - errno: ECONNABORTED - - Aborted by the local host. - -BR/EDR connection LMP protocol error -==================================== - errno: EPROTO - - Failed due to LMP protocol error. - -BR/EDR connection canceled -========================== - errno: none - - Failed due to cancellation caused by adapter drop, unexpected device - drop, orincoming disconnection request before connection request is - completed. - -BR/EDR connection unknown error -=============================== - errno: ENOSYS - - Failed due to unknown reason. - -LE connection invalid arguments -=============================== - errno: EINVAL - - Failed due to invalid arguments. - -LE connection not powered -========================= - errno: EHOSTUNREACH - - Failed due to adapter not powered. - -LE connection not supported -=========================== - errno: EOPNOTSUPP, EPROTONOSUPPORT - - Failed due to unsupported state transition of L2CAP channel or other - features (e.g. LE features) either by the local host or the remote. - -LE connection already connected -=============================== - errno: EALREADY, EISCONN - - Either the BT IO is already connected or LE link connection in place. - -LE connection bad socket -======================== - errno: EBADFD - - Failed due to the socket is in bad state. - -LE connection memory allocation -=============================== - errno: ENOMEM - - Failed to allocate memory in either host stack or controller. - -LE connection busy -================== - errno: EBUSY - - Failed due to other ongoing operations, such as pairing, connecting, - busy L2CAP channel or the operation disallowed by the controller. - -LE connection refused -===================== - errno: ECONNREFUSED - - Failed due to that LE is not enabled or the attempt is refused by the - remote device due to limited resource, security reason or unacceptable - address type. - -LE connection create socket -=========================== - errno: EIO - - Failed to create or connect to BT IO socket. This can also indicate - hardware failure in the controller. - -LE connection timeout -===================== - errno: ETIMEDOUT - - Failed due to connection timeout - -LE connection concurrent connection limit -========================================= - errno: EMLINK - - Failed due to reaching the synchronous connection limit to a device. - -LE connection abort by remote -============================= - errno: ECONNRESET - - Aborted by the remote device due to limited resource or power off. - -LE connection abort by local -============================ - errno: ECONNABORTED - - Aborted by the local host. - -LE connection link layer protocol error -======================================= - errno: EPROTO - - Failed due to link layer protocol error. - -LE connection GATT browsing -=========================== - errno: none - - Failed to complete the GATT browsing. - -LE connection unknown error -=========================== - errno: ENOSYS - - Failed due to unknown reason. diff --git a/doc/gatt-api.txt b/doc/gatt-api.txt deleted file mode 100644 index 5042c54704e4be5467f60b675d2069fbb31e653b..0000000000000000000000000000000000000000 --- a/doc/gatt-api.txt +++ /dev/null @@ -1,509 +0,0 @@ -BlueZ D-Bus GATT API description -******************************** - -GATT local and remote services share the same high-level D-Bus API. Local -refers to GATT based service exported by a BlueZ plugin or an external -application. Remote refers to GATT services exported by the peer. - -BlueZ acts as a proxy, translating ATT operations to D-Bus method calls and -Properties (or the opposite). Support for D-Bus Object Manager is mandatory for -external services to allow seamless GATT declarations (Service, Characteristic -and Descriptors) discovery. Each GATT service tree is required to export a D-Bus -Object Manager at its root that is solely responsible for the objects that -belong to that service. - -Releasing a registered GATT service is not defined yet. Any API extension -should avoid breaking the defined API, and if possible keep an unified GATT -remote and local services representation. - -Service hierarchy -================= - -GATT remote and local service representation. Object path for local services -is freely definable. - -External applications implementing local services must register the services -using GattManager1 registration method and must implement the methods and -properties defined in GattService1 interface. - -Service org.bluez -Interface org.bluez.GattService1 -Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX - -Properties string UUID [read-only] - - 128-bit service UUID. - - boolean Primary [read-only] - - Indicates whether or not this GATT service is a - primary service. If false, the service is secondary. - - object Device [read-only, optional] - - Object path of the Bluetooth device the service - belongs to. Only present on services from remote - devices. - - array{object} Includes [read-only, optional] - - Array of object paths representing the included - services of this service. - - uint16 Handle [read-write, optional] (Server Only) - - Service handle. When available in the server it - would attempt to use to allocate into the database - which may fail, to auto allocate the value 0x0000 - shall be used which will cause the allocated handle to - be set once registered. - - -Characteristic hierarchy -======================== - -For local GATT defined services, the object paths need to follow the service -path hierarchy and are freely definable. - -Service org.bluez -Interface org.bluez.GattCharacteristic1 -Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX/charYYYY - -Methods array{byte} ReadValue(dict options) - - Issues a request to read the value of the - characteristic and returns the value if the - operation was successful. - - Possible options: "offset": uint16 offset - "mtu": Exchanged MTU (Server only) - "device": Object Device (Server only) - - Possible Errors: org.bluez.Error.Failed(string ecode) - org.bluez.Error.InProgress - org.bluez.Error.NotPermitted - org.bluez.Error.NotAuthorized - org.bluez.Error.InvalidOffset - org.bluez.Error.NotSupported - - Possible Error Code: string 0x80 - 0x9f - - void WriteValue(array{byte} value, dict options) - - Issues a request to write the value of the - characteristic. - - Possible options: "offset": Start offset - "type": string - Possible values: - "command": Write without - response - "request": Write with response - "reliable": Reliable Write - "mtu": Exchanged MTU (Server only) - "device": Device path (Server only) - "link": Link type (Server only) - "prepare-authorize": True if prepare - authorization - request - - Possible Errors: org.bluez.Error.Failed(string ecode) - org.bluez.Error.InProgress - org.bluez.Error.NotPermitted - org.bluez.Error.InvalidValueLength - org.bluez.Error.NotAuthorized - org.bluez.Error.NotSupported - - Possible Error Code: string 0x80 - 0x9f - - fd, uint16 AcquireWrite(dict options) [optional] - - Acquire file descriptor and MTU for writing. Only - sockets are supported. Usage of WriteValue will be - locked causing it to return NotPermitted error. - - For server the MTU returned shall be equal or smaller - than the negotiated MTU. - - For client it only works with characteristic that has - WriteAcquired property which relies on - write-without-response Flag. - - To release the lock the client shall close the file - descriptor, a HUP is generated in case the device - is disconnected. - - Note: the MTU can only be negotiated once and is - symmetric therefore this method may be delayed in - order to have the exchange MTU completed, because of - that the file descriptor is closed during - reconnections as the MTU has to be renegotiated. - - Possible options: "device": Object Device (Server only) - "mtu": Exchanged MTU (Server only) - "link": Link type (Server only) - - Possible Errors: org.bluez.Error.Failed - org.bluez.Error.NotSupported - - fd, uint16 AcquireNotify(dict options) [optional] - - Acquire file descriptor and MTU for notify. Only - sockets are support. Usage of StartNotify will be locked - causing it to return NotPermitted error. - - For server the MTU returned shall be equal or smaller - than the negotiated MTU. - - Only works with characteristic that has NotifyAcquired - which relies on notify Flag and no other client have - called StartNotify. - - Notification are enabled during this procedure so - StartNotify shall not be called, any notification - will be dispatched via file descriptor therefore the - Value property is not affected during the time where - notify has been acquired. - - To release the lock the client shall close the file - descriptor, a HUP is generated in case the device - is disconnected. - - Note: the MTU can only be negotiated once and is - symmetric therefore this method may be delayed in - order to have the exchange MTU completed, because of - that the file descriptor is closed during - reconnections as the MTU has to be renegotiated. - - Possible options: "device": Object Device (Server only) - "mtu": Exchanged MTU (Server only) - "link": Link type (Server only) - - Possible Errors: org.bluez.Error.Failed - org.bluez.Error.NotSupported - - void StartNotify() - - Starts a notification session from this characteristic - if it supports value notifications or indications. - - Possible Errors: org.bluez.Error.Failed - org.bluez.Error.NotPermitted - org.bluez.Error.InProgress - org.bluez.Error.NotConnected - org.bluez.Error.NotSupported - - void StopNotify() - - This method will cancel any previous StartNotify - transaction. Note that notifications from a - characteristic are shared between sessions thus - calling StopNotify will release a single session. - - Possible Errors: org.bluez.Error.Failed - - void Confirm() [optional] (Server only) - - This method doesn't expect a reply so it is just a - confirmation that value was received. - - Possible Errors: org.bluez.Error.Failed - -Properties string UUID [read-only] - - 128-bit characteristic UUID. - - object Service [read-only] - - Object path of the GATT service the characteristic - belongs to. - - array{byte} Value [read-only, optional] - - The cached value of the characteristic. This property - gets updated only after a successful read request and - when a notification or indication is received, upon - which a PropertiesChanged signal will be emitted. - - boolean WriteAcquired [read-only, optional] - - True, if this characteristic has been acquired by any - client using AcquireWrite. - - For client properties is ommited in case - 'write-without-response' flag is not set. - - For server the presence of this property indicates - that AcquireWrite is supported. - - boolean NotifyAcquired [read-only, optional] - - True, if this characteristic has been acquired by any - client using AcquireNotify. - - For client this properties is ommited in case 'notify' - flag is not set. - - For server the presence of this property indicates - that AcquireNotify is supported. - - boolean Notifying [read-only, optional] - - True, if notifications or indications on this - characteristic are currently enabled. - - array{string} Flags [read-only] - - Defines how the characteristic value can be used. See - Core spec "Table 3.5: Characteristic Properties bit - field", and "Table 3.8: Characteristic Extended - Properties bit field". - - The "x-notify" and "x-indicate" flags restrict access - to notifications and indications by imposing write - restrictions on a characteristic's client - characteristic configuration descriptor. - - Allowed values: - - "broadcast" - "read" - "write-without-response" - "write" - "notify" - "indicate" - "authenticated-signed-writes" - "extended-properties" - "reliable-write" - "writable-auxiliaries" - "encrypt-read" - "encrypt-write" - "encrypt-notify" (Server only) - "encrypt-indicate" (Server only) - "encrypt-authenticated-read" - "encrypt-authenticated-write" - "encrypt-authenticated-notify" (Server only) - "encrypt-authenticated-indicate" (Server only) - "secure-read" (Server only) - "secure-write" (Server only) - "secure-notify" (Server only) - "secure-indicate" (Server only) - "authorize" - - uint16 Handle [read-write, optional] (Server Only) - - Characteristic handle. When available in the server it - would attempt to use to allocate into the database - which may fail, to auto allocate the value 0x0000 - shall be used which will cause the allocated handle to - be set once registered. - - uint16 MTU [read-only] - - Characteristic MTU, this is valid both for ReadValue - and WriteValue but either method can use long - procedures when supported. - -Characteristic Descriptors hierarchy -==================================== - -Local or remote GATT characteristic descriptors hierarchy. - -Service org.bluez -Interface org.bluez.GattDescriptor1 -Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX/charYYYY/descriptorZZZ - -Methods array{byte} ReadValue(dict flags) - - Issues a request to read the value of the - characteristic and returns the value if the - operation was successful. - - Possible options: "offset": Start offset - "device": Device path (Server only) - "link": Link type (Server only) - - Possible Errors: org.bluez.Error.Failed - org.bluez.Error.InProgress - org.bluez.Error.NotPermitted - org.bluez.Error.NotAuthorized - org.bluez.Error.NotSupported - - void WriteValue(array{byte} value, dict flags) - - Issues a request to write the value of the - characteristic. - - Possible options: "offset": Start offset - "device": Device path (Server only) - "link": Link type (Server only) - "prepare-authorize": boolean Is prepare - authorization - request - - Possible Errors: org.bluez.Error.Failed - org.bluez.Error.InProgress - org.bluez.Error.NotPermitted - org.bluez.Error.InvalidValueLength - org.bluez.Error.NotAuthorized - org.bluez.Error.NotSupported - -Properties string UUID [read-only] - - 128-bit descriptor UUID. - - object Characteristic [read-only] - - Object path of the GATT characteristic the descriptor - belongs to. - - array{byte} Value [read-only, optional] - - The cached value of the descriptor. This property - gets updated only after a successful read request, upon - which a PropertiesChanged signal will be emitted. - - array{string} Flags [read-only] - - Defines how the descriptor value can be used. - - Possible values: - - "read" - "write" - "encrypt-read" - "encrypt-write" - "encrypt-authenticated-read" - "encrypt-authenticated-write" - "secure-read" (Server Only) - "secure-write" (Server Only) - "authorize" - - uint16 Handle [read-write, optional] (Server Only) - - Characteristic handle. When available in the server it - would attempt to use to allocate into the database - which may fail, to auto allocate the value 0x0000 - shall be used which will cause the allocated handle to - be set once registered. - -GATT Profile hierarchy -===================== - -Local profile (GATT client) instance. By registering this type of object -an application effectively indicates support for a specific GATT profile -and requests automatic connections to be established to devices -supporting it. - -Service <application dependent> -Interface org.bluez.GattProfile1 -Object path <application dependent> - -Methods void Release() - - This method gets called when the service daemon - unregisters the profile. The profile can use it to - do cleanup tasks. There is no need to unregister the - profile, because when this method gets called it has - already been unregistered. - -Properties array{string} UUIDs [read-only] - - 128-bit GATT service UUIDs to auto connect. - - -GATT Manager hierarchy -====================== - -GATT Manager allows external applications to register GATT services and -profiles. - -Registering a profile allows applications to subscribe to *remote* services. -These must implement the GattProfile1 interface defined above. - -Registering a service allows applications to publish a *local* GATT service, -which then becomes available to remote devices. A GATT service is represented by -a D-Bus object hierarchy where the root node corresponds to a service and the -child nodes represent characteristics and descriptors that belong to that -service. Each node must implement one of GattService1, GattCharacteristic1, -or GattDescriptor1 interfaces described above, based on the attribute it -represents. Each node must also implement the standard D-Bus Properties -interface to expose their properties. These objects collectively represent a -GATT service definition. - -To make service registration simple, BlueZ requires that all objects that belong -to a GATT service be grouped under a D-Bus Object Manager that solely manages -the objects of that service. Hence, the standard DBus.ObjectManager interface -must be available on the root service path. An example application hierarchy -containing two separate GATT services may look like this: - --> /com/example - | - org.freedesktop.DBus.ObjectManager - | - -> /com/example/service0 - | | - org.freedesktop.DBus.Properties - | | - org.bluez.GattService1 - | | - | -> /com/example/service0/char0 - | | - org.freedesktop.DBus.Properties - | | - org.bluez.GattCharacteristic1 - | | - | -> /com/example/service0/char1 - | | - org.freedesktop.DBus.Properties - | | - org.bluez.GattCharacteristic1 - | | - | -> /com/example/service0/char1/desc0 - | - org.freedesktop.DBus.Properties - | - org.bluez.GattDescriptor1 - | - -> /com/example/service1 - | - org.freedesktop.DBus.Properties - | - org.bluez.GattService1 - | - -> /com/example/service1/char0 - - org.freedesktop.DBus.Properties - - org.bluez.GattCharacteristic1 - -When a service is registered, BlueZ will automatically obtain information about -all objects using the service's Object Manager. Once a service has been -registered, the objects of a service should not be removed. If BlueZ receives an -InterfacesRemoved signal from a service's Object Manager, it will immediately -unregister the service. Similarly, if the application disconnects from the bus, -all of its registered services will be automatically unregistered. -InterfacesAdded signals will be ignored. - -Examples: - - Client - test/example-gatt-client - client/bluetoothctl - - Server - test/example-gatt-server - tools/gatt-service - - -Service org.bluez -Interface org.bluez.GattManager1 -Object path [variable prefix]/{hci0,hci1,...} - -Methods void RegisterApplication(object application, dict options) - - Registers a local GATT services hierarchy as described - above (GATT Server) and/or GATT profiles (GATT Client). - - The application object path together with the D-Bus - system bus connection ID define the identification of - the application registering a GATT based - service or profile. - - Possible errors: org.bluez.Error.InvalidArguments - org.bluez.Error.AlreadyExists - - void UnregisterApplication(object application) - - This unregisters the services 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.InvalidArguments - org.bluez.Error.DoesNotExist diff --git a/doc/hci.7 b/doc/hci.7 new file mode 100644 index 0000000000000000000000000000000000000000..06e377beb0d5ec0e74c1538cc6713d251f46628d --- /dev/null +++ b/doc/hci.7 @@ -0,0 +1,225 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "HCI" "7" "October 2024" "BlueZ" "Linux System Administration" +.SH NAME +hci \- Bluetooth HCI protocol +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +#include <sys/socket.h> +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> + +hci_socket = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +Bluetooth Host Controller Interface (HCI) is the standard protocol to +communicate with Bluetooth adapters. HCI protocol provides a uniform command +method for the Host to access Controller capabilities and to control connections +to other Controllers. +.SH SOCKET ADDRESS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +struct sockaddr_hci { + sa_family_t hci_family; + unsigned short hci_dev; + unsigned short hci_channel; +}; +.EE +.UNINDENT +.UNINDENT +.sp +Possible values for hci_channel: +.TS +box center; +l|l|l. +T{ +Define +T} T{ +Value +T} T{ +Description +T} +_ +T{ +\fBHCI_CHANNEL_RAW\fP +T} T{ +0x00 +T} T{ +Raw channel \- Used for raw HCI communication +T} +_ +T{ +\fBHCI_CHANNEL_USER\fP +T} T{ +0x01 +T} T{ +User channel \- Used for userspace HCI communication (disables kernel processing) +T} +_ +T{ +\fBHCI_CHANNEL_MONITOR\fP +T} T{ +0x02 +T} T{ +Monitor channel \- Used for monitoring HCI traffic (btmon(1)) +T} +_ +T{ +\fBHCI_CHANNEL_CONTROL\fP +T} T{ +0x03 +T} T{ +Control channel \- Used to manage local adapters (bluetoothd(7)) +T} +_ +T{ +\fBHCI_CHANNEL_LOGGING\fP +T} T{ +0x04 +T} T{ +Logging channel \- Used to inject logging messages (bluetoothd(7)) +T} +.TE +.sp +Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +struct sockaddr_hci addr; + +memset(&addr, 0, sizeof(addr)); +addr.hci_family = AF_BLUETOOTH; +addr.hci_dev = HCI_DEV_NONE; +addr.hci_channel = HCI_CHANNEL_CONTROL; +.EE +.UNINDENT +.UNINDENT +.SH SOCKET OPTIONS +.sp +The socket options listed below can be set by using \fBsetsockopt(2)\fP and read +with \fBgetsockopt(2)\fP with the socket level set to SOL_BLUETOOTH or SOL_HCI +(HCI_FILTER). +.SS HCI_FILTER (since Linux 2.6) +.sp +Filter by HCI events, requires hci_channel to be set to HCI_CHANNEL_RAW, +possible values: +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +struct hci_filter { + uint32_t type_mask; + uint32_t event_mask[2]; + uint16_t opcode; +}; +.EE +.UNINDENT +.UNINDENT +.sp +Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +struct hci_filter flt; + +memset(&flt, 0, sizeof(flt)); +flt.type_mask = 1 << BT_H4_EVT_PKT; +flt.event_mask[0] = 0xffffffff; +flt.event_mask[1] = 0xffffffff; + +setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)); +.EE +.UNINDENT +.UNINDENT +.SS BT_SNDBUF (since Linux 5.16) +.sp +Set send buffer size, requires hci_channel to be set to HCI_CHANNEL_MONITOR, +HCI_CHANNEL_CONTROL or HCI_CHANNEL_LOGGING. +.sp +Default value is 1028. +.sp +Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +uint16_t mtu = UINT16_MAX; +int err; + +err = setsockopt(fd, SOL_BLUETOOTH, BT_SNDMTU, &mtu, sizeof(mtu)); +.EE +.UNINDENT +.UNINDENT +.SS BT_RCVBUF (since Linux 5.16) +.sp +Set receive buffer size, requires hci_channel to be set to HCI_CHANNEL_MONITOR, +HCI_CHANNEL_CONTROL or HCI_CHANNEL_LOGGING. +.sp +Default value is 1028. +.sp +Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +uint16_t mtu; +socklen_t len; +int err; + +len = sizeof(mtu); +err = getsockopt(sock, SOL_BLUETOOTH, BT_RCVMTU, mtu, &len); +.EE +.UNINDENT +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH SEE ALSO +.sp +socket(7) +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/doc/hci.rst b/doc/hci.rst new file mode 100644 index 0000000000000000000000000000000000000000..d7f192a27d190dbe06c6c6453857c32e7ffa3e8a --- /dev/null +++ b/doc/hci.rst @@ -0,0 +1,152 @@ +=== +hci +=== + +---------------------- +Bluetooth HCI protocol +---------------------- + +:Version: BlueZ +:Copyright: Free use of this software is granted under ther terms of the GNU + Lesser General Public Licenses (LGPL). +:Date: October 2024 +:Manual section: 7 +:Manual group: Linux System Administration + +SYNOPSIS +======== + +.. code-block:: + + #include <sys/socket.h> + #include <bluetooth/bluetooth.h> + #include <bluetooth/hci.h> + + hci_socket = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); + +DESCRIPTION +=========== + +Bluetooth Host Controller Interface (HCI) is the standard protocol to +communicate with Bluetooth adapters. HCI protocol provides a uniform command +method for the Host to access Controller capabilities and to control connections +to other Controllers. + +SOCKET ADDRESS +============== + +.. code-block:: + + struct sockaddr_hci { + sa_family_t hci_family; + unsigned short hci_dev; + unsigned short hci_channel; + }; + +Possible values for hci_channel: + +.. csv-table:: + :header: "Define", "Value", "Description" + :widths: auto + + **HCI_CHANNEL_RAW**, 0x00, Raw channel - Used for raw HCI communication + **HCI_CHANNEL_USER**, 0x01, User channel - Used for userspace HCI communication (disables kernel processing) + **HCI_CHANNEL_MONITOR**, 0x02, Monitor channel - Used for monitoring HCI traffic (btmon(1)) + **HCI_CHANNEL_CONTROL**, 0x03, Control channel - Used to manage local adapters (bluetoothd(7)) + **HCI_CHANNEL_LOGGING**, 0x04, Logging channel - Used to inject logging messages (bluetoothd(7)) + +Example: + +.. code-block:: + + struct sockaddr_hci addr; + + memset(&addr, 0, sizeof(addr)); + addr.hci_family = AF_BLUETOOTH; + addr.hci_dev = HCI_DEV_NONE; + addr.hci_channel = HCI_CHANNEL_CONTROL; + +SOCKET OPTIONS +============== + +The socket options listed below can be set by using **setsockopt(2)** and read +with **getsockopt(2)** with the socket level set to SOL_BLUETOOTH or SOL_HCI +(HCI_FILTER). + +HCI_FILTER (since Linux 2.6) +---------------------------- + +Filter by HCI events, requires hci_channel to be set to HCI_CHANNEL_RAW, +possible values: + +.. code-block:: + + struct hci_filter { + uint32_t type_mask; + uint32_t event_mask[2]; + uint16_t opcode; + }; + +Example: + +.. code-block:: + + struct hci_filter flt; + + memset(&flt, 0, sizeof(flt)); + flt.type_mask = 1 << BT_H4_EVT_PKT; + flt.event_mask[0] = 0xffffffff; + flt.event_mask[1] = 0xffffffff; + + setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)); + +BT_SNDBUF (since Linux 5.16) +---------------------------- + +Set send buffer size, requires hci_channel to be set to HCI_CHANNEL_MONITOR, +HCI_CHANNEL_CONTROL or HCI_CHANNEL_LOGGING. + +Default value is 1028. + +Example: + +.. code-block:: + + uint16_t mtu = UINT16_MAX; + int err; + + err = setsockopt(fd, SOL_BLUETOOTH, BT_SNDMTU, &mtu, sizeof(mtu)); + +BT_RCVBUF (since Linux 5.16) +---------------------------- + +Set receive buffer size, requires hci_channel to be set to HCI_CHANNEL_MONITOR, +HCI_CHANNEL_CONTROL or HCI_CHANNEL_LOGGING. + +Default value is 1028. + +Example: + +.. code-block:: + + uint16_t mtu; + socklen_t len; + int err; + + len = sizeof(mtu); + err = getsockopt(sock, SOL_BLUETOOTH, BT_RCVMTU, mtu, &len); + +RESOURCES +========= + +http://www.bluez.org + +REPORTING BUGS +============== + +linux-bluetooth@vger.kernel.org + +SEE ALSO +======== + +socket(7) diff --git a/doc/input-api.txt b/doc/input-api.txt deleted file mode 100644 index 67da08b102c903c952d7c8a1272ffed3bcaee3f6..0000000000000000000000000000000000000000 --- a/doc/input-api.txt +++ /dev/null @@ -1,32 +0,0 @@ -BlueZ D-Bus Input API description -********************************* - -Input hierarchy -=============== - -Service org.bluez -Interface org.bluez.Input1 -Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX - -Properties string ReconnectMode [readonly] - - Determines the Connectability mode of the HID device as - defined by the HID Profile specification, Section 5.4.2. - - This mode is based in the two properties - HIDReconnectInitiate (see Section 5.3.4.6) and - HIDNormallyConnectable (see Section 5.3.4.14) which - define the following four possible values: - - "none" Device and host are not required to - automatically restore the connection. - - "host" Bluetooth HID host restores connection. - - "device" Bluetooth HID device restores - connection. - - "any" Bluetooth HID device shall attempt to - restore the lost connection, but - Bluetooth HID Host may also restore the - connection. diff --git a/doc/intel-variants.txt b/doc/intel-variants.txt deleted file mode 100644 index 4f51ca9f588739f6a39b0bb6d9580a069994e9ec..0000000000000000000000000000000000000000 --- a/doc/intel-variants.txt +++ /dev/null @@ -1,159 +0,0 @@ -Intel Hardware Varaints -======================= - -These are the list of Intel Bluetooth devices and its information. - -Some of devices were tested the following test cases: - Firmware loading after cold boot - Firmware loading after restart - Device discovery - Connection to LE Mouse - A2DP - HFP - Update to new firmware if available - -All Intel firmware can be found from linux-firmware git repo. -https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git - - -Device List ------------ - -Wilkins Peak (WP) -- HW ID: USB(0x8087:0x07dc) -- Device Type: Legacy ROM device -- Driver flag: BTUSB_INTEL_BROKEN_INITIAL_NCMD -- HW variant: 0x07 -- FW files: - WP2 B3 - intel/ibt-hw-37.7.10-fw-1.80.2.3.d.bseq - tested: Patch Version: 87 Release Version: 20.60.0.2 - 70353356f ("linux-firmware: Update firmware patch for Intel Bluetooth 7260 (B3/B4)") - WP2 B5 - intel/ibt-hw-37.7.10-fw-1.80.1.2d.d.bseq - tested: Patch Version: 42 Release Version: 20.60.0.2 - 629a5e089 ("linux-firmware: Update firmware patch for Intel Bluetooth 7260 (B5/B6)") - - WP1 B3 - intel/ibt-hw-37.7.10-fw-1.0.1.2d.d.bseq - - WP1 B3 - intel/ibt-hw-37.7.10-fw-1.0.2.3.d.bseq - - -Stone Peak (StP) -- HW ID: USB(0x8087:0x0a2a) -- Device Type: Legacy ROM device -- HW variant: 0x08 -- FW files: - StP - intel/ibt-hw-37.8.10-fw-1.10.2.27.d.bseq - - StP D1 - intel/ibt-hw-37.8.10-fw-1.10.3.11.e.bseq - tested: FW Build: REL_50_0002 Release Version: 20.60.0.2 - 9489f5524 ("linux-firmware: Update firmware patch for Intel Bluetooth 7265 (D0)") - - -Sandy Peak (SdP) -- HW ID: USB(0x8087:0x0aa7) -- Device Type: Legacy ROM device -- HCI Quirks: HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED -- HW variant: 0x08 - intel/ibt-hw-37.8.10-fw-22.50.19.14.f.bseq - tested: FW Patch Version: 0x42(66) - 195ecf149 ("linux-firmware: Intel BT 7265: Fix Security Issues") - - -Snow Field Peak (SfP) / Windstorm Peak (WsP) -- HW ID: USB(0x8087:0x0a2b) -- Device Type: Legacy Bootloader device -- HCI Quirks: HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED -- HW variant: 0x0b - SfP - intel/ibt-11-5.sfi - tested: FW Build: REL0522 Release Version: 20.100.0.3 - f0896585b ("linux-firmware: Update firmware patch for Intel Bluetooth 8260") -- HW variant: 0x0c - WsP - intel/ibt-12-16.sfi - tested: FW Build: REL1221 Release Version: 22.50.0.4 - 4116d72b9 ("linux-firmware: Update firmware file for Intel Bluetooth 8265") - tested: FW Build: REL0306 Release Version: 21.10.0.6 - 1f8ebdfc2 ("linux-firmware: Update firmware file for Intel Bluetooth 8265") - - -Jefferson Peak (JfP) -- HW ID: USB(0x8087:0x0aaa) -- Device Type: Legacy Bootloader device -- HCI Quirks: HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED - HCI_QUIRK_VALID_LE_STATES -- HW variant: 0x11 - intel/ibt-17-0-1.sfi - intel/ibt-17-16-1.sfi - - -Thunder Peak (ThP) -- HW ID: USB(0x8087:0x0025) -- Device Type: Legacy Bootloader device -- HCI Quirks: HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED - HCI_QUIRK_VALID_LE_STATES -- HW variant: 0x12 - intel/ibt-18-0-1.sfi - intel/ibt-18-16-1.sfi - tested: FW Build: REL19718 Release Version: 22.50.0.4 - 687d64a4d ("linux-firmware: Update firmware file for Intel Bluetooth 9260") - tested: FW Build: REL13313 Release Version: 21.120.0.4 - db3038082 ("linux-firmware: Update firmware file for Intel Bluetooth 9260") - - -Quasar(QsR) / Harrison Peak (HrP) -- HW ID: USB(0x8087:0x0026) -- Device Type: Legacy Bootloader device -- HCI Quirks: HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED -- HW variant: 0x13 - Quasar with JfP - intel/ibt-19-0-1.sfi - intel/ibt-19-240-1.sfi - - Quasar with HrP - intel/ibt-19-0-4.sfi - intel/ibt-19-240-4.sfi - - intel/ibt-19-0-0.sfi - intel/ibt-19-16-4.sfi - intel/ibt-19-32-0.sfi - intel/ibt-19-32-1.sfi - intel/ibt-19-32-4.sfi - - -Cyclone Peak (CcP) -- HW ID: USB(0x8087:0x0029) -- Device Type: Legacy Bootloader device -- HCI Quirks: HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED -- HW variant: 0x14 - intel/ibt-20-0-3.sfi - intel/ibt-20-1-3.sfi - tested: FW Build: REL25791 Release Version: 22.60.0.3 - 34803c20f ("linux-firmware: Update firmware file for Intel Bluetooth AX200") - intel/ibt-20-1-4.sfi - - -Typhon Peak (TyP) -- HW ID: USB(0x8087:0x0032) -- Device Type: TLV based Bootloader device -- HCI Quirks: HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED -- HW variant: 0x17 - intel/ibt-0041-0041.sfi - tested: FW Build: REL25171 Release Version: 22.60.0.3 - 25ddc612f ("linux-firmware: Update firmware file for Intel Bluetooth AX210") - tested: FW Build: REL17510 Release Version: 22.20.0.3 - 28185ecdc ("linux-firmware: Update firmware file for Intel Bluetooth AX210") - - -Garfield Peak (GfP) -- HW ID: USB(0x8087:0x0033) -- Device Type: TLV based Bootloader device -- HCI Quirks: HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED - HCI_QUIRK_VALID_LE_STATES -- HW variant: 0x18 diff --git a/doc/l2cap.7 b/doc/l2cap.7 new file mode 100644 index 0000000000000000000000000000000000000000..4117f6baae4480396f23c77ff5dc75d1d129c220 --- /dev/null +++ b/doc/l2cap.7 @@ -0,0 +1,578 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "L2CAP" "7" "May 2024" "BlueZ" "Linux System Administration" +.SH NAME +l2cap \- L2CAP protocol +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +#include <sys/socket.h> +#include <bluetooth/bluetooth.h> +#include <bluetooth/l2cap.h> + +l2cap_socket = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +L2CAP is a protocol that provides an interface for higher\-level protocols to +send and receive data over a Bluetooth connection. L2CAP sits on top of the +Bluetooth Host Controller Interface (HCI) and provides a set of channels that +can be used by higher\-level protocols to transmit data. +.sp +L2CAP provides a number of services to higher\-level protocols, including +segmentation and reassembly of large data packets and flow control to prevent +overloading of the receiver. L2CAP also supports multiple channels per +connection, allowing for concurrent data transmission using different protocols. +.SH SOCKET ADDRESS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +struct sockaddr_l2 { + sa_family_t l2_family; + unsigned short l2_psm; + bdaddr_t l2_bdaddr; + unsigned short l2_cid; + uint8_t l2_bdaddr_type; +}; +.EE +.UNINDENT +.UNINDENT +.sp +Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +struct sockaddr_l2 addr; + +memset(&addr, 0, sizeof(addr)); +addr.l2_family = AF_BLUETOOTH; +bacpy(&addr.l2_bdaddr, bdaddr); + +if (cid) + addr.l2_cid = htobs(cid); +else + addr.l2_psm = htobs(psm); + +addr.l2_bdaddr_type = bdaddr_type; +.EE +.UNINDENT +.UNINDENT +.SH SOCKET OPTIONS +.sp +The socket options listed below can be set by using \fBsetsockopt(2)\fP and read +with \fBgetsockopt(2)\fP with the socket level set to SOL_BLUETOOTH. +.SS BT_SECURITY (since Linux 2.6.30) +.sp +Channel security level, possible values: +.TS +box center; +l|l|l|l. +T{ +Value +T} T{ +Security Level +T} T{ +Link Key Type +T} T{ +Encryption +T} +_ +T{ +\fBBT_SECURITY_SDP\fP +T} T{ +0 (SDP Only) +T} T{ +None +T} T{ +Not required +T} +_ +T{ +\fBBT_SECURITY_LOW\fP +T} T{ +1 (Low) +T} T{ +Unauthenticated +T} T{ +Not required +T} +_ +T{ +\fBBT_SECURITY_MEDIUM\fP +T} T{ +2 (Medium \- default) +T} T{ +Unauthenticated +T} T{ +Desired +T} +_ +T{ +\fBBT_SECURITY_HIGH\fP +T} T{ +3 (High) +T} T{ +Authenticated +T} T{ +Required +T} +_ +T{ +\fBBT_SECURITY_FIPS\fP (since Linux 3.15) +T} T{ +4 (Secure Only) +T} T{ +Authenticated (P\-256 based Secure Simple Pairing and Secure Authentication) +T} T{ +Required +T} +.TE +.sp +Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +int level = BT_SECURITY_HIGH; +int err = setsockopt(l2cap_socket, SOL_BLUETOOTH, BT_SECURITY, &level, + sizeof(level)); +if (err == \-1) { + perror(\(dqsetsockopt\(dq); + return 1; +} +.EE +.UNINDENT +.UNINDENT +.SS BT_DEFER_SETUP (since Linux 2.6.30) +.sp +Channel defer connection setup, this control if the connection procedure +needs to be authorized by userspace before responding which allows +authorization at profile level, possible values: +.TS +box center; +l|l|l. +T{ +Value +T} T{ +Description +T} T{ +Authorization +T} +_ +T{ +\fB0\fP +T} T{ +Disable (default) +T} T{ +Not required +T} +_ +T{ +\fB1\fP +T} T{ +Enable +T} T{ +Required +T} +.TE +.sp +Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +int defer_setup = 1; +int err = setsockopt(l2cap_socket, SOL_BLUETOOTH, BT_DEFER_SETUP, + &defer_setup, sizeof(defer_setup)); +if (err == \-1) { + perror(\(dqsetsockopt\(dq); + return err; +} + +err = listen(l2cap_socket, 5); +if (err) { + perror(\(dqlisten\(dq); + return err; +} + +struct sockaddr_l2 remote_addr = {0}; +socklen_t addr_len = sizeof(remote_addr); +int new_socket = accept(l2cap_socket, (struct sockaddr*)&remote_addr, + &addr_len); +if (new_socket < 0) { + perror(\(dqaccept\(dq); + return new_socket; +} + +/* To complete the connection setup of new_socket read 1 byte */ +char c; +struct pollfd pfd; + +memset(&pfd, 0, sizeof(pfd)); +pfd.fd = new_socket; +pfd.events = POLLOUT; + +err = poll(&pfd, 1, 0); +if (err) { + perror(\(dqpoll\(dq); + return err; +} + +if (!(pfd.revents & POLLOUT)) { + err = read(sk, &c, 1); + if (err < 0) { + perror(\(dqread\(dq); + return err; + } +} +.EE +.UNINDENT +.UNINDENT +.SS BT_FLUSHABLE (since Linux 2.6.39) +.sp +Channel flushable flag, this control if the channel data can be flushed or +not, possible values: +.TS +box center; +l|l|l. +T{ +Define +T} T{ +Value +T} T{ +Description +T} +_ +T{ +\fBBT_FLUSHABLE_OFF\fP +T} T{ +0x00 (default) +T} T{ +Do not flush data +T} +_ +T{ +\fBBT_FLUSHABLE_ON\fP +T} T{ +0x01 +T} T{ +Flush data +T} +.TE +.SS BT_POWER (since Linux 3.1) +.sp +Channel power policy, this control if the channel shall force exit of sniff +mode or not, possible values: +.TS +box center; +l|l|l. +T{ +Define +T} T{ +Value +T} T{ +Description +T} +_ +T{ +\fBBT_POWER_FORCE_ACTIVE_OFF\fP +T} T{ +0x00 (default) +T} T{ +Don\(aqt force exit of sniff mode +T} +_ +T{ +\fBBT_POWER_FORCE_ACTIVE_ON\fP +T} T{ +0x01 +T} T{ +Force exit of sniff mode +T} +.TE +.SS BT_CHANNEL_POLICY (since Linux 3.10) +.sp +High\-speed (AMP) channel policy, possible values: +.TS +box center; +l|l|l. +T{ +Define +T} T{ +Value +T} T{ +Description +T} +_ +T{ +\fBBT_CHANNEL_POLICY_BREDR_ONLY\fP +T} T{ +0 (default) +T} T{ +BR/EDR only +T} +_ +T{ +\fBBT_CHANNEL_POLICY_BREDR_PREFERRED\fP +T} T{ +1 +T} T{ +BR/EDR Preferred +T} +_ +T{ +\fBBT_CHANNEL_POLICY_BREDR_PREFERRED\fP +T} T{ +2 +T} T{ +AMP Preferred +T} +.TE +.SS BT_PHY (since Linux 5.10) +.sp +Channel supported PHY(s), possible values: +.TS +box center; +l|l|l. +T{ +Define +T} T{ +Value +T} T{ +Description +T} +_ +T{ +\fBBT_PHY_BR_1M_1SLOT\fP +T} T{ +BIT 0 +T} T{ +BR 1Mbps 1SLOT +T} +_ +T{ +\fBBT_PHY_BR_1M_3SLOT\fP +T} T{ +BIT 1 +T} T{ +BR 1Mbps 3SLOT +T} +_ +T{ +\fBBT_PHY_BR_1M_5SLOT\fP +T} T{ +BIT 2 +T} T{ +BR 1Mbps 5SLOT +T} +_ +T{ +\fBBT_PHY_BR_2M_1SLOT\fP +T} T{ +BIT 3 +T} T{ +EDR 2Mbps 1SLOT +T} +_ +T{ +\fBBT_PHY_BR_2M_3SLOT\fP +T} T{ +BIT 4 +T} T{ +EDR 2Mbps 3SLOT +T} +_ +T{ +\fBBT_PHY_BR_2M_5SLOT\fP +T} T{ +BIT 5 +T} T{ +EDR 2Mbps 5SLOT +T} +_ +T{ +\fBBT_PHY_BR_3M_1SLOT\fP +T} T{ +BIT 6 +T} T{ +EDR 3Mbps 1SLOT +T} +_ +T{ +\fBBT_PHY_BR_3M_3SLOT\fP +T} T{ +BIT 7 +T} T{ +EDR 3Mbps 3SLOT +T} +_ +T{ +\fBBT_PHY_BR_3M_5SLOT\fP +T} T{ +BIT 8 +T} T{ +EDR 3Mbps 5SLOT +T} +_ +T{ +\fBBT_PHY_LE_1M_TX\fP +T} T{ +BIT 9 +T} T{ +LE 1Mbps TX +T} +_ +T{ +\fBBT_PHY_LE_1M_RX\fP +T} T{ +BIT 10 +T} T{ +LE 1Mbps RX +T} +_ +T{ +\fBBT_PHY_LE_2M_TX\fP +T} T{ +BIT 11 +T} T{ +LE 2Mbps TX +T} +_ +T{ +\fBBT_PHY_LE_2M_RX\fP +T} T{ +BIT 12 +T} T{ +LE 2Mbps RX +T} +_ +T{ +\fBBT_PHY_LE_CODED_TX\fP +T} T{ +BIT 13 +T} T{ +LE Coded TX +T} +_ +T{ +\fBBT_PHY_LE_CODED_RX\fP +T} T{ +BIT 14 +T} T{ +LE Coded RX +T} +.TE +.SS BT_MODE (since Linux 5.10) +.sp +Channel Mode, possible values: +.TS +box center; +l|l|l|l. +T{ +Define +T} T{ +Value +T} T{ +Description +T} T{ +Link +T} +_ +T{ +\fBBT_MODE_BASIC\fP +T} T{ +0x00 (default) +T} T{ +Basic mode +T} T{ +Any +T} +_ +T{ +\fBBT_MODE_ERTM\fP +T} T{ +0x01 +T} T{ +Enhanced Retransmission mode +T} T{ +BR/EDR +T} +_ +T{ +\fBBT_MODE_STREAM\fP +T} T{ +0x02 +T} T{ +Stream mode +T} T{ +BR/EDR +T} +_ +T{ +\fBBT_MODE_LE_FLOWCTL\fP +T} T{ +0x03 +T} T{ +Credit based flow control mode +T} T{ +LE +T} +_ +T{ +\fBBT_MODE_EXT_FLOWCTL\fP +T} T{ +0x04 +T} T{ +Extended Credit based flow control mode +T} T{ +Any +T} +.TE +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH SEE ALSO +.sp +socket(7), l2test(1) +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/doc/l2cap.rst b/doc/l2cap.rst new file mode 100644 index 0000000000000000000000000000000000000000..f90f88222ae815214a4a224f7c618c07f2cdcdf5 --- /dev/null +++ b/doc/l2cap.rst @@ -0,0 +1,258 @@ +===== +l2cap +===== + +-------------- +L2CAP protocol +-------------- + +:Version: BlueZ +:Copyright: Free use of this software is granted under ther terms of the GNU + Lesser General Public Licenses (LGPL). +:Date: May 2024 +:Manual section: 7 +:Manual group: Linux System Administration + +SYNOPSIS +======== + +.. code-block:: + + #include <sys/socket.h> + #include <bluetooth/bluetooth.h> + #include <bluetooth/l2cap.h> + + l2cap_socket = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + +DESCRIPTION +=========== + +L2CAP is a protocol that provides an interface for higher-level protocols to +send and receive data over a Bluetooth connection. L2CAP sits on top of the +Bluetooth Host Controller Interface (HCI) and provides a set of channels that +can be used by higher-level protocols to transmit data. + +L2CAP provides a number of services to higher-level protocols, including +segmentation and reassembly of large data packets and flow control to prevent +overloading of the receiver. L2CAP also supports multiple channels per +connection, allowing for concurrent data transmission using different protocols. + +SOCKET ADDRESS +============== + +.. code-block:: + + struct sockaddr_l2 { + sa_family_t l2_family; + unsigned short l2_psm; + bdaddr_t l2_bdaddr; + unsigned short l2_cid; + uint8_t l2_bdaddr_type; + }; + +Example: + +.. code-block:: + + struct sockaddr_l2 addr; + + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + bacpy(&addr.l2_bdaddr, bdaddr); + + if (cid) + addr.l2_cid = htobs(cid); + else + addr.l2_psm = htobs(psm); + + addr.l2_bdaddr_type = bdaddr_type; + +SOCKET OPTIONS +============== + +The socket options listed below can be set by using **setsockopt(2)** and read +with **getsockopt(2)** with the socket level set to SOL_BLUETOOTH. + +BT_SECURITY (since Linux 2.6.30) +-------------------------------- + +Channel security level, possible values: + +.. csv-table:: + :header: "Value", "Security Level", "Link Key Type", "Encryption" + :widths: auto + + **BT_SECURITY_SDP**, 0 (SDP Only), None, Not required + **BT_SECURITY_LOW**, 1 (Low), Unauthenticated, Not required + **BT_SECURITY_MEDIUM**, 2 (Medium - default), Unauthenticated, Desired + **BT_SECURITY_HIGH**, 3 (High), Authenticated, Required + **BT_SECURITY_FIPS** (since Linux 3.15), 4 (Secure Only), Authenticated (P-256 based Secure Simple Pairing and Secure Authentication), Required + +Example: + +.. code-block:: + + int level = BT_SECURITY_HIGH; + int err = setsockopt(l2cap_socket, SOL_BLUETOOTH, BT_SECURITY, &level, + sizeof(level)); + if (err == -1) { + perror("setsockopt"); + return 1; + } + +BT_DEFER_SETUP (since Linux 2.6.30) +----------------------------------- + +Channel defer connection setup, this control if the connection procedure +needs to be authorized by userspace before responding which allows +authorization at profile level, possible values: + +.. csv-table:: + :header: "Value", "Description", "Authorization" + :widths: auto + + **0**, Disable (default), Not required + **1**, Enable, Required + +Example: + +.. code-block:: + + int defer_setup = 1; + int err = setsockopt(l2cap_socket, SOL_BLUETOOTH, BT_DEFER_SETUP, + &defer_setup, sizeof(defer_setup)); + if (err == -1) { + perror("setsockopt"); + return err; + } + + err = listen(l2cap_socket, 5); + if (err) { + perror("listen"); + return err; + } + + struct sockaddr_l2 remote_addr = {0}; + socklen_t addr_len = sizeof(remote_addr); + int new_socket = accept(l2cap_socket, (struct sockaddr*)&remote_addr, + &addr_len); + if (new_socket < 0) { + perror("accept"); + return new_socket; + } + + /* To complete the connection setup of new_socket read 1 byte */ + char c; + struct pollfd pfd; + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = new_socket; + pfd.events = POLLOUT; + + err = poll(&pfd, 1, 0); + if (err) { + perror("poll"); + return err; + } + + if (!(pfd.revents & POLLOUT)) { + err = read(sk, &c, 1); + if (err < 0) { + perror("read"); + return err; + } + } + +BT_FLUSHABLE (since Linux 2.6.39) +--------------------------------- + +Channel flushable flag, this control if the channel data can be flushed or +not, possible values: + +.. csv-table:: + :header: "Define", "Value", "Description" + :widths: auto + + **BT_FLUSHABLE_OFF**, 0x00 (default), Do not flush data + **BT_FLUSHABLE_ON**, 0x01, Flush data + +BT_POWER (since Linux 3.1) +-------------------------- + +Channel power policy, this control if the channel shall force exit of sniff +mode or not, possible values: + +.. csv-table:: + :header: "Define", "Value", "Description" + :widths: auto + + **BT_POWER_FORCE_ACTIVE_OFF**, 0x00 (default), Don't force exit of sniff mode + **BT_POWER_FORCE_ACTIVE_ON**, 0x01, Force exit of sniff mode + +BT_CHANNEL_POLICY (since Linux 3.10) +------------------------------------ + +High-speed (AMP) channel policy, possible values: + +.. csv-table:: + :header: "Define", "Value", "Description" + :widths: auto + + **BT_CHANNEL_POLICY_BREDR_ONLY**, 0 (default), BR/EDR only + **BT_CHANNEL_POLICY_BREDR_PREFERRED**, 1, BR/EDR Preferred + **BT_CHANNEL_POLICY_BREDR_PREFERRED**, 2, AMP Preferred + +BT_PHY (since Linux 5.10) +------------------------- + +Channel supported PHY(s), possible values: + +.. csv-table:: + :header: "Define", "Value", "Description" + :widths: auto + + **BT_PHY_BR_1M_1SLOT**, BIT 0, BR 1Mbps 1SLOT + **BT_PHY_BR_1M_3SLOT**, BIT 1, BR 1Mbps 3SLOT + **BT_PHY_BR_1M_5SLOT**, BIT 2, BR 1Mbps 5SLOT + **BT_PHY_BR_2M_1SLOT**, BIT 3, EDR 2Mbps 1SLOT + **BT_PHY_BR_2M_3SLOT**, BIT 4, EDR 2Mbps 3SLOT + **BT_PHY_BR_2M_5SLOT**, BIT 5, EDR 2Mbps 5SLOT + **BT_PHY_BR_3M_1SLOT**, BIT 6, EDR 3Mbps 1SLOT + **BT_PHY_BR_3M_3SLOT**, BIT 7, EDR 3Mbps 3SLOT + **BT_PHY_BR_3M_5SLOT**, BIT 8, EDR 3Mbps 5SLOT + **BT_PHY_LE_1M_TX**, BIT 9, LE 1Mbps TX + **BT_PHY_LE_1M_RX**, BIT 10, LE 1Mbps RX + **BT_PHY_LE_2M_TX**, BIT 11, LE 2Mbps TX + **BT_PHY_LE_2M_RX**, BIT 12, LE 2Mbps RX + **BT_PHY_LE_CODED_TX**, BIT 13, LE Coded TX + **BT_PHY_LE_CODED_RX**, BIT 14, LE Coded RX + +BT_MODE (since Linux 5.10) +-------------------------- + +Channel Mode, possible values: + +.. csv-table:: + :header: "Define", "Value", "Description", "Link" + :widths: auto + + **BT_MODE_BASIC**, 0x00 (default), Basic mode, Any + **BT_MODE_ERTM**, 0x01, Enhanced Retransmission mode, BR/EDR + **BT_MODE_STREAM**, 0x02, Stream mode, BR/EDR + **BT_MODE_LE_FLOWCTL**, 0x03, Credit based flow control mode, LE + **BT_MODE_EXT_FLOWCTL**, 0x04, Extended Credit based flow control mode, Any + +RESOURCES +========= + +http://www.bluez.org + +REPORTING BUGS +============== + +linux-bluetooth@vger.kernel.org + +SEE ALSO +======== + +socket(7), l2test(1) diff --git a/doc/maintainer-guidelines.txt b/doc/maintainer-guidelines.txt deleted file mode 100644 index 21162d4e936a8e3a5d1496dcf157aa675ac177db..0000000000000000000000000000000000000000 --- a/doc/maintainer-guidelines.txt +++ /dev/null @@ -1,114 +0,0 @@ -Maintainer guidelines -********************* - -This document is intended for the maintainers of the BlueZ project. It -serves as basic guidelines for handling patch review and commit access. - - -Rule 1: Keep the GIT tree clean and linear -========================================== - -The bluetooth.git, bluetooth-next.git and bluez.git trees are not your -private playground. The history is meant to be clean and linear. - - - NO merges - - NO branches - - NO tags - -If anyone needs testing or work on a feature, clone the tree and do -it in your own copy. The master trees are off limits. - -One advise to avoid any accidental errors in this area to set proper -options in global ~/.gitconfig or local .git/config files. - - [merge] - ff = only - -Violations of this rule are not acceptable. This rule is enforced. If -in doubt ask one of the seasoned maintainers. - - -Rule 2: Enforce clean commit messages -===================================== - -The commit messages are required to be clean and follow style guidelines -to be consistent. - -Commit messages should adhere to a 72 characters by line limit. That -makes it easy to read them via git log in a terminal window. Exceptions -to this rule are logs, trace or other verbatim copied information. - -Every commit requires full names and email addresses. No synonyms or -nicknames are allowed. It is also important that the Outlook style -names with lastname, firstname are not allowed. It is the maintainers -job to ensure we get proper firstname lastname <email> authorship. - -It is also important that the committer itself uses a valid name and -email address when committing patches. So ensure that either the -global ~/.gitconfig or local .git/config provides proper values. - - [user] - name = Peter Mustermann - email = peter@mustermann.de - -Commit messages for bluez.git shall not contain Signed-off-by -signatures. They are not used in userspace and with that it is the -maintainers job to ensure they do not get committed to the repository. - -For bluetooth.git and bluetooth-next.git The Signed-off-by process is -used and the signatures are required. - -Tags like Change-Id generated from Gerrit are never acceptable. It is -the maintainers job to ensure that these are not committed into the -repositories. - -Violations of this rule create a mess in the tree that can not be -reversed. If in doubt ask one of the seasoned maintainers. - - -Rule 3: Enforce correct coding style -==================================== - -The coding style follows roughly the kernel coding style with any -exceptions documented in doc/coding-style.txt. - -To ensure trivial white-space errors don't get committed, have the -following in your .gitconfig: - - [apply] - whitespace = error - -It can also be helpful to use the checkpatch.pl script coming with the -Linux kernel to do some automated checking. Adding the following to your -.git/hooks/pre-commit and .git/hooks/pre-applypatch is a simple way to -do this: - - exec git diff --cached | ~/src/linux/scripts/checkpatch.pl -q \ - --no-tree --no-signoff --show-types \ - --ignore CAMELCASE,NEW_TYPEDEFS,INITIALISED_STATIC - - -The above assumes that a kernel tree resides in ~/src/linux/. - - -Rule 4: Pay extra attention to adding new files to the tree -=========================================================== - -New files that are added to the tree require several things to be -verified first: - - - Check that the names are acceptible with other maintainers - - Ensure that the file modes are correct - - Verify that the license & copyright headers are correct - - If the file is supposed to be part of the release tarball, - make sure that it gets picked up by 'make dist' (particularly - important for documentation or other files that are not code) - - -Rule 5: Keep the mailing list in sync with the commit process -============================================================= - -When applying patches, be sure to send a response to the mailing list as -soon as the code has been pushed to the upstream tree. Usually this -means one email per patch, however patch-sets may only have one response -covering the entire set. If applying a subset of a patch-set clearly -state what was applied in your response. diff --git a/doc/media-api.txt b/doc/media-api.txt deleted file mode 100644 index 847f8bee72a92b679e232b483754b403e9625491..0000000000000000000000000000000000000000 --- a/doc/media-api.txt +++ /dev/null @@ -1,779 +0,0 @@ -BlueZ D-Bus Media API description -********************************* - - -Media hierarchy -=============== - -Service org.bluez -Interface org.bluez.Media1 -Object path [variable prefix]/{hci0,hci1,...} - -Methods void RegisterEndpoint(object endpoint, dict properties) - - Register a local end point to sender, the sender can - register as many end points as it likes. - - Note: If the sender disconnects the end points are - automatically unregistered. - - possible properties: - - string UUID: - - UUID of the profile which the endpoint - is for. - - UUID must be in the list of - SupportedUUIDS. - - byte Codec: - - Assigned number of codec that the - endpoint implements. The values should - match the profile specification which - is indicated by the UUID. - - array{byte} Capabilities: - - Capabilities blob, it is used as it is - so the size and byte order must match. - - Possible Errors: org.bluez.Error.InvalidArguments - org.bluez.Error.NotSupported - emitted - when interface for the end-point is - disabled. - - void UnregisterEndpoint(object endpoint) - - Unregister sender end point. - - void RegisterPlayer(object player, dict properties) - - Register a media player object to sender, the sender - can register as many objects as it likes. - - Object must implement at least - org.mpris.MediaPlayer2.Player as defined in MPRIS 2.2 - spec: - - http://specifications.freedesktop.org/mpris-spec/latest/ - - Note: If the sender disconnects its objects are - automatically unregistered. - - Possible Errors: org.bluez.Error.InvalidArguments - org.bluez.Error.NotSupported - - void UnregisterPlayer(object player) - - Unregister sender media player. - - void RegisterApplication(object root, dict options) - - Register endpoints an player objects within root - object which must implement ObjectManager. - - The application object path together with the D-Bus - system bus connection ID define the identification of - the application. - - Possible errors: org.bluez.Error.InvalidArguments - org.bluez.Error.AlreadyExists - - void UnregisterApplication(object application) - - This unregisters the services 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.InvalidArguments - org.bluez.Error.DoesNotExist - -Properties array{string} SupportedUUIDs [readonly]: - - List of 128-bit UUIDs that represents the supported - Endpoint registration. - -Media Control hierarchy -======================= - -Service org.bluez -Interface org.bluez.MediaControl1 -Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX - -Methods void Play() [Deprecated] - - Resume playback. - - void Pause() [Deprecated] - - Pause playback. - - void Stop() [Deprecated] - - Stop playback. - - void Next() [Deprecated] - - Next item. - - void Previous() [Deprecated] - - Previous item. - - void VolumeUp() [Deprecated] - - Adjust remote volume one step up - - void VolumeDown() [Deprecated] - - Adjust remote volume one step down - - void FastForward() [Deprecated] - - Fast forward playback, this action is only stopped - when another method in this interface is called. - - void Rewind() [Deprecated] - - Rewind playback, this action is only stopped - when another method in this interface is called. - -Properties - - boolean Connected [readonly] - - object Player [readonly, optional] - - Addressed Player object path. - - -MediaPlayer1 hierarchy -====================== - -Service org.bluez (Controller role) -Interface org.bluez.MediaPlayer1 -Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/playerX - -Methods void Play() - - Resume playback. - - Possible Errors: org.bluez.Error.NotSupported - org.bluez.Error.Failed - - void Pause() - - Pause playback. - - Possible Errors: org.bluez.Error.NotSupported - org.bluez.Error.Failed - - void Stop() - - Stop playback. - - Possible Errors: org.bluez.Error.NotSupported - org.bluez.Error.Failed - - void Next() - - Next item. - - Possible Errors: org.bluez.Error.NotSupported - org.bluez.Error.Failed - - void Previous() - - Previous item. - - Possible Errors: org.bluez.Error.NotSupported - org.bluez.Error.Failed - - void FastForward() - - Fast forward playback, this action is only stopped - when another method in this interface is called. - - Possible Errors: org.bluez.Error.NotSupported - org.bluez.Error.Failed - - void Rewind() - - Rewind playback, this action is only stopped - when another method in this interface is called. - - Possible Errors: org.bluez.Error.NotSupported - org.bluez.Error.Failed - - void Press(byte avc_key) - - Press a specific key to send as passthrough command. - The key will be released automatically. Use Hold() - instead if the intention is to hold down the key. - - Possible Errors: org.bluez.Error.InvalidArguments - org.bluez.Error.NotSupported - org.bluez.Error.Failed - - void Hold(byte avc_key) - - Press and hold a specific key to send as passthrough - command. It is your responsibility to make sure that - Release() is called after calling this method. The held - key will also be released when any other method in this - interface is called. - - Possible Errors: org.bluez.Error.InvalidArguments - org.bluez.Error.NotSupported - org.bluez.Error.Failed - - void Release() - - Release the previously held key invoked using Hold(). - - Possible Errors: org.bluez.Error.NotSupported - org.bluez.Error.Failed - -Properties string Equalizer [readwrite] - - Possible values: "off" or "on" - - string Repeat [readwrite] - - Possible values: "off", "singletrack", "alltracks" or - "group" - - string Shuffle [readwrite] - - Possible values: "off", "alltracks" or "group" - - string Scan [readwrite] - - Possible values: "off", "alltracks" or "group" - - string Status [readonly] - - Possible status: "playing", "stopped", "paused", - "forward-seek", "reverse-seek" - or "error" - - uint32 Position [readonly] - - Playback position in milliseconds. Changing the - position may generate additional events that will be - sent to the remote device. When position is 0 it means - the track is starting and when it's greater than or - equal to track's duration the track has ended. Note - that even if duration is not available in metadata it's - possible to signal its end by setting position to the - maximum uint32 value. - - dict Track [readonly] - - Track metadata. - - Possible values: - - string Title: - - Track title name - - string Artist: - - Track artist name - - string Album: - - Track album name - - string Genre: - - Track genre name - - uint32 NumberOfTracks: - - Number of tracks in total - - uint32 TrackNumber: - - Track number - - uint32 Duration: - - Track duration in milliseconds - - object Device [readonly] - - Device object path. - - string Name [readonly] - - Player name - - string Type [readonly] - - Player type - - Possible values: - - "Audio" - "Video" - "Audio Broadcasting" - "Video Broadcasting" - - string Subtype [readonly] - - Player subtype - - Possible values: - - "Audio Book" - "Podcast" - - boolean Browsable [readonly] - - If present indicates the player can be browsed using - MediaFolder interface. - - Possible values: - - True: Supported and active - False: Supported but inactive - - Note: If supported but inactive clients can enable it - by using MediaFolder interface but it might interfere - in the playback of other players. - - - boolean Searchable [readonly] - - If present indicates the player can be searched using - MediaFolder interface. - - Possible values: - - True: Supported and active - False: Supported but inactive - - Note: If supported but inactive clients can enable it - by using MediaFolder interface but it might interfere - in the playback of other players. - - object Playlist - - Playlist object path. - -MediaFolder1 hierarchy -====================== - -Service unique name (Target role) - org.bluez (Controller role) -Interface org.bluez.MediaFolder1 -Object path freely definable (Target role) - [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/playerX - (Controller role) - -Methods object Search(string value, dict filter) - - Return a folder object containing the search result. - - To list the items found use the folder object returned - and pass to ChangeFolder. - - Possible Errors: org.bluez.Error.NotSupported - org.bluez.Error.Failed - - array{objects, properties} ListItems(dict filter) - - Return a list of items found - - Possible Errors: org.bluez.Error.InvalidArguments - org.bluez.Error.NotSupported - org.bluez.Error.Failed - - void ChangeFolder(object folder) - - Change current folder. - - Note: By changing folder the items of previous folder - might be destroyed and have to be listed again, the - exception is NowPlaying folder which should be always - present while the player is active. - - Possible Errors: org.bluez.Error.InvalidArguments - org.bluez.Error.NotSupported - org.bluez.Error.Failed - -Properties uint32 NumberOfItems [readonly] - - Number of items in the folder - - string Name [readonly] - - Folder name: - - Possible values: - "/Filesystem/...": Filesystem scope - "/NowPlaying/...": NowPlaying scope - - Note: /NowPlaying folder might not be listed if player - is stopped, folders created by Search are virtual so - once another Search is perform or the folder is - changed using ChangeFolder it will no longer be listed. - -Filters uint32 Start: - - Offset of the first item. - - Default value: 0 - - uint32 End: - - Offset of the last item. - - Default value: NumbeOfItems - - array{string} Attributes - - Item properties that should be included in the list. - - Possible Values: - - "title", "artist", "album", "genre", - "number-of-tracks", "number", "duration" - - Default Value: All - -MediaItem1 hierarchy -==================== - -Service unique name (Target role) - org.bluez (Controller role) -Interface org.bluez.MediaItem1 -Object path freely definable (Target role) - [variable - prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/playerX/itemX - (Controller role) - -Methods void Play() - - Play item - - Possible Errors: org.bluez.Error.NotSupported - org.bluez.Error.Failed - - void AddtoNowPlaying() - - Add item to now playing list - - Possible Errors: org.bluez.Error.NotSupported - org.bluez.Error.Failed - -Properties object Player [readonly] - - Player object path the item belongs to - - string Name [readonly] - - Item displayable name - - string Type [readonly] - - Item type - - Possible values: "video", "audio", "folder" - - string FolderType [readonly, optional] - - Folder type. - - Possible values: "mixed", "titles", "albums", "artists" - - Available if property Type is "Folder" - - boolean Playable [readonly, optional] - - Indicates if the item can be played - - Available if property Type is "folder" - - dict Metadata [readonly] - - Item metadata. - - Possible values: - - string Title - - Item title name - - Available if property Type is "audio" - or "video" - - string Artist - - Item artist name - - Available if property Type is "audio" - or "video" - - string Album - - Item album name - - Available if property Type is "audio" - or "video" - - string Genre - - Item genre name - - Available if property Type is "audio" - or "video" - - uint32 NumberOfTracks - - Item album number of tracks in total - - Available if property Type is "audio" - or "video" - - uint32 Number - - Item album number - - Available if property Type is "audio" - or "video" - - uint32 Duration - - Item duration in milliseconds - - Available if property Type is "audio" - or "video" - -MediaEndpoint1 hierarchy -======================== - -Service unique name (Server role) - org.bluez (Client role) -Interface org.bluez.MediaEndpoint1 -Object path freely definable (Server role) - [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/sepX - (Client role) - -Methods void SetConfiguration(object transport, dict properties) - - Set configuration for the transport. - - For client role transport must be set with a server - endpoint oject which will be configured and the - properties must contain the following properties: - - array{byte} Capabilities [Mandatory] - array{byte} Metadata [ISO only] - byte CIG [ISO only] - byte CIS [ISO only] - uint32 Interval [ISO only] - bool Framing [ISO only] - string PHY [ISO only] - uint16 SDU [ISO only] - byte Retransmissions [ISO only] - uint16 Latency [ISO only] - uint32 Delay [ISO only] - uint8 TargetLatency [ISO Latency] - - array{byte} SelectConfiguration(array{byte} capabilities) - - Select preferable configuration from the supported - capabilities. - - Returns a configuration which can be used to setup - a transport. - - Note: There is no need to cache the selected - configuration since on success the configuration is - send back as parameter of SetConfiguration. - - dict SelectProperties(dict properties) - - Select preferable properties from the supported - properties: - object Endpoint [ISO only] - Refer to SetConfiguration for the list of - other possible properties. - - Returns propeties which can be used to setup - a transport. - - Note: There is no need to cache the selected - properties since on success the configuration is - send back as parameter of SetConfiguration. - - void ClearConfiguration(object transport) - - Clear transport configuration. - - void Release() - - This method gets called when the service daemon - unregisters the endpoint. An endpoint can use it to do - cleanup tasks. There is no need to unregister the - endpoint, because when this method gets called it has - already been unregistered. - -Properties string UUID [readonly, optional]: - - UUID of the profile which the endpoint is for. - - byte Codec [readonly, optional]: - - Assigned number of codec that the endpoint implements. - The values should match the profile specification which - is indicated by the UUID. - - array{byte} Capabilities [readonly, optional]: - - Capabilities blob, it is used as it is so the size and - byte order must match. - - object Device [readonly, optional]: - - Device object which the endpoint is belongs to. - - bool DelayReporting [readonly, optional]: - - Indicates if endpoint supports Delay Reporting. - - byte Framing [ISO only] - - Indicates endpoint support framing. - - byte PHY [ISO only] - - Indicates endpoint supported PHY. - - uint16_t MaximumLatency [ISO only] - - Indicates endpoint maximum latency. - - uint32_t MinimumDelay [ISO only] - - Indicates endpoint minimum presentation delay. - - uint32_t MaximumDelay [ISO only] - - Indicates endpoint maximum presentation delay. - - uint32_t PreferredMinimumDelay [ISO only] - - Indicates endpoint preferred minimum presentation delay. - - uint32_t PreferredMinimumDelay [ISO only] - - Indicates endpoint preferred minimum presentation delay. - - uint32 Location [ISO only] - - Indicates endpoint supported locations. - - uint16 SupportedContext [ISO only] - - Indicates endpoint supported audio context. - - uint16 Context [ISO only] - - Indicates endpoint available audio context. - -MediaTransport1 hierarchy -========================= - -Service org.bluez -Interface org.bluez.MediaTransport1 -Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/fdX - -Methods fd, uint16, uint16 Acquire() - - Acquire transport file descriptor and the MTU for read - and write respectively. - - Possible Errors: org.bluez.Error.NotAuthorized - org.bluez.Error.Failed - - fd, uint16, uint16 TryAcquire() - - Acquire transport file descriptor only if the transport - is in "pending" state at the time the message is - received by BlueZ. Otherwise no request will be sent - to the remote device and the function will just fail - with org.bluez.Error.NotAvailable. - - Possible Errors: org.bluez.Error.NotAuthorized - org.bluez.Error.Failed - org.bluez.Error.NotAvailable - - void Release() - - Releases file descriptor. - -Properties object Device [readonly] - - Device object which the transport is connected to. - - string UUID [readonly] - - UUID of the profile which the transport is for. - - byte Codec [readonly] - - Assigned number of codec that the transport support. - The values should match the profile specification which - is indicated by the UUID. - - array{byte} Configuration [readonly] - - Configuration blob, it is used as it is so the size and - byte order must match. - - string State [readonly] - - Indicates the state of the transport. Possible - values are: - "idle": not streaming - "pending": streaming but not acquired - "active": streaming and acquired - - uint16 Delay [readwrite] - - Optional. Transport delay in 1/10 of millisecond, this - property is only writeable when the transport was - acquired by the sender. - - uint16 Volume [readwrite] - - Optional. Indicates volume level of the transport, - this property is only writeable when the transport was - acquired by the sender. - - Possible Values: 0-127 - - object Endpoint [readonly, optional, experimental] - - Endpoint object which the transport is associated - with. - - uint32 Location [readonly, ISO only, experimental] - - Indicates transport Audio Location. - - array{byte} Metadata [ISO Only, experimental] - - Indicates transport Metadata. - - array{object} Links [readonly, optional, ISO only, experimental] - - Linked transport objects which the transport is - associated with. diff --git a/doc/mesh-api.txt b/doc/mesh-api.txt deleted file mode 100644 index 85de6705e331f685fccb413233e596a109053d43..0000000000000000000000000000000000000000 --- a/doc/mesh-api.txt +++ /dev/null @@ -1,1247 +0,0 @@ -BlueZ D-Bus Mesh API description -******************************** - -Mesh Network Hierarchy -====================== -Service org.bluez.mesh -Interface org.bluez.mesh.Network1 -Object path /org/bluez/mesh - -Methods: - void Join(object app_root, array{byte}[16] uuid) - - This is the first method that an application has to call to - become a provisioned node on a mesh network. The call will - initiate broadcasting of Unprovisioned Device Beacon. - - The app_root parameter is a D-Bus object root path of - the application that implements org.bluez.mesh.Application1 - interface. The application represents a node where child mesh - elements have their own objects that implement - org.bluez.mesh.Element1 interface. The application hierarchy - also contains a provision agent object that implements - org.bluez.mesh.ProvisionAgent1 interface. The standard - DBus.ObjectManager interface must be available on the - app_root path. - - The uuid parameter is a 16-byte array that contains Device UUID. - This UUID must be unique (at least from the daemon perspective), - therefore attempting to call this function using already - registered UUID results in an error. The composition of the UUID - octets must be in compliance with RFC 4122. - - When provisioning finishes, the daemon will call either - JoinComplete or JoinFailed method on object implementing - org.bluez.mesh.Application1 interface. - - PossibleErrors: - org.bluez.mesh.Error.InvalidArguments - org.bluez.mesh.Error.AlreadyExists, - - void Cancel(void) - - Cancels an outstanding provisioning request initiated by Join() - method. - - object node, array{byte, array{(uint16, dict)}} configuration - Attach(object app_root, uint64 token) - - This is the first method that an application must call to get - access to mesh node functionalities. - - The app_root parameter is a D-Bus object root path of - the application that implements org.bluez.mesh.Application1 - interface. The application represents a node where child mesh - elements have their own objects that implement - org.bluez.mesh.Element1 interface. The standard - DBus.ObjectManager interface must be available on the - app_root path. - - The token parameter is a 64-bit number that has been assigned to - the application when it first got provisioned/joined mesh - network, i.e. upon receiving JoinComplete() method. The daemon - uses the token to verify whether the application is authorized - to assume the mesh node identity. - - In case of success, the method call returns mesh node object - (see Mesh Node Hierarchy section) and current configuration - settings. The return value of configuration parameter is an - array, where each entry is a structure that contains element - configuration. The element configuration structure is organized - as follows: - - byte - - Element index, identifies the element to which this - configuration entry pertains. - - array{struct} - - Models array where each entry is a structure with the - following members: - - uint16 - - Either a SIG Model Identifier or, if Vendor key - is present in model configuration dictionary, a - 16-bit vendor-assigned Model Identifier - - dict - - A dictionary that contains model configuration - with the following keys defined: - - array{uint16} Bindings - - Indices of application keys bound to the - model - - uint32 PublicationPeriod - - Model publication period in milliseconds - - uint16 Vendor - - A 16-bit Company ID as defined by the - Bluetooth SIG - - array{variant} Subscriptions - - Addresses the model is subscribed to. - - Each address is provided either as - uint16 for group addresses, or - as array{byte} for virtual labels. - - PossibleErrors: - org.bluez.mesh.Error.InvalidArguments - org.bluez.mesh.Error.NotFound, - org.bluez.mesh.Error.AlreadyExists, - org.bluez.mesh.Error.Busy, - org.bluez.mesh.Error.Failed - - void Leave(uint64 token) - - This removes the configuration information about the mesh node - identified by the 64-bit token parameter. The token parameter - has been obtained as a result of successful Join() method call. - - PossibleErrors: - org.bluez.mesh.Error.InvalidArguments - org.bluez.mesh.Error.NotFound - org.bluez.mesh.Error.Busy - - void CreateNetwork(object app_root, array{byte}[16] uuid) - - This is the first method that an application calls to become - a Provisioner node, and a Configuration Client on a newly - created Mesh Network. - - The app_root parameter is a D-Bus object root path of the - application that implements org.bluez.mesh.Application1 - interface, and a org.bluez.mesh.Provisioner1 interface. The - application represents a node where child mesh elements have - their own objects that implement org.bluez.mesh.Element1 - interface. The application hierarchy also contains a provision - agent object that implements org.bluez.mesh.ProvisionAgent1 - interface. The standard DBus.ObjectManager interface must be - available on the app_root path. - - The uuid parameter is a 16-byte array that contains Device UUID. - This UUID must be unique (at least from the daemon perspective), - therefore attempting to call this function using already - registered UUID results in an error. The composition of the UUID - octets must be in compliance with RFC 4122. - - The other information the bluetooth-meshd daemon will preserve - about the initial node, is to give it the initial primary - unicast address (0x0001), and create and assign a net_key as the - primary network net_index (0x000). - - Upon successful processing of Create() method, the daemon - will call JoinComplete method on object implementing - org.bluez.mesh.Application1. - - PossibleErrors: - org.bluez.mesh.Error.InvalidArguments - org.bluez.mesh.Error.AlreadyExists, - - void Import(object app_root, array{byte}[16] uuid, - array{byte}[16] dev_key, - array{byte}[16] net_key, uint16 net_index, - dict flags, uint32 iv_index, uint16 unicast) - - This method creates a local mesh node based on node - configuration that has been generated outside bluetooth-meshd. - - The app_root parameter is a D-Bus object root path of the - application that implements org.bluez.mesh.Application1 - interface. - - The uuid parameter is a 16-byte array that contains Device UUID. - This UUID must be unique (at least from the daemon perspective), - therefore attempting to call this function using already - registered UUID results in an error. The composition of the UUID - octets must be in compliance with RFC 4122. - - The dev_key parameter is the 16-byte value of the dev key of - the imported mesh node. - - Remaining parameters correspond to provisioning data: - - The net_key and net_index parameters describe the network (or a - subnet, if net_index is not 0) the imported mesh node belongs - to. - - The flags parameter is a dictionary containing provisioning - flags. Supported values are: - - boolean IvUpdate - - When true, indicates that the network is in the - middle of IV Index Update procedure. - - boolean KeyRefresh - - When true, indicates that the specified net key - is in the middle of a key refresh procedure. - - The iv_index parameter is the current IV Index value used by - the network. This value is known by the provisioner. - - The unicast parameter is the primary unicast address of the - imported node. - - Upon successful processing of Import() method, the daemon will - call JoinComplete method on object implementing - org.bluez.mesh.Application1 interface. - - PossibleErrors: - org.bluez.mesh.Error.InvalidArguments, - org.bluez.mesh.Error.AlreadyExists, - org.bluez.mesh.Error.NotSupported, - org.bluez.mesh.Error.Failed - -Mesh Node Hierarchy -=================== -Service org.bluez.mesh -Interface org.bluez.mesh.Node1 -Object path /org/bluez/mesh/node<uuid> - where <uuid> is the Device UUID passed to Join(), - CreateNetwork() or Import() - -Methods: - void Send(object element_path, uint16 destination, uint16 key_index, - dict options, array{byte} data) - - This method is used to send a message originated by a local - model. - - The element_path parameter is the object path of an element from - a collection of the application elements (see Mesh Application - Hierarchy section). - - The destination parameter contains the destination address. This - destination must be a uint16 to a unicast address, or a well - known group address. - - The key_index parameter determines which application key to use - for encrypting the message. The key_index must be valid for that - element, i.e., the application key must be bound to a model on - this element. Otherwise, org.bluez.mesh.Error.NotAuthorized will - be returned. - - The options parameter is a dictionary with the following keys - defined: - - bool ForceSegmented - Specifies whether to force sending of a short - message as one-segment payload. If not present, - the default setting is "false". - - The data parameter is an outgoing message to be encypted by the - bluetooth-meshd daemon and sent on. - - Possible errors: - org.bluez.mesh.Error.NotAuthorized - org.bluez.mesh.Error.InvalidArguments - org.bluez.mesh.Error.NotFound - - void DevKeySend(object element_path, uint16 destination, boolean remote, - uint16 net_index, dict options, array{byte} data) - - This method is used to send a message originated by a local - model encoded with the device key of the remote node. - - The element_path parameter is the object path of an element from - a collection of the application elements (see Mesh Application - Hierarchy section). - - The destination parameter contains the destination address. This - destination must be a uint16 to a unicast address, or a well - known group address. - - The remote parameter, if true, looks up the device key by the - destination address in the key database to encrypt the message. - If remote is true, but requested key does not exist, a NotFound - error will be returned. If set to false, the local node's - device key is used. - - The net_index parameter is the subnet index of the network on - which the message is to be sent. - - The options parameter is a dictionary with the following keys - defined: - - bool ForceSegmented - Specifies whether to force sending of a short - message as one-segment payload. If not present, - the default setting is "false". - - The data parameter is an outgoing message to be encypted by the - meshd daemon and sent on. - - Possible errors: - org.bluez.mesh.Error.InvalidArguments - org.bluez.mesh.Error.NotFound - - void AddNetKey(object element_path, uint16 destination, - uint16 subnet_index, uint16 net_index, boolean update) - - This method is used to send add or update network key originated - by the local configuration client to a remote configuration - server. - - The element_path parameter is the object path of an element from - a collection of the application elements (see Mesh Application - Hierarchy section). - - The destination parameter contains the destination address. This - destination must be a uint16 to a nodes primary unicast address. - - The subnet_index parameter refers to the subnet index of the - network that is being added or updated. This key must exist in - the local key database. - - The net_index parameter is the subnet index of the network on - which the message is to be sent. - - The update parameter indicates if this is an addition or an - update. If true, the subnet key must be in the phase 1 state of - the key update procedure. - - Possible errors: - org.bluez.mesh.Error.InvalidArguments - org.bluez.mesh.Error.NotFound - - void AddAppKey(object element_path, uint16 destination, - uint16 app_index, uint16 net_index, boolean update) - - This method is used to send add or update network key originated - by the local configuration client to a remote configuration - server. - - The element_path parameter is the object path of an element from - a collection of the application elements (see Mesh Application - Hierarchy section). - - The destination parameter contains the destination address. This - destination must be a uint16 to a nodes primary unicast address. - - The app_index parameter refers to the application key which is - being added or updated. This key must exist in the local key - database. - - The net_index parameter is the subnet index of the network on - which the message is to be sent. - - The update parameter indicates if this is an addition or an - update. If true, the subnet key must be in the phase 1 state of - the key update procedure. - - Possible errors: - org.bluez.mesh.Error.InvalidArguments - org.bluez.mesh.Error.NotFound - - void Publish(object element_path, uint16 model, dict options, - array{byte} data) - - This method is used to send a publication originated by a local - model. If the model does not exist, or it has no publication - record, the method returns org.bluez.mesh.Error.DoesNotExist - error. - - The element_path parameter is the object path of an element from - a collection of the application elements (see Mesh Application - Hierarchy section). - - The model parameter contains a model ID, as defined by the - Bluetooth SIG. If the options dictionary contains a "Vendor" - key, then this ID is defined by the specified vendor. - - The options parameter is a dictionary with the following keys - defined: - - bool ForceSegmented - Specifies whether to force sending of a short - message as one-segment payload. If not present, - the default setting is "false". - - uint16 Vendor - A 16-bit Company ID as defined by the - Bluetooth SIG. This key should only exist when - publishing on a Vendor defined model. - - The data parameter is an outgoing message to be encypted by the - meshd daemon and sent on. - - Since only one Publish record may exist per element-model, the - destination and key_index are obtained from the Publication - record cached by the daemon. - - Possible errors: - org.bluez.mesh.Error.DoesNotExist - org.bluez.mesh.Error.InvalidArguments - - -Properties: - dict Features [read-only] - - The dictionary that contains information about feature support. - The following keys are defined: - - boolean Friend - - Indicates the ability to establish a friendship with a - Low Power node - - boolean LowPower - - Indicates support for operating in Low Power node mode - - boolean Proxy - - Indicates support for GATT proxy - - boolean Relay - Indicates support for relaying messages - - If a key is absent from the dictionary, the feature is not supported. - Otherwise, true means that the feature is enabled and false means that - the feature is disabled. - - boolean Beacon [read-only] - - This property indicates whether the periodic beaconing is - enabled (true) or disabled (false). - - boolean IvUpdate [read-only] - - When true, indicates that the network is in the middle of IV - Index Update procedure. This information is only useful for - provisioning. - - uint32 IvIndex [read-only] - - This property may be read at any time to determine the IV_Index - that the current network is on. This information is only useful - for provisioning. - - uint32 SecondsSinceLastHeard [read-only] - - This property may be read at any time to determine the number of - seconds since mesh network layer traffic was last detected on - this node's network. - - array{uint16} Addresses [read-only] - - This property contains unicast addresses of node's elements. - - uint32 SequenceNumber [read-only] - - This property may be read at any time to determine the - sequence number. - -Mesh Provisioning Hierarchy -============================ -Service org.bluez.mesh -Interface org.bluez.mesh.Management1 -Object path /org/bluez/mesh/node<uuid> - where <uuid> is the Device UUID passed to Join(), - CreateNetwork() or Import() - -Methods: - void UnprovisionedScan(dict options) - - This method is used by the application that supports - org.bluez.mesh.Provisioner1 interface to start listening - (scanning) for unprovisioned devices in the area. - - The options parameter is a dictionary with the following keys - defined: - - uint16 Seconds - Specifies number of seconds for scanning to be active. - If set to 0 or if this key is not present, then the - scanning will continue until UnprovisionedScanCancel() - or AddNode() methods are called. - - Each time a unique unprovisioned beacon is heard, the - ScanResult() method on the app will be called with the result. - - PossibleErrors: - org.bluez.mesh.Error.InvalidArguments - org.bluez.mesh.Error.NotAuthorized - org.bluez.mesh.Error.Busy - - void UnprovisionedScanCancel(void) - - This method is used by the application that supports - org.bluez.mesh.Provisioner1 interface to stop listening - (scanning) for unprovisioned devices in the area. - - PossibleErrors: - org.bluez.mesh.Error.InvalidArguments - org.bluez.mesh.Error.NotAuthorized - - void AddNode(array{byte}[16] uuid, dict options) - - This method is used by the application that supports - org.bluez.mesh.Provisioner1 interface to add the - unprovisioned device specified by uuid, to the Network. - - The uuid parameter is a 16-byte array that contains Device UUID - of the unprovisioned device to be added to the network. - - The options parameter is a dictionary that may contain - additional configuration info (currently an empty placeholder - for forward compatibility). - - PossibleErrors: - org.bluez.mesh.Error.InvalidArguments - org.bluez.mesh.Error.NotAuthorized - - void CreateSubnet(uint16 net_index) - - This method is used by the application to generate and add a new - network subnet key. - - The net_index parameter is a 12-bit value (0x001-0xFFF) - specifying which net key to add. - - This call affects the local bluetooth-meshd key database only. - - PossibleErrors: - org.bluez.mesh.Error.Failed - org.bluez.mesh.Error.InvalidArguments - org.bluez.mesh.Error.AlreadyExists - - void ImportSubnet(uint16 net_index, array{byte}[16] net_key) - - This method is used by the application to add a network subnet - key, that was originally generated by a remote Config Client. - - The net_index parameter is a 12-bit value (0x000-0xFFF) - specifying which net key to add. - - The net_key parameter is the 16-byte value of the net key being - imported. - - This call affects the local bluetooth-meshd key database only. - - PossibleErrors: - org.bluez.mesh.Error.Failed - org.bluez.mesh.Error.InvalidArguments - org.bluez.mesh.Error.AlreadyExists - - void UpdateSubnet(uint16 net_index) - - This method is used by the application to generate a new network - subnet key, and set it's key refresh state to Phase 1. - - The net_index parameter is a 12-bit value (0x000-0xFFF) - specifying which net key to update. Note that the subnet must - exist prior to updating. - - This call affects the local bluetooth-meshd key database only. - - PossibleErrors: - org.bluez.mesh.Error.Failed - org.bluez.mesh.Error.InvalidArguments - org.bluez.mesh.Error.DoesNotExist - org.bluez.mesh.Error.Busy - - void DeleteSubnet(uint16 net_index) - - This method is used by the application that to delete a subnet. - - The net_index parameter is a 12-bit value (0x001-0xFFF) - specifying which net key to delete. The primary net key (0x000) - may not be deleted. - - This call affects the local bluetooth-meshd key database only. - - PossibleErrors: - org.bluez.mesh.Error.InvalidArguments - - void SetKeyPhase(uint16 net_index, uint8 phase) - This method is used to set the flooding key update phase of the - given subnet. When finalizing the procedure, it is important - to CompleteAppKeyUpdate() on all app keys that have been - updated during the procedure prior to setting phase 3. - - The net_index parameter is a 12-bit value (0x000-0xFFF) - specifying which subnet phase to set. - - The phase parameter is used to cycle the local key database - through the phases as defined by the Mesh Profile Specification. - Allowed values: - 0 - Cancel Key Refresh (May only be called from Phase 1, - and should never be called once the new key has - started propagating) - 1 - Invalid Argument (see NetKeyUpdate method) - 2 - Go to Phase 2 (May only be called from Phase 1) - 3 - Complete Key Refresh procedure (May only be called - from Phase 2) - - This call affects the local bluetooth-meshd key database only. - It is the responsibility of the application to maintain the key - refresh phases per the Mesh Profile Specification. - - PossibleErrors: - org.bluez.mesh.Error.Failed - org.bluez.mesh.Error.InvalidArguments - org.bluez.mesh.Error.DoesNotExist - - void CreateAppKey(uint16 net_index, uint16 app_index) - - This method is used by the application to generate and add a new - application key. - - The net_index parameter is a 12-bit value (0x000-0xFFF) - specifying which net key to bind the application key to. - - The app_index parameter is a 12-bit value (0x000-0xFFF) - specifying which app key to add. - - This call affects the local bluetooth-meshd key database only. - - PossibleErrors: - org.bluez.mesh.Error.Failed - org.bluez.mesh.Error.InvalidArguments - org.bluez.mesh.Error.AlreadyExists - org.bluez.mesh.Error.DoesNotExist - - void ImportAppKey(uint16 net_index, uint16 app_index, - array{byte}[16] app_key) - - This method is used by the application to add an application - key, that was originally generated by a remote Config Client. - - The net_index parameter is a 12-bit value (0x000-0xFFF) - specifying which net key to bind the application key to. - - The app_index parameter is a 12-bit value (0x000-0xFFF) - specifying which app key to import. - - The app_key parameter is the 16-byte value of the key being - imported. - - This call affects the local bluetooth-meshd key database only. - - PossibleErrors: - org.bluez.mesh.Error.Failed - org.bluez.mesh.Error.InvalidArguments - org.bluez.mesh.Error.AlreadyExists - org.bluez.mesh.Error.DoesNotExist - - void UpdateAppKey(uint16 app_index) - - This method is used by the application to generate a new - application key. - - The app_index parameter is a 12-bit value (0x000-0xFFF) - specifying which app key to update. Note that the subnet that - the key is bound to must exist and be in Phase 1. - - This call affects the local bluetooth-meshd key database only. - - PossibleErrors: - org.bluez.mesh.Error.Failed - org.bluez.mesh.Error.InvalidArguments - org.bluez.mesh.Error.DoesNotExist - org.bluez.mesh.Error.InProgress - - void DeleteAppKey(uint16 app_index) - - This method is used by the application to delete an application - key. - - The app_index parameter is a 12-bit value (0x000-0xFFF) - specifying which app key to delete. - - This call affects the local bluetooth-meshd key database only. - - PossibleErrors: - org.bluez.mesh.Error.InvalidArguments - - void ImportRemoteNode(uint16 primary, uint8 count, - array{byte}[16] device_key) - - This method is used by the application to import a remote node - that has been provisioned by an external process. - - The primary parameter specifies the unicast address of the - the node being imported. - - The count parameter specifies the number of elements that are - assigned to this remote node. - - The device_key parameter is the access layer key that will be - will used to decrypt privledged messages from this remote node. - - This call affects the local bluetooth-meshd key database only. - - It is an error to call this with address range overlapping - with local element addresses. - - PossibleErrors: - org.bluez.mesh.Error.Failed - org.bluez.mesh.Error.InvalidArguments - - void DeleteRemoteNode(uint16 primary, uint8 count) - - This method is used by the application to delete a remote node - from the local device key database. - - The primary parameter specifies the unicast address of the - the node being deleted. - - The count parameter specifies the number of elements that were - assigned to the remote node. - - This call affects the local bluetooth-meshd key database only. - - It is an error to call this with address range overlapping - with local element addresses. - - PossibleErrors: - org.bluez.mesh.Error.InvalidArguments - - dict ExportKeys(void) - - This method is used by the application to export information - about network keys, application keys and device keys present - in the local key database. - - dict - A dictionary that contains information for the keys - stored in the keyring with the following keys defined: - - NetKeys: - array{struct} net_keys: - - uint16 index - Subnet index - - array{byte}[16] key - - dict: - A dictionary that contains optional - key info with the following keys - defined: - - uint8 Phase - Key Refresh phase of the subnet - - array{byte}[16] OldKey - - array{struct} AppKeys: - - uint16 index - - Application key index - - array{byte}[16] key - - dict: - A dictionary of optional - key info with the - following keys defined: - - array{byte}[16] OldKey - - DevKeys: - array{struct} dev_keys: - - Device Key information for known remote - nodes in the configured Mesh network - - uint16 unicast - - Unicast address of the node's primary - element - - array{byte}[16] key - -Mesh Application Hierarchy -========================== -Service unique name -Interface org.bluez.mesh.Application1 -Object path <app_root> - -An application is a collection of elements that host SIG defined and vendor -specific models. It is expected that an application implements -org.freedesktop.DBus.ObjectManager interface at app_root path. - -An example mesh application hierarchy may look like this: - --> /com/example - | - org.freedesktop.DBus.ObjectManager - | - -> /com/example/application - | - org.bluez.mesh.Application1 - | - org.bluez.mesh.Attention1 (optional) - | - org.bluez.mesh.Provisioner1 (optional,Provisioner) - | - -> /com/example/agent - | - org.bluez.mesh.ProvisionAgent1 - | - -> /com/example/ele00 - | - org.bluez.mesh.Element1 - | - -> /com/example/ele01 - | - org.bluez.mesh.Element1 - | - ... - -> /com/example/elexx - - org.bluez.mesh.Element1 - -Methods: - void JoinComplete(uint64 token) - - This method is called when the node provisioning initiated - by a Join() method call successfully completed. - - The token parameter serves as a unique identifier of the - particular node. The token must be preserved by the application - in order to authenticate itself to the mesh daemon and attach to - the network as a mesh node by calling Attach() method or - permanently remove the identity of the mesh node by calling - Leave() method. - - If this method returns an error, the daemon will assume that the - application failed to preserve the token, and will remove the - freshly created node. - - void JoinFailed(string reason) - - This method is called when the node provisioning initiated by - Join() has failed. - - The reason parameter identifies the reason for provisioning - failure. The defined values are: "timeout", "bad-pdu", - "confirmation-failed", "out-of-resources", "decryption-error", - "unexpected-error", "cannot-assign-addresses". - -Properties: - uint16 CompanyID [read-only] - - A 16-bit Bluetooth-assigned Company Identifier of the vendor as - defined by Bluetooth SIG - - uint16 ProductID [read-only] - - A 16-bit vendor-assigned product identifier - - uint16 VersionID [read-only] - - A 16-bit vendor-assigned product version identifier - - uint16 CRPL [read-only, optional] - - A 16-bit minimum number of replay protection list entries - - -Mesh Element Hierarchy -====================== -Service unique name -Interface org.bluez.mesh.Element1 -Object path <app_defined_element_path> - -Methods: - void MessageReceived(uint16 source, uint16 key_index, - variant destination, array{byte} data) - - This method is called by bluetooth-meshd daemon when a message - arrives addressed to the application. - - The source parameter is unicast address of the remote - node-element that sent the message. - - The key_index parameter indicates which application key has been - used to decode the incoming message. The same key_index should - be used by the application when sending a response to this - message (in case a response is expected). - - The destination parameter contains the destination address of - received message. Underlying variant types are: - - uint16 - - Destination is an unicast address, or a well known - group address - - array{byte} - - Destination is a virtual address label - - The data parameter is the incoming message. - - void DevKeyMessageReceived(uint16 source, boolean remote, - uint16 net_index, array{byte} data) - - This method is called by meshd daemon when a message arrives - addressed to the application, which was sent with the remote - node's device key. - - The source parameter is unicast address of the remote - node-element that sent the message. - - The remote parameter if true indicates that the device key - used to decrypt the message was from the sender. False - indicates that the local nodes device key was used, and the - message has permissions to modify local states. - - The net_index parameter indicates what subnet the message was - received on, and if a response is required, the same subnet - must be used to send the response. - - The data parameter is the incoming message. - - void UpdateModelConfiguration(uint16 model_id, dict config) - - This method is called by bluetooth-meshd daemon when a model's - configuration is updated. - - The model_id parameter contains BT SIG Model Identifier or, if - Vendor key is present in config dictionary, a 16-bit - vendor-assigned Model Identifier. - - The config parameter is a dictionary with the following keys - defined: - - array{uint16} Bindings - - Indices of application keys bound to the model - - uint32 PublicationPeriod - - Model publication period in milliseconds - - uint16 Vendor - - A 16-bit Bluetooth-assigned Company Identifier of the - vendor as defined by Bluetooth SIG - - array{variant} Subscriptions - - Addresses the model is subscribed to. - - Each address is provided either as uint16 for group - addresses, or as array{byte} for virtual labels. - -Properties: - uint8 Index [read-only] - - Element index. It is required that the application follows - sequential numbering scheme for the elements, starting with 0. - - array{(uint16 id, dict caps)} Models [read-only] - - An array of SIG Models: - - id - SIG Model Identifier - - options - a dictionary that may contain additional model - info. The following keys are defined: - - boolean Publish - indicates whether the model - supports publication mechanism. If not - present, publication is enabled. - - boolean Subscribe - indicates whether the model - supports subscription mechanism. If not - present, subscriptons are enabled. - - The array may be empty. - - - array{(uint16 vendor, uint16 id, dict options)} VendorModels [read-only] - - An array of Vendor Models: - - vendor - a 16-bit Bluetooth-assigned Company ID as - defined by Bluetooth SIG. - - id - a 16-bit vendor-assigned Model Identifier - - options - a dictionary that may contain additional model - info. The following keys are defined: - - boolean Publish - indicates whether the model - supports publication mechanism - - boolean Subscribe - indicates whether the model - supports subscription mechanism - - The array may be empty. - - uint16 Location [read-only, optional] - - Location descriptor as defined in the GATT Bluetooth Namespace - Descriptors section of the Bluetooth SIG Assigned Numbers - - -Mesh Attention Hierarchy -======================== -Service unique name -Interface org.bluez.mesh.Attention1 -Object path freely definable - -This is an optional interface that implements health attention timer. - -Methods: - void SetTimer(uint8 element_index, uint16 time) - - The element_index parameter is the element's index within the - node where the health server model is hosted. - - The time parameter indicates how many seconds the attention - state shall be on. - - PossibleErrors: - org.bluez.mesh.Error.NotSupported - - uint16 GetTimer(uint16 element) - - The element parameter is the unicast address within the node - where the health server model is hosted. - - Returns the number of seconds for how long the attention action - remains staying on. - - PossibleErrors: - org.bluez.mesh.Error.NotSupported - - -Mesh Provisioner Hierarchy -============================ -Service unique name -Interface org.bluez.mesh.Provisioner1 -Object path freely definable - - void ScanResult(int16 rssi, array{byte} data, dict options) - - The method is called from the bluetooth-meshd daemon when a - unique UUID has been seen during UnprovisionedScan() for - unprovsioned devices. - - The rssi parameter is a signed, normalized measurement of the - signal strength of the recieved unprovisioned beacon. - - The data parameter is a variable length byte array, that may - have 1, 2 or 3 distinct fields contained in it including the 16 - byte remote device UUID (always), a 16 bit mask of OOB - authentication flags (optional), and a 32 bit URI hash (if URI - bit set in OOB mask). Whether these fields exist or not is a - decision of the remote device. - - The options parameter is a dictionary that may contain - additional scan result info (currently an empty placeholder for - forward compatibility). - - If a beacon with a UUID that has already been reported is - recieved by the daemon, it will be silently discarded unless it - was recieved at a higher rssi power level. - - - uint16 net_index, uint16 unicast RequestProvData(uint8 count) - - This method is implemented by a Provisioner capable application - and is called when the remote device has been fully - authenticated and confirmed. - - The count parameter is the number of consecutive unicast - addresses the remote device is requesting. - - Return Parameters are from the Mesh Profile Spec: - net_index - Subnet index of the net_key - unicast - Primary Unicast address of the new node - - PossibleErrors: - org.bluez.mesh.Error.Abort - - void AddNodeComplete(array{byte}[16] uuid, uint16 unicast, uint8 count) - - This method is called when the node provisioning initiated - by an AddNode() method call successfully completed. - - The unicast parameter is the primary address that has been - assigned to the new node, and the address of it's config server. - - The count parameter is the number of unicast addresses assigned - to the new node. - - The new node may now be sent messages using the credentials - supplied by the RequestProvData method. - - void AddNodeFailed(array{byte}[16] uuid, string reason) - - This method is called when the node provisioning initiated by - AddNode() has failed. Depending on how far Provisioning - proceeded before failing, some cleanup of cached data may be - required. - - The reason parameter identifies the reason for provisioning - failure. The defined values are: "aborted", "timeout", - "bad-pdu", "confirmation-failed", "out-of-resources", - "decryption-error", "unexpected-error", - "cannot-assign-addresses". - -Provisioning Agent Hierarchy -============================ -Service unique name -Interface org.bluez.mesh.ProvisionAgent1 -Object path freely definable - -Methods: - array{byte} PrivateKey() - - This method is called during provisioning if the Provisioner - has requested Out-Of-Band ECC key exchange. The Private key is - returned to the Daemon, and the Public Key is delivered to the - remote Provisioner using a method that does not involve the - Bluetooth Mesh system. The Private Key returned must be 32 - octets in size, or the Provisioning procedure will fail and be - canceled. - - This function will only be called if the Provisioner has - requested pre-determined keys to be exchanged Out-of-Band, and - the local role is Unprovisioned device. - - array{byte} PublicKey() - - This method is called during provisioning if the local device is - the Provisioner, and is requestng Out-Of-Band ECC key exchange. - The Public key is returned to the Daemon that is the matched - pair of the Private key of the remote device. The Public Key - returned must be 64 octets in size, or the Provisioning - procedure will fail and be canceled. - - This function will only be called if the Provisioner has - requested pre-determined keys to be exchanged Out-of-Band, and - the local role is Provisioner. - - void DisplayString(string value) - - This method is called when the Daemon has something important - for the Agent to Display, but does not require any additional - input locally. For instance: "Enter "ABCDE" on remote device". - - void DisplayNumeric(string type, uint32 number) - - This method is called when the Daemon has something important - for the Agent to Display, but does not require any additional - input locally. For instance: "Enter 14939264 on remote device". - - The type parameter indicates the display method. Allowed values - are: - "blink" - Locally blink LED - "beep" - Locally make a noise - "vibrate" - Locally vibrate - "out-numeric" - Display value to enter remotely - "push" - Request pushes on remote button - "twist" - Request twists on remote knob - - The number parameter is the specific value represented by the - Prompt. - - uint32 PromptNumeric(string type) - - This method is called when the Daemon requests the user to - enter a decimal value between 1-99999999. - - The type parameter indicates the input method. Allowed values - are: - "blink" - Enter times remote LED blinked - "beep" - Enter times remote device beeped - "vibrate" - Enter times remote device vibrated - "in-numeric" - Enter remotely displayed value - "push" - Push local button remotely requested times - "twist" - Twist local knob remotely requested times - - - This agent should prompt the user for specific input. For - instance: "Enter value being displayed by remote device". - - array{byte}[16] PromptStatic(string type) - - This method is called when the Daemon requires a 16 octet byte - array, as an Out-of-Band authentication. - - The type parameter indicates the input method. Allowed values - are: - "static-oob" - return 16 octet array - "in-alpha" - return 16 octet alpha array - - The Static data returned must be 16 octets in size, or the - Provisioning procedure will fail and be canceled. If input type - is "in-alpha", the printable characters should be - left-justified, with trailing 0x00 octets filling the remaining - bytes. - - void Cancel() - - This method gets called by the daemon to cancel any existing - Agent Requests. When called, any pending user input should be - canceled, and any display requests removed. - - -Properties: - array{string} Capabilities [read-only] - - An array of strings with the following allowed values: - "blink" - "beep" - "vibrate" - "out-numeric" - "out-alpha" - "push" - "twist" - "in-numeric" - "in-alpha" - "static-oob" - "public-oob" - - array{string} OutOfBandInfo [read-only, optional] - - Indicates availability of OOB data. An array of strings with the - following allowed values: - "other" - "uri" - "machine-code-2d" - "bar-code" - "nfc" - "number" - "string" - "on-box" - "in-box" - "on-paper", - "in-manual" - "on-device" - - string URI [read-only, optional] - - Uniform Resource Identifier points to out-of-band (OOB) - information (e.g., a public key) diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt index 90d612ed84ddcbc6611f64667cd4789d0c461ed7..59e61d361dc2c277622e2c13b5106149b76d9ae0 100644 --- a/doc/mgmt-api.txt +++ b/doc/mgmt-api.txt @@ -332,7 +332,10 @@ Read Controller Information Command 15 Static Address 16 PHY Configuration 17 Wideband Speech - 18 Quality Report + 18 Connected Isochronous Stream - Central + 19 Connected Isochronous Stream - Peripheral + 20 Isochronous Broadcaster + 21 Synchronized Receiver This command generates a Command Complete event on success or a Command Status event on failure. @@ -2925,7 +2928,8 @@ Read Extended Controller Information Command 15 Static Address 16 PHY Configuration 17 Wideband Speech - 18 Quality Report + 18 Connected Isochronous Stream - Central + 19 Connected Isochronous Stream - Peripheral The EIR_Data field contains information about class of device, local name and other values. Not all of them might be present. For @@ -4395,6 +4399,7 @@ Device Found Event 2 Not Connectable 3 Reserved (not in use) 4 Name Request Failed + 5 Scan Response For the RSSI field a value of 127 indicates that the RSSI is not available. That can happen with Bluetooth 1.1 and earlier diff --git a/doc/network-api.txt b/doc/network-api.txt deleted file mode 100644 index 109da28bf10de4c0aa26c108a38771a3194523b8..0000000000000000000000000000000000000000 --- a/doc/network-api.txt +++ /dev/null @@ -1,76 +0,0 @@ -BlueZ D-Bus Network API description -*********************************** - - -Network hierarchy -================= - -Service org.bluez -Interface org.bluez.Network1 -Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX - -Methods string Connect(string uuid) - - Connect to the network device and return the network - interface name. Examples of the interface name are - bnep0, bnep1 etc. - - uuid can be either one of "gn", "panu" or "nap" (case - insensitive) or a traditional string representation of - UUID or a hexadecimal number. - - The connection will be closed and network device - released either upon calling Disconnect() or when - the client disappears from the message bus. - - Possible errors: org.bluez.Error.AlreadyConnected - org.bluez.Error.ConnectionAttemptFailed - - 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 - -Properties boolean Connected [readonly] - - Indicates if the device is connected. - - string Interface [readonly] - - Indicates the network interface name when available. - - string UUID [readonly] - - Indicates the connection role when available. - - -Network server hierarchy -======================== - -Service org.bluez -Interface org.bluez.NetworkServer1 -Object path /org/bluez/{hci0,hci1,...} - -Methods void Register(string uuid, string bridge) - - Register server for the provided UUID. Every new - connection to this server will be added the bridge - interface. - - Valid UUIDs are "gn", "panu" or "nap". - - Initially no network server SDP is provided. Only - after this method a SDP record will be available - and the BNEP server will be ready for incoming - connections. - - void Unregister(string uuid) - - Unregister the server for provided UUID. - - All servers will be automatically unregistered when - the calling application terminates. diff --git a/doc/obex-agent-api.txt b/doc/obex-agent-api.txt deleted file mode 100644 index 3923da6df9067215dbc20d6bfc7fe47d42283d13..0000000000000000000000000000000000000000 --- a/doc/obex-agent-api.txt +++ /dev/null @@ -1,61 +0,0 @@ -OBEX D-Bus Agent API description -******************************** - - -Agent Manager hierarchy -======================= - -Service org.bluez.obex -Interface org.bluez.obex.AgentManager1 -Object path /org/bluez/obex - -Methods void RegisterAgent(object agent) - - Register an agent to request authorization of - the user to accept/reject objects. Object push - service needs to authorize each received object. - - Possible errors: org.bluez.obex.Error.AlreadyExists - - void UnregisterAgent(object agent) - - This unregisters the agent that has been previously - registered. The object path parameter must match the - same value that has been used on registration. - - Possible errors: org.bluez.obex.Error.DoesNotExist - - -Agent hierarchy -=============== - -Service unique name -Interface org.bluez.obex.Agent1 -Object path freely definable - -Methods void Release() - - This method gets called when the service daemon - unregisters the agent. An agent can use it to do - cleanup tasks. There is no need to unregister the - agent, because when this method gets called it has - already been unregistered. - - string AuthorizePush(object transfer) - - This method gets called when the service daemon - needs to accept/reject a Bluetooth object push request. - - Returns the full path (including the filename) where - the object shall be stored. The tranfer object will - contain a Filename property that contains the default - location and name that can be returned. - - Possible errors: org.bluez.obex.Error.Rejected - org.bluez.obex.Error.Canceled - - void Cancel() - - This method gets called to indicate that the agent - request failed before a reply was returned. It cancels - the previous request. diff --git a/doc/obex-api.txt b/doc/obex-api.txt deleted file mode 100644 index f39355af0ee768723fbbddef3bf98ae2117b739c..0000000000000000000000000000000000000000 --- a/doc/obex-api.txt +++ /dev/null @@ -1,894 +0,0 @@ -OBEX D-Bus API description -************************** - - -Client hierarchy -================ - -Service org.bluez.obex -Interface org.bluez.obex.Client1 -Object path /org/bluez/obex - -Methods object CreateSession(string destination, dict args) - - Create a new OBEX session for the given remote address. - - The last parameter is a dictionary to hold optional or - type-specific parameters. Typical parameters that can - be set in this dictionary include the following: - - string "Target" : type of session to be created - string "Source" : local address to be used - byte "Channel" - - The currently supported targets are the following: - - "ftp" - "map" - "opp" - "pbap" - "sync" - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - - void RemoveSession(object session) - - Unregister session and abort pending transfers. - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.NotAuthorized - -Session hierarchy -================= - -Service org.bluez.obex -Interface org.bluez.obex.Session1 -Object path /org/bluez/obex/server/session{0, 1, 2, ...} or - /org/bluez/obex/client/session{0, 1, 2, ...} - -Methods string GetCapabilities() - - Get remote device capabilities. - - Possible errors: org.bluez.obex.Error.NotSupported - org.bluez.obex.Error.Failed - -Properties string Source [readonly] - - Bluetooth adapter address - - string Destination [readonly] - - Bluetooth device address - - byte Channel [readonly] - - Bluetooth channel - - string Target [readonly] - - Target UUID - - string Root [readonly] - - Root path - - -Transfer hierarchy -================== - -Service org.bluez.obex -Interface org.bluez.obex.Transfer1 -Object path [Session object path]/transfer{0, 1, 2, ...} - -Methods void Cancel() - - Stops the current transference. - - Possible errors: org.bluez.obex.Error.NotAuthorized - org.bluez.obex.Error.InProgress - org.bluez.obex.Error.Failed - - void Suspend() - - Suspend transference. - - Possible errors: org.bluez.obex.Error.NotAuthorized - org.bluez.obex.Error.NotInProgress - - Note that it is not possible to suspend transfers - which are queued which is why NotInProgress is listed - as possible error. - - void Resume() - - Resume transference. - - Possible errors: org.bluez.obex.Error.NotAuthorized - org.bluez.obex.Error.NotInProgress - - Note that it is not possible to resume transfers - which are queued which is why NotInProgress is listed - as possible error. - -Properties string Status [readonly] - - Inform the current status of the transfer. - - Possible values: "queued", "active", "suspended", - "complete" or "error" - - object Session [readonly] - - The object path of the session the transfer belongs - to. - - string Name [readonly] - - Name of the transferred object. Either Name or Type - or both will be present. - - string Type [readonly] - - Type of the transferred object. Either Name or Type - or both will be present. - - uint64 Time [readonly, optional] - - Time of the transferred object if this is - provided by the remote party. - - uint64 Size [readonly, optional] - - Size of the transferred object. If the size is - unknown, then this property will not be present. - - uint64 Transferred [readonly, optional] - - Number of bytes transferred. For queued transfers, this - value will not be present. - - string Filename [readonly, optional] - - Complete name of the file being received or sent. - - For incoming object push transaction, this will be - the proposed default location and name. It can be - overwritten by the AuthorizePush agent callback - and will be then updated accordingly. - - -Object Push hierarchy -===================== - -Service org.bluez.obex -Interface org.bluez.obex.ObjectPush1 -Object path [Session object path] - -Methods object, dict SendFile(string sourcefile) - - Send one local file to the remote device. - - The returned path represents the newly created transfer, - which should be used to find out if the content has been - successfully transferred or if the operation fails. - - The properties of this transfer are also returned along - with the object path, to avoid a call to GetProperties. - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - - object, dict PullBusinessCard(string targetfile) - - Request the business card from a remote device and - store it in the local file. - - If an empty target file is given, a name will be - automatically calculated for the temporary file. - - The returned path represents the newly created transfer, - which should be used to find out if the content has been - successfully transferred or if the operation fails. - - The properties of this transfer are also returned along - with the object path, to avoid a call to GetProperties. - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - - object, dict ExchangeBusinessCards(string clientfile, - string targetfile) - - Push the client's business card to the remote device - and then retrieve the remote business card and store - it in a local file. - - If an empty target file is given, a name will be - automatically calculated for the temporary file. - - The returned path represents the newly created transfer, - which should be used to find out if the content has been - successfully transferred or if the operation fails. - - The properties of this transfer are also returned along - with the object path, to avoid a call to GetProperties. - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - - -File Transfer hierarchy -======================= - -Service org.bluez.obex -Interface org.bluez.obex.FileTransfer -Object path [Session object path] - -Methods void ChangeFolder(string folder) - - Change the current folder of the remote device. - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - - void CreateFolder(string folder) - - Create a new folder in the remote device. - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - - array{dict} ListFolder() - - Returns a dictionary containing information about - the current folder content. - - The following keys are defined: - - string Name : Object name in UTF-8 format - string Type : Either "folder" or "file" - uint64 Size : Object size or number of items in - folder - string Permission : Group, owner and other - permission - uint64 Modified : Last change - uint64 Accessed : Last access - uint64 Created : Creation date - - Possible errors: org.bluez.obex.Error.Failed - - object, dict GetFile(string targetfile, string sourcefile) - - Copy the source file (from remote device) to the - target file (on local filesystem). - - If an empty target file is given, a name will be - automatically calculated for the temporary file. - - The returned path represents the newly created transfer, - which should be used to find out if the content has been - successfully transferred or if the operation fails. - - The properties of this transfer are also returned along - with the object path, to avoid a call to GetProperties. - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - - object, dict PutFile(string sourcefile, string targetfile) - - Copy the source file (from local filesystem) to the - target file (on remote device). - - The returned path represents the newly created transfer, - which should be used to find out if the content has been - successfully transferred or if the operation fails. - - The properties of this transfer are also returned along - with the object path, to avoid a call to GetProperties. - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - - void CopyFile(string sourcefile, string targetfile) - - Copy a file within the remote device from source file - to target file. - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - - void MoveFile(string sourcefile, string targetfile) - - Move a file within the remote device from source file - to the target file. - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - - void Delete(string file) - - Deletes the specified file/folder. - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - - -Phonebook Access hierarchy -========================== - -Service org.bluez.obex -Interface org.bluez.obex.PhonebookAccess1 -Object path [Session object path] - -Methods void Select(string location, string phonebook) - - Select the phonebook object for other operations. Should - be call before all the other operations. - - location : Where the phonebook is stored, possible - inputs : - "int" ( "internal" which is default ) - "sim" ( "sim1" ) - "sim2" - ... - - phonebook : Possible inputs : - "pb" : phonebook for the saved contacts - "ich": incoming call history - "och": outgoing call history - "mch": missing call history - "cch": combination of ich och mch - "spd": speed dials entry ( only for "internal" ) - "fav": favorites entry ( only for "internal" ) - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - - object, dict PullAll(string targetfile, dict filters) - - Return the entire phonebook object from the PSE server - in plain string with vcard format, and store it in - a local file. - - If an empty target file is given, a name will be - automatically calculated for the temporary file. - - The returned path represents the newly created transfer, - which should be used to find out if the content has been - successfully transferred or if the operation fails. - - The properties of this transfer are also returned along - with the object path, to avoid a call to GetProperties. - - Possible filters: Format, Order, Offset, MaxCount and - Fields - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Forbidden - - array{string vcard, string name} List(dict filters) - - Return an array of vcard-listing data where every entry - consists of a pair of strings containing the vcard - handle and the contact name. For example: - "1.vcf" : "John" - - Possible filters: Order, Offset and MaxCount - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Forbidden - - object, dict - Pull(string vcard, string targetfile, dict filters) - - Given a vcard handle, retrieve the vcard in the current - phonebook object and store it in a local file. - - If an empty target file is given, a name will be - automatically calculated for the temporary file. - - The returned path represents the newly created transfer, - which should be used to find out if the content has been - successfully transferred or if the operation fails. - - The properties of this transfer are also returned along - with the object path, to avoid a call to GetProperties. - - Possbile filters: Format and Fields - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Forbidden - org.bluez.obex.Error.Failed - - array{string vcard, string name} - Search(string field, string value, dict filters) - - Search for entries matching the given condition and - return an array of vcard-listing data where every entry - consists of a pair of strings containing the vcard - handle and the contact name. - - vcard : name paired string match the search condition. - - field : the field in the vcard to search with - { "name" (default) | "number" | "sound" } - value : the string value to search for - - - Possible filters: Order, Offset and MaxCount - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Forbidden - org.bluez.obex.Error.Failed - - uint16 GetSize() - - Return the number of entries in the selected phonebook - object that are actually used (i.e. indexes that - correspond to non-NULL entries). - - Possible errors: org.bluez.obex.Error.Forbidden - org.bluez.obex.Error.Failed - - void UpdateVersion() - - Attempt to update PrimaryCounter and SecondaryCounter. - - Possible errors: org.bluez.obex.Error.NotSupported - org.bluez.obex.Error.Forbidden - org.bluez.obex.Error.Failed - - array{string} ListFilterFields() - - Return All Available fields that can be used in Fields - filter. - - Possible errors: None - -Filter: string Format: - - Items vcard format - - Possible values: "vcard21" (default) or "vcard30" - - string Order: - - Items order - - Possible values: "indexed" (default), "alphanumeric" or - "phonetic" - - uint16 Offset: - - Offset of the first item, default is 0 - - uint16 MaxCount: - - Maximum number of items, default is unlimited (65535) - - array{string} Fields: - - Item vcard fields, default is all values. - - Possible values can be query with ListFilterFields. - - array{string} FilterAll: - - Filter items by fields using AND logic, cannot be used - together with FilterAny. - - Possible values can be query with ListFilterFields. - - array{string} FilterAny: - - Filter items by fields using OR logic, cannot be used - together with FilterAll. - - Possible values can be query with ListFilterFields. - - bool ResetNewMissedCalls - - Reset new the missed calls items, shall only be used - for folders mch and cch. - -Properties string Folder [readonly] - - Current folder. - - string DatabaseIdentifier [readonly, optional] - - 128 bits persistent database identifier. - - Possible values: 32-character hexadecimal such - as A1A2A3A4B1B2C1C2D1D2E1E2E3E4E5E6 - - string PrimaryCounter [readonly, optional] - - 128 bits primary version counter. - - Possible values: 32-character hexadecimal such - as A1A2A3A4B1B2C1C2D1D2E1E2E3E4E5E6 - - string SecondaryCounter [readonly, optional] - - 128 bits secondary version counter. - - Possible values: 32-character hexadecimal such - as A1A2A3A4B1B2C1C2D1D2E1E2E3E4E5E6 - - bool FixedImageSize [readonly, optional] - - Indicate support for fixed image size. - - Possible values: True if image is JPEG 300x300 pixels - otherwise False. - -Synchronization hierarchy -========================= - -Service org.bluez.obex -Interface org.bluez.obex.Synchronization1 -Object path [Session object path] - -Methods void SetLocation(string location) - - Set the phonebook object store location for other - operations. Should be called before all the other - operations. - - location: Where the phonebook is stored, possible - values: - "int" ( "internal" which is default ) - "sim1" - "sim2" - ...... - - Possible errors: org.bluez.obex.Error.InvalidArguments - - object, dict GetPhonebook(string targetfile) - - Retrieve an entire Phonebook Object store from remote - device, and stores it in a local file. - - If an empty target file is given, a name will be - automatically calculated for the temporary file. - - The returned path represents the newly created transfer, - which should be used to find out if the content has been - successfully transferred or if the operation fails. - - The properties of this transfer are also returned along - with the object path, to avoid a call to GetProperties. - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - - object, dict PutPhonebook(string sourcefile) - - Send an entire Phonebook Object store to remote device. - - The returned path represents the newly created transfer, - which should be used to find out if the content has been - successfully transferred or if the operation fails. - - The properties of this transfer are also returned along - with the object path, to avoid a call to GetProperties. - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - - -Message Access hierarchy -========================= - -Service org.bluez.obex -Interface org.bluez.obex.MessageAccess1 -Object path [Session object path] - -Methods void SetFolder(string name) - - Set working directory for current session, *name* may - be the directory name or '..[/dir]'. - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - - array{dict} ListFolders(dict filter) - - Returns a dictionary containing information about - the current folder content. - - The following keys are defined: - - string Name : Folder name - - Possible filters: Offset and MaxCount - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - - array{string} ListFilterFields() - - Return all available fields that can be used in Fields - filter. - - Possible errors: None - - array{object, dict} ListMessages(string folder, dict filter) - - Returns an array containing the messages found in the - given subfolder of the current folder, or in the - current folder if folder is empty. - - Possible Filters: Offset, MaxCount, SubjectLength, Fields, - Type, PeriodStart, PeriodEnd, Status, Recipient, Sender, - Priority - - Each message is represented by an object path followed - by a dictionary of the properties. - - Properties: - - string Subject: - - Message subject - - string Timestamp: - - Message timestamp - - string Sender: - - Message sender name - - string SenderAddress: - - Message sender address - - string ReplyTo: - - Message Reply-To address - - string Recipient: - - Message recipient name - - string RecipientAddress: - - Message recipient address - - string Type: - - Message type - - Possible values: "email", "sms-gsm", - "sms-cdma" and "mms" - - uint64 Size: - - Message size in bytes - - boolean Text: - - Message text flag - - Specifies whether message has textual - content or is binary only - - string Status: - - Message status - - Possible values for received messages: - "complete", "fractioned", "notification" - - Possible values for sent messages: - "delivery-success", "sending-success", - "delivery-failure", "sending-failure" - - uint64 AttachmentSize: - - Message overall attachment size in bytes - - boolean Priority: - - Message priority flag - - boolean Read: - - Message read flag - - boolean Sent: - - Message sent flag - - boolean Protected: - - Message protected flag - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - - void UpdateInbox(void) - - Request remote to update its inbox. - - Possible errors: org.bluez.obex.Error.Failed - - object, dict - PushMessage(string sourcefile, string folder, dict args) - - Transfer a message (in bMessage format) to the - remote device. - - The message is transferred either to the given - subfolder of the current folder, or to the current - folder if folder is empty. - - Possible args: Transparent, Retry, Charset - - The returned path represents the newly created transfer, - which should be used to find out if the content has been - successfully transferred or if the operation fails. - - The properties of this transfer are also returned along - with the object path, to avoid a call to GetAll. - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - - -Filter: uint16 Offset: - - Offset of the first item, default is 0 - - uint16 MaxCount: - - Maximum number of items, default is 1024 - - byte SubjectLength: - - Maximum length of the Subject property in the - message, default is 256 - - array{string} Fields: - - Message fields, default is all values. - - Possible values can be query with ListFilterFields. - - array{string} Types: - - Filter messages by type. - - Possible values: "sms", "email", "mms". - - string PeriodBegin: - - Filter messages by starting period. - - Possible values: Date in "YYYYMMDDTHHMMSS" format. - - string PeriodEnd: - - Filter messages by ending period. - - Possible values: Date in "YYYYMMDDTHHMMSS" format. - - boolean Read: - - Filter messages by read flag. - - Possible values: True for read or False for unread - - string Recipient: - - Filter messages by recipient address. - - string Sender: - - Filter messages by sender address. - - boolean Priority: - - Filter messages by priority flag. - - Possible values: True for high priority or False for - non-high priority - -Message hierarchy -================= - -Service org.bluez.obex -Interface org.bluez.obex.Message1 -Object path [Session object path]/{message0,...} - -Methods object, dict Get(string targetfile, boolean attachment) - - Download message and store it in the target file. - - If an empty target file is given, a temporary file - will be automatically generated. - - The returned path represents the newly created transfer, - which should be used to find out if the content has been - successfully transferred or if the operation fails. - - The properties of this transfer are also returned along - with the object path, to avoid a call to GetProperties. - - Possible errors: org.bluez.obex.Error.InvalidArguments - org.bluez.obex.Error.Failed - -Properties string Folder [readonly] - - Folder which the message belongs to - - string Subject [readonly] - - Message subject - - string Timestamp [readonly] - - Message timestamp - - string Sender [readonly] - - Message sender name - - string SenderAddress [readonly] - - Message sender address - - string ReplyTo [readonly] - - Message Reply-To address - - string Recipient [readonly] - - Message recipient name - - string RecipientAddress [readonly] - - Message recipient address - - string Type [readonly] - - Message type - - Possible values: "email", "sms-gsm", - "sms-cdma" and "mms" - - uint64 Size [readonly] - - Message size in bytes - - string Status [readonly] - - Message reception status - - Possible values: "complete", - "fractioned" and "notification" - - boolean Priority [readonly] - - Message priority flag - - boolean Read [read/write] - - Message read flag - - boolean Deleted [writeonly] - - Message deleted flag - - boolean Sent [readonly] - - Message sent flag - - boolean Protected [readonly] - - Message protected flag diff --git a/doc/org.bluez.Adapter.5 b/doc/org.bluez.Adapter.5 new file mode 100644 index 0000000000000000000000000000000000000000..40cc4053ec378c1f05a14e6faf4d83aefff53382 --- /dev/null +++ b/doc/org.bluez.Adapter.5 @@ -0,0 +1,486 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.ADAPTER" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.Adapter \- BlueZ D-Bus Adapter API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.Adapter1 +.TP +.B Object path +[variable prefix]/{hci0,hci1,...} +.UNINDENT +.SS Methods +.SS void StartDiscovery() +.INDENT 0.0 +.INDENT 3.5 +Starts device discovery session which may include starting an inquiry +and/or scanning procedures and remote device name resolving. +.sp +Use \fBStopDiscovery\fP to release the sessions acquired. +.sp +This process will start creating Device objects as new devices are +discovered. +.sp +During discovery RSSI delta\-threshold is imposed. +.sp +Each client can request a single device discovery session per adapter. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotReady +.TP +.B org.bluez.Error.Failed +.TP +.B org.bluez.Error.InProgress +.UNINDENT +.UNINDENT +.UNINDENT +.SS void StopDiscovery() +.INDENT 0.0 +.INDENT 3.5 +Stops device discovery session started by \fBStartDiscovery\fP\&. +.sp +Note that a discovery procedure is shared between all discovery sessions +thus calling StopDiscovery will only release a single session and +discovery will stop when all sessions from all clients have finished. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotReady +.TP +.B org.bluez.Error.Failed +.TP +.B org.bluez.Error.NotAuthorized +.UNINDENT +.UNINDENT +.UNINDENT +.SS void RemoveDevice(object device) +.INDENT 0.0 +.INDENT 3.5 +Removes the remote device object at the given path including cahed +information such as bonding information. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void SetDiscoveryFilter(dict filter) +.INDENT 0.0 +.INDENT 3.5 +Sets the device discovery filter for the caller. When this method is +called with no filter parameter, filter is removed. +.sp +Possible filter values: +.INDENT 0.0 +.TP +.B array{string} UUIDs +Filter by service UUIDs, empty means match \fIany\fP UUID. +.sp +When a remote device is found that advertises any UUID from +UUIDs, it will be reported if: +.INDENT 7.0 +.IP \(bu 2 +\fBPathloss\fP and \fBRSSI\fP are both empty. +.IP \(bu 2 +only \fBPathloss\fP param is set, device advertise TX power, and +computed pathloss is less than Pathloss param. +.IP \(bu 2 +only \fBRSSI\fP param is set, and received RSSI is higher +than RSSI param. +.UNINDENT +.TP +.B int16 RSSI +RSSI threshold value. +.sp +PropertiesChanged signals will be emitted for already existing +Device objects, with updated RSSI value. If one or more +discovery filters have been set, the RSSI delta\-threshold, that +is imposed by StartDiscovery by default, will not be applied. +.TP +.B uint16 Pathloss +Pathloss threshold value. +.sp +PropertiesChanged signals will be emitted for already existing +Device objects, with updated Pathloss value. +.TP +.B string Transport (Default \(dqauto\(dq) +Transport parameter determines the type of scan. +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dqauto\(dq +Interleaved scan, use LE, BREDR, or both, depending on +what\(aqs currently enabled. +.TP +.B \(dqbredr\(dq +BR/EDR inquiry only. +.TP +.B \(dqle\(dq +LE scan only. +.UNINDENT +.TP +.B bool DuplicateData (Default true) +Disables duplicate detection of advertisement data. +.sp +When enabled PropertiesChanged signals will be generated for +either ManufacturerData and ServiceData everytime they are +discovered. +.TP +.B bool Discoverable (Default false) +Make adapter discoverable while discovering, if the adapter is +already discoverable setting this filter won\(aqt do anything. +.TP +.B string Pattern (Default none) +Discover devices where the pattern matches either the prefix of +the address or device name which is convenient way to limited +the number of device objects created during a discovery. +.sp +When set disregards device discoverable flags. +.sp +Note: The pattern matching is ignored if there are other client +that don\(aqt set any pattern as it work as a logical OR, also +setting empty string \(dq\(dq pattern will match any device found. +.sp +When discovery filter is set, Device objects will be created as +new devices with matching criteria are discovered regardless of +they are connectable or discoverable which enables listening to +non\-connectable and non\-discoverable devices. +.sp +When multiple clients call SetDiscoveryFilter, their filters are +internally merged, and notifications about new devices are sent +to all clients. Therefore, each client must check that device +updates actually match its filter. +.sp +When SetDiscoveryFilter is called multiple times by the same +client, last filter passed will be active for given client. +.sp +SetDiscoveryFilter can be called before StartDiscovery. +It is useful when client will create first discovery session, +to ensure that proper scan will be started right after call to +StartDiscovery. +.sp +Possible errors: +.INDENT 7.0 +.TP +.B org.bluez.Error.NotReady +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.SS array{string} GetDiscoveryFilters() +.INDENT 0.0 +.INDENT 3.5 +Returns available filters that can be given to \fBSetDiscoveryFilter\fP\&. +.sp +Possible errors: None +.UNINDENT +.UNINDENT +.SS object ConnectDevice(dict properties) [experimental] +.INDENT 0.0 +.INDENT 3.5 +connects to device without need of performing General Discovery. +Connection mechanism is similar to Connect method on +\fBorg.bluez.Device1(5)\fP interface with exception that this method +returns success when physical connection is established and you can +specify bearer to connect with parameter. After this method returns, +services discovery will continue and any supported profile will be +connected. There is no need for calling Connect on Device1 after this +call. If connection was successful this method returns object path to +created device object or device that already exist. +.sp +Possible properties values: +.INDENT 0.0 +.TP +.B string Address (Mandatory) +The Bluetooth device address of the remote device. +.TP +.B string AddressType (Default \(dqBR/EDR\(dq) +The Bluetooth device Address Type. This is address type that +should be used for initial connection. +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dqpublic\(dq +Public address +.TP +.B \(dqrandom\(dq +Random address +.UNINDENT +.UNINDENT +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.AlreadyExists +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.NotReady +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS Properties +.SS string Address [readonly] +.INDENT 0.0 +.INDENT 3.5 +The Bluetooth device address. +.UNINDENT +.UNINDENT +.SS string AddressType [readonly] +.INDENT 0.0 +.INDENT 3.5 +The Bluetooth Address Type. For dual\-mode and BR/EDR only adapter this +defaults to \(dqpublic\(dq. Single mode LE adapters may have either value. +With privacy enabled this contains type of Identity Address and not +type of address used for connection. +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqpublic\(dq +Public address. +.TP +.B \(dqrandom +Random address. +.UNINDENT +.UNINDENT +.UNINDENT +.SS string Name [readonly] +.INDENT 0.0 +.INDENT 3.5 +The Bluetooth system name (pretty hostname). +.sp +This property is either a static system default or controlled by an +external daemon providing access to the pretty hostname configuration. +.UNINDENT +.UNINDENT +.SS string Alias [readwrite] +.INDENT 0.0 +.INDENT 3.5 +The Bluetooth friendly name. This value can be changed. +.sp +In case no alias is set, it will return the system provided name. +Setting an empty string as alias will convert it back to the system +provided name. +.sp +When resetting the alias with an empty string, the property will default +back to system name. +.sp +On a well configured system, this property never needs to be changed +since it defaults to the system name and provides the pretty hostname. +Only if the local name needs to be different from the pretty hostname, +this property should be used as last resort. +.UNINDENT +.UNINDENT +.SS uint32 Class [readonly] +.INDENT 0.0 +.INDENT 3.5 +The Bluetooth class of device. +.sp +This property represents the value that is either automatically +configured by DMI/ACPI information or provided as static configuration. +.UNINDENT +.UNINDENT +.SS boolean Connectable [readwrite] +.INDENT 0.0 +.INDENT 3.5 +Set an adapter to connectable or non\-connectable. This is a global +setting and should only be used by the settings application. +.sp +Setting this property to false will set the Discoverable property +of the adapter to false as well, which will not be reverted if +if Connectable is set back to true. If required, the application +will need to manually set Discoverable to true. +.sp +Note that this property only affects incoming connections. +.UNINDENT +.UNINDENT +.SS boolean Powered [readwrite] +.INDENT 0.0 +.INDENT 3.5 +Switch an adapter on or off. This will also set the appropriate +connectable state of the controller. +.sp +The value of this property is not persistent. After restart or +unplugging of the adapter it will reset back to false. +.UNINDENT +.UNINDENT +.SS string PowerState [readonly, experimental] +.INDENT 0.0 +.INDENT 3.5 +The power state of an adapter. +.sp +The power state will show whether the adapter is turning off, or turning +on, as well as being on or off. +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqon\(dq +Powered on. +.TP +.B \(dqoff\(dq +Powered off +.TP +.B \(dqoff\-enabling\(dq +Transitioning from \(dqoff\(dq to \(dqon\(dq. +.TP +.B \(dqon\-disabling\(dq +Transitioning from \(dqon\(dq to \(dqoff\(dq. +.TP +.B \(dqoff\-blocked\(dq +Blocked by rfkill. +.UNINDENT +.UNINDENT +.UNINDENT +.SS boolean Discoverable [readwrite] (Default: false) +.INDENT 0.0 +.INDENT 3.5 +Switch an adapter to discoverable or non\-discoverable to either make it +visible or hide it. This is a global setting and should only be used by +the settings application. +.sp +If the DiscoverableTimeout is set to a non\-zero value then the system +will set this value back to false after the timer expired. +.sp +In case the adapter is switched off, setting this value will fail. +.sp +When changing the Powered property the new state of this property will +be updated via a PropertiesChanged signal. +.UNINDENT +.UNINDENT +.SS boolean Pairable [readwrite] (Default: true) +.INDENT 0.0 +.INDENT 3.5 +Switch an adapter to pairable or non\-pairable. This is a global setting +and should only be used by the settings application. +.sp +Note that this property only affects incoming pairing requests. +.UNINDENT +.UNINDENT +.SS uint32 PairableTimeout [readwrite] (Default: 0) +.INDENT 0.0 +.INDENT 3.5 +The pairable timeout in seconds. A value of zero means that the timeout +is disabled and it will stay in pairable mode forever. +.UNINDENT +.UNINDENT +.SS uint32 DiscoverableTimeout [readwrite] (Default: 180) +.INDENT 0.0 +.INDENT 3.5 +The discoverable timeout in seconds. A value of zero means that the +timeout is disabled and it will stay in discoverable/limited mode +forever. +.UNINDENT +.UNINDENT +.SS boolean Discovering [readonly] +.INDENT 0.0 +.INDENT 3.5 +Indicates that a device discovery procedure is active. +.UNINDENT +.UNINDENT +.SS array{string} UUIDs [readonly] +.INDENT 0.0 +.INDENT 3.5 +List of 128\-bit UUIDs that represents the available local services. +.UNINDENT +.UNINDENT +.SS string Modalias [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Local Device ID information in modalias format used by the kernel and +udev. +.UNINDENT +.UNINDENT +.SS array{string} Roles [readonly] +.INDENT 0.0 +.INDENT 3.5 +List of supported roles. +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqcentral\(dq +Supports the central role. +.TP +.B \(dqperipheral\(dq +Supports the peripheral role. +.TP +.B \(dqcentral\-peripheral\(dq +Supports both roles concurrently. +.UNINDENT +.UNINDENT +.UNINDENT +.SS array{string} ExperimentalFeatures [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +List of 128\-bit UUIDs that represents the experimental features +currently enabled. +.UNINDENT +.UNINDENT +.SS uint16 Manufacturer [readonly] +.INDENT 0.0 +.INDENT 3.5 +The manufacturer of the device, as a uint16 company identifier defined +by the Core Bluetooth Specification. +.UNINDENT +.UNINDENT +.SS byte Version [readonly] +.INDENT 0.0 +.INDENT 3.5 +The Bluetooth version supported by the device, as a core version code +defined by the Core Bluetooth Specification. +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.Adapter.rst b/doc/org.bluez.Adapter.rst new file mode 100644 index 0000000000000000000000000000000000000000..3f5fdc8fe9941965e5a03e6fbf55a8aebe05654e --- /dev/null +++ b/doc/org.bluez.Adapter.rst @@ -0,0 +1,425 @@ +================= +org.bluez.Adapter +================= + +------------------------------------- +BlueZ D-Bus Adapter API documentation +------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez +:Interface: org.bluez.Adapter1 +:Object path: [variable prefix]/{hci0,hci1,...} + +Methods +------- + +void StartDiscovery() +````````````````````` + + Starts device discovery session which may include starting an inquiry + and/or scanning procedures and remote device name resolving. + + Use **StopDiscovery** to release the sessions acquired. + + This process will start creating Device objects as new devices are + discovered. + + During discovery RSSI delta-threshold is imposed. + + Each client can request a single device discovery session per adapter. + + Possible errors: + + :org.bluez.Error.NotReady: + :org.bluez.Error.Failed: + :org.bluez.Error.InProgress: + +void StopDiscovery() +```````````````````` + + Stops device discovery session started by **StartDiscovery**. + + Note that a discovery procedure is shared between all discovery sessions + thus calling StopDiscovery will only release a single session and + discovery will stop when all sessions from all clients have finished. + + Possible errors: + + :org.bluez.Error.NotReady: + :org.bluez.Error.Failed: + :org.bluez.Error.NotAuthorized: + +void RemoveDevice(object device) +```````````````````````````````` + + Removes the remote device object at the given path including cahed + information such as bonding information. + + Possible errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.Failed: + +void SetDiscoveryFilter(dict filter) +```````````````````````````````````` + + Sets the device discovery filter for the caller. When this method is + called with no filter parameter, filter is removed. + + Possible filter values: + + :array{string} UUIDs: + + Filter by service UUIDs, empty means match *any* UUID. + + When a remote device is found that advertises any UUID from + UUIDs, it will be reported if: + + - **Pathloss** and **RSSI** are both empty. + - only **Pathloss** param is set, device advertise TX power, and + computed pathloss is less than Pathloss param. + - only **RSSI** param is set, and received RSSI is higher + than RSSI param. + + :int16 RSSI: + + RSSI threshold value. + + PropertiesChanged signals will be emitted for already existing + Device objects, with updated RSSI value. If one or more + discovery filters have been set, the RSSI delta-threshold, that + is imposed by StartDiscovery by default, will not be applied. + + :uint16 Pathloss: + + Pathloss threshold value. + + PropertiesChanged signals will be emitted for already existing + Device objects, with updated Pathloss value. + + :string Transport (Default "auto"): + + Transport parameter determines the type of scan. + + Possible values: + + :"auto": + + Interleaved scan, use LE, BREDR, or both, depending on + what's currently enabled. + + :"bredr": + + BR/EDR inquiry only. + + :"le": + + LE scan only. + + + :bool DuplicateData (Default true): + + Disables duplicate detection of advertisement data. + + When enabled PropertiesChanged signals will be generated for + either ManufacturerData and ServiceData everytime they are + discovered. + + :bool Discoverable (Default false): + + Make adapter discoverable while discovering, if the adapter is + already discoverable setting this filter won't do anything. + + :string Pattern (Default none): + + Discover devices where the pattern matches either the prefix of + the address or device name which is convenient way to limited + the number of device objects created during a discovery. + + When set disregards device discoverable flags. + + Note: The pattern matching is ignored if there are other client + that don't set any pattern as it work as a logical OR, also + setting empty string "" pattern will match any device found. + + When discovery filter is set, Device objects will be created as + new devices with matching criteria are discovered regardless of + they are connectable or discoverable which enables listening to + non-connectable and non-discoverable devices. + + When multiple clients call SetDiscoveryFilter, their filters are + internally merged, and notifications about new devices are sent + to all clients. Therefore, each client must check that device + updates actually match its filter. + + When SetDiscoveryFilter is called multiple times by the same + client, last filter passed will be active for given client. + + SetDiscoveryFilter can be called before StartDiscovery. + It is useful when client will create first discovery session, + to ensure that proper scan will be started right after call to + StartDiscovery. + + Possible errors: + + :org.bluez.Error.NotReady: + :org.bluez.Error.NotSupported: + :org.bluez.Error.Failed: + +array{string} GetDiscoveryFilters() +``````````````````````````````````` + + Returns available filters that can be given to **SetDiscoveryFilter**. + + Possible errors: None + +object ConnectDevice(dict properties) [experimental] +```````````````````````````````````````````````````` + + connects to device without need of performing General Discovery. + Connection mechanism is similar to Connect method on + **org.bluez.Device1(5)** interface with exception that this method + returns success when physical connection is established and you can + specify bearer to connect with parameter. After this method returns, + services discovery will continue and any supported profile will be + connected. There is no need for calling Connect on Device1 after this + call. If connection was successful this method returns object path to + created device object or device that already exist. + + Possible properties values: + + :string Address (Mandatory): + + The Bluetooth device address of the remote device. + + :string AddressType (Default "BR/EDR"): + + The Bluetooth device Address Type. This is address type that + should be used for initial connection. + + Possible values: + + :"public": + + Public address + + :"random": + + Random address + + Possible errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.AlreadyExists: + :org.bluez.Error.NotSupported: + :org.bluez.Error.NotReady: + :org.bluez.Error.Failed: + +Properties +---------- + +string Address [readonly] +````````````````````````` + + The Bluetooth device address. + +string AddressType [readonly] +````````````````````````````` + + The Bluetooth Address Type. For dual-mode and BR/EDR only adapter this + defaults to "public". Single mode LE adapters may have either value. + With privacy enabled this contains type of Identity Address and not + type of address used for connection. + + Possible values: + + :"public": + + Public address. + + + :"random: + + Random address. + +string Name [readonly] +`````````````````````` + + The Bluetooth system name (pretty hostname). + + This property is either a static system default or controlled by an + external daemon providing access to the pretty hostname configuration. + +string Alias [readwrite] +```````````````````````` + + The Bluetooth friendly name. This value can be changed. + + In case no alias is set, it will return the system provided name. + Setting an empty string as alias will convert it back to the system + provided name. + + When resetting the alias with an empty string, the property will default + back to system name. + + On a well configured system, this property never needs to be changed + since it defaults to the system name and provides the pretty hostname. + Only if the local name needs to be different from the pretty hostname, + this property should be used as last resort. + +uint32 Class [readonly] +``````````````````````` + + The Bluetooth class of device. + + This property represents the value that is either automatically + configured by DMI/ACPI information or provided as static configuration. + +boolean Connectable [readwrite] +``````````````````````````````` + + Set an adapter to connectable or non-connectable. This is a global + setting and should only be used by the settings application. + + Setting this property to false will set the Discoverable property + of the adapter to false as well, which will not be reverted if + if Connectable is set back to true. If required, the application + will need to manually set Discoverable to true. + + Note that this property only affects incoming connections. + +boolean Powered [readwrite] +``````````````````````````` + + Switch an adapter on or off. This will also set the appropriate + connectable state of the controller. + + The value of this property is not persistent. After restart or + unplugging of the adapter it will reset back to false. + +string PowerState [readonly, experimental] +`````````````````````````````````````````` + + The power state of an adapter. + + The power state will show whether the adapter is turning off, or turning + on, as well as being on or off. + + Possible values: + + :"on": + + Powered on. + + :"off": + + Powered off + + :"off-enabling": + + Transitioning from "off" to "on". + + :"on-disabling": + + Transitioning from "on" to "off". + + :"off-blocked": + + Blocked by rfkill. + +boolean Discoverable [readwrite] (Default: false) +````````````````````````````````````````````````` + + Switch an adapter to discoverable or non-discoverable to either make it + visible or hide it. This is a global setting and should only be used by + the settings application. + + If the DiscoverableTimeout is set to a non-zero value then the system + will set this value back to false after the timer expired. + + In case the adapter is switched off, setting this value will fail. + + When changing the Powered property the new state of this property will + be updated via a PropertiesChanged signal. + +boolean Pairable [readwrite] (Default: true) +```````````````````````````````````````````` + + Switch an adapter to pairable or non-pairable. This is a global setting + and should only be used by the settings application. + + Note that this property only affects incoming pairing requests. + +uint32 PairableTimeout [readwrite] (Default: 0) +``````````````````````````````````````````````` + + The pairable timeout in seconds. A value of zero means that the timeout + is disabled and it will stay in pairable mode forever. + +uint32 DiscoverableTimeout [readwrite] (Default: 180) +````````````````````````````````````````````````````` + + The discoverable timeout in seconds. A value of zero means that the + timeout is disabled and it will stay in discoverable/limited mode + forever. + +boolean Discovering [readonly] +`````````````````````````````` + + Indicates that a device discovery procedure is active. + +array{string} UUIDs [readonly] +`````````````````````````````` + + List of 128-bit UUIDs that represents the available local services. + +string Modalias [readonly, optional] +```````````````````````````````````` + + Local Device ID information in modalias format used by the kernel and + udev. + +array{string} Roles [readonly] +`````````````````````````````` + + List of supported roles. + + Possible values: + + :"central": + + Supports the central role. + + :"peripheral": + + Supports the peripheral role. + + :"central-peripheral": + + Supports both roles concurrently. + +array{string} ExperimentalFeatures [readonly, optional] +``````````````````````````````````````````````````````` + + List of 128-bit UUIDs that represents the experimental features + currently enabled. + +uint16 Manufacturer [readonly] +`````````````````````````````` + + The manufacturer of the device, as a uint16 company identifier defined + by the Core Bluetooth Specification. + +byte Version [readonly] +``````````````````````` + + The Bluetooth version supported by the device, as a core version code + defined by the Core Bluetooth Specification. diff --git a/doc/org.bluez.AdminPolicySet.5 b/doc/org.bluez.AdminPolicySet.5 new file mode 100644 index 0000000000000000000000000000000000000000..9367bf99d1e0800e2ebf340386ea13f00783a9b9 --- /dev/null +++ b/doc/org.bluez.AdminPolicySet.5 @@ -0,0 +1,79 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.ADMINPOLICYSET" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.AdminPolicySet \- BlueZ D-Bus AdminPolicySet API documentation +.SH DESCRIPTION +.sp +This API provides methods to control the behavior of \fBbluetoothd(8)\fP as an +administrator. +.sp +Interface AdminPolicySet1 provides methods to set policies. Once the policy is +set successfully, it will affect all clients and stay persistently even after +restarting \fBbluetoothd(8)\fP\&. The only way to clear it is to overwrite the +policy with the same method. +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.AdminPolicySet1 [experimental] +.TP +.B Object path +[variable prefix]/{hci0,hci1,...} +.UNINDENT +.SS Methods +.SS void SetServiceAllowList(array{string} UUIDs) +.INDENT 0.0 +.INDENT 3.5 +Sets the service allowlist by specifying service UUIDs. +.sp +When called, \fBbluetoothd(8)\fP will block incoming and outgoing +connections to the service not in UUIDs for all of the clients. +.sp +Any subsequent calls to this method will supersede any previously set +allowlist values. Calling this method with an empty array will allow +any service UUIDs to be used. +.sp +The default value is an empty array. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.AdminPolicySet.rst b/doc/org.bluez.AdminPolicySet.rst new file mode 100644 index 0000000000000000000000000000000000000000..7ce4efcfed9954664b4d01813b15978f1d754541 --- /dev/null +++ b/doc/org.bluez.AdminPolicySet.rst @@ -0,0 +1,52 @@ +======================== +org.bluez.AdminPolicySet +======================== + +-------------------------------------------- +BlueZ D-Bus AdminPolicySet API documentation +-------------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Description +============ + +This API provides methods to control the behavior of **bluetoothd(8)** as an +administrator. + +Interface AdminPolicySet1 provides methods to set policies. Once the policy is +set successfully, it will affect all clients and stay persistently even after +restarting **bluetoothd(8)**. The only way to clear it is to overwrite the +policy with the same method. + +Interface +========= + +:Service: org.bluez +:Interface: org.bluez.AdminPolicySet1 [experimental] +:Object path: [variable prefix]/{hci0,hci1,...} + +Methods +------- + +void SetServiceAllowList(array{string} UUIDs) +````````````````````````````````````````````` + + Sets the service allowlist by specifying service UUIDs. + + When called, **bluetoothd(8)** will block incoming and outgoing + connections to the service not in UUIDs for all of the clients. + + Any subsequent calls to this method will supersede any previously set + allowlist values. Calling this method with an empty array will allow + any service UUIDs to be used. + + The default value is an empty array. + + Possible errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.Failed: diff --git a/doc/org.bluez.AdminPolicyStatus.5 b/doc/org.bluez.AdminPolicyStatus.5 new file mode 100644 index 0000000000000000000000000000000000000000..e11d28ec993edcd27f2c769f710f43b25a6bb89f --- /dev/null +++ b/doc/org.bluez.AdminPolicyStatus.5 @@ -0,0 +1,77 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.ADMINPOLICYSTATUS" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.AdminPolicyStatus \- BlueZ D-Bus AdminPolicyStatus API documentation +.SH DESCRIPTION +.sp +Interface AdminPolicyStatus1 provides readonly properties to indicate the +current values of admin policy affecting the Adapter and Device objects. +.SH INTERFACE +.SS Adapter +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.AdminPolicyStatus1 [experimental] +.TP +.B Object path +[variable prefix]/{hci0,hci1,...} +.UNINDENT +.SS Device +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.AdminPolicyStatus1 [experimental] +.TP +.B Object path +[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX +.UNINDENT +.SS Properties +.SS array{string} ServiceAllowList [readonly, adapter\-only] +.INDENT 0.0 +.INDENT 3.5 +Current value of service allow list. +.UNINDENT +.UNINDENT +.SS bool IsAffectedByPolicy [readonly, device\-only] +.INDENT 0.0 +.INDENT 3.5 +Indicate if there is any auto\-connect profile in this device is not +allowed by admin policy. +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.AdminPolicyStatus.rst b/doc/org.bluez.AdminPolicyStatus.rst new file mode 100644 index 0000000000000000000000000000000000000000..ad2dc58dec0a45a7a987d7b0aa60538d505784a3 --- /dev/null +++ b/doc/org.bluez.AdminPolicyStatus.rst @@ -0,0 +1,49 @@ +=========================== +org.bluez.AdminPolicyStatus +=========================== + +----------------------------------------------- +BlueZ D-Bus AdminPolicyStatus API documentation +----------------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Description +=========== + +Interface AdminPolicyStatus1 provides readonly properties to indicate the +current values of admin policy affecting the Adapter and Device objects. + +Interface +========= + +Adapter +------- + +:Service: org.bluez +:Interface: org.bluez.AdminPolicyStatus1 [experimental] +:Object path: [variable prefix]/{hci0,hci1,...} + +Device +------ + +:Service: org.bluez +:Interface: org.bluez.AdminPolicyStatus1 [experimental] +:Object path: [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX + +Properties +---------- + +array{string} ServiceAllowList [readonly, adapter-only] +``````````````````````````````````````````````````````` + + Current value of service allow list. + +bool IsAffectedByPolicy [readonly, device-only] +``````````````````````````````````````````````` + + Indicate if there is any auto-connect profile in this device is not + allowed by admin policy. diff --git a/doc/org.bluez.AdvertisementMonitor.5 b/doc/org.bluez.AdvertisementMonitor.5 new file mode 100644 index 0000000000000000000000000000000000000000..b1058e09b6229e75df430334f69e635696b27e1b --- /dev/null +++ b/doc/org.bluez.AdvertisementMonitor.5 @@ -0,0 +1,189 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.ADVERTISEMENTMONITOR" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.AdvertisementMonitor \- BlueZ D-Bus AdvertisementMonitor API documentation +.SH DESCRIPTION +.sp +This API allows an client to specify a job of monitoring advertisements by +registering the root of hierarchy and then exposing advertisement monitors +under the root with filtering conditions, thresholds of RSSI and timers +of RSSI thresholds. +.sp +Once a monitoring job is activated by \fBbluetoothd(8)\fP, the client can expect +to get notified on the targeted advertisements no matter if there is an ongoing +discovery session (see \fBStartDiscovery()\fP in \fBorg.bluez.Adapter(5)\fP). +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.AdvertisementMonitor1 [experimental] +.TP +.B Object path +freely definable +.UNINDENT +.SS Methods +.SS void Release() [noreply] +.INDENT 0.0 +.INDENT 3.5 +This gets called as a signal for a client to perform clean\-up when: +.INDENT 0.0 +.IP \(bu 2 +Monitor cannot be activated after it was exposed +.IP \(bu 2 +Monitor has been deactivated. +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Activate() [noreply] +.INDENT 0.0 +.INDENT 3.5 +After a monitor was exposed, this gets called as a signal for client to +get acknowledged when a monitor has been activated, so the client can +expect to receive calls on \fBDeviceFound()\fP or \fBDeviceLost()\fP\&. +.UNINDENT +.UNINDENT +.SS void DeviceFound(object device) [noreply] +.INDENT 0.0 +.INDENT 3.5 +This gets called to notify the client of finding the targeted device. +Once receiving the call, the client should start to monitor the +corresponding device to retrieve the changes on RSSI and advertisement +content. +.UNINDENT +.UNINDENT +.SS void DeviceLost(object device) [noreply] +.INDENT 0.0 +.INDENT 3.5 +This gets called to notify the client of losing the targeted device. +Once receiving this call, the client should stop monitoring the +corresponding device. +.UNINDENT +.UNINDENT +.SS Properties +.SS string Type [read\-only] +.INDENT 0.0 +.INDENT 3.5 +The type of the monitor. See \fBSupportedMonitorTypes\fP in +\fBorg.bluez.AdvertisementMonitorManager(5)\fP for the available options. +.UNINDENT +.UNINDENT +.SS int16 RSSILowThreshold [read\-only, optional] +.INDENT 0.0 +.INDENT 3.5 +Used in conjunction with \fBRSSILowTimeout\fP to determine whether a +device becomes out\-of\-range. Valid range is \-127 to 20 (dBm), while 127 +indicates unset. +.UNINDENT +.UNINDENT +.SS int16 RSSIHighThreshold [read\-only, optional] +.INDENT 0.0 +.INDENT 3.5 +Used in conjunction with RSSIHighTimeout to determine whether a device +becomes in\-range. Valid range is \-127 to 20 (dBm), while 127 indicates +unset. +.UNINDENT +.UNINDENT +.SS uint16 RSSILowTimeout [read\-only, optional] +.INDENT 0.0 +.INDENT 3.5 +The time it takes to consider a device as out\-of\-range. If this many +seconds elapses without receiving any signal at least as strong as +\fBRSSILowThreshold\fP, a currently in\-range device will be considered as +out\-of\-range (lost). Valid range is 1 to 300 (seconds), while 0 +indicates unset. +.UNINDENT +.UNINDENT +.SS uint16 RSSIHighTimeout [read\-only, optional] +.INDENT 0.0 +.INDENT 3.5 +The time it takes to consider a device as in\-range. If this many +seconds elapses while we continuouslyreceive signals at least as strong +as \fBRSSIHighThreshold\fP, a currently out\-of\-range device will be +considered as in\-range (found). Valid range is 1 to 300 (seconds), +while 0 indicates unset. +.UNINDENT +.UNINDENT +.SS uint16 RSSISamplingPeriod [read\-only, optional] +.INDENT 0.0 +.INDENT 3.5 +Grouping rules on how to propagate the received advertisement packets +to the client. +.sp +Possible values: +.INDENT 0.0 +.TP +.B 0 +All advertisement packets from in\-range devices would be +propagated. +.TP +.B 255 +Only the first advertisement packet of in\-range devices would +be propagated. If the device becomes lost, then the first +packet when it is found again will also be propagated. +.TP +.B 1 to 254 +Advertisement packets would be grouped into 100ms * N time +period. Packets in the same group will only be reported once, +with the RSSI value being averaged out. +.UNINDENT +.sp +Currently this is unimplemented in user space, so the value is only +used to be forwarded to the kernel. +.UNINDENT +.UNINDENT +.SS array{(uint8, uint8, array{byte})} Patterns [read\-only, optional] +.INDENT 0.0 +.INDENT 3.5 +If the \fBType\fP property is set to \fB\(dqor_patterns\(dq\fP, then this +property must exist and have at least one entry in the array. +.sp +The structure of a pattern contains the following: +.INDENT 0.0 +.TP +.B uint8 start_position +The index in an AD data field where the search hould start. The +beginning of an AD data field is index 0. +.TP +.B uint8 AD_data_type +See <https://www.bluetooth.com/specifications/assigned\-numbers/> +generic\-access\-profile/ for the possible allowed value. +.TP +.B array{byte} content_of_pattern +This is the value of the pattern. The maximum length of the +bytes is 31. +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.AdvertisementMonitor.rst b/doc/org.bluez.AdvertisementMonitor.rst new file mode 100644 index 0000000000000000000000000000000000000000..98852ac68b59d33c4c0164444addaf7c5a187b90 --- /dev/null +++ b/doc/org.bluez.AdvertisementMonitor.rst @@ -0,0 +1,153 @@ +============================== +org.bluez.AdvertisementMonitor +============================== + +-------------------------------------------------- +BlueZ D-Bus AdvertisementMonitor API documentation +-------------------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Description +=========== + +This API allows an client to specify a job of monitoring advertisements by +registering the root of hierarchy and then exposing advertisement monitors +under the root with filtering conditions, thresholds of RSSI and timers +of RSSI thresholds. + +Once a monitoring job is activated by **bluetoothd(8)**, the client can expect +to get notified on the targeted advertisements no matter if there is an ongoing +discovery session (see **StartDiscovery()** in **org.bluez.Adapter(5)**). + +Interface +========= + +:Service: org.bluez +:Interface: org.bluez.AdvertisementMonitor1 [experimental] +:Object path: freely definable + +Methods +------- + +void Release() [noreply] +```````````````````````` + + This gets called as a signal for a client to perform clean-up when: + + - Monitor cannot be activated after it was exposed + - Monitor has been deactivated. + +void Activate() [noreply] +````````````````````````` + + After a monitor was exposed, this gets called as a signal for client to + get acknowledged when a monitor has been activated, so the client can + expect to receive calls on **DeviceFound()** or **DeviceLost()**. + +void DeviceFound(object device) [noreply] +````````````````````````````````````````` + + This gets called to notify the client of finding the targeted device. + Once receiving the call, the client should start to monitor the + corresponding device to retrieve the changes on RSSI and advertisement + content. + +void DeviceLost(object device) [noreply] +```````````````````````````````````````` + + This gets called to notify the client of losing the targeted device. + Once receiving this call, the client should stop monitoring the + corresponding device. + +Properties +---------- + +string Type [read-only] +``````````````````````` + + The type of the monitor. See **SupportedMonitorTypes** in + **org.bluez.AdvertisementMonitorManager(5)** for the available options. + +int16 RSSILowThreshold [read-only, optional] +```````````````````````````````````````````` + + Used in conjunction with **RSSILowTimeout** to determine whether a + device becomes out-of-range. Valid range is -127 to 20 (dBm), while 127 + indicates unset. + +int16 RSSIHighThreshold [read-only, optional] +````````````````````````````````````````````` + + Used in conjunction with RSSIHighTimeout to determine whether a device + becomes in-range. Valid range is -127 to 20 (dBm), while 127 indicates + unset. + +uint16 RSSILowTimeout [read-only, optional] +``````````````````````````````````````````` + + The time it takes to consider a device as out-of-range. If this many + seconds elapses without receiving any signal at least as strong as + **RSSILowThreshold**, a currently in-range device will be considered as + out-of-range (lost). Valid range is 1 to 300 (seconds), while 0 + indicates unset. + +uint16 RSSIHighTimeout [read-only, optional] +```````````````````````````````````````````` + + The time it takes to consider a device as in-range. If this many + seconds elapses while we continuouslyreceive signals at least as strong + as **RSSIHighThreshold**, a currently out-of-range device will be + considered as in-range (found). Valid range is 1 to 300 (seconds), + while 0 indicates unset. + +uint16 RSSISamplingPeriod [read-only, optional] +``````````````````````````````````````````````` + + Grouping rules on how to propagate the received advertisement packets + to the client. + + Possible values: + + :0: + All advertisement packets from in-range devices would be + propagated. + + :255: + Only the first advertisement packet of in-range devices would + be propagated. If the device becomes lost, then the first + packet when it is found again will also be propagated. + + :1 to 254: + Advertisement packets would be grouped into 100ms * N time + period. Packets in the same group will only be reported once, + with the RSSI value being averaged out. + + Currently this is unimplemented in user space, so the value is only + used to be forwarded to the kernel. + +array{(uint8, uint8, array{byte})} Patterns [read-only, optional] +````````````````````````````````````````````````````````````````` + + If the **Type** property is set to **"or_patterns"**, then this + property must exist and have at least one entry in the array. + + The structure of a pattern contains the following: + + :uint8 start_position: + + The index in an AD data field where the search hould start. The + beginning of an AD data field is index 0. + + :uint8 AD_data_type: + + See https://www.bluetooth.com/specifications/assigned-numbers/ + generic-access-profile/ for the possible allowed value. + + :array{byte} content_of_pattern: + + This is the value of the pattern. The maximum length of the + bytes is 31. diff --git a/doc/org.bluez.AdvertisementMonitorManager.5 b/doc/org.bluez.AdvertisementMonitorManager.5 new file mode 100644 index 0000000000000000000000000000000000000000..a35541f45c6957f4cfbafd4e45657428f4d8af77 --- /dev/null +++ b/doc/org.bluez.AdvertisementMonitorManager.5 @@ -0,0 +1,119 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.ADVERTISEMENTMONITORMANAGER" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.AdvertisementMonitorManager \- BlueZ D-Bus AdvertisementMonitorManager API documentation +.SH INTERFACE +.sp +Service org.bluez +Interface org.bluez.AdvertisementMonitorManager1 [experimental] +Object path /org/bluez/{hci0,hci1,...} +.SS Methods +.SS void RegisterMonitor(object application) +.INDENT 0.0 +.INDENT 3.5 +Registers the root path of a hierarchy of advertisement monitors +implementing \fBorg.bluez.AdvertisementMonitor(5)\fP\&. +.sp +The application object path together with the D\-Bus ystem bus +connection ID define the identification of the application registering +advertisement monitors. +.sp +Once a root path is registered by a client via this method, the client +can freely expose/unexpose advertisement monitors without re\-registering +the root path again. After use, the client should call +\fBUnregisterMonitor()\fP method to invalidate the advertisement monitors. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.AlreadyExists +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void UnregisterMonitor(object application) +.INDENT 0.0 +.INDENT 3.5 +Unregisters a hierarchy of advertisement monitors that has been +previously registered with \fBRegisterMonitor()\fP\&. The object path +parameter must match the same value that has been used on registration. +.sp +Upon unregistration, the advertisement monitor(s) should expect to +receive \fBRelease()\fP method as the signal that the advertisement +monitor(s) has been deactivated. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.DoesNotExist +.UNINDENT +.UNINDENT +.UNINDENT +.SS Properties +.SS array{string} SupportedMonitorTypes [read\-only] +.INDENT 0.0 +.INDENT 3.5 +This lists the supported types of advertisement monitors. An application +should check this before instantiate and expose an object of +\fBorg.bluez.AdvertisementMonitor(5)\fP\&. +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqor_patterns\(dq +Patterns with logic OR applied. With this type, property +\fBPatterns\fP must exist and has at least one pattern. +.UNINDENT +.UNINDENT +.UNINDENT +.SS array{string} SupportedFeatures [read\-only] +.INDENT 0.0 +.INDENT 3.5 +This lists the features of advertisement monitoring supported by +\fBbluetoothd(8)\fP\&. +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqcontroller\-patterns\(dq +If the controller is capable of performing advertisement +monitoring by patterns, \fBbluetoothd(8)\fP would offload the +patterns to the controller to reduce power consumption. +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.AdvertisementMonitorManager.rst b/doc/org.bluez.AdvertisementMonitorManager.rst new file mode 100644 index 0000000000000000000000000000000000000000..3775a483543c7039017cbf0dffd96c2886ce6065 --- /dev/null +++ b/doc/org.bluez.AdvertisementMonitorManager.rst @@ -0,0 +1,90 @@ +===================================== +org.bluez.AdvertisementMonitorManager +===================================== + +--------------------------------------------------------- +BlueZ D-Bus AdvertisementMonitorManager API documentation +--------------------------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +Service org.bluez +Interface org.bluez.AdvertisementMonitorManager1 [experimental] +Object path /org/bluez/{hci0,hci1,...} + +Methods +------- + +void RegisterMonitor(object application) +```````````````````````````````````````` + + Registers the root path of a hierarchy of advertisement monitors + implementing **org.bluez.AdvertisementMonitor(5)**. + + The application object path together with the D-Bus ystem bus + connection ID define the identification of the application registering + advertisement monitors. + + Once a root path is registered by a client via this method, the client + can freely expose/unexpose advertisement monitors without re-registering + the root path again. After use, the client should call + **UnregisterMonitor()** method to invalidate the advertisement monitors. + + Possible errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.AlreadyExists: + :org.bluez.Error.Failed: + +void UnregisterMonitor(object application) +`````````````````````````````````````````` + + Unregisters a hierarchy of advertisement monitors that has been + previously registered with **RegisterMonitor()**. The object path + parameter must match the same value that has been used on registration. + + Upon unregistration, the advertisement monitor(s) should expect to + receive **Release()** method as the signal that the advertisement + monitor(s) has been deactivated. + + Possible errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.DoesNotExist: + +Properties +---------- + +array{string} SupportedMonitorTypes [read-only] +``````````````````````````````````````````````` + + This lists the supported types of advertisement monitors. An application + should check this before instantiate and expose an object of + **org.bluez.AdvertisementMonitor(5)**. + + Possible values: + + :"or_patterns": + + Patterns with logic OR applied. With this type, property + **Patterns** must exist and has at least one pattern. + +array{string} SupportedFeatures [read-only] +``````````````````````````````````````````` + + This lists the features of advertisement monitoring supported by + **bluetoothd(8)**. + + Possible values: + + :"controller-patterns": + + If the controller is capable of performing advertisement + monitoring by patterns, **bluetoothd(8)** would offload the + patterns to the controller to reduce power consumption. diff --git a/doc/org.bluez.Agent.5 b/doc/org.bluez.Agent.5 new file mode 100644 index 0000000000000000000000000000000000000000..d187bc5ac70a05d5a505f86402283b92d677b198 --- /dev/null +++ b/doc/org.bluez.Agent.5 @@ -0,0 +1,201 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.AGENT" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.Agent \- BlueZ D-Bus Agent API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +unique name +.TP +.B Interface +org.bluez.Agent1 +.TP +.B Object path +freely definable +.UNINDENT +.SS Methods +.SS void Release() +.INDENT 0.0 +.INDENT 3.5 +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. +.UNINDENT +.UNINDENT +.SS string RequestPinCode(object device) +.INDENT 0.0 +.INDENT 3.5 +This method gets called when the service daemon needs to get the passkey +for an authentication. +.sp +The return value should be a string of 1\-16 characters length. The +string can be alphanumeric. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Rejected +.TP +.B org.bluez.Error.Canceled +.UNINDENT +.UNINDENT +.UNINDENT +.SS void DisplayPinCode(object device, string pincode) +.INDENT 0.0 +.INDENT 3.5 +This method gets called when the service daemon needs to display a +pincode for an authentication. +.sp +An empty reply should be returned. When the pincode needs no longer to +be displayed, the Cancel method of the agent will be called. +.sp +This is used during the pairing process of keyboards that don\(aqt support +Bluetooth 2.1 Secure Simple Pairing, in contrast to DisplayPasskey which +is used for those that do. +.sp +This method will only ever be called once since older keyboards do not +support typing notification. +.sp +Note that the PIN will always be a 6\-digit number, zero\-padded to 6 +digits. This is for harmony with the later specification. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Rejected +.TP +.B org.bluez.Error.Canceled +.UNINDENT +.UNINDENT +.UNINDENT +.SS uint32 RequestPasskey(object device) +.INDENT 0.0 +.INDENT 3.5 +This method gets called when the service daemon needs to get the passkey +for an authentication. +.sp +The return value should be a numeric value between 0\-999999. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Rejected +.TP +.B org.bluez.Error.Canceled +.UNINDENT +.UNINDENT +.UNINDENT +.SS void DisplayPasskey(object device, uint32 passkey, uint16 entered) +.INDENT 0.0 +.INDENT 3.5 +This method gets called when the service daemon needs to display a +passkey for an authentication. +.sp +The entered parameter indicates the number of already typed keys on the +remote side. +.sp +An empty reply should be returned. When the passkey needs no longer to +be displayed, the Cancel method of the agent will be called. +.sp +During the pairing process this method might be called multiple times to +update the entered value. +.sp +Note that the passkey will always be a 6\-digit number, so the display +should be zero\-padded at the start if the value contains less than 6 +digits. +.UNINDENT +.UNINDENT +.SS void RequestConfirmation(object device, uint32 passkey) +.INDENT 0.0 +.INDENT 3.5 +This method gets called when the service daemon needs to confirm a +passkey for an authentication. +.sp +To confirm the value it should return an empty reply or an error in case +the passkey is invalid. +.sp +Note that the passkey will always be a 6\-digit number, so the display +should be zero\-padded at the start if the value contains less than 6 +digits. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Rejected +.TP +.B org.bluez.Error.Canceled +.UNINDENT +.UNINDENT +.UNINDENT +.SS void RequestAuthorization(object device) +.INDENT 0.0 +.INDENT 3.5 +This method gets called to request the user to authorize an incoming +pairing attempt which would in other circumstances trigger the +just\-works model, or when the user plugged in a device that implements +cable pairing. In the latter case, the device would not be connected to +the adapter via Bluetooth yet. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Rejected +.TP +.B org.bluez.Error.Canceled +.UNINDENT +.UNINDENT +.UNINDENT +.SS void AuthorizeService(object device, string uuid) +.INDENT 0.0 +.INDENT 3.5 +This method gets called when the service daemon needs to authorize a +connection/service request. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Rejected +.TP +.B org.bluez.Error.Canceled +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Cancel() +.INDENT 0.0 +.INDENT 3.5 +This method gets called to indicate that the agent request failed before +a reply was returned. +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.Agent.rst b/doc/org.bluez.Agent.rst new file mode 100644 index 0000000000000000000000000000000000000000..11d09b94d228a4c0e2a9f82d78e5e4afc6f4bee4 --- /dev/null +++ b/doc/org.bluez.Agent.rst @@ -0,0 +1,149 @@ +=============== +org.bluez.Agent +=============== + +----------------------------------- +BlueZ D-Bus Agent API documentation +----------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: unique name +:Interface: org.bluez.Agent1 +:Object path: freely definable + +Methods +------- + +void Release() +`````````````` + + This method gets called when the service daemon unregisters the agent. + An agent can use it to do cleanup tasks. There is no need to unregister + the agent, because when this method gets called it has already been + unregistered. + +string 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: + +void DisplayPinCode(object device, string pincode) +`````````````````````````````````````````````````` + + This method gets called when the service daemon needs to display a + pincode for an authentication. + + An empty reply should be returned. When the pincode needs no longer to + be displayed, the Cancel method of the agent will be called. + + This is used during the pairing process of keyboards that don't support + Bluetooth 2.1 Secure Simple Pairing, in contrast to DisplayPasskey which + is used for those that do. + + This method will only ever be called once since older keyboards do not + support typing notification. + + Note that the PIN will always be a 6-digit number, zero-padded to 6 + digits. This is for harmony with the later specification. + + Possible errors: + + :org.bluez.Error.Rejected: + :org.bluez.Error.Canceled: + +uint32 RequestPasskey(object device) +```````````````````````````````````` + + This method gets called when the service daemon 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, uint16 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. + + Note that the passkey will always be a 6-digit number, so the display + should be zero-padded at the start if the value contains less than 6 + digits. + +void RequestConfirmation(object device, uint32 passkey) +``````````````````````````````````````````````````````` + + This method gets called when the service daemon 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. + + Note that the passkey will always be a 6-digit number, so the display + should be zero-padded at the start if the value contains less than 6 + digits. + + Possible errors: + + :org.bluez.Error.Rejected: + :org.bluez.Error.Canceled: + +void RequestAuthorization(object device) +```````````````````````````````````````` + + This method gets called to request the user to authorize an incoming + pairing attempt which would in other circumstances trigger the + just-works model, or when the user plugged in a device that implements + cable pairing. In the latter case, the device would not be connected to + the adapter via Bluetooth yet. + + Possible errors: + + :org.bluez.Error.Rejected: + :org.bluez.Error.Canceled: + +void AuthorizeService(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 Cancel() +````````````` + + This method gets called to indicate that the agent request failed before + a reply was returned. diff --git a/doc/org.bluez.AgentManager.5 b/doc/org.bluez.AgentManager.5 new file mode 100644 index 0000000000000000000000000000000000000000..fb0f2f43d173a48bac076940552d7bc9885cf7d8 --- /dev/null +++ b/doc/org.bluez.AgentManager.5 @@ -0,0 +1,122 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.AGENTMANAGER" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.AgentManager \- BlueZ D-Bus AgentManager API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.AgentManager1 +.TP +.B Object path +/org/bluez +.UNINDENT +.SS Methods +.SS void RegisterAgent(object agent, string capability) +.INDENT 0.0 +.INDENT 3.5 +Registers pairing agent. +.sp +The object path defines the path of the agent that will be called when +user input is needed and must implement \fBorg.bluez.Agent(5)\fP +interface. +.sp +Every application can register its own agent and for all actions +triggered by that application its agent is used. +.sp +It is not required by an application to register an agent. If an +application does chooses to not register an agent, the default agent is +used. This is on most cases a good idea. Only application like a pairing +wizard should register their own agent. +.sp +An application can only register one agent. Multiple agents per +application is not supported. +.sp +Possible capability values: +.INDENT 0.0 +.TP +.B \(dq\(dq +Fallback to \(dqKeyboardDisplay\(dq. +.TP +.B \(dqDisplayOnly\(dq +.TP +.B \(dqDisplayYesNo\(dq +.TP +.B \(dqKeyboardOnly\(dq +.TP +.B \(dqNoInputNoOutput\(dq +.TP +.B \(dqKeyboardDisplay\(dq +.UNINDENT +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.AlreadyExists +.UNINDENT +.UNINDENT +.UNINDENT +.SS void UnregisterAgent(object agent) +.INDENT 0.0 +.INDENT 3.5 +Unregisters an agent that has been previously registered using +\fBRegisterAgent\fP\&. The object path parameter must match the same value +that has been used on registration. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.DoesNotExist +.UNINDENT +.UNINDENT +.UNINDENT +.SS void RequestDefaultAgent(object agent) +.INDENT 0.0 +.INDENT 3.5 +Requests to make the application agent the default agent. The +application is required to register an agent. +.sp +Special permission might be required to become the default agent. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.DoesNotExist +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.AgentManager.rst b/doc/org.bluez.AgentManager.rst new file mode 100644 index 0000000000000000000000000000000000000000..dfc0297da8d2582c66ab81c66448ab027d1f0043 --- /dev/null +++ b/doc/org.bluez.AgentManager.rst @@ -0,0 +1,83 @@ +====================== +org.bluez.AgentManager +====================== + +------------------------------------------ +BlueZ D-Bus AgentManager API documentation +------------------------------------------ + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez +:Interface: org.bluez.AgentManager1 +:Object path: /org/bluez + +Methods +------- + +void RegisterAgent(object agent, string capability) +``````````````````````````````````````````````````` + + Registers pairing agent. + + The object path defines the path of the agent that will be called when + user input is needed and must implement **org.bluez.Agent(5)** + interface. + + Every application can register its own agent and for all actions + triggered by that application its agent is used. + + It is not required by an application to register an agent. If an + application does chooses to not register an agent, the default agent is + used. This is on most cases a good idea. Only application like a pairing + wizard should register their own agent. + + An application can only register one agent. Multiple agents per + application is not supported. + + Possible capability values: + + :"": + + Fallback to "KeyboardDisplay". + + :"DisplayOnly": + :"DisplayYesNo": + :"KeyboardOnly": + :"NoInputNoOutput": + :"KeyboardDisplay": + + Possible errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.AlreadyExists: + +void UnregisterAgent(object agent) +`````````````````````````````````` + + Unregisters an agent that has been previously registered using + **RegisterAgent**. The object path parameter must match the same value + that has been used on registration. + + Possible errors: + + :org.bluez.Error.DoesNotExist: + +void RequestDefaultAgent(object agent) +`````````````````````````````````````` + + Requests to make the application agent the default agent. The + application is required to register an agent. + + Special permission might be required to become the default agent. + + Possible errors: + + :org.bluez.Error.DoesNotExist: + diff --git a/doc/org.bluez.Battery.5 b/doc/org.bluez.Battery.5 new file mode 100644 index 0000000000000000000000000000000000000000..6dff39299fa14be841984e6c8b71cc713cdf1528 --- /dev/null +++ b/doc/org.bluez.Battery.5 @@ -0,0 +1,66 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.BATTERY" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.Battery \- BlueZ D-Bus Battery API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.Battery1 +.TP +.B Object path +[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX +.UNINDENT +.SS Properties +.SS byte Percentage [readonly] +.INDENT 0.0 +.INDENT 3.5 +The percentage of battery left as an unsigned 8\-bit integer. +.UNINDENT +.UNINDENT +.SS string Source [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Describes where the battery information comes from. +.sp +This property is informational only and may be useful for debugging +purposes. +.sp +Providers from \fBorg.bluez.BatteryProvider(5)\fP may make use +of this property to indicate where the battery report comes from +(e.g. \(dqHFP 1.7\(dq, \(dqHID\(dq, or the profile UUID). +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.Battery.rst b/doc/org.bluez.Battery.rst new file mode 100644 index 0000000000000000000000000000000000000000..d7e903c496ecb23f9763ffb9cc1370544ad05139 --- /dev/null +++ b/doc/org.bluez.Battery.rst @@ -0,0 +1,39 @@ +================= +org.bluez.Battery +================= + +------------------------------------- +BlueZ D-Bus Battery API documentation +------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez +:Interface: org.bluez.Battery1 +:Object path: [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX + +Properties +---------- + +byte Percentage [readonly] +`````````````````````````` + + The percentage of battery left as an unsigned 8-bit integer. + +string Source [readonly, optional] +`````````````````````````````````` + + Describes where the battery information comes from. + + This property is informational only and may be useful for debugging + purposes. + + Providers from **org.bluez.BatteryProvider(5)** may make use + of this property to indicate where the battery report comes from + (e.g. "HFP 1.7", "HID", or the profile UUID). diff --git a/doc/org.bluez.BatteryProvider.5 b/doc/org.bluez.BatteryProvider.5 new file mode 100644 index 0000000000000000000000000000000000000000..c079ebd458df15658d66e8a7c61a92be4be5dc32 --- /dev/null +++ b/doc/org.bluez.BatteryProvider.5 @@ -0,0 +1,58 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.BATTERYPROVIDER" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.BatteryProvider \- BlueZ D-Bus BatteryProvider API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +<client D\-Bus address> +.TP +.B Interface +org.bluez.BatteryProvider1 +.TP +.B Object path +{provider_root}/{unique battery object path} +.UNINDENT +.SS Properties +.sp +Objects provided on this interface contain the same properties as +\fBorg.bluez.Battery(5)\fP interface. Additionally, this interface needs to have +the Device property indicating the object path of the device this battery +provides. +.SS object Device [readonly] +.INDENT 0.0 +.INDENT 3.5 +The object path of the device that has this battery. +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.BatteryProvider.rst b/doc/org.bluez.BatteryProvider.rst new file mode 100644 index 0000000000000000000000000000000000000000..b8d8b1c2ddd0625f846e6f2b0c152f00ea552941 --- /dev/null +++ b/doc/org.bluez.BatteryProvider.rst @@ -0,0 +1,32 @@ +========================= +org.bluez.BatteryProvider +========================= + +--------------------------------------------- +BlueZ D-Bus BatteryProvider API documentation +--------------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: <client D-Bus address> +:Interface: org.bluez.BatteryProvider1 +:Object path: {provider_root}/{unique battery object path} + +Properties +---------- + +Objects provided on this interface contain the same properties as +**org.bluez.Battery(5)** interface. Additionally, this interface needs to have +the Device property indicating the object path of the device this battery +provides. + +object Device [readonly] +```````````````````````` + + The object path of the device that has this battery. diff --git a/doc/org.bluez.BatteryProviderManager.5 b/doc/org.bluez.BatteryProviderManager.5 new file mode 100644 index 0000000000000000000000000000000000000000..0d5db9888cc4c1041cee6cd8be3a231875a0e118 --- /dev/null +++ b/doc/org.bluez.BatteryProviderManager.5 @@ -0,0 +1,75 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.BATTERYPROVIDERMANAGER" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.BatteryProviderManager \- BlueZ D-Bus BatteryProviderManager API documentation +.SH DESCRIPTION +.sp +A battery provider starts by registering itself as a battery provider with the +\fBRegisterBatteryProvider()\fP method passing an object path as the provider ID. +Then, it can start exposing \fBorg.bluez.BatteryProvider(5)\fP objects having the +path starting with the given provider ID. It can also remove objects at any +time. +The objects and their properties exposed by battery providers will be reflected +on \fBorg.bluez.Battery(5)\fP interface. +.sp +\fBbluetoothd(8)\fP will stop monitoring these exposed and removed objects after +UnregisterBatteryProvider is called for that provider ID. +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.BatteryProviderManager1 +.TP +.B Object path +/org/bluez/{hci0,hci1,...} +.UNINDENT +.SS Methods +.SS void RegisterBatteryProvider(object provider) +.INDENT 0.0 +.INDENT 3.5 +Registers a battery provider. A registered battery provider can then +expose objects with \fBorg.bluez.BatteryProvider(5)\fP interface. +.UNINDENT +.UNINDENT +.SS void UnregisterBatteryProvider(object provider) +.INDENT 0.0 +.INDENT 3.5 +Unregisters a battery provider previously registered with +\fBRegisterBatteryProvider()\fP\&. After unregistration, the +\fBorg.bluez.BatteryProvider(5)\fP objects provided by this client are +ignored by \fBbluetoothd(8)\fP\&. +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.BatteryProviderManager.rst b/doc/org.bluez.BatteryProviderManager.rst new file mode 100644 index 0000000000000000000000000000000000000000..ab5cf2d4cadca6d7657077931366d59b5eea6cff --- /dev/null +++ b/doc/org.bluez.BatteryProviderManager.rst @@ -0,0 +1,50 @@ +================================ +org.bluez.BatteryProviderManager +================================ + +---------------------------------------------------- +BlueZ D-Bus BatteryProviderManager API documentation +---------------------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Description +============ + +A battery provider starts by registering itself as a battery provider with the +**RegisterBatteryProvider()** method passing an object path as the provider ID. +Then, it can start exposing **org.bluez.BatteryProvider(5)** objects having the +path starting with the given provider ID. It can also remove objects at any +time. +The objects and their properties exposed by battery providers will be reflected +on **org.bluez.Battery(5)** interface. + +**bluetoothd(8)** will stop monitoring these exposed and removed objects after +UnregisterBatteryProvider is called for that provider ID. + +Interface +========= + +:Service: org.bluez +:Interface: org.bluez.BatteryProviderManager1 +:Object path: /org/bluez/{hci0,hci1,...} + +Methods +------- + +void RegisterBatteryProvider(object provider) +````````````````````````````````````````````` + + Registers a battery provider. A registered battery provider can then + expose objects with **org.bluez.BatteryProvider(5)** interface. + +void UnregisterBatteryProvider(object provider) +``````````````````````````````````````````````` + + Unregisters a battery provider previously registered with + **RegisterBatteryProvider()**. After unregistration, the + **org.bluez.BatteryProvider(5)** objects provided by this client are + ignored by **bluetoothd(8)**. diff --git a/doc/org.bluez.Device.5 b/doc/org.bluez.Device.5 new file mode 100644 index 0000000000000000000000000000000000000000..a1f2a7f705fee4c7ecda3cc7d7546937900b1348 --- /dev/null +++ b/doc/org.bluez.Device.5 @@ -0,0 +1,445 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.DEVICE" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.Device \- BlueZ D-Bus Device API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.Device1 +.TP +.B Object path +[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX +.UNINDENT +.SS Methods +.SS void Connect() +.INDENT 0.0 +.INDENT 3.5 +Connects all profiles the remote device supports that can be connected +to and have been flagged as auto\-connectable. If only subset of profiles +is already connected it will try to connect currently disconnected ones. +.sp +If at least one profile was connected successfully this method will +indicate success. +.sp +For dual\-mode devices only one bearer is connected at time, the +conditions are in the following order: +.INDENT 0.0 +.IP 1. 3 +Connect the disconnected bearer if already connected. +.UNINDENT +.sp +2. Connect first the bonded bearer. If no bearers are bonded or both +are skip and check latest seen bearer. +.sp +3. Connect last seen bearer, in case the timestamps are the same BR/EDR +takes precedence. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotReady +.TP +.B org.bluez.Error.Failed +.TP +.B org.bluez.Error.InProgress +.TP +.B org.bluez.Error.AlreadyConnected +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Disconnect() +.INDENT 0.0 +.INDENT 3.5 +Disconnects all connected profiles and then terminates low\-level ACL +connection. +.sp +ACL connection will be terminated even if some profiles were not +disconnected properly e.g. due to misbehaving device. +.sp +This method can be also used to cancel a preceding Connect call before +a reply to it has been received. +.sp +For non\-trusted devices connected over LE bearer calling this method +will disable incoming connections until Connect method is called again. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotConnected +.UNINDENT +.UNINDENT +.UNINDENT +.SS void ConnectProfile(string uuid) +.INDENT 0.0 +.INDENT 3.5 +Connects a specific profile of this device. The UUID provided is the +remote service UUID for the profile. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Failed +.TP +.B org.bluez.Error.InProgress +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.NotAvailable +.TP +.B org.bluez.Error.NotReady +.UNINDENT +.UNINDENT +.UNINDENT +.SS void DisconnectProfile(string uuid) +.INDENT 0.0 +.INDENT 3.5 +Disconnects a specific profile of this device. The profile needs to be +registered client profile. +.sp +There is no connection tracking for a profile, so as long as the +profile is registered this will always succeed. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Failed +.TP +.B org.bluez.Error.InProgress +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.NotSupported +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Pair() +.INDENT 0.0 +.INDENT 3.5 +Connects to the remote device and initiate pairing procedure then +proceed with service discovery. +.sp +If the application has registered its own agent, then that specific +agent will be used. Otherwise it will use the default agent. +.sp +Only for applications like a pairing wizard it would make sense to have +its own agent. In almost all other cases the default agent will handle +this just fine. +.sp +In case there is no application agent and also no default agent present, +this method will fail. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.Failed +.TP +.B org.bluez.Error.AlreadyExists +.TP +.B org.bluez.Error.AuthenticationCanceled +.TP +.B org.bluez.Error.AuthenticationFailed +.TP +.B org.bluez.Error.AuthenticationRejected +.TP +.B org.bluez.Error.AuthenticationTimeout +.TP +.B org.bluez.Error.ConnectionAttemptFailed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void CancelPairing() +.INDENT 0.0 +.INDENT 3.5 +Cancels a pairing operation initiated by the \fBPair\fP method. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.DoesNotExist +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS array{array{byte}} GetServiceRecords() [experimental] +.INDENT 0.0 +.INDENT 3.5 +Returns all currently known BR/EDR service records for the device. Each +individual byte array represents a raw SDP record, as defined by the +Bluetooth Service Discovery Protocol specification. +.sp +This method is intended to be only used by compatibility layers like +Wine, that need to provide access to raw SDP records to support foreign +Bluetooth APIs. General applications should instead use the Profile API +for services\-related functionality. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Failed +.TP +.B org.bluez.Error.NotReady +.TP +.B org.bluez.Error.NotConnected +.TP +.B org.bluez.Error.DoesNotExist +.UNINDENT +.UNINDENT +.UNINDENT +.SS Properties +.SS string Address [readonly] +.INDENT 0.0 +.INDENT 3.5 +The Bluetooth device address of the remote device. +.UNINDENT +.UNINDENT +.SS string AddressType [readonly] +.INDENT 0.0 +.INDENT 3.5 +The Bluetooth device Address Type. For dual\-mode and BR/EDR only devices +this defaults to \(dqpublic\(dq. Single mode LE devices may have either value. +If remote device uses privacy than before pairing this represents +address type used for connection and Identity Address after pairing. +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqpublic\(dq +Public address +.TP +.B \(dqrandom\(dq +Random address +.UNINDENT +.UNINDENT +.UNINDENT +.SS string Name [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +The Bluetooth remote name. +.sp +This value is only present for completeness. It is better to always use +the \fBAlias\fP property when displaying the devices name. +.sp +If the \fBAlias\fP property is unset, it will reflect this value which +makes it more convenient. +.UNINDENT +.UNINDENT +.SS string Icon [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Proposed icon name according to the freedesktop.org icon naming +specification. +.UNINDENT +.UNINDENT +.SS uint32 Class [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +The Bluetooth class of device of the remote device. +.UNINDENT +.UNINDENT +.SS uint16 Appearance [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +External appearance of device, as found on GAP service. +.UNINDENT +.UNINDENT +.SS array{string} UUIDs [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +List of 128\-bit UUIDs that represents the available remote services. +.UNINDENT +.UNINDENT +.SS boolean Paired [readonly] +.INDENT 0.0 +.INDENT 3.5 +Indicates if the remote device is paired. Paired means the pairing +process where devices exchange the information to establish an +encrypted connection has been completed. +.UNINDENT +.UNINDENT +.SS boolean Bonded [readonly] +.INDENT 0.0 +.INDENT 3.5 +Indicates if the remote device is bonded. Bonded means the information +exchanged on pairing process has been stored and will be persisted. +.UNINDENT +.UNINDENT +.SS boolean Connected [readonly] +.INDENT 0.0 +.INDENT 3.5 +Indicates if the remote device is currently connected. +A PropertiesChanged signal indicate changes to this status. +.UNINDENT +.UNINDENT +.SS boolean Trusted [readwrite] +.INDENT 0.0 +.INDENT 3.5 +Indicates if the remote is seen as trusted. This setting can be changed +by the application. +.UNINDENT +.UNINDENT +.SS boolean Blocked [readwrite] +.INDENT 0.0 +.INDENT 3.5 +If set to true any incoming connections from the device will be +immediately rejected. Any device drivers will also be removed and +no new ones will be probed as long as the device is blocked. +.UNINDENT +.UNINDENT +.SS boolean WakeAllowed [readwrite] +.INDENT 0.0 +.INDENT 3.5 +If set to true this device will be allowed to wake the host from +system suspend. +.UNINDENT +.UNINDENT +.SS string Alias [readwrite] +.INDENT 0.0 +.INDENT 3.5 +The name alias for the remote device. The alias can be used to have a +different friendly name for the remote device. +.sp +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. +.sp +When resetting the alias with an empty string, the property will default +back to the remote name. +.UNINDENT +.UNINDENT +.SS object Adapter [readonly] +.INDENT 0.0 +.INDENT 3.5 +The object path of the adapter the device belongs to. +.UNINDENT +.UNINDENT +.SS boolean LegacyPairing [readonly] +.INDENT 0.0 +.INDENT 3.5 +Set to true if the device only supports the pre\-2.1 pairing mechanism. +This property is useful during device discovery to anticipate whether +legacy or simple pairing will occur if pairing is initiated. +.sp +Note that this property can exhibit false\-positives in the case of +Bluetooth 2.1 (or newer) devices that have disabled Extended Inquiry +Response support. +.UNINDENT +.UNINDENT +.SS string Modalias [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Remote Device ID information in modalias format used by the kernel and +udev. +.UNINDENT +.UNINDENT +.SS int16 RSSI [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Received Signal Strength Indicator of the remote device (inquiry or +advertising). +.UNINDENT +.UNINDENT +.SS int16 TxPower [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Advertised transmitted power level (inquiry or advertising). +.UNINDENT +.UNINDENT +.SS dict ManufacturerData [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Manufacturer specific advertisement data. Keys are 16 bits Manufacturer +ID followed by its byte array value. +.UNINDENT +.UNINDENT +.SS dict ServiceData [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Service advertisement data. Keys are the UUIDs in string format followed +by its byte array value. +.UNINDENT +.UNINDENT +.SS bool ServicesResolved [readonly] +.INDENT 0.0 +.INDENT 3.5 +Indicate whether or not service discovery has been resolved. +.UNINDENT +.UNINDENT +.SS array{byte} AdvertisingFlags [readonly] +.INDENT 0.0 +.INDENT 3.5 +The Advertising Data Flags of the remote device. +.UNINDENT +.UNINDENT +.SS dict AdvertisingData [readonly] +.INDENT 0.0 +.INDENT 3.5 +The Advertising Data of the remote device. Keys are 1 byte AD Type +followed by data as byte array. +.sp +Note: Only types considered safe to be handled by application are +exposed. +.sp +Possible values: +.INDENT 0.0 +.TP +.B <type> +<byte array> +.UNINDENT +.sp +Example: +.INDENT 0.0 +.INDENT 3.5 +<Transport Discovery> <Organization Flags...> +0x26 0x01 0x01... +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.SS array{object, dict} Sets [readonly, experimental] +.INDENT 0.0 +.INDENT 3.5 +The object paths of the sets the device belongs to followed by a +dictionary which can contain the following: +.INDENT 0.0 +.TP +.B byte Rank +Rank of the device in the Set. +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.Device.rst b/doc/org.bluez.Device.rst new file mode 100644 index 0000000000000000000000000000000000000000..f8d4a68a6b41783a7b71ceccbe7e1d947afd8ec7 --- /dev/null +++ b/doc/org.bluez.Device.rst @@ -0,0 +1,348 @@ +================ +org.bluez.Device +================ + +------------------------------------ +BlueZ D-Bus Device API documentation +------------------------------------ + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez +:Interface: org.bluez.Device1 +:Object path: [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX + +Methods +------- + +void Connect() +`````````````` + + Connects all profiles the remote device supports that can be connected + to and have been flagged as auto-connectable. If only subset of profiles + is already connected it will try to connect currently disconnected ones. + + If at least one profile was connected successfully this method will + indicate success. + + For dual-mode devices only one bearer is connected at time, the + conditions are in the following order: + + 1. Connect the disconnected bearer if already connected. + + 2. Connect first the bonded bearer. If no bearers are bonded or both + are skip and check latest seen bearer. + + 3. Connect last seen bearer, in case the timestamps are the same BR/EDR + takes precedence. + + Possible errors: + + :org.bluez.Error.NotReady: + :org.bluez.Error.Failed: + :org.bluez.Error.InProgress: + :org.bluez.Error.AlreadyConnected: + +void Disconnect() +````````````````` + + Disconnects all connected profiles and then terminates low-level ACL + connection. + + ACL connection will be terminated even if some profiles were not + disconnected properly e.g. due to misbehaving device. + + This method can be also used to cancel a preceding Connect call before + a reply to it has been received. + + For non-trusted devices connected over LE bearer calling this method + will disable incoming connections until Connect method is called again. + + Possible errors: + + :org.bluez.Error.NotConnected: + +void ConnectProfile(string uuid) +```````````````````````````````` + + Connects a specific profile of this device. The UUID provided is the + remote service UUID for the profile. + + Possible errors: + + :org.bluez.Error.Failed: + :org.bluez.Error.InProgress: + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.NotAvailable: + :org.bluez.Error.NotReady: + +void DisconnectProfile(string uuid) +``````````````````````````````````` + + Disconnects a specific profile of this device. The profile needs to be + registered client profile. + + There is no connection tracking for a profile, so as long as the + profile is registered this will always succeed. + + Possible errors: + + :org.bluez.Error.Failed: + :org.bluez.Error.InProgress: + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.NotSupported: + +void Pair() +``````````` + + Connects to the remote device and initiate pairing procedure then + proceed with service discovery. + + If the application has registered its own agent, then that specific + agent will be used. Otherwise it will use the default agent. + + Only for applications like a pairing wizard it would make sense to have + its own agent. In almost all other cases the default agent will handle + this just fine. + + In case there is no application agent and also no default agent present, + this method will fail. + + Possible errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.Failed: + :org.bluez.Error.AlreadyExists: + :org.bluez.Error.AuthenticationCanceled: + :org.bluez.Error.AuthenticationFailed: + :org.bluez.Error.AuthenticationRejected: + :org.bluez.Error.AuthenticationTimeout: + :org.bluez.Error.ConnectionAttemptFailed: + +void CancelPairing() +```````````````````` + + Cancels a pairing operation initiated by the **Pair** method. + + Possible errors: + + :org.bluez.Error.DoesNotExist: + :org.bluez.Error.Failed: + +array{array{byte}} GetServiceRecords() [experimental] +````````````````````````````````````````````````````` + + Returns all currently known BR/EDR service records for the device. Each + individual byte array represents a raw SDP record, as defined by the + Bluetooth Service Discovery Protocol specification. + + This method is intended to be only used by compatibility layers like + Wine, that need to provide access to raw SDP records to support foreign + Bluetooth APIs. General applications should instead use the Profile API + for services-related functionality. + + Possible errors: + + :org.bluez.Error.Failed: + :org.bluez.Error.NotReady: + :org.bluez.Error.NotConnected: + :org.bluez.Error.DoesNotExist: + +Properties +---------- + +string Address [readonly] +````````````````````````` + + The Bluetooth device address of the remote device. + +string AddressType [readonly] +````````````````````````````` + + The Bluetooth device Address Type. For dual-mode and BR/EDR only devices + this defaults to "public". Single mode LE devices may have either value. + If remote device uses privacy than before pairing this represents + address type used for connection and Identity Address after pairing. + + Possible values: + + :"public": + + Public address + + :"random": + + Random address + +string Name [readonly, optional] +```````````````````````````````` + + The Bluetooth remote name. + + This value is only present for completeness. It is better to always use + the **Alias** property when displaying the devices name. + + If the **Alias** property is unset, it will reflect this value which + makes it more convenient. + +string Icon [readonly, optional] +```````````````````````````````` + + Proposed icon name according to the freedesktop.org icon naming + specification. + +uint32 Class [readonly, optional] +````````````````````````````````` + + The Bluetooth class of device of the remote device. + +uint16 Appearance [readonly, optional] +`````````````````````````````````````` + + External appearance of device, as found on GAP service. + +array{string} UUIDs [readonly, optional] +```````````````````````````````````````` + + List of 128-bit UUIDs that represents the available remote services. + +boolean Paired [readonly] +````````````````````````` + + Indicates if the remote device is paired. Paired means the pairing + process where devices exchange the information to establish an + encrypted connection has been completed. + +boolean Bonded [readonly] +````````````````````````` + + Indicates if the remote device is bonded. Bonded means the information + exchanged on pairing process has been stored and will be persisted. + +boolean Connected [readonly] +```````````````````````````` + + Indicates if the remote device is currently connected. + A PropertiesChanged 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. + +boolean Blocked [readwrite] +``````````````````````````` + + If set to true any incoming connections from the device will be + immediately rejected. Any device drivers will also be removed and + no new ones will be probed as long as the device is blocked. + +boolean WakeAllowed [readwrite] +``````````````````````````````` + + If set to true this device will be allowed to wake the host from + system suspend. + +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 resetting the alias with an empty string, the property will default + back to the remote name. + +object Adapter [readonly] +````````````````````````` + + The object path of the adapter the device belongs to. + +boolean LegacyPairing [readonly] +```````````````````````````````` + + Set to true if the device only supports the pre-2.1 pairing mechanism. + This property is useful during device discovery to anticipate whether + legacy or simple pairing will occur if pairing is initiated. + + Note that this property can exhibit false-positives in the case of + Bluetooth 2.1 (or newer) devices that have disabled Extended Inquiry + Response support. + +string Modalias [readonly, optional] +```````````````````````````````````` + + Remote Device ID information in modalias format used by the kernel and + udev. + +int16 RSSI [readonly, optional] +``````````````````````````````` + + Received Signal Strength Indicator of the remote device (inquiry or + advertising). + +int16 TxPower [readonly, optional] +`````````````````````````````````` + + Advertised transmitted power level (inquiry or advertising). + +dict ManufacturerData [readonly, optional] +`````````````````````````````````````````` + + Manufacturer specific advertisement data. Keys are 16 bits Manufacturer + ID followed by its byte array value. + +dict ServiceData [readonly, optional] +````````````````````````````````````` + + Service advertisement data. Keys are the UUIDs in string format followed + by its byte array value. + +bool ServicesResolved [readonly] +```````````````````````````````` + + Indicate whether or not service discovery has been resolved. + +array{byte} AdvertisingFlags [readonly] +``````````````````````````````````````` + + The Advertising Data Flags of the remote device. + +dict AdvertisingData [readonly] +``````````````````````````````` + + The Advertising Data of the remote device. Keys are 1 byte AD Type + followed by data as byte array. + + Note: Only types considered safe to be handled by application are + exposed. + + Possible values: + + :<type>: + + <byte array> + + Example: + + <Transport Discovery> <Organization Flags...> + 0x26 0x01 0x01... + +array{object, dict} Sets [readonly, experimental] +````````````````````````````````````````````````` + + The object paths of the sets the device belongs to followed by a + dictionary which can contain the following: + + :byte Rank: + + Rank of the device in the Set. diff --git a/doc/org.bluez.DeviceSet.5 b/doc/org.bluez.DeviceSet.5 new file mode 100644 index 0000000000000000000000000000000000000000..4386152104920a346ec47ee097309e199d4e9186 --- /dev/null +++ b/doc/org.bluez.DeviceSet.5 @@ -0,0 +1,107 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.DEVICESET" "5" "September 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.DeviceSet \- BlueZ D-Bus DeviceSet API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.DeviceSet1 +.TP +.B Object path +[variable prefix]/{hci0,hci1,...}/set_{sirk} +.UNINDENT +.SS Methods +.SS void Connect() [experimental] +.INDENT 0.0 +.INDENT 3.5 +Connects all \fBdevices\fP members of the set, each member is +connected in sequence as they were added/loaded following the +same proceedure as described in \fBDevice1.Connect\fP\&. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotReady +.TP +.B org.bluez.Error.Failed +.TP +.B org.bluez.Error.InProgress +.TP +.B org.bluez.Error.AlreadyConnected +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Disconnect() [experimental] +.INDENT 0.0 +.INDENT 3.5 +Disconnects all \fBdevices\fP members of the set, each member is +disconnected in sequence as they were connected following the +same proceedure as described in \fBDevice1.Disconnect\fP\&. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotConnected +.UNINDENT +.UNINDENT +.UNINDENT +.SS Properties +.SS object Adapter [readonly, experimental] +.INDENT 0.0 +.INDENT 3.5 +The object path of the adapter the set belongs to. +.UNINDENT +.UNINDENT +.SS bool AutoConnect [read\-write, experimental] +.INDENT 0.0 +.INDENT 3.5 +Indicates if the \fBdevices\fP members of the set shall be automatically +connected once any of its members is connected. +.UNINDENT +.UNINDENT +.SS array(object) Devices [ready\-only, experimental] +.INDENT 0.0 +.INDENT 3.5 +List of devices objects that are members of the set. +.UNINDENT +.UNINDENT +.SS byte Size [read\-only, experimental] +.INDENT 0.0 +.INDENT 3.5 +Set members size. +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.DeviceSet.rst b/doc/org.bluez.DeviceSet.rst new file mode 100644 index 0000000000000000000000000000000000000000..c6dc8b075980a95cf90b6e3448ae9c2e33422880 --- /dev/null +++ b/doc/org.bluez.DeviceSet.rst @@ -0,0 +1,71 @@ +=================== +org.bluez.DeviceSet +=================== + +--------------------------------------- +BlueZ D-Bus DeviceSet API documentation +--------------------------------------- + +:Version: BlueZ +:Date: September 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez +:Interface: org.bluez.DeviceSet1 +:Object path: [variable prefix]/{hci0,hci1,...}/set_{sirk} + +Methods +------- + +void Connect() [experimental] +````````````````````````````` + + Connects all **devices** members of the set, each member is + connected in sequence as they were added/loaded following the + same proceedure as described in **Device1.Connect**. + + Possible errors: + + :org.bluez.Error.NotReady: + :org.bluez.Error.Failed: + :org.bluez.Error.InProgress: + :org.bluez.Error.AlreadyConnected: + +void Disconnect() [experimental] +```````````````````````````````` + + Disconnects all **devices** members of the set, each member is + disconnected in sequence as they were connected following the + same proceedure as described in **Device1.Disconnect**. + + Possible errors: + + :org.bluez.Error.NotConnected: + +Properties +---------- + +object Adapter [readonly, experimental] +``````````````````````````````````````` + + The object path of the adapter the set belongs to. + +bool AutoConnect [read-write, experimental] +``````````````````````````````````````````` + + Indicates if the **devices** members of the set shall be automatically + connected once any of its members is connected. + +array(object) Devices [ready-only, experimental] +```````````````````````````````````````````````` + + List of devices objects that are members of the set. + +byte Size [read-only, experimental] +``````````````````````````````````` + + Set members size. diff --git a/doc/org.bluez.GattCharacteristic.5 b/doc/org.bluez.GattCharacteristic.5 new file mode 100644 index 0000000000000000000000000000000000000000..3ff54b63f6c66a241d5a6fbe9a4ba716ab5e261c --- /dev/null +++ b/doc/org.bluez.GattCharacteristic.5 @@ -0,0 +1,478 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.GATTCHARACTERISTIC" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.GattCharacteristic \- BlueZ D-Bus GattCharacteristic API documentation +.SH DESCRIPTION +.sp +GATT local/server and remote/client characteristic attribute representation +share the same high\-level D\-Bus API. +.sp +Local/Server refers to GATT based characteristics exported by a plugin or an +external application. +.sp +Remote/Client refers to GATT characteristics exported by the peer. +.SH INTERFACE +.SS Client +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.GattCharacteristic1 +.TP +.B Object path +[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX/charYYYY +.UNINDENT +.SS Server +.INDENT 0.0 +.TP +.B Service +unique name +.TP +.B Interface +org.bluez.GattCharacteristic1 +.TP +.B Object path +freely definable +.UNINDENT +.SS Methods +.SS array{byte} ReadValue(dict options) +.INDENT 0.0 +.INDENT 3.5 +Issues a request to read the value of the characteristic and returns the +value if the operation was successful. +.sp +Possible options: +.INDENT 0.0 +.TP +.B uint16_t offset +Read start offset in bytes. +.TP +.B uint16_t mtu (server only) +Exchange MTU in bytes. +.TP +.B object device (server only) +Device object. +.TP +.B string link (server only) +Link type. +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dqBR/EDR\(dq +.TP +.B \(dqLE\(dq +.UNINDENT +.UNINDENT +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Failed +Possible values: string 0x80 \- 0x9f +.TP +.B org.bluez.Error.InProgress +.TP +.B org.bluez.Error.NotPermitted +.TP +.B org.bluez.Error.NotAuthorized +.TP +.B org.bluez.Error.InvalidOffset +.TP +.B org.bluez.Error.NotSupported +.UNINDENT +.UNINDENT +.UNINDENT +.SS void WriteValue(array{byte} value, dict options) +.INDENT 0.0 +.INDENT 3.5 +Issues a request to write the value of the characteristic. +.sp +Possible options: +.INDENT 0.0 +.TP +.B uint16 offset +Write start offset in bytes. +.TP +.B string type +Possible values: +.INDENT 7.0 +.TP +.B \(dqcommand\(dq +Use Write without response procedure. +.TP +.B \(dqrequest\(dq +Use Write with response procedure. +.TP +.B \(dqreliable\(dq +Use Reliable Write procedure. +.UNINDENT +.TP +.B uint16 mtu +Exchanged MTU (Server only). +.TP +.B object device +Device path (Server only). +.TP +.B string link +Link type (Server only). +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dqBR/EDR\(dq +.TP +.B \(dqLE\(dq +.UNINDENT +.TP +.B boolean prepare\-authorize +True if prepare authorization request. +.UNINDENT +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Failed +Possible values: string 0x80 \- 0x9f +.TP +.B org.bluez.Error.InProgress +.TP +.B org.bluez.Error.NotPermitted +.TP +.B org.bluez.Error.InvalidValueLength +.TP +.B org.bluez.Error.NotAuthorized +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.ImproperlyConfigured +.UNINDENT +.UNINDENT +.UNINDENT +.SS fd, uint16 AcquireWrite(dict options) [optional] +.INDENT 0.0 +.INDENT 3.5 +Acquire file descriptor and MTU for writing. Only sockets are supported. +Usage of WriteValue will be locked causing it to return NotPermitted +error. +.sp +For server the MTU returned shall be equal or smaller than the +negotiated MTU. +.sp +For client it only works with characteristic that has \fBWriteAcquired\fP +property which relies on write\-without\-response \fBFlag\fP\&. +.sp +To release the lock the client shall close the file descriptor, a HUP +is generated in case the device is disconnected. +.sp +Note: the MTU can only be negotiated once and is symmetric therefore +this method may be delayed in order to have the exchange MTU completed, +because of that the file descriptor is closed during reconnections as +the MTU has to be renegotiated. +.sp +Possible options: +.INDENT 0.0 +.TP +.B object device +Object Device (Server only). +.TP +.B uint16 mtu +Exchanged MTU (Server only). +.TP +.B string link +Link type (Server only). +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dqBR/EDR\(dq +.TP +.B \(dqLE\(dq +.UNINDENT +.UNINDENT +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Failed +.TP +.B org.bluez.Error.NotSupported +.UNINDENT +.UNINDENT +.UNINDENT +.SS fd, uint16 AcquireNotify(dict options) [optional] +.INDENT 0.0 +.INDENT 3.5 +Acquire file descriptor and MTU for notify. Only sockets are support. +.sp +Usage of StartNotify will be locked causing it to return +\fBorg.bluez.Error.NotPermitted\fP\&. +.sp +For server the MTU returned shall be equal or smaller than the +negotiated MTU. +.sp +Only works with characteristic that has \fBNotifyAcquired\fP property +which relies on \fB\(dqnotify\(dq\fP \fBFlag\fP and no other client have called +\fBStartNotify()\fP\&. +.sp +Notification are enabled during this procedure so \fBStartNotify()\fP +shall not be called, any notification will be dispatched via file +descriptor therefore the Value property is not affected during the time +where notify has been acquired. +.sp +To release the lock the client shall close the file descriptor, a HUP is +generated in case the device is disconnected. +.sp +Note: the MTU can only be negotiated once and is symmetric therefore +this method may be delayed in order to have the exchange MTU completed, +because of that the file descriptor is closed during reconnections as +the MTU has to be renegotiated. +.sp +Possible options: +.INDENT 0.0 +.TP +.B object device +Object Device (Server only). +.TP +.B uint16 mtu +Exchanged MTU (Server only). +.TP +.B string link +Link type (Server only). +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dqBR/EDR\(dq +.TP +.B \(dqLE\(dq +.UNINDENT +.UNINDENT +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Failed +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.NotPermitted +.UNINDENT +.UNINDENT +.UNINDENT +.SS void StartNotify() +.INDENT 0.0 +.INDENT 3.5 +Starts a notification session from this characteristic if it supports +value notifications or indications. +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Failed +.TP +.B org.bluez.Error.NotPermitted +.TP +.B org.bluez.Error.InProgress +.TP +.B org.bluez.Error.NotConnected +.TP +.B org.bluez.Error.NotSupported +.UNINDENT +.UNINDENT +.UNINDENT +.SS void StopNotify() +.INDENT 0.0 +.INDENT 3.5 +Stops or cancel session previously created by \fBStartNotify()\fP\&. +.sp +Note that notifications from a characteristic are shared between +sessions thus calling StopNotify will release a single session. +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Confirm() [noreply, optional] (Server only) +.INDENT 0.0 +.INDENT 3.5 +Confirms value was received. +.sp +Possible Errors: +.sp +org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.SS Properties +.SS string UUID [read\-only] +.INDENT 0.0 +.INDENT 3.5 +128\-bit characteristic UUID. +.UNINDENT +.UNINDENT +.SS object Service [read\-only] +.INDENT 0.0 +.INDENT 3.5 +Object path of the GATT service the characteristic belongs to. +.UNINDENT +.UNINDENT +.SS array{byte} Value [read\-only, optional] +.INDENT 0.0 +.INDENT 3.5 +The cached value of the characteristic. This property gets updated only +after a successful read request and when a notification or indication +is received, upon which a PropertiesChanged signal will be emitted. +.UNINDENT +.UNINDENT +.SS boolean WriteAcquired [read\-only, optional] +.INDENT 0.0 +.INDENT 3.5 +True, if this characteristic has been acquired by any client using +AcquireWrite. +.sp +For client properties is ommited in case \(aqwrite\-without\-response\(aq flag +is not set. +.sp +For server the presence of this property indicates that AcquireWrite is +supported. +.UNINDENT +.UNINDENT +.SS boolean NotifyAcquired [read\-only, optional] +.INDENT 0.0 +.INDENT 3.5 +True, if this characteristic has been acquired by any client using +AcquireNotify. +.sp +For client this properties is ommited in case \(aqnotify\(aq flag is not set. +.sp +For server the presence of this property indicates that AcquireNotify +is supported. +.UNINDENT +.UNINDENT +.SS boolean Notifying [read\-only, optional] +.INDENT 0.0 +.INDENT 3.5 +True, if notifications or indications on this characteristic are +currently enabled. +.UNINDENT +.UNINDENT +.SS array{string} Flags [read\-only] +.INDENT 0.0 +.INDENT 3.5 +Defines how the characteristic value can be used. See Core spec +\(dqTable 3.5: Characteristic Properties bit field\(dq, and +\(dqTable 3.8: Characteristic Extended Properties bit field\(dq. +.sp +The \(dqx\-notify\(dq and \(dqx\-indicate\(dq flags restrict access to notifications +and indications by imposing write restrictions on a characteristic\(aqs +client characteristic configuration descriptor. +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqbroadcast\(dq +.TP +.B \(dqread\(dq +.TP +.B \(dqwrite\-without\-response\(dq +.TP +.B \(dqwrite\(dq +.TP +.B \(dqnotify\(dq +.TP +.B \(dqindicate\(dq +.TP +.B \(dqauthenticated\-signed\-writes\(dq +.TP +.B \(dqextended\-properties\(dq +.TP +.B \(dqreliable\-write\(dq +.TP +.B \(dqwritable\-auxiliaries\(dq +.TP +.B \(dqencrypt\-read\(dq +.TP +.B \(dqencrypt\-write\(dq +.TP +.B \(dqencrypt\-notify\(dq (Server only) +.TP +.B \(dqencrypt\-indicate\(dq (Server only) +.TP +.B \(dqencrypt\-authenticated\-read\(dq +.TP +.B \(dqencrypt\-authenticated\-write\(dq +.TP +.B \(dqencrypt\-authenticated\-notify\(dq (Server only) +.TP +.B \(dqencrypt\-authenticated\-indicate\(dq (Server only) +.TP +.B \(dqsecure\-read\(dq (Server only) +.TP +.B \(dqsecure\-write\(dq (Server only) +.TP +.B \(dqsecure\-notify\(dq (Server only) +.TP +.B \(dqsecure\-indicate\(dq (Server only) +.TP +.B \(dqauthorize\(dq +.UNINDENT +.UNINDENT +.UNINDENT +.SS uint16 Handle [read\-only] (Client Only) +.INDENT 0.0 +.INDENT 3.5 +Characteristic handle. +.UNINDENT +.UNINDENT +.SS uint16 Handle [read\-write, optional] (Server Only) +.INDENT 0.0 +.INDENT 3.5 +Characteristic handle. When available in the server it would attempt to +use to allocate into the database which may fail, to auto allocate the +value 0x0000 shall be used which will cause the allocated handle to be +set once registered. +.UNINDENT +.UNINDENT +.SS uint16 MTU [read\-only] +.INDENT 0.0 +.INDENT 3.5 +Characteristic MTU, this is valid both for \fBReadValue()\fP and +\fBWriteValue()\fP but either method can use long procedures when +supported. +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.GattCharacteristic.rst b/doc/org.bluez.GattCharacteristic.rst new file mode 100644 index 0000000000000000000000000000000000000000..a43476d2adbd1faa3412ce582b6c5a97c32c6344 --- /dev/null +++ b/doc/org.bluez.GattCharacteristic.rst @@ -0,0 +1,385 @@ +============================ +org.bluez.GattCharacteristic +============================ + +------------------------------------------------ +BlueZ D-Bus GattCharacteristic API documentation +------------------------------------------------ + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Description +=========== + +GATT local/server and remote/client characteristic attribute representation +share the same high-level D-Bus API. + +Local/Server refers to GATT based characteristics exported by a plugin or an +external application. + +Remote/Client refers to GATT characteristics exported by the peer. + +Interface +========= + +Client +------ + +:Service: org.bluez +:Interface: org.bluez.GattCharacteristic1 +:Object path: [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX/charYYYY + +Server +------ + +:Service: unique name +:Interface: org.bluez.GattCharacteristic1 +:Object path: freely definable + +Methods +------- + +array{byte} ReadValue(dict options) +``````````````````````````````````` + + Issues a request to read the value of the characteristic and returns the + value if the operation was successful. + + Possible options: + + :uint16_t offset: + + Read start offset in bytes. + + :uint16_t mtu (server only): + + Exchange MTU in bytes. + + :object device (server only): + + Device object. + + :string link (server only): + + Link type. + + Possible values: + + :"BR/EDR": + :"LE": + + Possible Errors: + + :org.bluez.Error.Failed: + + Possible values: string 0x80 - 0x9f + + :org.bluez.Error.InProgress: + :org.bluez.Error.NotPermitted: + :org.bluez.Error.NotAuthorized: + :org.bluez.Error.InvalidOffset: + :org.bluez.Error.NotSupported: + +void WriteValue(array{byte} value, dict options) +```````````````````````````````````````````````` + + Issues a request to write the value of the characteristic. + + Possible options: + + :uint16 offset: + + Write start offset in bytes. + + :string type: + + Possible values: + + :"command": + + Use Write without response procedure. + + :"request": + + Use Write with response procedure. + + :"reliable": + + Use Reliable Write procedure. + + :uint16 mtu: + + Exchanged MTU (Server only). + + :object device: + + Device path (Server only). + + :string link: + + Link type (Server only). + + Possible values: + + :"BR/EDR": + :"LE": + + :boolean prepare-authorize: + + True if prepare authorization request. + + Possible Errors: + + :org.bluez.Error.Failed: + + Possible values: string 0x80 - 0x9f + + :org.bluez.Error.InProgress: + :org.bluez.Error.NotPermitted: + :org.bluez.Error.InvalidValueLength: + :org.bluez.Error.NotAuthorized: + :org.bluez.Error.NotSupported: + :org.bluez.Error.ImproperlyConfigured: + +fd, uint16 AcquireWrite(dict options) [optional] +```````````````````````````````````````````````` + + Acquire file descriptor and MTU for writing. Only sockets are supported. + Usage of WriteValue will be locked causing it to return NotPermitted + error. + + For server the MTU returned shall be equal or smaller than the + negotiated MTU. + + For client it only works with characteristic that has **WriteAcquired** + property which relies on write-without-response **Flag**. + + To release the lock the client shall close the file descriptor, a HUP + is generated in case the device is disconnected. + + Note: the MTU can only be negotiated once and is symmetric therefore + this method may be delayed in order to have the exchange MTU completed, + because of that the file descriptor is closed during reconnections as + the MTU has to be renegotiated. + + Possible options: + + :object device: + + Object Device (Server only). + + :uint16 mtu: + + Exchanged MTU (Server only). + + :string link: + + Link type (Server only). + + Possible values: + + :"BR/EDR": + :"LE": + + Possible Errors: + + :org.bluez.Error.Failed: + :org.bluez.Error.NotSupported: + +fd, uint16 AcquireNotify(dict options) [optional] +````````````````````````````````````````````````` + + Acquire file descriptor and MTU for notify. Only sockets are support. + + Usage of StartNotify will be locked causing it to return + **org.bluez.Error.NotPermitted**. + + For server the MTU returned shall be equal or smaller than the + negotiated MTU. + + Only works with characteristic that has **NotifyAcquired** property + which relies on **"notify"** **Flag** and no other client have called + **StartNotify()**. + + Notification are enabled during this procedure so **StartNotify()** + shall not be called, any notification will be dispatched via file + descriptor therefore the Value property is not affected during the time + where notify has been acquired. + + To release the lock the client shall close the file descriptor, a HUP is + generated in case the device is disconnected. + + Note: the MTU can only be negotiated once and is symmetric therefore + this method may be delayed in order to have the exchange MTU completed, + because of that the file descriptor is closed during reconnections as + the MTU has to be renegotiated. + + Possible options: + + :object device: + + Object Device (Server only). + + :uint16 mtu: + + Exchanged MTU (Server only). + + :string link: + + Link type (Server only). + + Possible values: + + :"BR/EDR": + :"LE": + + Possible Errors: + + :org.bluez.Error.Failed: + :org.bluez.Error.NotSupported: + :org.bluez.Error.NotPermitted: + +void StartNotify() +`````````````````` + + Starts a notification session from this characteristic if it supports + value notifications or indications. + + Possible Errors: + + :org.bluez.Error.Failed: + :org.bluez.Error.NotPermitted: + :org.bluez.Error.InProgress: + :org.bluez.Error.NotConnected: + :org.bluez.Error.NotSupported: + +void StopNotify() +````````````````` + + Stops or cancel session previously created by **StartNotify()**. + + Note that notifications from a characteristic are shared between + sessions thus calling StopNotify will release a single session. + + Possible Errors: + + :org.bluez.Error.Failed: + +void Confirm() [noreply, optional] (Server only) +```````````````````````````````````````````````` + + + Confirms value was received. + + Possible Errors: + + org.bluez.Error.Failed + +Properties +---------- + +string UUID [read-only] +``````````````````````` + + 128-bit characteristic UUID. + +object Service [read-only] +`````````````````````````` + + Object path of the GATT service the characteristic belongs to. + +array{byte} Value [read-only, optional] +``````````````````````````````````````` + + The cached value of the characteristic. This property gets updated only + after a successful read request and when a notification or indication + is received, upon which a PropertiesChanged signal will be emitted. + +boolean WriteAcquired [read-only, optional] +``````````````````````````````````````````` + + True, if this characteristic has been acquired by any client using + AcquireWrite. + + For client properties is ommited in case 'write-without-response' flag + is not set. + + For server the presence of this property indicates that AcquireWrite is + supported. + +boolean NotifyAcquired [read-only, optional] +```````````````````````````````````````````` + + True, if this characteristic has been acquired by any client using + AcquireNotify. + + For client this properties is ommited in case 'notify' flag is not set. + + For server the presence of this property indicates that AcquireNotify + is supported. + +boolean Notifying [read-only, optional] +``````````````````````````````````````` + + True, if notifications or indications on this characteristic are + currently enabled. + +array{string} Flags [read-only] +``````````````````````````````` + + Defines how the characteristic value can be used. See Core spec + "Table 3.5: Characteristic Properties bit field", and + "Table 3.8: Characteristic Extended Properties bit field". + + The "x-notify" and "x-indicate" flags restrict access to notifications + and indications by imposing write restrictions on a characteristic's + client characteristic configuration descriptor. + + Possible values: + + :"broadcast": + :"read": + :"write-without-response": + :"write": + :"notify": + :"indicate": + :"authenticated-signed-writes": + :"extended-properties": + :"reliable-write": + :"writable-auxiliaries": + :"encrypt-read": + :"encrypt-write": + :"encrypt-notify" (Server only): + :"encrypt-indicate" (Server only): + :"encrypt-authenticated-read": + :"encrypt-authenticated-write": + :"encrypt-authenticated-notify" (Server only): + :"encrypt-authenticated-indicate" (Server only): + :"secure-read" (Server only): + :"secure-write" (Server only): + :"secure-notify" (Server only): + :"secure-indicate" (Server only): + :"authorize": + +uint16 Handle [read-only] (Client Only) +``````````````````````````````````````` + + Characteristic handle. + +uint16 Handle [read-write, optional] (Server Only) +`````````````````````````````````````````````````` + + Characteristic handle. When available in the server it would attempt to + use to allocate into the database which may fail, to auto allocate the + value 0x0000 shall be used which will cause the allocated handle to be + set once registered. + +uint16 MTU [read-only] +`````````````````````` + + Characteristic MTU, this is valid both for **ReadValue()** and + **WriteValue()** but either method can use long procedures when + supported. diff --git a/doc/org.bluez.GattDescriptor.5 b/doc/org.bluez.GattDescriptor.5 new file mode 100644 index 0000000000000000000000000000000000000000..40b36fac41189c1406ba58ff99a92b6e15c58f2a --- /dev/null +++ b/doc/org.bluez.GattDescriptor.5 @@ -0,0 +1,226 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.GATTDESCRIPTOR" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.GattDescriptor \- BlueZ D-Bus GattDescriptor API documentation +.SH DESCRIPTION +.sp +GATT local/server and remote/client descriptor attribute representation +share the same high\-level D\-Bus API. +.sp +Local/Server refers to GATT based descriptors exported by a plugin or an +external application. +.sp +Remote/Client refers to GATT descriptors exported by the peer. +.SH INTERFACE +.SS Client +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.GattDescriptor1 +.TP +.B Object path +[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX/charYYYY/descriptorZZZ +.UNINDENT +.SS Server +.INDENT 0.0 +.TP +.B Service +unique name +.TP +.B Interface +org.bluez.GattDescriptor1 +.TP +.B Object path +freely definable +.UNINDENT +.SS Methods +.SS array{byte} ReadValue(dict flags) +.INDENT 0.0 +.INDENT 3.5 +Issues a request to read the value of the descriptor and returns the +value if the operation was successful. +.sp +Possible options: +.INDENT 0.0 +.TP +.B uint16_t offset +Read start offset in bytes. +.TP +.B object device (server only) +Device object. +.TP +.B string link +Link type (Server only). +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dqBR/EDR\(dq +.TP +.B \(dqLE\(dq +.UNINDENT +.UNINDENT +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Failed +.TP +.B org.bluez.Error.InProgress +.TP +.B org.bluez.Error.NotPermitted +.TP +.B org.bluez.Error.NotAuthorized +.TP +.B org.bluez.Error.NotSupported +.UNINDENT +.UNINDENT +.UNINDENT +.SS void WriteValue(array{byte} value, dict flags) +.INDENT 0.0 +.INDENT 3.5 +Issues a request to write the value of the descriptor. +.sp +Possible flags: +.INDENT 0.0 +.TP +.B uint16 offset +Write start offset in bytes. +.TP +.B uint16 mtu +Exchanged MTU (Server only). +.TP +.B object device +Device path (Server only). +.TP +.B string link +Link type (Server only). +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dqBR/EDR\(dq +.TP +.B \(dqLE\(dq +.UNINDENT +.TP +.B boolean prepare\-authorize +True if prepare authorization request. +.UNINDENT +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Failed +.TP +.B org.bluez.Error.InProgress +.TP +.B org.bluez.Error.NotPermitted +.TP +.B org.bluez.Error.InvalidValueLength +.TP +.B org.bluez.Error.NotAuthorized +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.ImproperlyConfigured +.UNINDENT +.UNINDENT +.UNINDENT +.SS Properties +.SS string UUID [read\-only] +.INDENT 0.0 +.INDENT 3.5 +128\-bit descriptor UUID. +.UNINDENT +.UNINDENT +.SS object Characteristic [read\-only] +.INDENT 0.0 +.INDENT 3.5 +Object path of the GATT characteristic the descriptor belongs to. +.UNINDENT +.UNINDENT +.SS array{byte} Value [read\-only, optional] +.INDENT 0.0 +.INDENT 3.5 +The cached value of the descriptor. This property gets updated only +after a successful read request, upon which a PropertiesChanged signal +will be emitted. +.UNINDENT +.UNINDENT +.SS array{string} Flags [read\-only] +.INDENT 0.0 +.INDENT 3.5 +Defines how the descriptor value can be used. +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqread\(dq +.TP +.B \(dqwrite\(dq +.TP +.B \(dqencrypt\-read\(dq +.TP +.B \(dqencrypt\-write\(dq +.TP +.B \(dqencrypt\-authenticated\-read\(dq +.TP +.B \(dqencrypt\-authenticated\-write\(dq +.TP +.B \(dqsecure\-read\(dq (Server Only) +.TP +.B \(dqsecure\-write\(dq (Server Only) +.TP +.B \(dqauthorize\(dq +.UNINDENT +.UNINDENT +.UNINDENT +.SS uint16 Handle [read\-only] (Client Only) +.INDENT 0.0 +.INDENT 3.5 +Descriptor handle. +.UNINDENT +.UNINDENT +.SS uint16 Handle [read\-write, optional] (Server Only) +.INDENT 0.0 +.INDENT 3.5 +Descriptor handle. When available in the server it would attempt to +use to allocate into the database which may fail, to auto allocate the +value 0x0000 shall be used which will cause the allocated handle to be +set once registered. +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.GattDescriptor.rst b/doc/org.bluez.GattDescriptor.rst new file mode 100644 index 0000000000000000000000000000000000000000..f4497c6d5b150f1e8e6153b77d5134764b89c328 --- /dev/null +++ b/doc/org.bluez.GattDescriptor.rst @@ -0,0 +1,168 @@ +======================== +org.bluez.GattDescriptor +======================== + +-------------------------------------------- +BlueZ D-Bus GattDescriptor API documentation +-------------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Description +=========== + +GATT local/server and remote/client descriptor attribute representation +share the same high-level D-Bus API. + +Local/Server refers to GATT based descriptors exported by a plugin or an +external application. + +Remote/Client refers to GATT descriptors exported by the peer. + +Interface +========= + +Client +------ + +:Service: org.bluez +:Interface: org.bluez.GattDescriptor1 +:Object path: [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX/charYYYY/descriptorZZZ + +Server +------ + +:Service: unique name +:Interface: org.bluez.GattDescriptor1 +:Object path: freely definable + +Methods +------- + +array{byte} ReadValue(dict flags) +````````````````````````````````` + + Issues a request to read the value of the descriptor and returns the + value if the operation was successful. + + Possible options: + + :uint16_t offset: + + Read start offset in bytes. + + :object device (server only): + + Device object. + + :string link: + + Link type (Server only). + + Possible values: + + :"BR/EDR": + :"LE": + + Possible Errors: + + :org.bluez.Error.Failed: + :org.bluez.Error.InProgress: + :org.bluez.Error.NotPermitted: + :org.bluez.Error.NotAuthorized: + :org.bluez.Error.NotSupported: + +void WriteValue(array{byte} value, dict flags) +`````````````````````````````````````````````` + + Issues a request to write the value of the descriptor. + + Possible flags: + + :uint16 offset: + + Write start offset in bytes. + + :uint16 mtu: + + Exchanged MTU (Server only). + + :object device: + + Device path (Server only). + + :string link: + + Link type (Server only). + + Possible values: + + :"BR/EDR": + :"LE": + + :boolean prepare-authorize: + + True if prepare authorization request. + + Possible Errors: + + :org.bluez.Error.Failed: + :org.bluez.Error.InProgress: + :org.bluez.Error.NotPermitted: + :org.bluez.Error.InvalidValueLength: + :org.bluez.Error.NotAuthorized: + :org.bluez.Error.NotSupported: + :org.bluez.Error.ImproperlyConfigured: + +Properties +---------- + +string UUID [read-only] +``````````````````````` + + 128-bit descriptor UUID. + +object Characteristic [read-only] +````````````````````````````````` + + Object path of the GATT characteristic the descriptor belongs to. + +array{byte} Value [read-only, optional] +``````````````````````````````````````` + + The cached value of the descriptor. This property gets updated only + after a successful read request, upon which a PropertiesChanged signal + will be emitted. + +array{string} Flags [read-only] +``````````````````````````````` + + Defines how the descriptor value can be used. + + Possible values: + + :"read": + :"write": + :"encrypt-read": + :"encrypt-write": + :"encrypt-authenticated-read": + :"encrypt-authenticated-write": + :"secure-read" (Server Only): + :"secure-write" (Server Only): + :"authorize": + +uint16 Handle [read-only] (Client Only) +``````````````````````````````````````` + + Descriptor handle. + +uint16 Handle [read-write, optional] (Server Only) +`````````````````````````````````````````````````` + + Descriptor handle. When available in the server it would attempt to + use to allocate into the database which may fail, to auto allocate the + value 0x0000 shall be used which will cause the allocated handle to be + set once registered. diff --git a/doc/org.bluez.GattManager.5 b/doc/org.bluez.GattManager.5 new file mode 100644 index 0000000000000000000000000000000000000000..7285048d5f6e3345b86c0884c1bb70b7fde7c691 --- /dev/null +++ b/doc/org.bluez.GattManager.5 @@ -0,0 +1,149 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.GATTMANAGER" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.GattManager \- BlueZ D-Bus GattManager API documentation +.SH DESCRIPTION +.sp +GATT Manager allows external applications to register GATT services and +profiles. +.sp +Registering a profile allows applications to subscribe to \fIremote/client\fP +services. +.sp +Registering a service allows applications to publish a \fIlocal/server\fP GATT +service, which then becomes available to remote devices. A GATT service is +represented by a D\-Bus object hierarchy where the root node corresponds to a +service and the child nodes represent characteristics and descriptors that +belong to that service. Each node must implement one of +\fBorg.bluez.GattService(5)\fP, \fBorg.bluez.GattCharacteristic(5)\fP or +\fBorg.bluez.GattDescriptor(5)\fP interfaces, based on the attribute it +represents. Each node must also implement the standard D\-Bus Properties +interface to expose their properties. These objects collectively represent a +GATT service definition. +.sp +To make service registration simple, \fBbluetoothd(8)\fP requires that all objects +that belong to a GATT service be grouped under a D\-Bus Object Manager that +solely manages the objects of that service. Hence, the standard +DBus.ObjectManager interface must be available on the root service path. An +example application hierarchy containing two separate GATT services may look +like this: +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +\-> /com/example + | \- org.freedesktop.DBus.ObjectManager + | + \-> /com/example/service0 + | | \- org.freedesktop.DBus.Properties + | | \- org.bluez.GattService1 + | | + | \-> /com/example/service0/char0 + | | \- org.freedesktop.DBus.Properties + | | \- org.bluez.GattCharacteristic1 + | | + | \-> /com/example/service0/char1 + | | \- org.freedesktop.DBus.Properties + | | \- org.bluez.GattCharacteristic1 + | | + | \-> /com/example/service0/char1/desc0 + | \- org.freedesktop.DBus.Properties + | \- org.bluez.GattDescriptor1 + | + \-> /com/example/service1 + | \- org.freedesktop.DBus.Properties + | \- org.bluez.GattService1 + | + \-> /com/example/service1/char0 + \- org.freedesktop.DBus.Properties + \- org.bluez.GattCharacteristic1 +.EE +.UNINDENT +.UNINDENT +.sp +When a service is registered, \fBbluetoothd(8)\fP will automatically obtain +information about all objects using the service\(aqs Object Manager. Once a service +has been registered, the objects of a service should not be removed. If +\fBbluetoothd(8)\fP receives an InterfacesRemoved signal from a service\(aqs Object +Manager, it will immediately unregister the service. Similarly, if the +application disconnects from the bus, all of its registered services will be +automatically unregistered. InterfacesAdded signals will be ignored. +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.GattManager1 +.TP +.B Object path +[variable prefix]/{hci0,hci1,...} +.UNINDENT +.SS Methods +.SS void RegisterApplication(object application, dict options) +.INDENT 0.0 +.INDENT 3.5 +Registers a local GATT services hierarchy as described above +(GATT Server) and/or GATT profiles (GATT Client). +.sp +The application object path together with the D\-Bus system bus +connection ID define the identification of the application registering +a GATT based service (\fBorg.bluez.GattService(5)\fP) and/or profile +(\fBorg.bluez.GattProfile(5)\fP). +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.AlreadyExists +.UNINDENT +.UNINDENT +.UNINDENT +.SS void UnregisterApplication(object application) +.INDENT 0.0 +.INDENT 3.5 +This unregisters the services and/or profiles that has been previously +registered using \fBRegisterApplication()\fP\&. The object path parameter +must match the same value that has been used on registration. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.DoesNotExist +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.GattManager.rst b/doc/org.bluez.GattManager.rst new file mode 100644 index 0000000000000000000000000000000000000000..f98296b89a01888bdd8beec28dd131246bfc677e --- /dev/null +++ b/doc/org.bluez.GattManager.rst @@ -0,0 +1,114 @@ +===================== +org.bluez.GattManager +===================== + +----------------------------------------- +BlueZ D-Bus GattManager API documentation +----------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Description +=========== + +GATT Manager allows external applications to register GATT services and +profiles. + +Registering a profile allows applications to subscribe to *remote/client* +services. + +Registering a service allows applications to publish a *local/server* GATT +service, which then becomes available to remote devices. A GATT service is +represented by a D-Bus object hierarchy where the root node corresponds to a +service and the child nodes represent characteristics and descriptors that +belong to that service. Each node must implement one of +**org.bluez.GattService(5)**, **org.bluez.GattCharacteristic(5)** or +**org.bluez.GattDescriptor(5)** interfaces, based on the attribute it +represents. Each node must also implement the standard D-Bus Properties +interface to expose their properties. These objects collectively represent a +GATT service definition. + +To make service registration simple, **bluetoothd(8)** requires that all objects +that belong to a GATT service be grouped under a D-Bus Object Manager that +solely manages the objects of that service. Hence, the standard +DBus.ObjectManager interface must be available on the root service path. An +example application hierarchy containing two separate GATT services may look +like this: + +.. code-block:: + + -> /com/example + | - org.freedesktop.DBus.ObjectManager + | + -> /com/example/service0 + | | - org.freedesktop.DBus.Properties + | | - org.bluez.GattService1 + | | + | -> /com/example/service0/char0 + | | - org.freedesktop.DBus.Properties + | | - org.bluez.GattCharacteristic1 + | | + | -> /com/example/service0/char1 + | | - org.freedesktop.DBus.Properties + | | - org.bluez.GattCharacteristic1 + | | + | -> /com/example/service0/char1/desc0 + | - org.freedesktop.DBus.Properties + | - org.bluez.GattDescriptor1 + | + -> /com/example/service1 + | - org.freedesktop.DBus.Properties + | - org.bluez.GattService1 + | + -> /com/example/service1/char0 + - org.freedesktop.DBus.Properties + - org.bluez.GattCharacteristic1 + +When a service is registered, **bluetoothd(8)** will automatically obtain +information about all objects using the service's Object Manager. Once a service +has been registered, the objects of a service should not be removed. If +**bluetoothd(8)** receives an InterfacesRemoved signal from a service's Object +Manager, it will immediately unregister the service. Similarly, if the +application disconnects from the bus, all of its registered services will be +automatically unregistered. InterfacesAdded signals will be ignored. + +Interface +========= + +:Service: org.bluez +:Interface: org.bluez.GattManager1 +:Object path: [variable prefix]/{hci0,hci1,...} + +Methods +------- + +void RegisterApplication(object application, dict options) +`````````````````````````````````````````````````````````` + + Registers a local GATT services hierarchy as described above + (GATT Server) and/or GATT profiles (GATT Client). + + The application object path together with the D-Bus system bus + connection ID define the identification of the application registering + a GATT based service (**org.bluez.GattService(5)**) and/or profile + (**org.bluez.GattProfile(5)**). + + Possible errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.AlreadyExists: + +void UnregisterApplication(object application) +`````````````````````````````````````````````` + + This unregisters the services and/or profiles that has been previously + registered using **RegisterApplication()**. The object path parameter + must match the same value that has been used on registration. + + Possible errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.DoesNotExist: diff --git a/doc/org.bluez.GattProfile.5 b/doc/org.bluez.GattProfile.5 new file mode 100644 index 0000000000000000000000000000000000000000..0af433549594f0fe0aabbeeca89b8f2b3d9914ff --- /dev/null +++ b/doc/org.bluez.GattProfile.5 @@ -0,0 +1,69 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.GATTPROFILE" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.GattProfile \- BlueZ D-Bus GattProfile API documentation +.SH DESCRIPTION +.sp +Local profile (GATT client) instance. By registering this type of object +an application effectively indicates support for a specific GATT profile +and requests automatic connections to be established to devices +supporting it. +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +<application dependent> +.TP +.B Interface +org.bluez.GattProfile1 +.TP +.B Object path +<application dependent> +.UNINDENT +.SS Methods +.SS void Release() +.INDENT 0.0 +.INDENT 3.5 +This method gets called when the service daemon +unregisters the profile. The profile can use it to do cleanup tasks. +There is no need to unregister the profile, because when this method +gets called it has already been unregistered. +.UNINDENT +.UNINDENT +.SS Properties +.SS array{string} UUIDs [read\-only] +.INDENT 0.0 +.INDENT 3.5 +128\-bit GATT service UUIDs to auto connect. +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.GattProfile.rst b/doc/org.bluez.GattProfile.rst new file mode 100644 index 0000000000000000000000000000000000000000..904301a9773bf7a9ab6d1d3b9bec41f0af4467cc --- /dev/null +++ b/doc/org.bluez.GattProfile.rst @@ -0,0 +1,46 @@ +===================== +org.bluez.GattProfile +===================== + +----------------------------------------- +BlueZ D-Bus GattProfile API documentation +----------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Description +=========== + +Local profile (GATT client) instance. By registering this type of object +an application effectively indicates support for a specific GATT profile +and requests automatic connections to be established to devices +supporting it. + +Interface +========= + +:Service: <application dependent> +:Interface: org.bluez.GattProfile1 +:Object path: <application dependent> + +Methods +------- + +void Release() +`````````````` + + This method gets called when the service daemon + unregisters the profile. The profile can use it to do cleanup tasks. + There is no need to unregister the profile, because when this method + gets called it has already been unregistered. + +Properties +---------- + +array{string} UUIDs [read-only] +``````````````````````````````` + + 128-bit GATT service UUIDs to auto connect. diff --git a/doc/org.bluez.GattService.5 b/doc/org.bluez.GattService.5 new file mode 100644 index 0000000000000000000000000000000000000000..2d44b79225e127431f2c57693e5f58eada00394b --- /dev/null +++ b/doc/org.bluez.GattService.5 @@ -0,0 +1,111 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.GATTSERVICE" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.GattService \- BlueZ D-Bus GattService API documentation +.SH DESCRIPTION +.sp +GATT local/server and remote/client services share the same high\-level D\-Bus +API. +.sp +Local/Server refers to GATT based service exported by a plugin or an external +application. +.sp +Remote/Client refers to GATT services exported by the peer. +.SH INTERFACE +.SS Client +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.GattService1 +.TP +.B Object path +[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX +.UNINDENT +.SS Server +.INDENT 0.0 +.TP +.B Service +unique name +.TP +.B Interface +org.bluez.GattService1 +.TP +.B Object path +freely definable +.UNINDENT +.SS Properties +.SS string UUID [read\-only] +.INDENT 0.0 +.INDENT 3.5 +128\-bit service UUID. +.UNINDENT +.UNINDENT +.SS boolean Primary [read\-only] +.INDENT 0.0 +.INDENT 3.5 +Indicates whether or not this GATT service is a primary service. If +false, the service is secondary. +.UNINDENT +.UNINDENT +.SS object Device [read\-only, optional] +.INDENT 0.0 +.INDENT 3.5 +Object path of the Bluetooth device the service belongs to. Only +present on services from remote devices. +.UNINDENT +.UNINDENT +.SS array{object} Includes [read\-only, optional] +.INDENT 0.0 +.INDENT 3.5 +Array of object paths representing the included services of this +service. +.UNINDENT +.UNINDENT +.SS uint16 Handle [read\-only] (client only) +.INDENT 0.0 +.INDENT 3.5 +Service handle. +.UNINDENT +.UNINDENT +.SS uint16 Handle [read\-write, optional] (Server Only) +.INDENT 0.0 +.INDENT 3.5 +Service handle. When available in the server it would attempt to use to +allocate into the database which may fail, to auto allocate the value +0x0000 shall be used which will cause the allocated handle to be set +once registered. +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.GattService.rst b/doc/org.bluez.GattService.rst new file mode 100644 index 0000000000000000000000000000000000000000..4a1e81fc9e03c8f079bbe735c75c23efb84faafc --- /dev/null +++ b/doc/org.bluez.GattService.rst @@ -0,0 +1,79 @@ +===================== +org.bluez.GattService +===================== + +------------------------------------------------- +BlueZ D-Bus GattService API documentation +------------------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Description +=========== + +GATT local/server and remote/client services share the same high-level D-Bus +API. + +Local/Server refers to GATT based service exported by a plugin or an external +application. + +Remote/Client refers to GATT services exported by the peer. + +Interface +========= + +Client +------ + +:Service: org.bluez +:Interface: org.bluez.GattService1 +:Object path: [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX + +Server +------ + +:Service: unique name +:Interface: org.bluez.GattService1 +:Object path: freely definable + +Properties +---------- + +string UUID [read-only] +``````````````````````` + + 128-bit service UUID. + +boolean Primary [read-only] +``````````````````````````` + + Indicates whether or not this GATT service is a primary service. If + false, the service is secondary. + +object Device [read-only, optional] +``````````````````````````````````` + + Object path of the Bluetooth device the service belongs to. Only + present on services from remote devices. + +array{object} Includes [read-only, optional] +```````````````````````````````````````````` + + Array of object paths representing the included services of this + service. + +uint16 Handle [read-only] (client only) +``````````````````````````````````````` + + Service handle. + +uint16 Handle [read-write, optional] (Server Only) +`````````````````````````````````````````````````` + + Service handle. When available in the server it would attempt to use to + allocate into the database which may fail, to auto allocate the value + 0x0000 shall be used which will cause the allocated handle to be set + once registered. diff --git a/doc/org.bluez.Input.5 b/doc/org.bluez.Input.5 new file mode 100644 index 0000000000000000000000000000000000000000..c9870276f081ebf2c5a74afc15bdfa4606c64d87 --- /dev/null +++ b/doc/org.bluez.Input.5 @@ -0,0 +1,75 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.INPUT" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.Input \- BlueZ D-Bus Input API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.Input1 +.TP +.B Object path +[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX +.UNINDENT +.SS Properties +.SS string ReconnectMode [readonly] +.INDENT 0.0 +.INDENT 3.5 +Indicates the Connectability mode of the HID device as defined by the +HID Profile specification, Section 5.4.2. +.sp +This mode is based in the two properties HIDReconnectInitiate (see +Section 5.3.4.6) and HIDNormallyConnectable (see Section 5.3.4.14) which +define the following four possible values: +.INDENT 0.0 +.TP +.B \(dqnone\(dq +Device and host are not required to automatically restore the +connection. +.TP +.B \(dqhost\(dq +Bluetooth HID host restores connection. +.TP +.B \(dqdevice\(dq +Bluetooth HID device restores connection. +.TP +.B \(dqany\(dq +Bluetooth HID device shall attempt to restore the lost +connection, but Bluetooth HID Host may also restore the +connection. +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.Input.rst b/doc/org.bluez.Input.rst new file mode 100644 index 0000000000000000000000000000000000000000..c3c223c913d8936f6ee9c75e9924e379346f7349 --- /dev/null +++ b/doc/org.bluez.Input.rst @@ -0,0 +1,51 @@ +=============== +org.bluez.Input +=============== + +----------------------------------- +BlueZ D-Bus Input API documentation +----------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez +:Interface: org.bluez.Input1 +:Object path: [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX + +Properties +---------- + +string ReconnectMode [readonly] +``````````````````````````````` + + Indicates the Connectability mode of the HID device as defined by the + HID Profile specification, Section 5.4.2. + + This mode is based in the two properties HIDReconnectInitiate (see + Section 5.3.4.6) and HIDNormallyConnectable (see Section 5.3.4.14) which + define the following four possible values: + + :"none": + + Device and host are not required to automatically restore the + connection. + + :"host": + + Bluetooth HID host restores connection. + + :"device": + + Bluetooth HID device restores connection. + + :"any": + + Bluetooth HID device shall attempt to restore the lost + connection, but Bluetooth HID Host may also restore the + connection. diff --git a/doc/org.bluez.LEAdvertisement.5 b/doc/org.bluez.LEAdvertisement.5 new file mode 100644 index 0000000000000000000000000000000000000000..6bbb1ffa69b78d98f0c812225976ac70c7756ca6 --- /dev/null +++ b/doc/org.bluez.LEAdvertisement.5 @@ -0,0 +1,244 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.LEADVERTISEMENT" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.LEAdvertisement \- BlueZ D-Bus LEAdvertisement API documentation +.SH DESCRIPTION +.sp +Advertising packets are structured data which is broadcast on the LE Advertising +channels and available for all devices in range. Because of the limited space +available in LE Advertising packets, each packet\(aqs contents must be carefully +controlled. +.sp +The service daemon acts as a store for the Advertisement Data which is meant to +be sent. It constructs the correct Advertisement Data from the structured +data and configured the kernel to send the correct advertisement. +.SH INTERFACE +.sp +Specifies the Advertisement Data to be broadcast and some advertising +parameters. Properties which are not present will not be included in the +data. Required advertisement data types will always be included. +All UUIDs are 128\-bit versions in the API, and 16 or 32\-bit +versions of the same UUID will be used in the advertising data as appropriate. +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.LEAdvertisement1 +.TP +.B Object path +freely definable +.UNINDENT +.SS Methods +.SS void Release() [noreply] +.INDENT 0.0 +.INDENT 3.5 +This method gets called when the service daemon removes the +Advertisement. A client can use it to do cleanup tasks. There is no +need to call \fBUnregisterAdvertisement()\fP because when this method +gets called it has already been unregistered. +.UNINDENT +.UNINDENT +.SS Properties +.SS string Type [readonly] +.INDENT 0.0 +.INDENT 3.5 +Determines the type of advertising packet requested. +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqbroadcast\(dq +.TP +.B \(dqperipheral\(dq +.UNINDENT +.UNINDENT +.UNINDENT +.SS array{string} ServiceUUIDs +.INDENT 0.0 +.INDENT 3.5 +List of UUIDs to include in the \(dqService UUID\(dq field of the Advertising +Data. +.UNINDENT +.UNINDENT +.SS dict ManufacturerData +.INDENT 0.0 +.INDENT 3.5 +Manufacturer Data fields to include in the Advertising Data. Keys are +the Manufacturer ID to associate with the data. +.UNINDENT +.UNINDENT +.SS array{string} SolicitUUIDs +.INDENT 0.0 +.INDENT 3.5 +Array of UUIDs to include in \(dqService Solicitation\(dq Advertisement Data. +.UNINDENT +.UNINDENT +.SS dict ServiceData +.INDENT 0.0 +.INDENT 3.5 +Service Data elements to include. The keys are the UUID to associate +with the data. +.UNINDENT +.UNINDENT +.SS dict Data +.INDENT 0.0 +.INDENT 3.5 +Advertising Data to include. Key is the advertising type and value is +the data as byte array. +.sp +Note: Types already handled by other properties shall not be used. +.sp +Possible values: +.INDENT 0.0 +.TP +.B <type> +<byte array> +.UNINDENT +.INDENT 0.0 +.TP +.B Example: +<Transport Discovery> <Organization Flags...> +0x26 0x01 0x01... +.UNINDENT +.UNINDENT +.UNINDENT +.SS bool Discoverable +.INDENT 0.0 +.INDENT 3.5 +Advertise as general discoverable. When present this will override +adapter Discoverable property. +.sp +Note: This property shall not be set when \fBType\fP is set to +\(dqbroadcast\(dq. +.UNINDENT +.UNINDENT +.SS uint16 DiscoverableTimeout +.INDENT 0.0 +.INDENT 3.5 +The discoverable timeout in seconds. A value of zero means that the +timeout is disabled and it will stay in discoverable/limited mode +forever. +.sp +Note: This property shall not be set when \fBType\fP is set to +\(dqbroadcast\(dq. +.UNINDENT +.UNINDENT +.SS array{string} Includes +.INDENT 0.0 +.INDENT 3.5 +List of features to be included in the advertising packet. +.sp +Possible values: +.sp +See \fBorg.bluez.LEAdvertisingManager(5)\fP \fBSupportedIncludes\fP +property. +.UNINDENT +.UNINDENT +.SS string LocalName +.INDENT 0.0 +.INDENT 3.5 +Local name to be used in the advertising report. If the string is too +big to fit into the packet it will be truncated. +.sp +If this property is available \(aqlocal\-name\(aq cannot be present in the +\fBIncludes\fP\&. +.UNINDENT +.UNINDENT +.SS uint16 Appearance +.INDENT 0.0 +.INDENT 3.5 +Appearance to be used in the advertising report. +.sp +Possible values: as found on GAP Service. +.UNINDENT +.UNINDENT +.SS uint16_t Duration +.INDENT 0.0 +.INDENT 3.5 +Rotation duration of the advertisement in seconds. If there are other +applications advertising no duration is set the default is 2 seconds. +.UNINDENT +.UNINDENT +.SS uint16_t Timeout +.INDENT 0.0 +.INDENT 3.5 +Timeout of the advertisement in seconds. This defines the lifetime of +the advertisement. +.UNINDENT +.UNINDENT +.SS string SecondaryChannel +.INDENT 0.0 +.INDENT 3.5 +Secondary channel to be used. Primary channel is always set to \(dq1M\(dq +except when \(dqCoded\(dq is set. +.sp +Possible value: +.INDENT 0.0 +.TP +.B \(dq1M\(dq (default) +.TP +.B \(dq2M\(dq +.TP +.B \(dqCoded\(dq +.UNINDENT +.UNINDENT +.UNINDENT +.SS uint32 MinInterval +.INDENT 0.0 +.INDENT 3.5 +Minimum advertising interval to be used by the advertising set, in +milliseconds. Acceptable values are in the range [20ms, 10,485s]. +If the provided MinInterval is larger than the provided MaxInterval, +the registration will return failure. +.UNINDENT +.UNINDENT +.SS uint32 MaxInterval +.INDENT 0.0 +.INDENT 3.5 +Maximum advertising interval to be used by the advertising set, in +milliseconds. Acceptable values are in the range [20ms, 10,485s]. If the +provided MinInterval is larger than the provided MaxInterval, the +registration will return failure. +.UNINDENT +.UNINDENT +.SS int16 TxPower +.INDENT 0.0 +.INDENT 3.5 +Requested transmission power of this advertising set. The provided value +is used only if the \(dqCanSetTxPower\(dq feature is enabled on the +\fBorg.bluez.LEAdvertisingManager(5)\fP\&. The provided value must be in +range [\-127 to +20], where units are in dBm. +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.LEAdvertisement.rst b/doc/org.bluez.LEAdvertisement.rst new file mode 100644 index 0000000000000000000000000000000000000000..d3f9cc480470d4c03c663838797dcd4f8703f5b1 --- /dev/null +++ b/doc/org.bluez.LEAdvertisement.rst @@ -0,0 +1,195 @@ +========================= +org.bluez.LEAdvertisement +========================= + +--------------------------------------------- +BlueZ D-Bus LEAdvertisement API documentation +--------------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Description +=========== + +Advertising packets are structured data which is broadcast on the LE Advertising +channels and available for all devices in range. Because of the limited space +available in LE Advertising packets, each packet's contents must be carefully +controlled. + +The service daemon acts as a store for the Advertisement Data which is meant to +be sent. It constructs the correct Advertisement Data from the structured +data and configured the kernel to send the correct advertisement. + +Interface +========= + +Specifies the Advertisement Data to be broadcast and some advertising +parameters. Properties which are not present will not be included in the +data. Required advertisement data types will always be included. +All UUIDs are 128-bit versions in the API, and 16 or 32-bit +versions of the same UUID will be used in the advertising data as appropriate. + +:Service: org.bluez +:Interface: org.bluez.LEAdvertisement1 +:Object path: freely definable + +Methods +------- + +void Release() [noreply] +```````````````````````` + + This method gets called when the service daemon removes the + Advertisement. A client can use it to do cleanup tasks. There is no + need to call **UnregisterAdvertisement()** because when this method + gets called it has already been unregistered. + +Properties +---------- + +string Type [readonly] +`````````````````````` + + Determines the type of advertising packet requested. + + Possible values: + + :"broadcast": + :"peripheral": + +array{string} ServiceUUIDs +`````````````````````````` + + List of UUIDs to include in the "Service UUID" field of the Advertising + Data. + +dict ManufacturerData +````````````````````` + + Manufacturer Data fields to include in the Advertising Data. Keys are + the Manufacturer ID to associate with the data. + +array{string} SolicitUUIDs +`````````````````````````` + + Array of UUIDs to include in "Service Solicitation" Advertisement Data. + +dict ServiceData +```````````````` + + Service Data elements to include. The keys are the UUID to associate + with the data. + +dict Data +````````` + + Advertising Data to include. Key is the advertising type and value is + the data as byte array. + + Note: Types already handled by other properties shall not be used. + + Possible values: + + :<type>: + + <byte array> + + Example: + <Transport Discovery> <Organization Flags...> + 0x26 0x01 0x01... + +bool Discoverable +````````````````` + + Advertise as general discoverable. When present this will override + adapter Discoverable property. + + Note: This property shall not be set when **Type** is set to + "broadcast". + +uint16 DiscoverableTimeout +`````````````````````````` + + The discoverable timeout in seconds. A value of zero means that the + timeout is disabled and it will stay in discoverable/limited mode + forever. + + Note: This property shall not be set when **Type** is set to + "broadcast". + +array{string} Includes +`````````````````````` + + List of features to be included in the advertising packet. + + Possible values: + + See **org.bluez.LEAdvertisingManager(5)** **SupportedIncludes** + property. + +string LocalName +```````````````` + + Local name to be used in the advertising report. If the string is too + big to fit into the packet it will be truncated. + + If this property is available 'local-name' cannot be present in the + **Includes**. + +uint16 Appearance +````````````````` + + Appearance to be used in the advertising report. + + Possible values: as found on GAP Service. + +uint16_t Duration +````````````````` + + Rotation duration of the advertisement in seconds. If there are other + applications advertising no duration is set the default is 2 seconds. + +uint16_t Timeout +```````````````` + + Timeout of the advertisement in seconds. This defines the lifetime of + the advertisement. + +string SecondaryChannel +``````````````````````` + + Secondary channel to be used. Primary channel is always set to "1M" + except when "Coded" is set. + + Possible value: + + :"1M" (default): + :"2M": + :"Coded": + +uint32 MinInterval +`````````````````` + + Minimum advertising interval to be used by the advertising set, in + milliseconds. Acceptable values are in the range [20ms, 10,485s]. + If the provided MinInterval is larger than the provided MaxInterval, + the registration will return failure. + +uint32 MaxInterval +`````````````````` + + Maximum advertising interval to be used by the advertising set, in + milliseconds. Acceptable values are in the range [20ms, 10,485s]. If the + provided MinInterval is larger than the provided MaxInterval, the + registration will return failure. + +int16 TxPower +````````````` + + Requested transmission power of this advertising set. The provided value + is used only if the "CanSetTxPower" feature is enabled on the + **org.bluez.LEAdvertisingManager(5)**. The provided value must be in + range [-127 to +20], where units are in dBm. diff --git a/doc/org.bluez.LEAdvertisingManager.5 b/doc/org.bluez.LEAdvertisingManager.5 new file mode 100644 index 0000000000000000000000000000000000000000..fc0fb56d854b47dd698347a6865725486a01bec8 --- /dev/null +++ b/doc/org.bluez.LEAdvertisingManager.5 @@ -0,0 +1,189 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.LEADVERTISINGMANAGER" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.LEAdvertisingManager \- BlueZ D-Bus LEAvertisingManager API documentation +.SH INTERFACE +.sp +The Advertising Manager allows external applications to register Advertisement +Data which should be broadcast to devices. Advertisement Data elements must +follow the API for LE Advertisement Data described above. +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.LEAdvertisingManager1 +.TP +.B Object path +/org/bluez/{hci0,hci1,...} +.UNINDENT +.SS Methods +.SS void RegisterAdvertisement(object advertisement, dict options) +.INDENT 0.0 +.INDENT 3.5 +Registers an advertisement object to be sent over the LE Advertising +channel. The service must implement \fBorg.bluez.LEAdvertisement(5)\fP +interface. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +Indicates that the object has invalid or conflicting properties. +.TP +.B org.bluez.Error.AlreadyExists +Indicates the object is already registered. +.TP +.B org.bluez.Error.InvalidLength +Indicates that the data provided generates a data packet which +is too long +.TP +.B org.bluez.Error.NotPermitted +Indicates the maximum number of advertisement instances has +been reached. +.UNINDENT +.UNINDENT +.UNINDENT +.SS void UnregisterAdvertisement(object advertisement) +.INDENT 0.0 +.INDENT 3.5 +Unregisters an advertisement that has been previously registered using +\fBRegisterAdvertisement()\fP\&. The object path parameter must match the +same value that has been used on registration. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.DoesNotExist +.UNINDENT +.UNINDENT +.UNINDENT +.SS Properties +.SS byte ActiveInstances [readonly] +.INDENT 0.0 +.INDENT 3.5 +Number of active advertising instances. +.UNINDENT +.UNINDENT +.SS byte SupportedInstances [readonly] +.INDENT 0.0 +.INDENT 3.5 +Number of available advertising instances. +.UNINDENT +.UNINDENT +.SS array{string} SupportedIncludes [readonly] +.INDENT 0.0 +.INDENT 3.5 +List of supported system includes. +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqtx\-power\(dq +.TP +.B \(dqappearance\(dq +.TP +.B \(dqlocal\-name\(dq +.TP +.B \(dqrsi\(dq +.UNINDENT +.UNINDENT +.UNINDENT +.SS array{string} SupportedSecondaryChannels [readonly] +.INDENT 0.0 +.INDENT 3.5 +List of supported Secondary channels. Secondary channels can be used to +advertise with the corresponding PHY. +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dq1M\(dq +.TP +.B \(dq2M\(dq +.TP +.B \(dqCoded\(dq +.UNINDENT +.UNINDENT +.UNINDENT +.SS dict SupportedCapabilities [readonly] +.INDENT 0.0 +.INDENT 3.5 +Enumerates Advertising\-related controller capabilities useful to the +client. +.sp +Possible Values: +.INDENT 0.0 +.TP +.B byte MaxAdvLen +Max advertising data length +.TP +.B byte MaxScnRspLen +Max advertising scan response length +.UNINDENT +.sp +;int16 MinTxPower: +.INDENT 0.0 +.INDENT 3.5 +Min advertising tx power (dBm) +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B int16 MaxTxPower +Max advertising tx power (dBm) +.UNINDENT +.UNINDENT +.UNINDENT +.SS array{string} SupportedFeatures [readonly,optional] +.INDENT 0.0 +.INDENT 3.5 +List of supported platform features. If no features are available on +the platform, the SupportedFeatures array will be empty. +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqCanSetTxPower\(dq +Indicates whether platform can specify tx power on each +advertising instance. +.TP +.B \(dqHardwareOffload\(dq +Indicates whether multiple advertising will be offloaded to the +controller. +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.LEAdvertisingManager.rst b/doc/org.bluez.LEAdvertisingManager.rst new file mode 100644 index 0000000000000000000000000000000000000000..7f6359dff1f8c621e6baea644727896f082948c7 --- /dev/null +++ b/doc/org.bluez.LEAdvertisingManager.rst @@ -0,0 +1,144 @@ +============================== +org.bluez.LEAdvertisingManager +============================== + +------------------------------------------------- +BlueZ D-Bus LEAvertisingManager API documentation +------------------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +The Advertising Manager allows external applications to register Advertisement +Data which should be broadcast to devices. Advertisement Data elements must +follow the API for LE Advertisement Data described above. + +:Service: org.bluez +:Interface: org.bluez.LEAdvertisingManager1 +:Object path: /org/bluez/{hci0,hci1,...} + +Methods +------- + +void RegisterAdvertisement(object advertisement, dict options) +`````````````````````````````````````````````````````````````` + + Registers an advertisement object to be sent over the LE Advertising + channel. The service must implement **org.bluez.LEAdvertisement(5)** + interface. + + Possible errors: + + :org.bluez.Error.InvalidArguments: + + Indicates that the object has invalid or conflicting properties. + + :org.bluez.Error.AlreadyExists: + + Indicates the object is already registered. + + :org.bluez.Error.InvalidLength: + + Indicates that the data provided generates a data packet which + is too long + + :org.bluez.Error.NotPermitted: + + Indicates the maximum number of advertisement instances has + been reached. + +void UnregisterAdvertisement(object advertisement) +`````````````````````````````````````````````````` + + Unregisters an advertisement that has been previously registered using + **RegisterAdvertisement()**. The object path parameter must match the + same value that has been used on registration. + + Possible errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.DoesNotExist: + +Properties +---------- + +byte ActiveInstances [readonly] +``````````````````````````````` + + Number of active advertising instances. + +byte SupportedInstances [readonly] +`````````````````````````````````` + + Number of available advertising instances. + +array{string} SupportedIncludes [readonly] +`````````````````````````````````````````` + + List of supported system includes. + + Possible values: + + :"tx-power": + :"appearance": + :"local-name": + :"rsi": + +array{string} SupportedSecondaryChannels [readonly] +``````````````````````````````````````````````````` + + List of supported Secondary channels. Secondary channels can be used to + advertise with the corresponding PHY. + + Possible values: + + :"1M": + :"2M": + :"Coded": + +dict SupportedCapabilities [readonly] +````````````````````````````````````` + + Enumerates Advertising-related controller capabilities useful to the + client. + + Possible Values: + + :byte MaxAdvLen: + + Max advertising data length + + :byte MaxScnRspLen: + + Max advertising scan response length + + ;int16 MinTxPower: + + Min advertising tx power (dBm) + + :int16 MaxTxPower: + + Max advertising tx power (dBm) + +array{string} SupportedFeatures [readonly,optional] +``````````````````````````````````````````````````` + + List of supported platform features. If no features are available on + the platform, the SupportedFeatures array will be empty. + + Possible values: + + :"CanSetTxPower": + + Indicates whether platform can specify tx power on each + advertising instance. + + :"HardwareOffload": + + Indicates whether multiple advertising will be offloaded to the + controller. diff --git a/doc/org.bluez.Media.5 b/doc/org.bluez.Media.5 new file mode 100644 index 0000000000000000000000000000000000000000..cd2c16a322f142876ef28cea2097f89bed1654cf --- /dev/null +++ b/doc/org.bluez.Media.5 @@ -0,0 +1,175 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.MEDIA" "5" "September 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.Media \- BlueZ D-Bus Media API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.Media1 +.TP +.B Object path +[variable prefix]/{hci0,hci1,...} +.UNINDENT +.SS Methods +.SS void RegisterEndpoint(object endpoint, dict properties) +.INDENT 0.0 +.INDENT 3.5 +Register a local end point to sender, the sender can register as many +end points as it likes. +.sp +Note: If the sender disconnects the end points are automatically +unregistered. +.sp +possible properties: +.INDENT 0.0 +.TP +.B string UUID +UUID of the profile which the endpoint is for. +.sp +UUID must be in the list of SupportedUUIDS. +.TP +.B byte Codec +Assigned number of codec that the endpoint implements. The +values should match the profile specification which is +indicated by the UUID. +.TP +.B uint32_t Vendor [Optional] +Vendor\-specific Company ID, Codec ID tuple that the endpoint +implements. +.sp +It shall be set to appropriate value when Vendor Specific Codec +(0xff) is used. +.TP +.B array{byte} Capabilities +Capabilities blob, it is used as it is so the size and byte +order must match. +.TP +.B array{byte} Metadata [Optional] +Metadata blob, it is used as it is so the size and byte order +must match. +.UNINDENT +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.NotSupported +emitted when interface for the end\-point is disabled +.UNINDENT +.UNINDENT +.UNINDENT +.SS void UnregisterEndpoint(object endpoint) +.INDENT 0.0 +.INDENT 3.5 +Unregister sender end point. +.UNINDENT +.UNINDENT +.SS void RegisterPlayer(object player, dict properties) +.INDENT 0.0 +.INDENT 3.5 +Register a media player object to sender, the sender can register as +many objects as it likes. +.sp +Object must implement at least org.mpris.MediaPlayer2.Player as defined +in MPRIS 2.2 spec: +.INDENT 0.0 +.INDENT 3.5 + <http://specifications.freedesktop.org/mpris\-spec/latest/> +.UNINDENT +.UNINDENT +.sp +Note: If the sender disconnects its objects are automatically +unregistered. +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.NotSupported +.UNINDENT +.UNINDENT +.UNINDENT +.SS void UnregisterPlayer(object player) +.INDENT 0.0 +.INDENT 3.5 +Unregister sender media player. +.UNINDENT +.UNINDENT +.SS void RegisterApplication(object root, dict options) +.INDENT 0.0 +.INDENT 3.5 +Register endpoints an player objects within root object which must +implement ObjectManager. +.sp +The application object path together with the D\-Bus system bus +connection ID define the identification of the application. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.AlreadyExists +.UNINDENT +.UNINDENT +.UNINDENT +.SS void UnregisterApplication(object application) +.INDENT 0.0 +.INDENT 3.5 +This unregisters the services that has been previously registered. The +object path parameter must match the same value that has been used on +registration. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.DoesNotExist +.UNINDENT +.UNINDENT +.UNINDENT +.SS Properties +.SS array{string} SupportedUUIDs [readonly] +.INDENT 0.0 +.INDENT 3.5 +List of 128\-bit UUIDs that represents the supported Endpoint +registration. +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.Media.rst b/doc/org.bluez.Media.rst new file mode 100644 index 0000000000000000000000000000000000000000..678e6090c6e13821f1e0de375ec78e49257d562a --- /dev/null +++ b/doc/org.bluez.Media.rst @@ -0,0 +1,133 @@ +=============== +org.bluez.Media +=============== + +----------------------------------- +BlueZ D-Bus Media API documentation +----------------------------------- + +:Version: BlueZ +:Date: September 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez +:Interface: org.bluez.Media1 +:Object path: [variable prefix]/{hci0,hci1,...} + +Methods +------- + +void RegisterEndpoint(object endpoint, dict properties) +``````````````````````````````````````````````````````` + + Register a local end point to sender, the sender can register as many + end points as it likes. + + Note: If the sender disconnects the end points are automatically + unregistered. + + possible properties: + + :string UUID: + + UUID of the profile which the endpoint is for. + + UUID must be in the list of SupportedUUIDS. + + :byte Codec: + + Assigned number of codec that the endpoint implements. The + values should match the profile specification which is + indicated by the UUID. + + :uint32_t Vendor [Optional]: + + Vendor-specific Company ID, Codec ID tuple that the endpoint + implements. + + It shall be set to appropriate value when Vendor Specific Codec + (0xff) is used. + + :array{byte} Capabilities: + + Capabilities blob, it is used as it is so the size and byte + order must match. + + :array{byte} Metadata [Optional]: + + Metadata blob, it is used as it is so the size and byte order + must match. + + Possible Errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.NotSupported: + + emitted when interface for the end-point is disabled + +void UnregisterEndpoint(object endpoint) +```````````````````````````````````````` + Unregister sender end point. + +void RegisterPlayer(object player, dict properties) +``````````````````````````````````````````````````` + + Register a media player object to sender, the sender can register as + many objects as it likes. + + Object must implement at least org.mpris.MediaPlayer2.Player as defined + in MPRIS 2.2 spec: + + http://specifications.freedesktop.org/mpris-spec/latest/ + + Note: If the sender disconnects its objects are automatically + unregistered. + + Possible Errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.NotSupported: + +void UnregisterPlayer(object player) +```````````````````````````````````` + + Unregister sender media player. + +void RegisterApplication(object root, dict options) +``````````````````````````````````````````````````` + + Register endpoints an player objects within root object which must + implement ObjectManager. + + The application object path together with the D-Bus system bus + connection ID define the identification of the application. + + Possible errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.AlreadyExists: + +void UnregisterApplication(object application) +`````````````````````````````````````````````` + + This unregisters the services 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.InvalidArguments: + :org.bluez.Error.DoesNotExist: + +Properties +---------- + +array{string} SupportedUUIDs [readonly] +``````````````````````````````````````` + + List of 128-bit UUIDs that represents the supported Endpoint + registration. diff --git a/doc/org.bluez.MediaAssistant.5 b/doc/org.bluez.MediaAssistant.5 new file mode 100644 index 0000000000000000000000000000000000000000..2c09cc34e623c027147390b27b7703a876312cd3 --- /dev/null +++ b/doc/org.bluez.MediaAssistant.5 @@ -0,0 +1,120 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.MEDIAASSISTANT" "5" "June 2024" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.MediaAssistant \- BlueZ D-Bus MediaAssistant API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.MediaAssistant1 +.TP +.B Object path +/org/bluez/{hci0,hci1,...}/src_XX_XX_XX_XX_XX_XX/dev_YY_YY_YY_YY_YY_YY/bisZ +.UNINDENT +.SS Methods +.SS void Push(dict properties) +.INDENT 0.0 +.INDENT 3.5 +Send stream information to the remote device. +.INDENT 0.0 +.TP +.B dict properties +.UNINDENT +.sp +Indicate stream properties that will be sent to the peer. +.sp +Values: +.INDENT 0.0 +.INDENT 3.5 +.INDENT 0.0 +.TP +.B array{byte} Metadata [ISO only] +See Metadata property. +.TP +.B dict QoS [ISO only] +See QoS property. +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.SS Properties +.SS string State [readonly] +.INDENT 0.0 +.INDENT 3.5 +Indicates the state of the assistant object. Possible values are: +.INDENT 0.0 +.TP +.B \(dqidle\(dq +assistant object was created for the stream +.TP +.B \(dqpending\(dq +assistant object was pushed (stream information was sent to the peer) +.TP +.B \(dqrequesting\(dq +remote device requires Broadcast_Code +.TP +.B \(dqactive\(dq +remote device started receiving stream +.UNINDENT +.UNINDENT +.UNINDENT +.SS array{byte} Metadata [readwrite, ISO Only, experimental] +.INDENT 0.0 +.INDENT 3.5 +Indicates stream Metadata. +.UNINDENT +.UNINDENT +.SS dict QoS [readwrite, ISO only, experimental] +.INDENT 0.0 +.INDENT 3.5 +Indicates stream QoS capabilities. +.sp +Values: +.INDENT 0.0 +.TP +.B byte Encryption +Indicates whether the stream is encrypted. +.UNINDENT +.sp +:array{byte} BCode +.INDENT 0.0 +.INDENT 3.5 +Indicates Broadcast_Code to decrypt stream. +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.MediaAssistant.rst b/doc/org.bluez.MediaAssistant.rst new file mode 100644 index 0000000000000000000000000000000000000000..4aac8953619d044d5ca73ac606ff512597e5c60d --- /dev/null +++ b/doc/org.bluez.MediaAssistant.rst @@ -0,0 +1,74 @@ +======================== +org.bluez.MediaAssistant +======================== + +-------------------------------------------- +BlueZ D-Bus MediaAssistant API documentation +-------------------------------------------- + +:Version: BlueZ +:Date: June 2024 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez +:Interface: org.bluez.MediaAssistant1 +:Object path: /org/bluez/{hci0,hci1,...}/src_XX_XX_XX_XX_XX_XX/dev_YY_YY_YY_YY_YY_YY/bisZ + +Methods +------- + +void Push(dict properties) +```````````````````````````````````````````````````````` + + Send stream information to the remote device. + + :dict properties: + + Indicate stream properties that will be sent to the peer. + + Values: + + :array{byte} Metadata [ISO only]: + + See Metadata property. + + :dict QoS [ISO only]: + + See QoS property. + +Properties +---------- + +string State [readonly] +``````````````````````` + + Indicates the state of the assistant object. Possible values are: + + :"idle": assistant object was created for the stream + :"pending": assistant object was pushed (stream information was sent to the peer) + :"requesting": remote device requires Broadcast_Code + :"active": remote device started receiving stream + +array{byte} Metadata [readwrite, ISO Only, experimental] +```````````````````````````````````````````````````````` + + Indicates stream Metadata. + +dict QoS [readwrite, ISO only, experimental] +````````````````````````````````````````````````````` + + Indicates stream QoS capabilities. + + Values: + + :byte Encryption: + + Indicates whether the stream is encrypted. + + :array{byte} BCode + + Indicates Broadcast_Code to decrypt stream. diff --git a/doc/org.bluez.MediaControl.5 b/doc/org.bluez.MediaControl.5 new file mode 100644 index 0000000000000000000000000000000000000000..43ec2d48cb1bafe76cb6cd74cc531ba7ce2672de --- /dev/null +++ b/doc/org.bluez.MediaControl.5 @@ -0,0 +1,111 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.MEDIACONTROL" "5" "September 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.MediaControl \- BlueZ D-Bus MediaControl API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.MediaControl1 +.TP +.B Object path +[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX +.UNINDENT +.SS Methods +.SS void Play() [Deprecated] +.INDENT 0.0 +.INDENT 3.5 +Resume playback. +.UNINDENT +.UNINDENT +.SS void Pause() [Deprecated] +.INDENT 0.0 +.INDENT 3.5 +Pause playback. +.UNINDENT +.UNINDENT +.SS void Stop() [Deprecated] +.INDENT 0.0 +.INDENT 3.5 +Stop playback. +.UNINDENT +.UNINDENT +.SS void Next() [Deprecated] +.INDENT 0.0 +.INDENT 3.5 +Next item. +.UNINDENT +.UNINDENT +.SS void Previous() [Deprecated] +.INDENT 0.0 +.INDENT 3.5 +Previous item. +.UNINDENT +.UNINDENT +.SS void VolumeUp() [Deprecated] +.INDENT 0.0 +.INDENT 3.5 +Adjust remote volume one step up +.UNINDENT +.UNINDENT +.SS void VolumeDown() [Deprecated] +.INDENT 0.0 +.INDENT 3.5 +Adjust remote volume one step down +.UNINDENT +.UNINDENT +.SS void FastForward() [Deprecated] +.INDENT 0.0 +.INDENT 3.5 +Fast forward playback, this action is only stopped when another method +in this interface is called. +.UNINDENT +.UNINDENT +.SS void Rewind() [Deprecated] +.INDENT 0.0 +.INDENT 3.5 +Rewind playback, this action is only stopped when another method in +this interface is called. +.UNINDENT +.UNINDENT +.SS Properties +.SS boolean Connected [readonly] +.SS object Player [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Addressed Player object path. +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.MediaControl.rst b/doc/org.bluez.MediaControl.rst new file mode 100644 index 0000000000000000000000000000000000000000..54e84e8c62eba5f5b94e2e6f881dcdf78c4c6c75 --- /dev/null +++ b/doc/org.bluez.MediaControl.rst @@ -0,0 +1,80 @@ +====================== +org.bluez.MediaControl +====================== + +------------------------------------------ +BlueZ D-Bus MediaControl API documentation +------------------------------------------ + +:Version: BlueZ +:Date: September 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez +:Interface: org.bluez.MediaControl1 +:Object path: [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX + +Methods +------- + +void Play() [Deprecated] +```````````````````````` + + Resume playback. + +void Pause() [Deprecated] +````````````````````````` + + Pause playback. + +void Stop() [Deprecated] +```````````````````````` + + Stop playback. + +void Next() [Deprecated] +```````````````````````` + + Next item. + +void Previous() [Deprecated] +```````````````````````````` + + Previous item. + +void VolumeUp() [Deprecated] +```````````````````````````` + + Adjust remote volume one step up + +void VolumeDown() [Deprecated] +`````````````````````````````` + + Adjust remote volume one step down + +void FastForward() [Deprecated] +``````````````````````````````` + + Fast forward playback, this action is only stopped when another method + in this interface is called. + +void Rewind() [Deprecated] +`````````````````````````` + + Rewind playback, this action is only stopped when another method in + this interface is called. + +Properties +---------- + +boolean Connected [readonly] +```````````````````````````` + +object Player [readonly, optional] +`````````````````````````````````` + + Addressed Player object path. diff --git a/doc/org.bluez.MediaEndpoint.5 b/doc/org.bluez.MediaEndpoint.5 new file mode 100644 index 0000000000000000000000000000000000000000..434ac74ea70bb04667c98fe22b6506987a44f692 --- /dev/null +++ b/doc/org.bluez.MediaEndpoint.5 @@ -0,0 +1,282 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.MEDIAENDPOINT" "5" "September 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.MediaEndpoint \- BlueZ D-Bus MediaEndpoint API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +unique name (Server role) +org.bluez (Client role) +.TP +.B Interface +org.bluez.MediaEndpoint1 +.TP +.B Object path +freely definable (Server role) +[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/sepX +(Client role) +.UNINDENT +.SS Methods +.SS void SetConfiguration(object transport, dict properties) +.INDENT 0.0 +.INDENT 3.5 +Set configuration for the transport. +.INDENT 0.0 +.TP +.B object transport +Configured transport object. +.TP +.B dict properties +Configured \fBorg.bluez.MediaTransport(5)\fP properties. +.UNINDENT +.sp +For client role transport must be set with a server endpoint +object which will be configured and the properties must +contain the following properties: +.INDENT 0.0 +.TP +.B array{byte} Capabilities [Mandatory] +See Capabilities property. +.TP +.B array{byte} Metadata [ISO only] +See Metadata property. +.TP +.B dict QoS [ISO only] +See \fBorg.bluez.MediaTransport(5)\fP QoS property. +.UNINDENT +.UNINDENT +.UNINDENT +.SS array{byte} SelectConfiguration(array{byte} capabilities) +.INDENT 0.0 +.INDENT 3.5 +Select preferable configuration from the supported capabilities. +.sp +Returns a configuration which can be used to setup a transport, see +\fBorg.bluez.MediaTransport(5)\fP for possible values. +.sp +Note: There is no need to cache the selected configuration since on +success the configuration is send back as parameter of SetConfiguration. +.UNINDENT +.UNINDENT +.SS dict SelectProperties(dict capabilities) +.INDENT 0.0 +.INDENT 3.5 +Select BAP unicast configuration from the supported capabilities: +.INDENT 0.0 +.TP +.B object Endpoint +.TP +.B array{byte} Capabilities +.TP +.B array{byte} Metadata +.TP +.B uint32 Locations +.TP +.B uint32_t ChannelAllocation +.TP +.B dict QoS +.INDENT 7.0 +.TP +.B byte Framing +.TP +.B byte PHY +.TP +.B uint16 MaximumLatency +.TP +.B uint32 MinimumDelay +.TP +.B uint32 MaximumDelay +.TP +.B uint32 PreferredMinimumDelay +.TP +.B uint32 PreferredMaximumDelay +.UNINDENT +.UNINDENT +.sp +See MediaEndpoint Properties for their possible values. +.sp +Returns a configuration which can be used to setup a transport: +.INDENT 0.0 +.TP +.B array{byte} Capabilities +.TP +.B array{byte} Metadata [optional] +.TP +.B dict QoS +.UNINDENT +.sp +See SetConfiguration for their possible values. +.sp +Note: There is no need to cache the selected properties since on +success the configuration is send back as parameter of SetConfiguration. +.UNINDENT +.UNINDENT +.SS void ClearConfiguration(object transport) +.INDENT 0.0 +.INDENT 3.5 +Clear transport configuration. +.UNINDENT +.UNINDENT +.SS void Release() +.INDENT 0.0 +.INDENT 3.5 +This method gets called when the service daemon unregisters the +endpoint. An endpoint can use it to do cleanup tasks. There is no need +to unregister the endpoint, because when this method gets called it has +already been unregistered. +.UNINDENT +.UNINDENT +.SS MediaEndpoint Properties +.SS string UUID [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +UUID of the profile which the endpoint is for. +.UNINDENT +.UNINDENT +.SS byte Codec [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Assigned number of codec that the endpoint implements. +The values should match the profile specification which is indicated by +the UUID. +.UNINDENT +.UNINDENT +.SS uint32_t Vendor [readonly, Optional] +.INDENT 0.0 +.INDENT 3.5 +Vendor\-specific Company ID, Codec ID tuple that the endpoint implements. +.sp +It shall be set to appropriate value when Vendor Specific Codec (0xff) +is used. +.UNINDENT +.UNINDENT +.SS array{byte} Capabilities [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Capabilities blob, it is used as it is so the size and byte order must +match. +.UNINDENT +.UNINDENT +.SS array{byte} Metadata [readonly, Optional] +.INDENT 0.0 +.INDENT 3.5 +Metadata blob, it is used as it is so the size and byte order must +match. +.UNINDENT +.UNINDENT +.SS object Device [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Device object which the endpoint is belongs to. +.UNINDENT +.UNINDENT +.SS bool DelayReporting [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Indicates if endpoint supports Delay Reporting. +.UNINDENT +.UNINDENT +.SS uint32 Locations [readonly, optional, ISO only, experimental] +.INDENT 0.0 +.INDENT 3.5 +Indicates endpoint supported locations. +.UNINDENT +.UNINDENT +.SS uint16 SupportedContext [readonly, optional, ISO only, experimental] +.INDENT 0.0 +.INDENT 3.5 +Indicates endpoint supported audio context. +.UNINDENT +.UNINDENT +.SS uint16 Context [readonly, optional, ISO only, experimental] +.INDENT 0.0 +.INDENT 3.5 +Indicates endpoint available audio context. +.UNINDENT +.UNINDENT +.SS dict QoS [readonly, optional, ISO only, experimental] +.INDENT 0.0 +.INDENT 3.5 +Indicates QoS capabilities. +.INDENT 0.0 +.TP +.B byte Framing +Indicates endpoint support framing. +.sp +Possible Values: +.INDENT 7.0 +.TP +.B 0x00 +Unframed PDUs supported. +.TP +.B 0x01 +Unframed PDUs not supported. +.UNINDENT +.TP +.B byte PHY +Indicates endpoint preferred PHY. +.sp +Possible values: +.INDENT 7.0 +.TP +.B bit 0 +LE 1M preferred. +.TP +.B bit 1 +LE 2M preferred. +.TP +.B bit 2 +LE Coded preferred. +.UNINDENT +.TP +.B byte Retransmissions +Indicates endpoint preferred number of retransmissions. +.TP +.B uint16 MaximumLatency +Indicates endpoint maximum latency. +.TP +.B uint32 MinimumDelay +Indicates endpoint minimum presentation delay. +.TP +.B uint32 MaximumDelay +Indicates endpoint maximum presentation delay. +.TP +.B uint32 PreferredMinimumDelay +Indicates endpoint preferred minimum presentation delay. +.TP +.B uint32 PreferredMaximumDelay +Indicates endpoint preferred maximum presentation delay. +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.MediaEndpoint.rst b/doc/org.bluez.MediaEndpoint.rst new file mode 100644 index 0000000000000000000000000000000000000000..f2b830ab0949e02e575260c8ae6c67609a06f0e0 --- /dev/null +++ b/doc/org.bluez.MediaEndpoint.rst @@ -0,0 +1,240 @@ +======================= +org.bluez.MediaEndpoint +======================= + +------------------------------------------- +BlueZ D-Bus MediaEndpoint API documentation +------------------------------------------- + +:Version: BlueZ +:Date: September 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: unique name (Server role) + org.bluez (Client role) +:Interface: org.bluez.MediaEndpoint1 +:Object path: freely definable (Server role) + [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/sepX + (Client role) + +Methods +------- + +.. _SetConfiguration: + +void SetConfiguration(object transport, dict properties) +```````````````````````````````````````````````````````` + + Set configuration for the transport. + + :object transport: + + Configured transport object. + + :dict properties: + + Configured **org.bluez.MediaTransport(5)** properties. + + For client role transport must be set with a server endpoint + object which will be configured and the properties must + contain the following properties: + + :array{byte} Capabilities [Mandatory]: + + See Capabilities property. + + :array{byte} Metadata [ISO only]: + + See Metadata property. + + :dict QoS [ISO only]: + + See **org.bluez.MediaTransport(5)** QoS property. + +array{byte} SelectConfiguration(array{byte} capabilities) +````````````````````````````````````````````````````````` + + Select preferable configuration from the supported capabilities. + + Returns a configuration which can be used to setup a transport, see + **org.bluez.MediaTransport(5)** for possible values. + + Note: There is no need to cache the selected configuration since on + success the configuration is send back as parameter of SetConfiguration. + +dict SelectProperties(dict capabilities) +```````````````````````````````````````` + + Select BAP unicast configuration from the supported capabilities: + + :object Endpoint: + + :array{byte} Capabilities: + + :array{byte} Metadata: + + :uint32 Locations: + + :uint32_t ChannelAllocation: + + :dict QoS: + + :byte Framing: + :byte PHY: + :uint16 MaximumLatency: + :uint32 MinimumDelay: + :uint32 MaximumDelay: + :uint32 PreferredMinimumDelay: + :uint32 PreferredMaximumDelay: + + See `MediaEndpoint Properties`_ for their possible values. + + Returns a configuration which can be used to setup a transport: + + :array{byte} Capabilities: + :array{byte} Metadata [optional]: + :dict QoS: + + See `SetConfiguration`_ for their possible values. + + Note: There is no need to cache the selected properties since on + success the configuration is send back as parameter of SetConfiguration. + +void ClearConfiguration(object transport) +````````````````````````````````````````` + + Clear transport configuration. + +void Release() +`````````````` + + This method gets called when the service daemon unregisters the + endpoint. An endpoint can use it to do cleanup tasks. There is no need + to unregister the endpoint, because when this method gets called it has + already been unregistered. + +MediaEndpoint Properties +------------------------ + +string UUID [readonly, optional] +```````````````````````````````` + + UUID of the profile which the endpoint is for. + +byte Codec [readonly, optional] +``````````````````````````````` + + Assigned number of codec that the endpoint implements. + The values should match the profile specification which is indicated by + the UUID. + +uint32_t Vendor [readonly, Optional] +```````````````````````````````````` + + Vendor-specific Company ID, Codec ID tuple that the endpoint implements. + + It shall be set to appropriate value when Vendor Specific Codec (0xff) + is used. + +array{byte} Capabilities [readonly, optional] +````````````````````````````````````````````` + + Capabilities blob, it is used as it is so the size and byte order must + match. + +array{byte} Metadata [readonly, Optional] +````````````````````````````````````````` + + Metadata blob, it is used as it is so the size and byte order must + match. + +object Device [readonly, optional] +`````````````````````````````````` + + Device object which the endpoint is belongs to. + +bool DelayReporting [readonly, optional] +```````````````````````````````````````` + + Indicates if endpoint supports Delay Reporting. + +uint32 Locations [readonly, optional, ISO only, experimental] +````````````````````````````````````````````````````````````` + + Indicates endpoint supported locations. + +uint16 SupportedContext [readonly, optional, ISO only, experimental] +```````````````````````````````````````````````````````````````````` + + Indicates endpoint supported audio context. + +uint16 Context [readonly, optional, ISO only, experimental] +``````````````````````````````````````````````````````````` + + Indicates endpoint available audio context. + +dict QoS [readonly, optional, ISO only, experimental] +````````````````````````````````````````````````````` + + Indicates QoS capabilities. + + :byte Framing: + + Indicates endpoint support framing. + + + Possible Values: + + :0x00: + + Unframed PDUs supported. + + :0x01: + + Unframed PDUs not supported. + + :byte PHY: + + Indicates endpoint preferred PHY. + + Possible values: + + :bit 0: + + LE 1M preferred. + + :bit 1: + + LE 2M preferred. + + :bit 2: + + LE Coded preferred. + + :byte Retransmissions: + + Indicates endpoint preferred number of retransmissions. + + :uint16 MaximumLatency: + + Indicates endpoint maximum latency. + + :uint32 MinimumDelay: + + Indicates endpoint minimum presentation delay. + + :uint32 MaximumDelay: + + Indicates endpoint maximum presentation delay. + + :uint32 PreferredMinimumDelay: + + Indicates endpoint preferred minimum presentation delay. + + :uint32 PreferredMaximumDelay: + + Indicates endpoint preferred maximum presentation delay. diff --git a/doc/org.bluez.MediaFolder.5 b/doc/org.bluez.MediaFolder.5 new file mode 100644 index 0000000000000000000000000000000000000000..3531a1ab8864ffc7a25660b938155c972a9f963e --- /dev/null +++ b/doc/org.bluez.MediaFolder.5 @@ -0,0 +1,156 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.MEDIAFOLDER" "5" "September 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.MediaFolder \- BlueZ D-Bus MediaFolder API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +unique name (Target role) +org.bluez (Controller role) +.TP +.B Interface +org.bluez.MediaFolder1 +.TP +.B Object path +freely definable (Target role) +[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/playerX +(Controller role) +.UNINDENT +.SS Methods +.SS object Search(string value, dict filter) +.INDENT 0.0 +.INDENT 3.5 +Return a folder object containing the search result. +.sp +To list the items found use the folder object returned and pass to +ChangeFolder. +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS array{objects, properties} ListItems(dict filter) +.INDENT 0.0 +.INDENT 3.5 +Return a list of items found +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void ChangeFolder(object folder) +.INDENT 0.0 +.INDENT 3.5 +Change current folder. +.sp +Note: By changing folder the items of previous folder might be destroyed +and have to be listed again, the exception is NowPlaying folder which +should be always present while the player is active. +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS Properties +.SS uint32 NumberOfItems [readonly] +.INDENT 0.0 +.INDENT 3.5 +Number of items in the folder +.UNINDENT +.UNINDENT +.SS string Name [readonly] +.INDENT 0.0 +.INDENT 3.5 +Folder name: +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dq/Filesystem/...\(dq +Filesystem scope +.TP +.B \(dq/NowPlaying/...\(dq +NowPlaying scope +.UNINDENT +.sp +Note: /NowPlaying folder might not be listed if player is stopped, +folders created by Search are virtual so once another Search is perform +or the folder is changed using ChangeFolder it will no longer be listed. +.UNINDENT +.UNINDENT +.SS Filters +.INDENT 0.0 +.TP +.B uint32 Start +Offset of the first item. +.sp +Default value: 0 +.TP +.B uint32 End +Offset of the last item. +.sp +Default value: NumbeOfItems +.TP +.B array{string} Attributes +Item properties that should be included in the list. +.sp +Possible Values: +.INDENT 7.0 +.INDENT 3.5 +\(dqtitle\(dq, \(dqartist\(dq, \(dqalbum\(dq, \(dqgenre\(dq, \(dqnumber\-of\-tracks\(dq, +\(dqnumber\(dq, \(dqduration\(dq +.sp +Default Value: All +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.MediaFolder.rst b/doc/org.bluez.MediaFolder.rst new file mode 100644 index 0000000000000000000000000000000000000000..dd56f06b41e48dfedda32f83efa439ddc0f4b5d5 --- /dev/null +++ b/doc/org.bluez.MediaFolder.rst @@ -0,0 +1,117 @@ +===================== +org.bluez.MediaFolder +===================== + +----------------------------------------- +BlueZ D-Bus MediaFolder API documentation +----------------------------------------- + +:Version: BlueZ +:Date: September 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: unique name (Target role) + org.bluez (Controller role) +:Interface: org.bluez.MediaFolder1 +:Object path: freely definable (Target role) + [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/playerX + (Controller role) + +Methods +------- + +object Search(string value, dict filter) +```````````````````````````````````````` + + Return a folder object containing the search result. + + To list the items found use the folder object returned and pass to + ChangeFolder. + + Possible Errors: + + :org.bluez.Error.NotSupported: + :org.bluez.Error.Failed: + +array{objects, properties} ListItems(dict filter) +````````````````````````````````````````````````` + + Return a list of items found + + Possible Errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.NotSupported: + :org.bluez.Error.Failed: + +void ChangeFolder(object folder) +```````````````````````````````` + + Change current folder. + + Note: By changing folder the items of previous folder might be destroyed + and have to be listed again, the exception is NowPlaying folder which + should be always present while the player is active. + + Possible Errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.NotSupported: + :org.bluez.Error.Failed: + +Properties +---------- + +uint32 NumberOfItems [readonly] +``````````````````````````````` + + Number of items in the folder + +string Name [readonly] +`````````````````````` + + Folder name: + + Possible values: + + :"/Filesystem/...": + + Filesystem scope + + :"/NowPlaying/...": + + NowPlaying scope + + Note: /NowPlaying folder might not be listed if player is stopped, + folders created by Search are virtual so once another Search is perform + or the folder is changed using ChangeFolder it will no longer be listed. + +Filters +------- + +:uint32 Start: + + Offset of the first item. + + Default value: 0 + +:uint32 End: + + Offset of the last item. + + Default value: NumbeOfItems + +:array{string} Attributes: + + Item properties that should be included in the list. + + Possible Values: + + "title", "artist", "album", "genre", "number-of-tracks", + "number", "duration" + + Default Value: All diff --git a/doc/org.bluez.MediaItem.5 b/doc/org.bluez.MediaItem.5 new file mode 100644 index 0000000000000000000000000000000000000000..e6d27806efd47be536ca68f52ab68ed59be3d837 --- /dev/null +++ b/doc/org.bluez.MediaItem.5 @@ -0,0 +1,163 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.MEDIAITEM" "5" "September 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.MediaItem \- BlueZ D-Bus MediaItem API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +unique name (Target role) +org.bluez (Controller role) +.TP +.B Interface +org.bluez.MediaItem1 +.TP +.B Object path +freely definable (Target role) +[variable +prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/playerX/itemX +(Controller role) +.UNINDENT +.SS Methods +.SS void Play() +.INDENT 0.0 +.INDENT 3.5 +Play item +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void AddtoNowPlaying() +.INDENT 0.0 +.INDENT 3.5 +Add item to now playing list +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS Properties +.SS object Player [readonly] +.INDENT 0.0 +.INDENT 3.5 +Player object path the item belongs to +.UNINDENT +.UNINDENT +.SS string Name [readonly] +.INDENT 0.0 +.INDENT 3.5 +Item displayable name +.UNINDENT +.UNINDENT +.SS string Type [readonly] +.INDENT 0.0 +.INDENT 3.5 +Item type +.sp +Possible values: \(dqvideo\(dq, \(dqaudio\(dq, \(dqfolder\(dq +.UNINDENT +.UNINDENT +.SS string FolderType [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Folder type. +.sp +Possible values: \(dqmixed\(dq, \(dqtitles\(dq, \(dqalbums\(dq, \(dqartists\(dq +.sp +Available if property Type is \(dqFolder\(dq +.UNINDENT +.UNINDENT +.SS boolean Playable [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Indicates if the item can be played +.sp +Available if property Type is \(dqfolder\(dq +.UNINDENT +.UNINDENT +.SS dict Metadata [readonly] +.INDENT 0.0 +.INDENT 3.5 +Item metadata. +.sp +Possible values: +.INDENT 0.0 +.TP +.B string Title +Item title name +.sp +Available if property Type is \(dqaudio\(dq or \(dqvideo\(dq +.TP +.B string Artist +Item artist name +.sp +Available if property Type is \(dqaudio\(dq or \(dqvideo\(dq +.TP +.B string Album +Item album name +.sp +Available if property Type is \(dqaudio\(dq or \(dqvideo\(dq +.TP +.B string Genre +Item genre name +.sp +Available if property Type is \(dqaudio\(dq or \(dqvideo\(dq +.TP +.B uint32 NumberOfTracks +Item album number of tracks in total +.sp +Available if property Type is \(dqaudio\(dq or \(dqvideo\(dq +.TP +.B uint32 Number +Item album number +.sp +Available if property Type is \(dqaudio\(dq or \(dqvideo\(dq +.TP +.B uint32 Duration +Item duration in milliseconds +.sp +Available if property Type is \(dqaudio\(dq or \(dqvideo\(dq +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.MediaItem.rst b/doc/org.bluez.MediaItem.rst new file mode 100644 index 0000000000000000000000000000000000000000..855e8a6395b784f6c799525462ac40bf3674aca8 --- /dev/null +++ b/doc/org.bluez.MediaItem.rst @@ -0,0 +1,131 @@ +=================== +org.bluez.MediaItem +=================== + +--------------------------------------- +BlueZ D-Bus MediaItem API documentation +--------------------------------------- + +:Version: BlueZ +:Date: September 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: unique name (Target role) + org.bluez (Controller role) +:Interface: org.bluez.MediaItem1 +:Object path: freely definable (Target role) + [variable + prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/playerX/itemX + (Controller role) + +Methods +------- + +void Play() +``````````` + + Play item + + Possible Errors: + + :org.bluez.Error.NotSupported: + :org.bluez.Error.Failed: + +void AddtoNowPlaying() +`````````````````````` + + Add item to now playing list + + Possible Errors: + + :org.bluez.Error.NotSupported: + :org.bluez.Error.Failed: + +Properties +---------- + +object Player [readonly] +```````````````````````` + + Player object path the item belongs to + +string Name [readonly] +`````````````````````` + + Item displayable name + +string Type [readonly] +`````````````````````` + + Item type + + Possible values: "video", "audio", "folder" + +string FolderType [readonly, optional] +`````````````````````````````````````` + + Folder type. + + Possible values: "mixed", "titles", "albums", "artists" + + Available if property Type is "Folder" + +boolean Playable [readonly, optional] +````````````````````````````````````` + + Indicates if the item can be played + + Available if property Type is "folder" + +dict Metadata [readonly] +```````````````````````` + + Item metadata. + + Possible values: + + :string Title: + + Item title name + + Available if property Type is "audio" or "video" + + :string Artist: + + Item artist name + + Available if property Type is "audio" or "video" + + :string Album: + + Item album name + + Available if property Type is "audio" or "video" + + :string Genre: + + Item genre name + + Available if property Type is "audio" or "video" + + :uint32 NumberOfTracks: + + Item album number of tracks in total + + Available if property Type is "audio" or "video" + + :uint32 Number: + + Item album number + + Available if property Type is "audio" or "video" + + :uint32 Duration: + + Item duration in milliseconds + + Available if property Type is "audio" or "video" diff --git a/doc/org.bluez.MediaPlayer.5 b/doc/org.bluez.MediaPlayer.5 new file mode 100644 index 0000000000000000000000000000000000000000..6ee5ecc99ae4eeb772b7eb5c31f23368d13bbde9 --- /dev/null +++ b/doc/org.bluez.MediaPlayer.5 @@ -0,0 +1,431 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.MEDIAPLAYER" "5" "September 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.MediaPlayer \- BlueZ D-Bus MediaPlayer API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez (Controller role) +.TP +.B Interface +org.bluez.MediaPlayer1 +.TP +.B Object path +[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/playerX +.UNINDENT +.SS Methods +.SS void Play() +.INDENT 0.0 +.INDENT 3.5 +Resume playback. +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Pause() +.INDENT 0.0 +.INDENT 3.5 +Pause playback. +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Stop() +.INDENT 0.0 +.INDENT 3.5 +Stop playback. +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Next() +.INDENT 0.0 +.INDENT 3.5 +Next item. +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Previous() +.INDENT 0.0 +.INDENT 3.5 +Previous item. +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void FastForward() +.INDENT 0.0 +.INDENT 3.5 +Fast forward playback, this action is only stopped when another method +in this interface is called. +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Rewind() +.INDENT 0.0 +.INDENT 3.5 +Rewind playback, this action is only stopped when another method in +this interface is called. +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Press(byte avc_key) +.INDENT 0.0 +.INDENT 3.5 +Press a specific key to send as passthrough command. The key will be +released automatically. Use Hold() instead if the intention is to hold +down the key. +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Hold(byte avc_key) +.INDENT 0.0 +.INDENT 3.5 +Press and hold a specific key to send as passthrough command. It is +your responsibility to make sure that Release() is called after calling +this method. The held key will also be released when any other method +in this interface is called. +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Release() +.INDENT 0.0 +.INDENT 3.5 +Release the previously held key invoked using Hold(). +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS Properties +.SS string Equalizer [readwrite] +.INDENT 0.0 +.INDENT 3.5 +Indicates Player Equalizer setting. +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqoff\(dq +.TP +.B \(dqon\(dq +.UNINDENT +.UNINDENT +.UNINDENT +.SS string Repeat [readwrite] +.INDENT 0.0 +.INDENT 3.5 +Indicates Player Repeat setting. +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqoff\(dq +.TP +.B \(dqsingletrack\(dq +.TP +.B \(dqalltracks\(dq +.TP +.B \(dqgroup\(dq +.UNINDENT +.UNINDENT +.UNINDENT +.SS string Shuffle [readwrite] +.INDENT 0.0 +.INDENT 3.5 +Indicates Player Suffle setting. +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqoff\(dq +.TP +.B \(dqalltracks\(dq +.TP +.B \(dqgroup\(dq +.UNINDENT +.UNINDENT +.UNINDENT +.SS string Scan [readwrite] +.INDENT 0.0 +.INDENT 3.5 +Indicates Player Scan setting. +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqoff\(dq +.TP +.B \(dqalltracks\(dq +.TP +.B \(dqgroup\(dq +.UNINDENT +.UNINDENT +.UNINDENT +.SS string Status [readonly] +.INDENT 0.0 +.INDENT 3.5 +Indicates Player Status setting. +.sp +Possible status: +.INDENT 0.0 +.TP +.B \(dqplaying\(dq +.TP +.B \(dqstopped\(dq +.TP +.B \(dqpaused\(dq +.TP +.B \(dqforward\-seek\(dq +.TP +.B \(dqreverse\-seek\(dq +.TP +.B \(dqerror\(dq +.UNINDENT +.UNINDENT +.UNINDENT +.SS uint32 Position [readonly] +.INDENT 0.0 +.INDENT 3.5 +Playback position in milliseconds. Changing the position may generate +additional events that will be sent to the remote device. When position +is 0 it means the track is starting and when it\(aqs greater than or equal +to track\(aqs duration the track has ended. +.sp +Note that even if duration is not available in metadata it\(aqs possible +to signal its end by setting position to the maximum uint32 value. +.UNINDENT +.UNINDENT +.SS dict Track [readonly] +.INDENT 0.0 +.INDENT 3.5 +Track metadata. +.sp +Possible values: +.INDENT 0.0 +.TP +.B string Title +Track title name +.TP +.B string Artist +Track artist name +.TP +.B string Album +Track album name +.TP +.B string Genre +Track genre name +.TP +.B uint32 NumberOfTracks +Number of tracks in total +.TP +.B uint32 TrackNumber +Track number +.TP +.B uint32 Duration +Track duration in milliseconds +.TP +.B string ImgHandle +[experimental] +.sp +Track image handle, available and valid only during the lifetime of an +OBEX BIP connection to the ObexPort. +.UNINDENT +.UNINDENT +.UNINDENT +.SS object Device [readonly] +.INDENT 0.0 +.INDENT 3.5 +Device object path. +.UNINDENT +.UNINDENT +.SS string Name [readonly] +.INDENT 0.0 +.INDENT 3.5 +Player name +.UNINDENT +.UNINDENT +.SS string Type [readonly] +.INDENT 0.0 +.INDENT 3.5 +Player type +.sp +Possible values: +.INDENT 0.0 +.INDENT 3.5 +\(dqAudio\(dq +\(dqVideo\(dq +\(dqAudio Broadcasting\(dq +\(dqVideo Broadcasting\(dq +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.SS string Subtype [readonly] +.INDENT 0.0 +.INDENT 3.5 +Player subtype +.sp +Possible values: +.INDENT 0.0 +.INDENT 3.5 +\(dqAudio Book\(dq +\(dqPodcast\(dq +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.SS boolean Browsable [readonly] +.INDENT 0.0 +.INDENT 3.5 +If present indicates the player can be browsed using MediaFolder +interface. +.sp +Possible values: +.INDENT 0.0 +.TP +.B True +Supported and active +.TP +.B False +Supported but inactive +.UNINDENT +.sp +Note: If supported but inactive clients can enable it by using +MediaFolder interface but it might interfere in the playback of other +players. +.UNINDENT +.UNINDENT +.SS boolean Searchable [readonly] +.INDENT 0.0 +.INDENT 3.5 +If present indicates the player can be searched using MediaFolder +interface. +.sp +Possible values: +.INDENT 0.0 +.TP +.B True +Supported and active +.TP +.B False +Supported but inactive +.UNINDENT +.sp +Note: If supported but inactive clients can enable it by using +MediaFolder interface but it might interfere in the playback of other +players. +.UNINDENT +.UNINDENT +.SS object Playlist +.INDENT 0.0 +.INDENT 3.5 +Playlist object path. +.UNINDENT +.UNINDENT +.SS uint16 ObexPort [readonly, experimental] +.INDENT 0.0 +.INDENT 3.5 +If present indicates the player can get cover art using BIP over OBEX +on this PSM port. +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.MediaPlayer.rst b/doc/org.bluez.MediaPlayer.rst new file mode 100644 index 0000000000000000000000000000000000000000..94f5b8472b24901b5f0d50c569e081215f5a9790 --- /dev/null +++ b/doc/org.bluez.MediaPlayer.rst @@ -0,0 +1,326 @@ +===================== +org.bluez.MediaPlayer +===================== + +----------------------------------------- +BlueZ D-Bus MediaPlayer API documentation +----------------------------------------- + +:Version: BlueZ +:Date: September 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez (Controller role) +:Interface: org.bluez.MediaPlayer1 +:Object path: [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/playerX + +Methods +------- + +void Play() +``````````` + + Resume playback. + + Possible Errors: + + :org.bluez.Error.NotSupported: + :org.bluez.Error.Failed: + +void Pause() +```````````` + + Pause playback. + + Possible Errors: + + :org.bluez.Error.NotSupported: + :org.bluez.Error.Failed: + +void Stop() +``````````` + + Stop playback. + + Possible Errors: + + :org.bluez.Error.NotSupported: + :org.bluez.Error.Failed: + +void Next() +``````````` + + Next item. + + Possible Errors: + + :org.bluez.Error.NotSupported: + :org.bluez.Error.Failed: + +void Previous() +``````````````` + + Previous item. + + Possible Errors: + + :org.bluez.Error.NotSupported: + :org.bluez.Error.Failed: + +void FastForward() +`````````````````` + + Fast forward playback, this action is only stopped when another method + in this interface is called. + + Possible Errors: + + :org.bluez.Error.NotSupported: + :org.bluez.Error.Failed: + +void Rewind() +````````````` + + Rewind playback, this action is only stopped when another method in + this interface is called. + + Possible Errors: + + :org.bluez.Error.NotSupported: + :org.bluez.Error.Failed: + +void Press(byte avc_key) +```````````````````````` + + Press a specific key to send as passthrough command. The key will be + released automatically. Use Hold() instead if the intention is to hold + down the key. + + Possible Errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.NotSupported: + :org.bluez.Error.Failed: + +void Hold(byte avc_key) +``````````````````````` + + Press and hold a specific key to send as passthrough command. It is + your responsibility to make sure that Release() is called after calling + this method. The held key will also be released when any other method + in this interface is called. + + Possible Errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.NotSupported: + :org.bluez.Error.Failed: + +void Release() +`````````````` + + Release the previously held key invoked using Hold(). + + Possible Errors: + + :org.bluez.Error.NotSupported: + :org.bluez.Error.Failed: + +Properties +---------- + +string Equalizer [readwrite] +```````````````````````````` + + Indicates Player Equalizer setting. + + Possible values: + + :"off": + :"on": + +string Repeat [readwrite] +````````````````````````` + + Indicates Player Repeat setting. + + Possible values: + + :"off": + :"singletrack": + :"alltracks": + :"group": + +string Shuffle [readwrite] +`````````````````````````` + + Indicates Player Suffle setting. + + Possible values: + + :"off": + :"alltracks": + :"group": + +string Scan [readwrite] +``````````````````````` + + Indicates Player Scan setting. + + Possible values: + + :"off": + :"alltracks": + :"group": + +string Status [readonly] +```````````````````````` + + Indicates Player Status setting. + + Possible status: + + :"playing": + :"stopped": + :"paused": + :"forward-seek": + :"reverse-seek": + :"error": + +uint32 Position [readonly] +`````````````````````````` + + Playback position in milliseconds. Changing the position may generate + additional events that will be sent to the remote device. When position + is 0 it means the track is starting and when it's greater than or equal + to track's duration the track has ended. + + Note that even if duration is not available in metadata it's possible + to signal its end by setting position to the maximum uint32 value. + +dict Track [readonly] +````````````````````` + + Track metadata. + + Possible values: + + :string Title: + + Track title name + + :string Artist: + + Track artist name + + :string Album: + + Track album name + + :string Genre: + + Track genre name + + :uint32 NumberOfTracks: + + Number of tracks in total + + :uint32 TrackNumber: + + Track number + + :uint32 Duration: + + Track duration in milliseconds + + :string ImgHandle: [experimental] + + Track image handle, available and valid only during the lifetime of an + OBEX BIP connection to the ObexPort. + +object Device [readonly] +```````````````````````` + + Device object path. + +string Name [readonly] +`````````````````````` + + Player name + +string Type [readonly] +`````````````````````` + + Player type + + Possible values: + + "Audio" + "Video" + "Audio Broadcasting" + "Video Broadcasting" + +string Subtype [readonly] +````````````````````````` + + Player subtype + + Possible values: + + "Audio Book" + "Podcast" + +boolean Browsable [readonly] +```````````````````````````` + + If present indicates the player can be browsed using MediaFolder + interface. + + Possible values: + + :True: + + Supported and active + + :False: + + Supported but inactive + + Note: If supported but inactive clients can enable it by using + MediaFolder interface but it might interfere in the playback of other + players. + +boolean Searchable [readonly] +````````````````````````````` + + If present indicates the player can be searched using MediaFolder + interface. + + Possible values: + + :True: + + Supported and active + + :False: + + Supported but inactive + + Note: If supported but inactive clients can enable it by using + MediaFolder interface but it might interfere in the playback of other + players. + +object Playlist +``````````````` + + Playlist object path. + +uint16 ObexPort [readonly, experimental] +```````````````````````````````````````` + + If present indicates the player can get cover art using BIP over OBEX + on this PSM port. diff --git a/doc/org.bluez.MediaTransport.5 b/doc/org.bluez.MediaTransport.5 new file mode 100644 index 0000000000000000000000000000000000000000..ed26c62c39fed0d3b478abd87f440f2e8ecb0150 --- /dev/null +++ b/doc/org.bluez.MediaTransport.5 @@ -0,0 +1,369 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.MEDIATRANSPORT" "5" "July 2024" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.MediaTransport \- BlueZ D-Bus MediaTransport API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.MediaTransport1 +.TP +.B Object path +[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/fdX +.UNINDENT +.SS Methods +.SS fd, uint16, uint16 Acquire() +.INDENT 0.0 +.INDENT 3.5 +Acquire transport file descriptor and the MTU for read and write +respectively. +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotAuthorized +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS fd, uint16, uint16 TryAcquire() +.INDENT 0.0 +.INDENT 3.5 +Acquire transport file descriptor only if the transport is in \(dqpending\(dq +state at the time the message is received by BlueZ. Otherwise no request +will be sent to the remote device and the function will just fail with +org.bluez.Error.NotAvailable. +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotAuthorized +.TP +.B org.bluez.Error.Failed +.TP +.B org.bluez.Error.NotAvailable +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Release() +.INDENT 0.0 +.INDENT 3.5 +Releases file descriptor. +.UNINDENT +.UNINDENT +.SS void Select() +.INDENT 0.0 +.INDENT 3.5 +Applicable only for transports created by a broadcast sink. This moves +the transport from \(aqidle\(aq to \(aqbroadcasting\(aq. This allows the user to +select which BISes he wishes to sync to via a 2 step process: +1) the user calls the method, changing the transport\(aqs state to broadcasting +2) the audio server detects that the transport is in the \(aqbroadcasting\(aq +state and automatically acquires it +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotAuthorized +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Unselect() +.INDENT 0.0 +.INDENT 3.5 +Applicable only for transports created by a broadcast sink. This moves +the transport from \(aqbroadcasting\(aq or \(aqactive\(aq to \(aqidle\(aq. This allows the +user to terminate the sync to a BIS to via a 2 step process: +1) the user calls this method, changing the transport\(aqs state to idle +2) the audio server detects this event and releases the transport +.sp +Possible Errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.NotAuthorized +.UNINDENT +.UNINDENT +.UNINDENT +.SS Properties +.SS object Device [readonly] +.INDENT 0.0 +.INDENT 3.5 +Device object which the transport is connected to. +.UNINDENT +.UNINDENT +.SS string UUID [readonly] +.INDENT 0.0 +.INDENT 3.5 +UUID of the profile which the transport is for. +.UNINDENT +.UNINDENT +.SS byte Codec [readonly] +.INDENT 0.0 +.INDENT 3.5 +Assigned number of codec that the transport support. +The values should match the profile specification which is indicated by +the UUID. +.UNINDENT +.UNINDENT +.SS array{byte} Configuration [readonly] +.INDENT 0.0 +.INDENT 3.5 +Configuration blob, it is used as it is so the size and byte order must +match. +.UNINDENT +.UNINDENT +.SS string State [readonly] +.INDENT 0.0 +.INDENT 3.5 +Indicates the state of the transport. Possible values are: +.INDENT 0.0 +.TP +.B \(dqidle\(dq +not streaming +.TP +.B \(dqpending\(dq +streaming but not acquired +.TP +.B \(dqbroadcasting\(dq +streaming but not acquired, applicable only for transports +created by a broadcast sink +.TP +.B \(dqactive\(dq +streaming and acquired +.UNINDENT +.UNINDENT +.UNINDENT +.SS uint16 Delay [readwrite, optional] +.INDENT 0.0 +.INDENT 3.5 +Transport delay in 1/10 of millisecond, this property is only writeable +when the transport corresponds to a sink endpoint and it was acquired by +the sender. +.UNINDENT +.UNINDENT +.SS uint16 Volume [readwrite, optional] +.INDENT 0.0 +.INDENT 3.5 +Indicates volume level of the transport, this property is only writeable +when the transport was acquired by the sender. +.sp +Possible Values: 0\-127 +.UNINDENT +.UNINDENT +.SS object Endpoint [readonly, optional, experimental] +.INDENT 0.0 +.INDENT 3.5 +Endpoint object which the transport is associated with. +.UNINDENT +.UNINDENT +.SS uint32 Location [readonly, ISO only, experimental] +.INDENT 0.0 +.INDENT 3.5 +Indicates transport Audio Location. +.UNINDENT +.UNINDENT +.SS array{byte} Metadata [readwrite, ISO Only, experimental] +.INDENT 0.0 +.INDENT 3.5 +Indicates transport Metadata. +.UNINDENT +.UNINDENT +.SS array{object} Links [readonly, optional, CIS only, experimental] +.INDENT 0.0 +.INDENT 3.5 +Linked transport objects which the transport is associated with. +.UNINDENT +.UNINDENT +.SS array{object} Links [readwrite, BIS only, experimental] +.INDENT 0.0 +.INDENT 3.5 +For a Broadcast Sink, the BIG sync procedure requires all +desired streams to be enumerated from the start and it cannot +be later reconfigured by adding or removing BISes. To avoid +terminating and recreating the BIG sync everytime a new +transport is selected for acquire, all transports selected via +Transport.Select need to be linked together. When the first +transport is acquired via Transport.Acquire, all links are +included in the BIG sync command. An acquired transport will +create and set fds for all its links. Then, each link needs +to be acquired separately, to get the fd and start receiving +audio. +.UNINDENT +.UNINDENT +.SS dict QoS [readwrite, optional, ISO only, experimental] +.INDENT 0.0 +.INDENT 3.5 +Only present when QoS is configured. +.sp +Possible values for Unicast: +.INDENT 0.0 +.TP +.B byte CIG +Indicates configured CIG. +.sp +Possible values: +.INDENT 7.0 +.TP +.B 0x00 \- 0xef +Valid ID range. +.TP +.B 0xff +Auto allocate. +.UNINDENT +.TP +.B byte CIS +Indicates configured CIS. +.sp +Possible values: +.INDENT 7.0 +.TP +.B 0x00 \- 0xef +Valid ID range. +.TP +.B 0xff +Auto allocate. +.UNINDENT +.TP +.B byte Framing +Indicates configured framing. +.sp +Possible values: +.INDENT 7.0 +.TP +.B 0x00 +Unframed. +.TP +.B 0x01 +Framed. +.UNINDENT +.TP +.B uint32 PresentationDelay +Indicates configured transport presentation delay (us). +.TP +.B byte TargetLatency +Indicates the requested target latency. +.sp +Possible values: +.INDENT 7.0 +.TP +.B 0x01 +Low Latency. +.TP +.B 0x02 +Balanced Latency/Reliability. +.TP +.B 0x03 +High Reliability. +.UNINDENT +.UNINDENT +.sp +Possible values for Broadcast: +.INDENT 0.0 +.TP +.B byte BIG +Indicates configured QoS BIG. +.TP +.B byte BIS +Indicates configured BIS. +.TP +.B byte SyncFactor +Indicates configured broadcast sync factor. +.TP +.B byte Packing +Indicates configured packing. +.TP +.B byte Framing +Indicates configured framing. +.TP +.B array{byte} BCode +Indicates the string used for encryption/decryption. +.TP +.B byte encryption +Indicates if the stream is encrypted. +.TP +.B byte Options +Indicates configured broadcast options. +.TP +.B uint16 Skip +Indicates configured broadcast skip. +.TP +.B byte SyncTimeout +Indicates configured broadcast sync timeout. +.TP +.B byte SyncType +Indicates configured broadcast sync CTE type. +.TP +.B byte MSE +Indicates configured broadcast MSE. +.TP +.B uint16 Timeout +Indicates configured broadcast timeout. +.UNINDENT +.sp +Possible values for both Unicast and Broadcast: +.INDENT 0.0 +.TP +.B uint32 Interval +Indicates configured ISO interval (us). +.TP +.B uint16 Latency +Indicates configured transport latency (ms). +.TP +.B uint16 SDU +Indicates configured maximum SDU. +.TP +.B byte PHY +Indicates configured PHY. +.sp +Possible values: +.INDENT 7.0 +.TP +.B bit 0 +LE 1M +.TP +.B bit 1 +LE 2M +.TP +.B bit 2 +LE Coded +.UNINDENT +.TP +.B byte Retransmissions +Indicates configured retransmissions. +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.MediaTransport.rst b/doc/org.bluez.MediaTransport.rst new file mode 100644 index 0000000000000000000000000000000000000000..78789bc8044a7033d5e0beea12743ecd7d2c482b --- /dev/null +++ b/doc/org.bluez.MediaTransport.rst @@ -0,0 +1,327 @@ +======================== +org.bluez.MediaTransport +======================== + +-------------------------------------------- +BlueZ D-Bus MediaTransport API documentation +-------------------------------------------- + +:Version: BlueZ +:Date: July 2024 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez +:Interface: org.bluez.MediaTransport1 +:Object path: [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/fdX + +Methods +------- + +fd, uint16, uint16 Acquire() +```````````````````````````` + + Acquire transport file descriptor and the MTU for read and write + respectively. + + Possible Errors: + + :org.bluez.Error.NotAuthorized: + :org.bluez.Error.Failed: + +fd, uint16, uint16 TryAcquire() +``````````````````````````````` + + Acquire transport file descriptor only if the transport is in "pending" + state at the time the message is received by BlueZ. Otherwise no request + will be sent to the remote device and the function will just fail with + org.bluez.Error.NotAvailable. + + Possible Errors: + + :org.bluez.Error.NotAuthorized: + :org.bluez.Error.Failed: + :org.bluez.Error.NotAvailable: + +void Release() +`````````````` + + Releases file descriptor. + +void Select() +````````````` + + Applicable only for transports created by a broadcast sink. This moves + the transport from 'idle' to 'broadcasting'. This allows the user to + select which BISes he wishes to sync to via a 2 step process: + 1) the user calls the method, changing the transport's state to broadcasting + 2) the audio server detects that the transport is in the 'broadcasting' + state and automatically acquires it + + Possible Errors: + + :org.bluez.Error.NotAuthorized: + +void Unselect() +``````````````` + + Applicable only for transports created by a broadcast sink. This moves + the transport from 'broadcasting' or 'active' to 'idle'. This allows the + user to terminate the sync to a BIS to via a 2 step process: + 1) the user calls this method, changing the transport's state to idle + 2) the audio server detects this event and releases the transport + + Possible Errors: + + :org.bluez.Error.NotAuthorized: + +Properties +---------- + +object Device [readonly] +```````````````````````` + + Device object which the transport is connected to. + +string UUID [readonly] +`````````````````````` + + UUID of the profile which the transport is for. + +byte Codec [readonly] +````````````````````` + + Assigned number of codec that the transport support. + The values should match the profile specification which is indicated by + the UUID. + +array{byte} Configuration [readonly] +```````````````````````````````````` + + Configuration blob, it is used as it is so the size and byte order must + match. + +string State [readonly] +``````````````````````` + + Indicates the state of the transport. Possible values are: + + :"idle": not streaming + :"pending": streaming but not acquired + :"broadcasting": streaming but not acquired, applicable only for transports + created by a broadcast sink + :"active": streaming and acquired + +uint16 Delay [readwrite, optional] +`````````````````````````````````` + + Transport delay in 1/10 of millisecond, this property is only writeable + when the transport corresponds to a sink endpoint and it was acquired by + the sender. + +uint16 Volume [readwrite, optional] +``````````````````````````````````` + + Indicates volume level of the transport, this property is only writeable + when the transport was acquired by the sender. + + Possible Values: 0-127 + +object Endpoint [readonly, optional, experimental] +`````````````````````````````````````````````````` + + Endpoint object which the transport is associated with. + +uint32 Location [readonly, ISO only, experimental] +`````````````````````````````````````````````````` + + Indicates transport Audio Location. + +array{byte} Metadata [readwrite, ISO Only, experimental] +```````````````````````````````````````````````````````` + + Indicates transport Metadata. + +array{object} Links [readonly, optional, CIS only, experimental] +```````````````````````````````````````````````````````````````` + + Linked transport objects which the transport is associated with. + +array{object} Links [readwrite, BIS only, experimental] +``````````````````````````````````````````````````````` + + For a Broadcast Sink, the BIG sync procedure requires all + desired streams to be enumerated from the start and it cannot + be later reconfigured by adding or removing BISes. To avoid + terminating and recreating the BIG sync everytime a new + transport is selected for acquire, all transports selected via + Transport.Select need to be linked together. When the first + transport is acquired via Transport.Acquire, all links are + included in the BIG sync command. An acquired transport will + create and set fds for all its links. Then, each link needs + to be acquired separately, to get the fd and start receiving + audio. + +dict QoS [readwrite, optional, ISO only, experimental] +`````````````````````````````````````````````````````` + + Only present when QoS is configured. + + Possible values for Unicast: + + :byte CIG: + + Indicates configured CIG. + + Possible values: + + :0x00 - 0xef: + + Valid ID range. + + :0xff: + + Auto allocate. + + :byte CIS: + + Indicates configured CIS. + + Possible values: + + :0x00 - 0xef: + + Valid ID range. + + :0xff: + + Auto allocate. + + :byte Framing: + + Indicates configured framing. + + Possible values: + + :0x00: + + Unframed. + + :0x01: + + Framed. + + :uint32 PresentationDelay: + + Indicates configured transport presentation delay (us). + + :byte TargetLatency: + + Indicates the requested target latency. + + Possible values: + + :0x01: + + Low Latency. + + :0x02: + + Balanced Latency/Reliability. + + :0x03: + + High Reliability. + + Possible values for Broadcast: + + :byte BIG: + + Indicates configured QoS BIG. + + :byte BIS: + + Indicates configured BIS. + + :byte SyncFactor: + + Indicates configured broadcast sync factor. + + :byte Packing: + + Indicates configured packing. + + :byte Framing: + + Indicates configured framing. + + :array{byte} BCode: + + Indicates the string used for encryption/decryption. + + :byte encryption: + + Indicates if the stream is encrypted. + + :byte Options: + + Indicates configured broadcast options. + + :uint16 Skip: + + Indicates configured broadcast skip. + + :byte SyncTimeout: + + Indicates configured broadcast sync timeout. + + :byte SyncType: + + Indicates configured broadcast sync CTE type. + + :byte MSE: + + Indicates configured broadcast MSE. + + :uint16 Timeout: + + Indicates configured broadcast timeout. + + Possible values for both Unicast and Broadcast: + + :uint32 Interval: + + Indicates configured ISO interval (us). + + :uint16 Latency: + + Indicates configured transport latency (ms). + + :uint16 SDU: + + Indicates configured maximum SDU. + + :byte PHY: + + Indicates configured PHY. + + Possible values: + + :bit 0: + + LE 1M + + :bit 1: + + LE 2M + + :bit 2: + + LE Coded + + :byte Retransmissions: + + Indicates configured retransmissions. diff --git a/doc/org.bluez.Network.5 b/doc/org.bluez.Network.5 new file mode 100644 index 0000000000000000000000000000000000000000..6d10927f3b47c18c6ae7d76b93069f222cbb5a46 --- /dev/null +++ b/doc/org.bluez.Network.5 @@ -0,0 +1,118 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.NETWORK" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.Network \- BlueZ D-Bus Network API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.Network1 +.TP +.B Object path +[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX +.UNINDENT +.SS Methods +.SS string Connect(string uuid) +.INDENT 0.0 +.INDENT 3.5 +Connects to the network device and return the network interface name. +.sp +Possible uuid values: +.INDENT 0.0 +.TP +.B \(dqpanu\(dq, \(dq00001115\-0000\-1000\-8000\-00805f9b34fb\(dq +Personal Network User role. +.TP +.B \(dqnap\(dq, \(dq00001116\-0000\-1000\-8000\-00805f9b34fb\(dq +Network Access Point role. +.TP +.B \(dqgn\(dq, \(dq00001117\-0000\-1000\-8000\-00805f9b34fb\(dq +Group Network role. +.UNINDENT +.sp +The connection will be closed and network device released either upon +calling \fBDisconnect()\fP or when the client disappears from the +message bus. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.NotSupported +.TP +.B org.bluez.Error.InProgress +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Disconnect() +.INDENT 0.0 +.INDENT 3.5 +Disconnects from the network device. +.sp +To abort a connection attempt in case of errors or timeouts in the +client it is fine to call this method. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Failed +.TP +.B org.bluez.Error.NotConnected +.UNINDENT +.UNINDENT +.UNINDENT +.SS Properties +.SS boolean Connected [readonly] +.INDENT 0.0 +.INDENT 3.5 +Indicates if the device is connected. +.UNINDENT +.UNINDENT +.SS string Interface [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Indicates the network interface name when available. +.UNINDENT +.UNINDENT +.SS string UUID [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Indicates the connection role when available. +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.Network.rst b/doc/org.bluez.Network.rst new file mode 100644 index 0000000000000000000000000000000000000000..d81a69d3c8af78d227f0b6dcb7d749bb1d3c7e3d --- /dev/null +++ b/doc/org.bluez.Network.rst @@ -0,0 +1,83 @@ +================= +org.bluez.Network +================= + +------------------------------------- +BlueZ D-Bus Network API documentation +------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez +:Interface: org.bluez.Network1 +:Object path: [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX + +Methods +------- + +string Connect(string uuid) +``````````````````````````` + + Connects to the network device and return the network interface name. + + Possible uuid values: + + :"panu", "00001115-0000-1000-8000-00805f9b34fb": + + Personal Network User role. + + :"nap", "00001116-0000-1000-8000-00805f9b34fb": + + Network Access Point role. + + :"gn", "00001117-0000-1000-8000-00805f9b34fb": + + Group Network role. + + The connection will be closed and network device released either upon + calling **Disconnect()** or when the client disappears from the + message bus. + + Possible errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.NotSupported: + :org.bluez.Error.InProgress: + :org.bluez.Error.Failed: + +void Disconnect() +````````````````` + + Disconnects 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: + :org.bluez.Error.NotConnected: + +Properties +---------- + +boolean Connected [readonly] +```````````````````````````` + + Indicates if the device is connected. + +string Interface [readonly, optional] +````````````````````````````````````` + + Indicates the network interface name when available. + +string UUID [readonly, optional] +```````````````````````````````` + + Indicates the connection role when available. diff --git a/doc/org.bluez.NetworkServer.5 b/doc/org.bluez.NetworkServer.5 new file mode 100644 index 0000000000000000000000000000000000000000..3f475965906db963749f7762eb517905478d6250 --- /dev/null +++ b/doc/org.bluez.NetworkServer.5 @@ -0,0 +1,100 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.NETWORKSERVER" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.NetworkServer \- BlueZ D-Bus NetworkServer API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.NetworkServer1 +.TP +.B Object path +/org/bluez/{hci0,hci1,...} +.UNINDENT +.SS Methods +.SS void Register(string uuid, string bridge) +.INDENT 0.0 +.INDENT 3.5 +Registers server for the provided UUID. +.sp +Every new connection to this server will be added the bridge interface. +.sp +Possible uuid values: +.INDENT 0.0 +.TP +.B \(dqpanu\(dq, \(dq00001115\-0000\-1000\-8000\-00805f9b34fb\(dq +Personal Network User role. +.TP +.B \(dqnap\(dq, \(dq00001116\-0000\-1000\-8000\-00805f9b34fb\(dq +Network Access Point role. +.TP +.B \(dqgn\(dq, \(dq00001117\-0000\-1000\-8000\-00805f9b34fb\(dq +Group Network role. +.UNINDENT +.sp +Initially no network server SDP is provided. Only after this method a +SDP record will be available and the BNEP server will be ready for +incoming connections. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.AlreadyExists +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Unregister(string uuid) +.INDENT 0.0 +.INDENT 3.5 +Unregisters the server for provided UUID which was previously +registered with \fBRegister()\fP method. +.sp +All servers will be automatically unregistered when the calling +application terminates. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.NetworkServer.rst b/doc/org.bluez.NetworkServer.rst new file mode 100644 index 0000000000000000000000000000000000000000..d15d223c5eca6f69c7322a3e1609386b16aa0841 --- /dev/null +++ b/doc/org.bluez.NetworkServer.rst @@ -0,0 +1,68 @@ +======================= +org.bluez.NetworkServer +======================= + +------------------------------------------- +BlueZ D-Bus NetworkServer API documentation +------------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez +:Interface: org.bluez.NetworkServer1 +:Object path: /org/bluez/{hci0,hci1,...} + + +Methods +------- + +void Register(string uuid, string bridge) +````````````````````````````````````````` + + Registers server for the provided UUID. + + Every new connection to this server will be added the bridge interface. + + Possible uuid values: + + :"panu", "00001115-0000-1000-8000-00805f9b34fb": + + Personal Network User role. + + :"nap", "00001116-0000-1000-8000-00805f9b34fb": + + Network Access Point role. + + :"gn", "00001117-0000-1000-8000-00805f9b34fb": + + Group Network role. + + Initially no network server SDP is provided. Only after this method a + SDP record will be available and the BNEP server will be ready for + incoming connections. + + Possible errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.AlreadyExists: + :org.bluez.Error.Failed: + +void Unregister(string uuid) +```````````````````````````` + + Unregisters the server for provided UUID which was previously + registered with **Register()** method. + + All servers will be automatically unregistered when the calling + application terminates. + + Possible errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.Failed: diff --git a/doc/org.bluez.Profile.5 b/doc/org.bluez.Profile.5 new file mode 100644 index 0000000000000000000000000000000000000000..3cbb5f2db360f084640f1c545f396d18a872762e --- /dev/null +++ b/doc/org.bluez.Profile.5 @@ -0,0 +1,81 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.PROFILE" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.Profile \- BlueZ D-Bus Profile API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +unique name +.TP +.B Interface +org.bluez.Profile1 +.TP +.B Object path +freely definable +.UNINDENT +.SS Methods +.SS void Release() [noreply] +.INDENT 0.0 +.INDENT 3.5 +This method gets called when the service daemon unregisters the profile. +A profile can use it to do cleanup tasks. There is no need to unregister +the profile, because when this method gets called it has already been +unregistered. +.UNINDENT +.UNINDENT +.SS void NewConnection(object device, fd, dict fd_properties) +.INDENT 0.0 +.INDENT 3.5 +This method gets called when a new service level connection has been +made and authorized. +.sp +Possible fd_properties values: +.INDENT 0.0 +.TP +.B uint16 Version [optional] +Profile version. +.TP +.B uint16 Features [optional] +Profile features. +.UNINDENT +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.Rejected +.TP +.B org.bluez.Error.Canceled +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.Profile.rst b/doc/org.bluez.Profile.rst new file mode 100644 index 0000000000000000000000000000000000000000..d8ae669c732311e198aee7199723d88c1f2ab5f8 --- /dev/null +++ b/doc/org.bluez.Profile.rst @@ -0,0 +1,51 @@ +================= +org.bluez.Profile +================= + +------------------------------------- +BlueZ D-Bus Profile API documentation +------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: unique name +:Interface: org.bluez.Profile1 +:Object path: freely definable + +Methods +------- + +void Release() [noreply] +```````````````````````` + + This method gets called when the service daemon unregisters the profile. + A profile can use it to do cleanup tasks. There is no need to unregister + the profile, because when this method gets called it has already been + unregistered. + +void NewConnection(object device, fd, dict fd_properties) +````````````````````````````````````````````````````````` + + This method gets called when a new service level connection has been + made and authorized. + + Possible fd_properties values: + + :uint16 Version [optional]: + + Profile version. + + :uint16 Features [optional]: + + Profile features. + + Possible errors: + + :org.bluez.Error.Rejected: + :org.bluez.Error.Canceled: diff --git a/doc/org.bluez.ProfileManager.5 b/doc/org.bluez.ProfileManager.5 new file mode 100644 index 0000000000000000000000000000000000000000..61f9a331268522931b1d1254fc54caabd914a64a --- /dev/null +++ b/doc/org.bluez.ProfileManager.5 @@ -0,0 +1,164 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.PROFILEMANAGER" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.ProfileManager \- BlueZ D-Bus ProfileManager API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez +.TP +.B Interface +org.bluez.ProfileManager1 +.TP +.B Object path +/org/bluez +.UNINDENT +.SS Methods +.SS void RegisterProfile(object profile, string uuid, dict options) +.INDENT 0.0 +.INDENT 3.5 +Registers profile agent. +.sp +The object path defines the path of the profile that will be called +when there is a connection and must implement \fBorg.bluez.Profile(5)\fP +interface. +.sp +If an application disconnects from the bus all its registered profiles +will be removed. +.sp +Possible uuid values: +.INDENT 0.0 +.TP +.B \(dq0000111f\-0000\-1000\-8000\-00805f9b34fb\(dq +HFP AG, default profile Version is 1.7, profile Features is +0b001001 and RFCOMM channel is 13. Authentication is required. +.TP +.B \(dq0000111e\-0000\-1000\-8000\-00805f9b34fb\(dq +HFP HS, default profile Version is 1.7, profile Features is +0b000000 and RFCOMM channel is 7. Authentication is required. +.TP +.B \(dq00001112\-0000\-1000\-8000\-00805f9b34fb\(dq +HSP AG, default profile Version is 1.2, RFCOMM channel is 12 and +Authentication is required. Does not support any Features, +option is ignored. +.TP +.B \(dq00001108\-0000\-1000\-8000\-00805f9b34fb\(dq +HSP HS, default profile Version is 1.2, profile Features is 0b0 +and RFCOMM channel is 6. Authentication is required. +Features is one bit value, specify capability of Remote Audio +Volume Control (by default turned off). +.TP +.B \(dq<vendor UUID>\(dq +Vendor defined UUID, no defaults, must set options. +.UNINDENT +.sp +Possible options values: +.INDENT 0.0 +.TP +.B string Name +Human readable name for the profile +.TP +.B string Service +The primary service class UUID (if different from the actual +profile UUID). +.TP +.B string Role +For asymmetric profiles that do not have UUIDs available to +uniquely identify each side this parameter allows specifying the +precise local role. +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dqclient\(dq +.TP +.B \(dqserver\(dq +.UNINDENT +.TP +.B uint16 Channel +RFCOMM channel number that is used for client and server UUIDs. +.sp +If applicable it will be used in the SDP record as well. +.TP +.B uint16 PSM +PSM number that is used for client and server UUIDs. +.sp +If applicable it will be used in the SDP record as well. +.TP +.B boolean RequireAuthentication +Pairing is required before connections will be established. +No devices will be connected if not paired. +.TP +.B boolean RequireAuthorization +Request authorization before any connection will be established. +.TP +.B boolean AutoConnect +In case of a client UUID this will force connection of the +RFCOMM or L2CAP channels when a remote device is connected. +.TP +.B string ServiceRecord +Provide a manual SDP record. +.TP +.B uint16 Version +Profile version (for SDP record) +.TP +.B uint16 Features +Profile features (for SDP record) +.UNINDENT +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.InvalidArguments +.TP +.B org.bluez.Error.AlreadyExists +.UNINDENT +.UNINDENT +.UNINDENT +.SS void UnregisterProfile(object profile) +.INDENT 0.0 +.INDENT 3.5 +Unregisters profile object that has been previously registered using +\fBRegisterProfile\fP\&. +.sp +The object path parameter must match the same value that has been used +on registration. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.Error.DoesNotExist +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.ProfileManager.rst b/doc/org.bluez.ProfileManager.rst new file mode 100644 index 0000000000000000000000000000000000000000..ccd7a2673d77101d245e911dca10b033c0612324 --- /dev/null +++ b/doc/org.bluez.ProfileManager.rst @@ -0,0 +1,141 @@ +======================== +org.bluez.ProfileManager +======================== + +-------------------------------------------- +BlueZ D-Bus ProfileManager API documentation +-------------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez +:Interface: org.bluez.ProfileManager1 +:Object path: /org/bluez + +Methods +------- + +void RegisterProfile(object profile, string uuid, dict options) +``````````````````````````````````````````````````````````````` + + Registers profile agent. + + The object path defines the path of the profile that will be called + when there is a connection and must implement **org.bluez.Profile(5)** + interface. + + If an application disconnects from the bus all its registered profiles + will be removed. + + Possible uuid values: + + :"0000111f-0000-1000-8000-00805f9b34fb": + + HFP AG, default profile Version is 1.7, profile Features is + 0b001001 and RFCOMM channel is 13. Authentication is required. + + :"0000111e-0000-1000-8000-00805f9b34fb": + + HFP HS, default profile Version is 1.7, profile Features is + 0b000000 and RFCOMM channel is 7. Authentication is required. + + :"00001112-0000-1000-8000-00805f9b34fb": + + HSP AG, default profile Version is 1.2, RFCOMM channel is 12 and + Authentication is required. Does not support any Features, + option is ignored. + + :"00001108-0000-1000-8000-00805f9b34fb": + + HSP HS, default profile Version is 1.2, profile Features is 0b0 + and RFCOMM channel is 6. Authentication is required. + Features is one bit value, specify capability of Remote Audio + Volume Control (by default turned off). + + :"<vendor UUID>": + + Vendor defined UUID, no defaults, must set options. + + Possible options values: + + :string Name: + + Human readable name for the profile + + :string Service: + + The primary service class UUID (if different from the actual + profile UUID). + + :string Role: + + For asymmetric profiles that do not have UUIDs available to + uniquely identify each side this parameter allows specifying the + precise local role. + + Possible values: + + :"client": + :"server": + + :uint16 Channel: + + RFCOMM channel number that is used for client and server UUIDs. + + If applicable it will be used in the SDP record as well. + + :uint16 PSM: + + PSM number that is used for client and server UUIDs. + + If applicable it will be used in the SDP record as well. + + :boolean RequireAuthentication: + + Pairing is required before connections will be established. + No devices will be connected if not paired. + + :boolean RequireAuthorization: + + Request authorization before any connection will be established. + + :boolean AutoConnect: + + In case of a client UUID this will force connection of the + RFCOMM or L2CAP channels when a remote device is connected. + + :string ServiceRecord: + + Provide a manual SDP record. + + :uint16 Version: + + Profile version (for SDP record) + + :uint16 Features: + + Profile features (for SDP record) + + Possible errors: + + :org.bluez.Error.InvalidArguments: + :org.bluez.Error.AlreadyExists: + +void UnregisterProfile(object profile) +`````````````````````````````````````` + + Unregisters profile object that has been previously registered using + **RegisterProfile**. + + The object path parameter must match the same value that has been used + on registration. + + Possible errors: + + :org.bluez.Error.DoesNotExist: diff --git a/doc/org.bluez.obex.Agent.5 b/doc/org.bluez.obex.Agent.5 new file mode 100644 index 0000000000000000000000000000000000000000..b65e047b41d5f9c1bfd70ea8ff92bb68e5d574af --- /dev/null +++ b/doc/org.bluez.obex.Agent.5 @@ -0,0 +1,78 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.OBEX.AGENT" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.obex.Agent \- BlueZ D-Bus OBEX Agent API documentation +.SH INTERFACE +.sp +;Service: unique name +:Interface: org.bluez.obex.Agent1 +:Object path: freely definable +.SS Methods +.SS void Release() +.INDENT 0.0 +.INDENT 3.5 +This method gets called when \fBobexd(8)\fP 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. +.UNINDENT +.UNINDENT +.SS string AuthorizePush(object transfer) +.INDENT 0.0 +.INDENT 3.5 +This method gets called when the \fBobexd(8)\fP needs to accept/reject a +Bluetooth object push request. +.sp +Returns the full path (including the filename) or the folder name +suffixed with \(aq/\(aq where the object shall be stored. +.sp +The transfer object, see \fBorg.bluez.obex.Transfer(5)\fP will contain a +Filename property that contains the default location and name that can +be returned. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.Rejected +.TP +.B org.bluez.obex.Error.Canceled +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Cancel() +.INDENT 0.0 +.INDENT 3.5 +This method gets called to indicate that the agent request failed before +a reply was returned. It cancels the previous request. +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.obex.Agent.rst b/doc/org.bluez.obex.Agent.rst new file mode 100644 index 0000000000000000000000000000000000000000..b832e278c86abfda9f4f4a59912d7c44bcb2c32b --- /dev/null +++ b/doc/org.bluez.obex.Agent.rst @@ -0,0 +1,54 @@ +==================== +org.bluez.obex.Agent +==================== + +---------------------------------------- +BlueZ D-Bus OBEX Agent API documentation +---------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +;Service: unique name +:Interface: org.bluez.obex.Agent1 +:Object path: freely definable + +Methods +------- + +void Release() +`````````````` + + This method gets called when **obexd(8)** daemon unregisters the agent. + An agent can use it to do cleanup tasks. There is no need to unregister + the agent, because when this method gets called it has already been + unregistered. + +string AuthorizePush(object transfer) +````````````````````````````````````` + + This method gets called when the **obexd(8)** needs to accept/reject a + Bluetooth object push request. + + Returns the full path (including the filename) or the folder name + suffixed with '/' where the object shall be stored. + + The transfer object, see **org.bluez.obex.Transfer(5)** will contain a + Filename property that contains the default location and name that can + be returned. + + Possible errors: + + :org.bluez.obex.Error.Rejected: + :org.bluez.obex.Error.Canceled: + +void Cancel() +````````````` + + This method gets called to indicate that the agent request failed before + a reply was returned. It cancels the previous request. diff --git a/doc/org.bluez.obex.AgentManager.5 b/doc/org.bluez.obex.AgentManager.5 new file mode 100644 index 0000000000000000000000000000000000000000..a8f6b76d2337d2ed1e6fd846939ca852b1520f88 --- /dev/null +++ b/doc/org.bluez.obex.AgentManager.5 @@ -0,0 +1,76 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.OBEX.AGENTMANAGER" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.obex.AgentManager \- BlueZ D-Bus OBEX AgentManager API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez.obex +.TP +.B Interface +org.bluez.obex.AgentManager1 +.TP +.B Object path +/org/bluez/obex +.UNINDENT +.SS Methods +.SS void RegisterAgent(object agent) +.INDENT 0.0 +.INDENT 3.5 +Registers an agent, which must implement \fBorg.bluez.obex.Agent(5)\fP, to +request authorization of the user to accept/reject objects. +.sp +Object push service needs to authorize each received object. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.AlreadyExists +.UNINDENT +.UNINDENT +.UNINDENT +.SS void UnregisterAgent(object agent) +.INDENT 0.0 +.INDENT 3.5 +Unregisters the agent that has been previously registered using +\fBRegisterAgent()\fP\&. The object path parameter must match the same value +that has been used on registration. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.DoesNotExist +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.obex.AgentManager.rst b/doc/org.bluez.obex.AgentManager.rst new file mode 100644 index 0000000000000000000000000000000000000000..f18f227bcb4b51b5456241643e48cf0e385f8892 --- /dev/null +++ b/doc/org.bluez.obex.AgentManager.rst @@ -0,0 +1,45 @@ +=========================== +org.bluez.obex.AgentManager +=========================== + +----------------------------------------------- +BlueZ D-Bus OBEX AgentManager API documentation +----------------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez.obex +:Interface: org.bluez.obex.AgentManager1 +:Object path: /org/bluez/obex + +Methods +``````` + +void RegisterAgent(object agent) +```````````````````````````````` + + Registers an agent, which must implement **org.bluez.obex.Agent(5)**, to + request authorization of the user to accept/reject objects. + + Object push service needs to authorize each received object. + + Possible errors: + + :org.bluez.obex.Error.AlreadyExists: + +void UnregisterAgent(object agent) +`````````````````````````````````` + + Unregisters the agent that has been previously registered using + **RegisterAgent()**. The object path parameter must match the same value + that has been used on registration. + + Possible errors: + + :org.bluez.obex.Error.DoesNotExist: diff --git a/doc/org.bluez.obex.Client.5 b/doc/org.bluez.obex.Client.5 new file mode 100644 index 0000000000000000000000000000000000000000..2b505830a9abddb823791d9b7d5371c367a865eb --- /dev/null +++ b/doc/org.bluez.obex.Client.5 @@ -0,0 +1,112 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.OBEX.CLIENT" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.obex.Client \- BlueZ D-Bus OBEX Client API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez.obex +.TP +.B Interface +org.bluez.obex.Client1 +.TP +.B Object path +/org/bluez/obex +.UNINDENT +.SS Methods +.SS object CreateSession(string destination, dict args) +.INDENT 0.0 +.INDENT 3.5 +Connects to the destination address and then proceed to create an OBEX +session object which implements \fBorg.bluez.obex.Session(5)\fP interface. +.sp +The last parameter is a dictionary to hold optional or type\-specific +parameters. +.sp +Possible args values: +.INDENT 0.0 +.TP +.B string Target +Type of session to be created. +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dqftp\(dq +.TP +.B \(dqmap\(dq +.TP +.B \(dqopp\(dq +.TP +.B \(dqpbap\(dq +.TP +.B \(dqsync\(dq +.TP +.B \(dqbip\-avrcp\(dq +.UNINDENT +.TP +.B string Source +Local address to be used. +.TP +.B byte Channel +Channel to be used. +.TP +.B uint16 PSM +L2CAP PSM to be used. +.UNINDENT +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void RemoveSession(object session) +.INDENT 0.0 +.INDENT 3.5 +Disconnects and removes session previously created by +\fBCreateSession()\fP aborting any pending transfers. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.NotAuthorized +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.obex.Client.rst b/doc/org.bluez.obex.Client.rst new file mode 100644 index 0000000000000000000000000000000000000000..f20dd5baa335349e26012b04b078d991a166b044 --- /dev/null +++ b/doc/org.bluez.obex.Client.rst @@ -0,0 +1,74 @@ +===================== +org.bluez.obex.Client +===================== + +----------------------------------------- +BlueZ D-Bus OBEX Client API documentation +----------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez.obex +:Interface: org.bluez.obex.Client1 +:Object path: /org/bluez/obex + +Methods +------- + +object CreateSession(string destination, dict args) +``````````````````````````````````````````````````` + + Connects to the destination address and then proceed to create an OBEX + session object which implements **org.bluez.obex.Session(5)** interface. + + The last parameter is a dictionary to hold optional or type-specific + parameters. + + Possible args values: + + :string Target: + + Type of session to be created. + + Possible values: + + :"ftp": + :"map": + :"opp": + :"pbap": + :"sync": + :"bip-avrcp": + + :string Source: + + Local address to be used. + + :byte Channel: + + Channel to be used. + + :uint16 PSM: + + L2CAP PSM to be used. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: + +void RemoveSession(object session) +`````````````````````````````````` + + Disconnects and removes session previously created by + **CreateSession()** aborting any pending transfers. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.NotAuthorized: diff --git a/doc/org.bluez.obex.FileTransfer.5 b/doc/org.bluez.obex.FileTransfer.5 new file mode 100644 index 0000000000000000000000000000000000000000..76432d56ef28bc2b5cff73d4b3787dd92352ec21 --- /dev/null +++ b/doc/org.bluez.obex.FileTransfer.5 @@ -0,0 +1,203 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.OBEX.FILETRANSFER" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.obex.FileTransfer \- BlueZ D-Bus OBEX FileTransfer API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez.obex +.TP +.B Interface +org.bluez.obex.FileTransfer1 +.TP +.B Object path +[Session object path] +.UNINDENT +.SS Methods +.SS void ChangeFolder(string folder) +.INDENT 0.0 +.INDENT 3.5 +Changes the current folder of the remote device. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void CreateFolder(string folder) +.INDENT 0.0 +.INDENT 3.5 +Creates a new folder in the remote device. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS array{dict} ListFolder() +.INDENT 0.0 +.INDENT 3.5 +Returns a dictionary containing information about the current folder +content. +.sp +Possible return values: +.INDENT 0.0 +.TP +.B string Name +Object name in UTF\-8 format. +.TP +.B string Type +Either \(dqfolder\(dq or \(dqfile\(dq. +.TP +.B uint64 Size +Object size or number of items in folder. +.TP +.B string Permission +Group, owner and other permission. +.TP +.B uint64 Modified +Last change. +.TP +.B uint64 Accessed +Last access. +.TP +.B uint64 Created +Creation date. +.UNINDENT +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS object, dict GetFile(string targetfile, string sourcefile) +.INDENT 0.0 +.INDENT 3.5 +Copies the contents of the source file (from remote device) to the +target file (on local filesystem). +.sp +If an empty target file is given, a name will be automatically generated +for the temporary file. +.sp +The returned path represents the newly created transfer, which should be +used to find out if the content has been successfully transferred or +if the operation fails. +.sp +The properties of this transfer are also returned along with the object +path, to avoid a call to GetProperties, see +\fBorg.bluez.obex.Transfer(5)\fP for the possible list of properties. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS object, dict PutFile(string sourcefile, string targetfile) +.INDENT 0.0 +.INDENT 3.5 +Copies the contents of the source file (from local filesystem) to the +target file (on remote device). +.sp +The returned path represents the newly created transfer, which should be +used to find out if the content has been successfully transferred or if +the operation fails. +.sp +The properties of this transfer are also returned along with the object +path, to avoid a call to GetProperties, see +\fBorg.bluez.obex.Transfer(5)\fP for the possible list of properties. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void CopyFile(string sourcefile, string targetfile) +.INDENT 0.0 +.INDENT 3.5 +Copies the contents from source file to target file on the remote +device. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void MoveFile(string sourcefile, string targetfile) +.INDENT 0.0 +.INDENT 3.5 +Moves a file within the remote device from source file to the target +file. +.sp +Possible errors: +.sp +;org.bluez.obex.Error.InvalidArguments: +:org.bluez.obex.Error.Failed: +.UNINDENT +.UNINDENT +.SS void Delete(string file) +.INDENT 0.0 +.INDENT 3.5 +Deletes the specified file/folder. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.obex.FileTransfer.rst b/doc/org.bluez.obex.FileTransfer.rst new file mode 100644 index 0000000000000000000000000000000000000000..6dce7e59d78e8d9f2dced6e3cf637d4c91c7ea38 --- /dev/null +++ b/doc/org.bluez.obex.FileTransfer.rst @@ -0,0 +1,155 @@ +=========================== +org.bluez.obex.FileTransfer +=========================== + +----------------------------------------------- +BlueZ D-Bus OBEX FileTransfer API documentation +----------------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez.obex +:Interface: org.bluez.obex.FileTransfer1 +:Object path: [Session object path] + +Methods +------- + +void ChangeFolder(string folder) +```````````````````````````````` + + Changes the current folder of the remote device. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: + +void CreateFolder(string folder) +```````````````````````````````` + + Creates a new folder in the remote device. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: + +array{dict} ListFolder() +```````````````````````` + + Returns a dictionary containing information about the current folder + content. + + Possible return values: + + :string Name: + + Object name in UTF-8 format. + + :string Type: + + Either "folder" or "file". + + :uint64 Size: + + Object size or number of items in folder. + + :string Permission: + + Group, owner and other permission. + + :uint64 Modified: + + Last change. + + :uint64 Accessed: + + Last access. + + :uint64 Created: + + Creation date. + + Possible errors: + + :org.bluez.obex.Error.Failed: + +object, dict GetFile(string targetfile, string sourcefile) +`````````````````````````````````````````````````````````` + + Copies the contents of the source file (from remote device) to the + target file (on local filesystem). + + If an empty target file is given, a name will be automatically generated + for the temporary file. + + The returned path represents the newly created transfer, which should be + used to find out if the content has been successfully transferred or + if the operation fails. + + The properties of this transfer are also returned along with the object + path, to avoid a call to GetProperties, see + **org.bluez.obex.Transfer(5)** for the possible list of properties. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: + +object, dict PutFile(string sourcefile, string targetfile) +`````````````````````````````````````````````````````````` + + Copies the contents of the source file (from local filesystem) to the + target file (on remote device). + + The returned path represents the newly created transfer, which should be + used to find out if the content has been successfully transferred or if + the operation fails. + + The properties of this transfer are also returned along with the object + path, to avoid a call to GetProperties, see + **org.bluez.obex.Transfer(5)** for the possible list of properties. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: + +void CopyFile(string sourcefile, string targetfile) +``````````````````````````````````````````````````` + + Copies the contents from source file to target file on the remote + device. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: + +void MoveFile(string sourcefile, string targetfile) +``````````````````````````````````````````````````` + + Moves a file within the remote device from source file to the target + file. + + Possible errors: + + ;org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: + +void Delete(string file) +```````````````````````` + + Deletes the specified file/folder. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: diff --git a/doc/org.bluez.obex.Image.5 b/doc/org.bluez.obex.Image.5 new file mode 100644 index 0000000000000000000000000000000000000000..4e24e37fc0e6da589030d5010bf2419dcc80a7a6 --- /dev/null +++ b/doc/org.bluez.obex.Image.5 @@ -0,0 +1,165 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.OBEX.IMAGE" "5" "August 2024" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.obex.Image \- BlueZ D-Bus OBEX Image API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez.obex +.TP +.B Interface +org.bluez.obex.Image1 [experimental] +.TP +.B Object path +[Session object path] +.UNINDENT +.SS Methods +.SS object, dict Get(string targetfile, string handle, dict description) +.INDENT 0.0 +.INDENT 3.5 +Retrieves the image corresponding to the handle and the description, as +one of the descriptions retrieved by GetImageProperties, and store it in +a local file. +.sp +If the \(dqtransform\(dq property description exists it should be set to one +of the value listed by GetImageProperties for this description. +.sp +If description is an empty dict, the native image will be retrieved. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS array{dict} Properties(string handle) +.INDENT 0.0 +.INDENT 3.5 +Retrieves the image properties corresponding to the handle. +.sp +The first dict entry is mandatory and correspond to \(aqhandle\(aq and \(aqname\(aq +of the image. +.sp +The second dict entry is mandatory and correspond to the native +description (\(aqtype\(aq:\(aqnative\(aq) of the image. +.sp +The following dict entries are optional and correspond to variant +descriptions of the image. If the \(aqtransform\(aq entry exists in the +description, it lists the available possible image transformations and +should be set to one of them before using the description as parameter +to GetImage. +.sp +Possible property values: +.INDENT 0.0 +.TP +.B string type +Type of dict properties. Mandatory for each dict. +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dqnative\(dq +.TP +.B \(dqvariant\(dq +.UNINDENT +.TP +.B string encoding +File encoding format. +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dqBMP\(dq +.TP +.B \(dqGIF\(dq +.TP +.B \(dqJPEG\(dq +.TP +.B \(dqJPEG2000\(dq +.TP +.B \(dqPNG\(dq +.TP +.B \(dqWBMP\(dq +.UNINDENT +.TP +.B string pixel +File encoding format size of form \(dq<width>*<height>\(dq. +.TP +.B uint64 size +File size. +.TP +.B uint64 maxsize +File maximum size. +.TP +.B string transformation +List of available transformations separated by space. +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dqcrop\(dq +.TP +.B \(dqfill\(dq +.TP +.B \(dqstretch\(dq +.UNINDENT +.UNINDENT +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS object, dict GetThumbnail(string targetfile, string handle) +.INDENT 0.0 +.INDENT 3.5 +Retrieves the image thumbnail corresponding to the handle and store it +in a local file. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.obex.Image.rst b/doc/org.bluez.obex.Image.rst new file mode 100644 index 0000000000000000000000000000000000000000..c40d3f481b46c1ae69fa08495b88ae76fc90405b --- /dev/null +++ b/doc/org.bluez.obex.Image.rst @@ -0,0 +1,118 @@ +==================== +org.bluez.obex.Image +==================== + +-------------------------------------------------- +BlueZ D-Bus OBEX Image API documentation +-------------------------------------------------- + +:Version: BlueZ +:Date: August 2024 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez.obex +:Interface: org.bluez.obex.Image1 [experimental] +:Object path: [Session object path] + +Methods +------- + +object, dict Get(string targetfile, string handle, dict description) +```````````````````````````````````````````````````````````````````` + + Retrieves the image corresponding to the handle and the description, as + one of the descriptions retrieved by GetImageProperties, and store it in + a local file. + + If the "transform" property description exists it should be set to one + of the value listed by GetImageProperties for this description. + + If description is an empty dict, the native image will be retrieved. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: + +array{dict} Properties(string handle) +````````````````````````````````````` + + Retrieves the image properties corresponding to the handle. + + The first dict entry is mandatory and correspond to 'handle' and 'name' + of the image. + + The second dict entry is mandatory and correspond to the native + description ('type':'native') of the image. + + The following dict entries are optional and correspond to variant + descriptions of the image. If the 'transform' entry exists in the + description, it lists the available possible image transformations and + should be set to one of them before using the description as parameter + to GetImage. + + Possible property values: + + :string type: + + Type of dict properties. Mandatory for each dict. + + Possible values: + + :"native": + :"variant": + + :string encoding: + + File encoding format. + + Possible values: + + :"BMP": + :"GIF": + :"JPEG": + :"JPEG2000": + :"PNG": + :"WBMP": + + :string pixel: + + File encoding format size of form "<width>*<height>". + + :uint64 size: + + File size. + + :uint64 maxsize: + + File maximum size. + + :string transformation: + + List of available transformations separated by space. + + Possible values: + + :"crop": + :"fill": + :"stretch": + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: + +object, dict GetThumbnail(string targetfile, string handle) +``````````````````````````````````````````````````````````` + + Retrieves the image thumbnail corresponding to the handle and store it + in a local file. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: diff --git a/doc/org.bluez.obex.Message.5 b/doc/org.bluez.obex.Message.5 new file mode 100644 index 0000000000000000000000000000000000000000..33543311b2a676289bf8c3bc734c3bf9b2a1446b --- /dev/null +++ b/doc/org.bluez.obex.Message.5 @@ -0,0 +1,191 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.OBEX.MESSAGE" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.obex.Message \- BlueZ D-Bus OBEX Message API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez.obex +.TP +.B Interface +org.bluez.obex.Message1 +.TP +.B Object path +[Session object path]/message{#} +.UNINDENT +.SS Methods +.SS object, dict Get(string targetfile, boolean attachment) +.INDENT 0.0 +.INDENT 3.5 +Download message and store it in the target file. +.sp +If an empty target file is given, a temporary file will be automatically +generated. +.sp +The returned path represents the newly created transfer, which should be +used to find out if the content has been successfully transferred or if +the operation fails. +.sp +The properties of this transfer are also returned along with the object +path, to avoid a call to GetProperties, see +\fBorg.bluez.obex.Transfer(5)\fP for the possible list of properties. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS Properties +.SS string Folder [readonly] +.INDENT 0.0 +.INDENT 3.5 +Folder which the message belongs to +.UNINDENT +.UNINDENT +.SS string Subject [readonly] +.INDENT 0.0 +.INDENT 3.5 +Message subject +.UNINDENT +.UNINDENT +.SS string Timestamp [readonly] +.INDENT 0.0 +.INDENT 3.5 +Message timestamp +.UNINDENT +.UNINDENT +.SS string Sender [readonly] +.INDENT 0.0 +.INDENT 3.5 +Message sender name +.UNINDENT +.UNINDENT +.SS string SenderAddress [readonly] +.INDENT 0.0 +.INDENT 3.5 +Message sender address +.UNINDENT +.UNINDENT +.SS string ReplyTo [readonly] +.INDENT 0.0 +.INDENT 3.5 +Message Reply\-To address +.UNINDENT +.UNINDENT +.SS string Recipient [readonly] +.INDENT 0.0 +.INDENT 3.5 +Message recipient name +.UNINDENT +.UNINDENT +.SS string RecipientAddress [readonly] +.INDENT 0.0 +.INDENT 3.5 +Message recipient address +.UNINDENT +.UNINDENT +.SS string Type [readonly] +.INDENT 0.0 +.INDENT 3.5 +Message type +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqemail\(dq +.TP +.B \(dqsms\-gsm\(dq +.TP +.B \(dqsms\-cdma\(dq +.TP +.B \(dqmms\(dq +.UNINDENT +.UNINDENT +.UNINDENT +.SS uint64 Size [readonly] +.INDENT 0.0 +.INDENT 3.5 +Message size in bytes +.UNINDENT +.UNINDENT +.SS string Status [readonly] +.INDENT 0.0 +.INDENT 3.5 +Message reception status +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqcomplete\(dq +.TP +.B \(dqfractioned\(dq +.TP +.B \(dqnotification\(dq +.UNINDENT +.UNINDENT +.UNINDENT +.SS boolean Priority [readonly] +.INDENT 0.0 +.INDENT 3.5 +Message priority flag +.UNINDENT +.UNINDENT +.SS boolean Read [read/write] +.INDENT 0.0 +.INDENT 3.5 +Message read flag +.UNINDENT +.UNINDENT +.SS boolean Deleted [writeonly] +.INDENT 0.0 +.INDENT 3.5 +Message deleted flag +.UNINDENT +.UNINDENT +.SS boolean Sent [readonly] +.INDENT 0.0 +.INDENT 3.5 +Message sent flag +.UNINDENT +.UNINDENT +.SS boolean Protected [readonly] +.INDENT 0.0 +.INDENT 3.5 +Message protected flag +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.obex.Message.rst b/doc/org.bluez.obex.Message.rst new file mode 100644 index 0000000000000000000000000000000000000000..082f872718875da13342d8b1949e56c9ebfc50fa --- /dev/null +++ b/doc/org.bluez.obex.Message.rst @@ -0,0 +1,139 @@ +====================== +org.bluez.obex.Message +====================== + +------------------------------------------ +BlueZ D-Bus OBEX Message API documentation +------------------------------------------ + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez.obex +:Interface: org.bluez.obex.Message1 +:Object path: [Session object path]/message{#} + +Methods +------- + +object, dict Get(string targetfile, boolean attachment) +``````````````````````````````````````````````````````` + + Download message and store it in the target file. + + If an empty target file is given, a temporary file will be automatically + generated. + + The returned path represents the newly created transfer, which should be + used to find out if the content has been successfully transferred or if + the operation fails. + + The properties of this transfer are also returned along with the object + path, to avoid a call to GetProperties, see + **org.bluez.obex.Transfer(5)** for the possible list of properties. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: + +Properties +---------- + +string Folder [readonly] +```````````````````````` + + Folder which the message belongs to + +string Subject [readonly] +````````````````````````` + + Message subject + +string Timestamp [readonly] +``````````````````````````` + + Message timestamp + +string Sender [readonly] +```````````````````````` + + Message sender name + +string SenderAddress [readonly] +``````````````````````````````` + + Message sender address + +string ReplyTo [readonly] +````````````````````````` + + Message Reply-To address + +string Recipient [readonly] +``````````````````````````` + + Message recipient name + +string RecipientAddress [readonly] +`````````````````````````````````` + + Message recipient address + +string Type [readonly] +`````````````````````` + + Message type + + Possible values: + + :"email": + :"sms-gsm": + :"sms-cdma": + :"mms": + +uint64 Size [readonly] +`````````````````````` + + Message size in bytes + +string Status [readonly] +```````````````````````` + + Message reception status + + Possible values: + + :"complete": + :"fractioned": + :"notification": + +boolean Priority [readonly] +``````````````````````````` + + Message priority flag + +boolean Read [read/write] +````````````````````````` + + Message read flag + +boolean Deleted [writeonly] +``````````````````````````` + + Message deleted flag + +boolean Sent [readonly] +``````````````````````` + + Message sent flag + +boolean Protected [readonly] +```````````````````````````` + + Message protected flag diff --git a/doc/org.bluez.obex.MessageAccess.5 b/doc/org.bluez.obex.MessageAccess.5 new file mode 100644 index 0000000000000000000000000000000000000000..8f16e5d9a746dc2eaed1bcbc7608644ffefbe091 --- /dev/null +++ b/doc/org.bluez.obex.MessageAccess.5 @@ -0,0 +1,279 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.OBEX.MESSAGEACCESS" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.obex.MessageAccess \- BlueZ D-Bus OBEX MessageAccess API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez.obex +.TP +.B Interface +org.bluez.obex.MessageAccess1 +.TP +.B Object path +[Session object path] +.UNINDENT +.SS Methods +.SS void SetFolder(string name) +.INDENT 0.0 +.INDENT 3.5 +Set working directory for current session. +.sp +Possible name: +.INDENT 0.0 +.INDENT 3.5 +Directory name or \(aq..[/dir]\(aq. +.UNINDENT +.UNINDENT +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS array{dict} ListFolders(dict filter) +.INDENT 0.0 +.INDENT 3.5 +Returns a dictionary containing information about the current folder +content. +.sp +Possible filter: +.INDENT 0.0 +.TP +.B uint16 Offset (default 0) +Offset of the first item. +.TP +.B uint16 MaxCount (default 1024) +Maximum number of items. +.UNINDENT +.sp +Possible return: +.INDENT 0.0 +.TP +.B string Name +Folder name +.UNINDENT +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS array{string} ListFilterFields() +.INDENT 0.0 +.INDENT 3.5 +Return all available fields that can be used in \fBFields\fP filter. +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqsubject\(dq +.TP +.B \(dqtimestamp\(dq +.TP +.B \(dqsender\(dq +.TP +.B \(dqsender\-address\(dq +.TP +.B \(dqrecipient\(dq +.TP +.B \(dqrecipient\-address\(dq +.TP +.B \(dqtype\(dq +.TP +.B \(dqsize\(dq +.TP +.B \(dqstatus\(dq +.TP +.B \(dqtext\(dq +.TP +.B \(dqattachment\(dq +.TP +.B \(dqpriority\(dq +.TP +.B \(dqread\(dq +.TP +.B \(dqsent\(dq +.TP +.B \(dqprotected\(dq +.TP +.B \(dqreplyto\(dq +.UNINDENT +.sp +Possible errors: None +.UNINDENT +.UNINDENT +.SS array{object, dict} ListMessages(string folder, dict filter) +.INDENT 0.0 +.INDENT 3.5 +Returns an array containing the messages objects found in the given +subfolder of the current folder, or in the current folder if folder is +empty. +.sp +Possible Filters: +.INDENT 0.0 +.TP +.B uint16 Offset (default 0) +Offset of the first item. +.UNINDENT +.sp +uint16 MaxCount (default 1024): +.INDENT 0.0 +.INDENT 3.5 +Maximum number of items. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B byte SubjectLength (default 256) +Maximum length of the Subject property in the message. +.TP +.B array{string} Fields +Message fields, default is all values. +.sp +See \fBListFilterFields()\fP for possible values. +.TP +.B array{string} Types +Filter messages by type. +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dqsms\(dq +.TP +.B \(dqemail\(dq +.TP +.B \(dqmms\(dq +.UNINDENT +.TP +.B string PeriodBegin +Filter messages by starting period. +.sp +Possible values: +.INDENT 7.0 +.INDENT 3.5 +Date in \(dqYYYYMMDDTHHMMSS\(dq format. +.UNINDENT +.UNINDENT +.TP +.B string PeriodEnd +Filter messages by ending period. +.sp +Possible values: +.INDENT 7.0 +.INDENT 3.5 +Date in \(dqYYYYMMDDTHHMMSS\(dq format. +.UNINDENT +.UNINDENT +.TP +.B boolean Read +Filter messages by read flag. +.sp +Possible values: +.INDENT 7.0 +.INDENT 3.5 +True for read or False for unread +.UNINDENT +.UNINDENT +.TP +.B string Recipient +Filter messages by recipient address. +.TP +.B string Sender +Filter messages by sender address. +.TP +.B boolean Priority +Filter messages by priority flag. +.sp +Possible values: +.INDENT 7.0 +.INDENT 3.5 +True for high priority or False for non\-high priority. +.UNINDENT +.UNINDENT +.UNINDENT +.sp +Each message is represented by an object path, which implements +\fBorg.bluez.obex.Message(5)\fP interface, followed by a dictionary +of its properties. +.UNINDENT +.UNINDENT +.sp +void UpdateInbox(void) +.INDENT 0.0 +.INDENT 3.5 +Requests remote to update its inbox. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS object, dict PushMessage(string sourcefile, string folder, dict args) +.INDENT 0.0 +.INDENT 3.5 +Transfers a message (in bMessage format) to the remote device. +.sp +The message is transferred either to the given subfolder of the current +folder, or to the current folder if folder is empty. +.sp +Possible args: Transparent, Retry, Charset +.sp +The returned path represents the newly created transfer, which should be +used to find out if the content has been successfully transferred or if +the operation fails. +.sp +The properties of this transfer are also returned along with the object +path, to avoid a call to GetProperties, see +\fBorg.bluez.obex.Transfer(5)\fP for the possible list of properties. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.obex.MessageAccess.rst b/doc/org.bluez.obex.MessageAccess.rst new file mode 100644 index 0000000000000000000000000000000000000000..4f7f07d1babd46510ab6a1b254e91593e32a5be6 --- /dev/null +++ b/doc/org.bluez.obex.MessageAccess.rst @@ -0,0 +1,201 @@ +============================ +org.bluez.obex.MessageAccess +============================ + +------------------------------------------------ +BlueZ D-Bus OBEX MessageAccess API documentation +------------------------------------------------ + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez.obex +:Interface: org.bluez.obex.MessageAccess1 +:Object path: [Session object path] + +Methods +------- + +void SetFolder(string name) +``````````````````````````` + + Set working directory for current session. + + Possible name: + + Directory name or '..[/dir]'. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: + +array{dict} ListFolders(dict filter) +```````````````````````````````````` + + Returns a dictionary containing information about the current folder + content. + + Possible filter: + + :uint16 Offset (default 0): + + Offset of the first item. + + :uint16 MaxCount (default 1024): + + Maximum number of items. + + Possible return: + + :string Name: + + Folder name + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: + +array{string} ListFilterFields() +```````````````````````````````` + + Return all available fields that can be used in **Fields** filter. + + Possible values: + + :"subject": + :"timestamp": + :"sender": + :"sender-address": + :"recipient": + :"recipient-address": + :"type": + :"size": + :"status": + :"text": + :"attachment": + :"priority": + :"read": + :"sent": + :"protected": + :"replyto": + + Possible errors: None + +array{object, dict} ListMessages(string folder, dict filter) +```````````````````````````````````````````````````````````` + + Returns an array containing the messages objects found in the given + subfolder of the current folder, or in the current folder if folder is + empty. + + Possible Filters: + + :uint16 Offset (default 0): + + Offset of the first item. + + uint16 MaxCount (default 1024): + + Maximum number of items. + + :byte SubjectLength (default 256): + + Maximum length of the Subject property in the message. + + :array{string} Fields: + + Message fields, default is all values. + + See **ListFilterFields()** for possible values. + + :array{string} Types: + + Filter messages by type. + + Possible values: + + :"sms": + :"email": + :"mms": + + :string PeriodBegin: + + Filter messages by starting period. + + Possible values: + + Date in "YYYYMMDDTHHMMSS" format. + + :string PeriodEnd: + + Filter messages by ending period. + + Possible values: + + Date in "YYYYMMDDTHHMMSS" format. + + :boolean Read: + + Filter messages by read flag. + + Possible values: + + True for read or False for unread + + :string Recipient: + + Filter messages by recipient address. + + :string Sender: + + Filter messages by sender address. + + :boolean Priority: + + Filter messages by priority flag. + + Possible values: + + True for high priority or False for non-high priority. + + Each message is represented by an object path, which implements + **org.bluez.obex.Message(5)** interface, followed by a dictionary + of its properties. + +void UpdateInbox(void) + + Requests remote to update its inbox. + + Possible errors: + + :org.bluez.obex.Error.Failed: + +object, dict PushMessage(string sourcefile, string folder, dict args) +````````````````````````````````````````````````````````````````````` + + Transfers a message (in bMessage format) to the remote device. + + The message is transferred either to the given subfolder of the current + folder, or to the current folder if folder is empty. + + Possible args: Transparent, Retry, Charset + + The returned path represents the newly created transfer, which should be + used to find out if the content has been successfully transferred or if + the operation fails. + + The properties of this transfer are also returned along with the object + path, to avoid a call to GetProperties, see + **org.bluez.obex.Transfer(5)** for the possible list of properties. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: diff --git a/doc/org.bluez.obex.ObjectPush.5 b/doc/org.bluez.obex.ObjectPush.5 new file mode 100644 index 0000000000000000000000000000000000000000..1c9510de7dee22ae02def30d86ab3acd4b920bbd --- /dev/null +++ b/doc/org.bluez.obex.ObjectPush.5 @@ -0,0 +1,121 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.OBEX.OBJECTPUSH" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.obex.ObjectPush \- BlueZ D-Bus OBEX ObjectPush API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez.obex +.TP +.B Interface +org.bluez.obex.ObjectPush1 +.TP +.B Object path +[Session object path] +.UNINDENT +.SS Methods +.SS object, dict SendFile(string sourcefile) +.INDENT 0.0 +.INDENT 3.5 +Sends local file to the remote device. +.sp +The returned path represents the newly created transfer, which should be +used to find out if the content has been successfully transferred or if +the operation fails. +.sp +The properties of this transfer are also returned along with the object +path, to avoid a call to GetProperties, see +\fBorg.bluez.obex.Transfer(5)\fP for the possible list of properties. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS object, dict PullBusinessCard(string targetfile) +.INDENT 0.0 +.INDENT 3.5 +Request the business card from a remote device and store it in the local +file. +.sp +If an empty target file is given, a name will be automatically +generated for the temporary file. +.sp +The returned path represents the newly created transfer, which should be +used to find out if the content has been successfully transferred or if +the operation fails. +.sp +The properties of this transfer are also returned along with the object +path, to avoid a call to GetProperties, see +\fBorg.bluez.obex.Transfer(5)\fP for the possible list of properties. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS object, dict ExchangeBusinessCards(string clientfile, string targetfile) +.INDENT 0.0 +.INDENT 3.5 +Push the client\(aqs business card to the remote device and then retrieve +the remote business card and store it in a local file. +.sp +If an empty target file is given, a name will be automatically +generated for the temporary file. +.sp +The returned path represents the newly created transfer, which should +be used to find out if the content has been successfully transferred or +if the operation fails. +.sp +The properties of this transfer are also returned along with the object +path, to avoid a call to GetProperties, see +\fBorg.bluez.obex.Transfer(5)\fP for the possible list of properties. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.obex.ObjectPush.rst b/doc/org.bluez.obex.ObjectPush.rst new file mode 100644 index 0000000000000000000000000000000000000000..aba2282a8480f14783227ab626b103721b9e9329 --- /dev/null +++ b/doc/org.bluez.obex.ObjectPush.rst @@ -0,0 +1,84 @@ +========================= +org.bluez.obex.ObjectPush +========================= + +--------------------------------------------- +BlueZ D-Bus OBEX ObjectPush API documentation +--------------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez.obex +:Interface: org.bluez.obex.ObjectPush1 +:Object path: [Session object path] + +Methods +------- + +object, dict SendFile(string sourcefile) +```````````````````````````````````````` + + Sends local file to the remote device. + + The returned path represents the newly created transfer, which should be + used to find out if the content has been successfully transferred or if + the operation fails. + + The properties of this transfer are also returned along with the object + path, to avoid a call to GetProperties, see + **org.bluez.obex.Transfer(5)** for the possible list of properties. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: + +object, dict PullBusinessCard(string targetfile) +```````````````````````````````````````````````` + + Request the business card from a remote device and store it in the local + file. + + If an empty target file is given, a name will be automatically + generated for the temporary file. + + The returned path represents the newly created transfer, which should be + used to find out if the content has been successfully transferred or if + the operation fails. + + The properties of this transfer are also returned along with the object + path, to avoid a call to GetProperties, see + **org.bluez.obex.Transfer(5)** for the possible list of properties. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: + +object, dict ExchangeBusinessCards(string clientfile, string targetfile) +```````````````````````````````````````````````````````````````````````` + + Push the client's business card to the remote device and then retrieve + the remote business card and store it in a local file. + + If an empty target file is given, a name will be automatically + generated for the temporary file. + + The returned path represents the newly created transfer, which should + be used to find out if the content has been successfully transferred or + if the operation fails. + + The properties of this transfer are also returned along with the object + path, to avoid a call to GetProperties, see + **org.bluez.obex.Transfer(5)** for the possible list of properties. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: diff --git a/doc/org.bluez.obex.PhonebookAccess.5 b/doc/org.bluez.obex.PhonebookAccess.5 new file mode 100644 index 0000000000000000000000000000000000000000..361d24ba4635a81960cbf16c6b15f95219bfabc6 --- /dev/null +++ b/doc/org.bluez.obex.PhonebookAccess.5 @@ -0,0 +1,515 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.OBEX.PHONEBOOKACCESS" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.obex.PhonebookAccess \- BlueZ D-Bus OBEX PhonebookAccess API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez.obex +.TP +.B Interface +org.bluez.obex.PhonebookAccess1 +.TP +.B Object path +[Session object path] +.UNINDENT +.SS Methods +.SS void Select(string location, string phonebook) +.INDENT 0.0 +.INDENT 3.5 +Selects the phonebook object for other operations. Should be call before +all the other operations. +.sp +Possible location values: +.INDENT 0.0 +.TP +.B \(dqint\(dq, \(dqinternal\(dq (default) +Store in the Internal memory. +.TP +.B \(dqsim{#}\(dq +Store in the sim number. +.UNINDENT +.sp +Possible phonebook values: +.INDENT 0.0 +.TP +.B \(dqpb\(dq +Store as contact. +.TP +.B \(dqich\(dq +Store as incoming call. +.TP +.B \(dqoch\(dq +Store as outgoing call. +.TP +.B \(dqmch\(dq +Store as missing call. +.TP +.B \(dqcch\(dq +Store as a combination of incoming, outgoing and missing call. +.UNINDENT +.sp +\(dqspd\(dq: +.INDENT 0.0 +.INDENT 3.5 +Store as speed dials entry ( only for \(dqinternal\(dq ) +.UNINDENT +.UNINDENT +.sp +\(dqfav\(dq: +.INDENT 0.0 +.INDENT 3.5 +Store as favorites entry ( only for \(dqinternal\(dq ) +.UNINDENT +.UNINDENT +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS object, dict PullAll(string targetfile, dict filters) +.INDENT 0.0 +.INDENT 3.5 +Returns the entire phonebook object from the PSE server in plain string +with vcard format, and store it in a local file. +.sp +If an empty target file is given, a name will be automatically generated +for the temporary file. +.sp +The returned path represents the newly created transfer, which should +be used to find out if the content has been successfully transferred or +if the operation fails. +.sp +The properties of this transfer are also returned along with the object +path, to avoid a call to GetProperties, see +\fBorg.bluez.obex.Transfer(5)\fP for the possible list of properties. +.sp +Possible filters: +.INDENT 0.0 +.TP +.B string Format +Items vcard format. +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dqvcard21\(dq (default) +.TP +.B \(dqvcard30\(dq +.UNINDENT +.TP +.B string Order +Items order. +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dq\(dq +.TP +.B \(dqindexed\(dq +.TP +.B \(dqalphanumeric\(dq +.TP +.B \(dqphonetic\(dq +.UNINDENT +.TP +.B uint16 Offset (default 0) +Offset of the first item. +.TP +.B uint16 MaxCount (default 65535) +Maximum number of items. +.TP +.B array{string} Fields (default all fields) +Item vcard fields. +.sp +See \fBListFilterFields()\fP for possible values. +.TP +.B array{string} FilterAll +Filter items by fields using AND logic, cannot be used +together with \fBFilterAny\fP\&. +.sp +See \fBListFilterFields()\fP for possible values. +.TP +.B array{string} FilterAny +Filter items by fields using OR logic, cannot be used together +with \fBFilterAll\fP\&. +.sp +See \fBListFilterFields()\fP for possible values. +.TP +.B bool ResetNewMissedCalls +Reset new the missed calls items, shall only be used for folders +mch and cch. +.UNINDENT +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Forbidden +.UNINDENT +.UNINDENT +.UNINDENT +.SS array{string vcard, string name} List(dict filters) +.INDENT 0.0 +.INDENT 3.5 +Returns array of vcard\-listing data where every entry consists of a +pair of strings containing the vcard handle and the contact name. +For example: +.INDENT 0.0 +.TP +.B \(dq1.vcf\(dq +\(dqJohn\(dq +.UNINDENT +.sp +Possible filters: +.INDENT 0.0 +.TP +.B string Order +Contact order. +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dq\(dq +.TP +.B \(dqindexed\(dq +.TP +.B \(dqalphanumeric\(dq +.TP +.B \(dqphonetic\(dq +.UNINDENT +.TP +.B uint16 Offset +Start offset. +.TP +.B uint16 MaxCount +Maximum number of contacts. +.UNINDENT +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Forbidden +.UNINDENT +.UNINDENT +.UNINDENT +.SS object, dict Pull(string vcard, string targetfile, dict filters) +.INDENT 0.0 +.INDENT 3.5 +Retrieves the vcard in the current phonebook object and store it in a +local file. +.sp +If an empty target file is given, a name will be automatically generated +for the temporary file. +.sp +The returned path represents the newly created transfer, which should be +used to find out if the content has been successfully transferred or if +the operation fails. +.sp +The properties of this transfer are also returned along with the object +path, to avoid a call to GetProperties, see +\fBorg.bluez.obex.Transfer(5)\fP for the possible list of properties. +.sp +Possible filters: +.INDENT 0.0 +.TP +.B string Format +Contact data format. +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dq\(dq +.TP +.B \(dqvcard21\(dq +.TP +.B \(dqvcard30\(dq +.UNINDENT +.TP +.B array{string} Fields +See \fBListFilterFields()\fP for possible values. +.UNINDENT +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Forbidden +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS array{string vcard, string name} Search(string field, string value, dict filters) +.INDENT 0.0 +.INDENT 3.5 +Searches for entries matching the given condition and return an array of +vcard\-listing data where every entry consists of a pair of strings +containing the vcard handle and the contact name. +.sp +Possible field values: +.INDENT 0.0 +.INDENT 3.5 +.INDENT 0.0 +.TP +.B \(dqname\(dq (default) +Search by name. +.TP +.B \(dqnumber\(dq +Search by number. +.TP +.B \(dqsound\(dq +Search by sound. +.UNINDENT +.UNINDENT +.UNINDENT +.sp +value: the string value to search for +.sp +Possible filters: +.INDENT 0.0 +.TP +.B string Order +Contact order. +.sp +Possible values: +.INDENT 7.0 +.TP +.B \(dq\(dq +.TP +.B \(dqindexed\(dq +.TP +.B \(dqalphanumeric\(dq +.TP +.B \(dqphonetic\(dq +.UNINDENT +.TP +.B uint16 Offset +Start offset. +.TP +.B uint16 MaxCount +Maximum number of contacts. +.UNINDENT +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Forbidden +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS uint16 GetSize() +.INDENT 0.0 +.INDENT 3.5 +Returns the number of entries in the selected phonebook object that are +actually used (i.e. indexes that correspond to non\-NULL entries). +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.Forbidden +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void UpdateVersion() +.INDENT 0.0 +.INDENT 3.5 +Attempts to update PrimaryCounter and SecondaryCounter. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.NotSupported +.TP +.B org.bluez.obex.Error.Forbidden +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS array{string} ListFilterFields() +.INDENT 0.0 +.INDENT 3.5 +Returns all Available fields that can be used in Fields filter. +.sp +Possible return: +.INDENT 0.0 +.TP +.B \(dqVERSION\(dq +.TP +.B \(dqFN\(dq +.TP +.B \(dqN\(dq +.TP +.B \(dqPHOTO\(dq +.TP +.B \(dqBDAY\(dq +.TP +.B \(dqADR\(dq +.TP +.B \(dqLABEL\(dq +.TP +.B \(dqTEL\(dq +.TP +.B \(dqEMAIL\(dq +.TP +.B \(dqMAILER\(dq +.TP +.B \(dqTZ\(dq +.TP +.B \(dqGEO\(dq +.TP +.B \(dqTITLE\(dq +.TP +.B \(dqROLE\(dq +.TP +.B \(dqLOGO\(dq +.TP +.B \(dqAGENT\(dq +.TP +.B \(dqORG\(dq +.TP +.B \(dqNOTE\(dq +.TP +.B \(dqREV\(dq +.TP +.B \(dqSOUND\(dq +.TP +.B \(dqURL\(dq +.TP +.B \(dqUID\(dq +.TP +.B \(dqKEY\(dq +.TP +.B \(dqNICKNAME\(dq +.TP +.B \(dqCATEGORIES\(dq +.TP +.B \(dqPROID\(dq +.TP +.B \(dqCLASS\(dq +.TP +.B \(dqSORT\-STRING\(dq +.TP +.B \(dqX\-IRMC\-CALL\-DATETIME\(dq +.TP +.B \(dqX\-BT\-SPEEDDIALKEY\(dq +.TP +.B \(dqX\-BT\-UCI\(dq +.TP +.B \(dqX\-BT\-UID\(dq +.TP +.B \(dqBIT\-{#}\(dq +.UNINDENT +.sp +Possible errors: None +.UNINDENT +.UNINDENT +.SS Properties +.SS string Folder [readonly] +.INDENT 0.0 +.INDENT 3.5 +Current folder. +.UNINDENT +.UNINDENT +.SS string DatabaseIdentifier [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +128 bits persistent database identifier. +.sp +Possible values: +.INDENT 0.0 +.INDENT 3.5 +32\-character hexadecimal such as +A1A2A3A4B1B2C1C2D1D2E1E2E3E4E5E6 +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.SS string PrimaryCounter [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +128 bits primary version counter. +.sp +Possible values: +.INDENT 0.0 +.INDENT 3.5 +32\-character hexadecimal such as +A1A2A3A4B1B2C1C2D1D2E1E2E3E4E5E6 +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.SS string SecondaryCounter [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +128 bits secondary version counter. +.sp +Possible values: +.INDENT 0.0 +.INDENT 3.5 +32\-character hexadecimal such as +A1A2A3A4B1B2C1C2D1D2E1E2E3E4E5E6 +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.SS bool FixedImageSize [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Indicate support for fixed image size. +.sp +Possible values: +.INDENT 0.0 +.INDENT 3.5 +True if image is JPEG 300x300 pixels otherwise False. +.UNINDENT +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.obex.PhonebookAccess.rst b/doc/org.bluez.obex.PhonebookAccess.rst new file mode 100644 index 0000000000000000000000000000000000000000..0e126b1b46c6a3517ef2497925b58c1623cdfe3a --- /dev/null +++ b/doc/org.bluez.obex.PhonebookAccess.rst @@ -0,0 +1,386 @@ +============================== +org.bluez.obex.PhonebookAccess +============================== + +-------------------------------------------------- +BlueZ D-Bus OBEX PhonebookAccess API documentation +-------------------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez.obex +:Interface: org.bluez.obex.PhonebookAccess1 +:Object path: [Session object path] + +Methods +------- + +void Select(string location, string phonebook) +`````````````````````````````````````````````` + + Selects the phonebook object for other operations. Should be call before + all the other operations. + + Possible location values: + + :"int", "internal" (default): + + Store in the Internal memory. + + :"sim{#}": + + Store in the sim number. + + Possible phonebook values: + + :"pb": + + Store as contact. + + :"ich": + + Store as incoming call. + + :"och": + + Store as outgoing call. + + :"mch": + + Store as missing call. + + :"cch": + + Store as a combination of incoming, outgoing and missing call. + + "spd": + + Store as speed dials entry ( only for "internal" ) + + "fav": + + Store as favorites entry ( only for "internal" ) + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: + +object, dict PullAll(string targetfile, dict filters) +````````````````````````````````````````````````````` + + Returns the entire phonebook object from the PSE server in plain string + with vcard format, and store it in a local file. + + If an empty target file is given, a name will be automatically generated + for the temporary file. + + The returned path represents the newly created transfer, which should + be used to find out if the content has been successfully transferred or + if the operation fails. + + The properties of this transfer are also returned along with the object + path, to avoid a call to GetProperties, see + **org.bluez.obex.Transfer(5)** for the possible list of properties. + + Possible filters: + + :string Format: + + Items vcard format. + + Possible values: + + :"vcard21" (default): + :"vcard30": + + :string Order: + + Items order. + + Possible values: + + :"": + :"indexed": + :"alphanumeric": + :"phonetic": + + :uint16 Offset (default 0): + + Offset of the first item. + + :uint16 MaxCount (default 65535): + + Maximum number of items. + + :array{string} Fields (default all fields): + + Item vcard fields. + + See **ListFilterFields()** for possible values. + + :array{string} FilterAll: + + Filter items by fields using AND logic, cannot be used + together with **FilterAny**. + + See **ListFilterFields()** for possible values. + + :array{string} FilterAny: + + Filter items by fields using OR logic, cannot be used together + with **FilterAll**. + + See **ListFilterFields()** for possible values. + + :bool ResetNewMissedCalls: + + Reset new the missed calls items, shall only be used for folders + mch and cch. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Forbidden: + +array{string vcard, string name} List(dict filters) +``````````````````````````````````````````````````` + + Returns array of vcard-listing data where every entry consists of a + pair of strings containing the vcard handle and the contact name. + For example: + + :"1.vcf": "John" + + Possible filters: + + :string Order: + + Contact order. + + Possible values: + + :"": + :"indexed": + :"alphanumeric": + :"phonetic": + + :uint16 Offset: + + Start offset. + + :uint16 MaxCount: + + Maximum number of contacts. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Forbidden: + +object, dict Pull(string vcard, string targetfile, dict filters) +```````````````````````````````````````````````````````````````` + + Retrieves the vcard in the current phonebook object and store it in a + local file. + + If an empty target file is given, a name will be automatically generated + for the temporary file. + + The returned path represents the newly created transfer, which should be + used to find out if the content has been successfully transferred or if + the operation fails. + + The properties of this transfer are also returned along with the object + path, to avoid a call to GetProperties, see + **org.bluez.obex.Transfer(5)** for the possible list of properties. + + Possible filters: + + :string Format: + + Contact data format. + + Possible values: + + :"": + :"vcard21": + :"vcard30": + + :array{string} Fields: + + See **ListFilterFields()** for possible values. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Forbidden: + :org.bluez.obex.Error.Failed: + +array{string vcard, string name} Search(string field, string value, dict filters) +````````````````````````````````````````````````````````````````````````````````` + + Searches for entries matching the given condition and return an array of + vcard-listing data where every entry consists of a pair of strings + containing the vcard handle and the contact name. + + Possible field values: + + :"name" (default): + + Search by name. + + :"number": + + Search by number. + + :"sound": + + Search by sound. + + value: the string value to search for + + Possible filters: + + :string Order: + + Contact order. + + Possible values: + + :"": + :"indexed": + :"alphanumeric": + :"phonetic": + + :uint16 Offset: + + Start offset. + + :uint16 MaxCount: + + Maximum number of contacts. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Forbidden: + :org.bluez.obex.Error.Failed: + +uint16 GetSize() +```````````````` + + Returns the number of entries in the selected phonebook object that are + actually used (i.e. indexes that correspond to non-NULL entries). + + Possible errors: + + :org.bluez.obex.Error.Forbidden: + :org.bluez.obex.Error.Failed: + +void UpdateVersion() +```````````````````` + + Attempts to update PrimaryCounter and SecondaryCounter. + + Possible errors: + + :org.bluez.obex.Error.NotSupported: + :org.bluez.obex.Error.Forbidden: + :org.bluez.obex.Error.Failed: + +array{string} ListFilterFields() +```````````````````````````````` + + Returns all Available fields that can be used in Fields filter. + + Possible return: + + :"VERSION": + :"FN": + :"N": + :"PHOTO": + :"BDAY": + :"ADR": + :"LABEL": + :"TEL": + :"EMAIL": + :"MAILER": + :"TZ": + :"GEO": + :"TITLE": + :"ROLE": + :"LOGO": + :"AGENT": + :"ORG": + :"NOTE": + :"REV": + :"SOUND": + :"URL": + :"UID": + :"KEY": + :"NICKNAME": + :"CATEGORIES": + :"PROID": + :"CLASS": + :"SORT-STRING": + :"X-IRMC-CALL-DATETIME": + :"X-BT-SPEEDDIALKEY": + :"X-BT-UCI": + :"X-BT-UID": + :"BIT-{#}": + + Possible errors: None + +Properties +---------- + +string Folder [readonly] +```````````````````````` + + Current folder. + +string DatabaseIdentifier [readonly, optional] +`````````````````````````````````````````````` + + 128 bits persistent database identifier. + + Possible values: + + 32-character hexadecimal such as + A1A2A3A4B1B2C1C2D1D2E1E2E3E4E5E6 + +string PrimaryCounter [readonly, optional] +`````````````````````````````````````````` + + 128 bits primary version counter. + + Possible values: + + 32-character hexadecimal such as + A1A2A3A4B1B2C1C2D1D2E1E2E3E4E5E6 + +string SecondaryCounter [readonly, optional] +```````````````````````````````````````````` + + 128 bits secondary version counter. + + Possible values: + + 32-character hexadecimal such as + A1A2A3A4B1B2C1C2D1D2E1E2E3E4E5E6 + +bool FixedImageSize [readonly, optional] +```````````````````````````````````````` + + Indicate support for fixed image size. + + Possible values: + + True if image is JPEG 300x300 pixels otherwise False. diff --git a/doc/org.bluez.obex.Session.5 b/doc/org.bluez.obex.Session.5 new file mode 100644 index 0000000000000000000000000000000000000000..8deb628efab9641c85a9876a338687a2d8793c45 --- /dev/null +++ b/doc/org.bluez.obex.Session.5 @@ -0,0 +1,99 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.OBEX.SESSION" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.obex.Session \- BlueZ D-Bus OBEX Client API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez.obex +.TP +.B Interface +org.bluez.obex.Session1 +.TP +.B Object path +/org/bluez/obex/server/session{#} or +/org/bluez/obex/client/session{#} +.UNINDENT +.SS Methods +.SS string GetCapabilities() +.INDENT 0.0 +.INDENT 3.5 +Get remote device capabilities. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.NotSupported +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS Properties +.SS string Source [readonly] +.INDENT 0.0 +.INDENT 3.5 +Bluetooth adapter address +.UNINDENT +.UNINDENT +.SS string Destination [readonly] +.INDENT 0.0 +.INDENT 3.5 +Bluetooth device address +.UNINDENT +.UNINDENT +.SS byte Channel [readonly] +.INDENT 0.0 +.INDENT 3.5 +Bluetooth channel +.UNINDENT +.UNINDENT +.SS uint16 PSM [readonly] +.INDENT 0.0 +.INDENT 3.5 +Bluetooth L2CAP PSM +.UNINDENT +.UNINDENT +.SS string Target [readonly] +.INDENT 0.0 +.INDENT 3.5 +Target UUID +.UNINDENT +.UNINDENT +.SS string Root [readonly] +.INDENT 0.0 +.INDENT 3.5 +Root path +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.obex.Session.rst b/doc/org.bluez.obex.Session.rst new file mode 100644 index 0000000000000000000000000000000000000000..fc5f14e5dccd529262533ed26b01b9f2275c20de --- /dev/null +++ b/doc/org.bluez.obex.Session.rst @@ -0,0 +1,66 @@ +====================== +org.bluez.obex.Session +====================== + +----------------------------------------- +BlueZ D-Bus OBEX Client API documentation +----------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez.obex +:Interface: org.bluez.obex.Session1 +:Object path: /org/bluez/obex/server/session{#} or + /org/bluez/obex/client/session{#} + +Methods +------- + +string GetCapabilities() +```````````````````````` + + Get remote device capabilities. + + Possible errors: + + :org.bluez.obex.Error.NotSupported: + :org.bluez.obex.Error.Failed: + +Properties +---------- + +string Source [readonly] +```````````````````````` + + Bluetooth adapter address + +string Destination [readonly] +````````````````````````````` + + Bluetooth device address + +byte Channel [readonly] +``````````````````````` + + Bluetooth channel + +uint16 PSM [readonly] +``````````````````````` + + Bluetooth L2CAP PSM + +string Target [readonly] +```````````````````````` + + Target UUID + +string Root [readonly] +`````````````````````` + + Root path diff --git a/doc/org.bluez.obex.Synchronization.5 b/doc/org.bluez.obex.Synchronization.5 new file mode 100644 index 0000000000000000000000000000000000000000..3edf3936bb0a5c3d6c53eae965817dccb818d839 --- /dev/null +++ b/doc/org.bluez.obex.Synchronization.5 @@ -0,0 +1,118 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.OBEX.SYNCHRONIZATION" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.obex.Synchronization \- BlueZ D-Bus OBEX Synchronization API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez.obex +.TP +.B Interface +org.bluez.obex.Synchronization1 +.TP +.B Object path +[Session object path] +.UNINDENT +.SS Methods +.SS void SetLocation(string location) +.INDENT 0.0 +.INDENT 3.5 +Sets the phonebook object store location for other operations. Should be +called before all the other operations. +.sp +Possible location: +.INDENT 0.0 +.TP +.B \(dqint\(dq ( \(dqinternal\(dq which is default ) +Store in the interval memory. +.TP +.B \(dqsim{#}\(dq +Store in sim card number #. +.UNINDENT +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.UNINDENT +.UNINDENT +.UNINDENT +.SS object, dict GetPhonebook(string targetfile) +.INDENT 0.0 +.INDENT 3.5 +Retrieves an entire Phonebook Object store from remote device, and +stores it in a local file. +.sp +If an empty target file is given, a name will be automatically +calculated for the temporary file. +.sp +The returned path represents the newly created transfer, which should be +used to find out if the content has been successfully transferred or if +the operation fails. +.sp +The properties of this transfer are also returned along with the object +path, to avoid a call to GetProperties, see +\fBorg.bluez.obex.Transfer(5)\fP for the possible list of properties. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS object, dict PutPhonebook(string sourcefile) +.INDENT 0.0 +.INDENT 3.5 +Sends an entire Phonebook Object store to remote device. +.sp +The returned path represents the newly created transfer, which should be +used to find out if the content has been successfully transferred or if +the operation fails. +.sp +The properties of this transfer are also returned along with the object +path, to avoid a call to GetProperties, see +\fBorg.bluez.obex.Transfer(5)\fP for the possible list of properties. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.InvalidArguments +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.obex.Synchronization.rst b/doc/org.bluez.obex.Synchronization.rst new file mode 100644 index 0000000000000000000000000000000000000000..a41197dfb926de5b1aabed89b4501fe209d99473 --- /dev/null +++ b/doc/org.bluez.obex.Synchronization.rst @@ -0,0 +1,82 @@ +============================== +org.bluez.obex.Synchronization +============================== + +-------------------------------------------------- +BlueZ D-Bus OBEX Synchronization API documentation +-------------------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez.obex +:Interface: org.bluez.obex.Synchronization1 +:Object path: [Session object path] + +Methods +------- + +void SetLocation(string location) +````````````````````````````````` + + Sets the phonebook object store location for other operations. Should be + called before all the other operations. + + Possible location: + + :"int" ( "internal" which is default ): + + Store in the interval memory. + + :"sim{#}": + + Store in sim card number #. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + +object, dict GetPhonebook(string targetfile) +```````````````````````````````````````````` + + Retrieves an entire Phonebook Object store from remote device, and + stores it in a local file. + + If an empty target file is given, a name will be automatically + calculated for the temporary file. + + The returned path represents the newly created transfer, which should be + used to find out if the content has been successfully transferred or if + the operation fails. + + The properties of this transfer are also returned along with the object + path, to avoid a call to GetProperties, see + **org.bluez.obex.Transfer(5)** for the possible list of properties. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: + +object, dict PutPhonebook(string sourcefile) +```````````````````````````````````````````` + + Sends an entire Phonebook Object store to remote device. + + The returned path represents the newly created transfer, which should be + used to find out if the content has been successfully transferred or if + the operation fails. + + The properties of this transfer are also returned along with the object + path, to avoid a call to GetProperties, see + **org.bluez.obex.Transfer(5)** for the possible list of properties. + + Possible errors: + + :org.bluez.obex.Error.InvalidArguments: + :org.bluez.obex.Error.Failed: diff --git a/doc/org.bluez.obex.Transfer.5 b/doc/org.bluez.obex.Transfer.5 new file mode 100644 index 0000000000000000000000000000000000000000..40ce404ce1c825a627e916433df1fb63dc48fcd1 --- /dev/null +++ b/doc/org.bluez.obex.Transfer.5 @@ -0,0 +1,171 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ORG.BLUEZ.OBEX.TRANSFER" "5" "October 2023" "BlueZ" "Linux System Administration" +.SH NAME +org.bluez.obex.Transfer \- BlueZ D-Bus OBEX Transfer API documentation +.SH INTERFACE +.INDENT 0.0 +.TP +.B Service +org.bluez.obex +.TP +.B Interface +org.bluez.obex.Transfer1 +.TP +.B Object path +[Session object path]/transfer{#} +.UNINDENT +.SS Methods +.SS void Cancel() +.INDENT 0.0 +.INDENT 3.5 +Cancels the current transference. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.NotAuthorized +.TP +.B org.bluez.obex.Error.InProgress +.TP +.B org.bluez.obex.Error.Failed +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Suspend() +.INDENT 0.0 +.INDENT 3.5 +Suspends transference. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.NotAuthorized +.TP +.B org.bluez.obex.Error.NotInProgress +If transfer is still in with \fBStatus\fP \fB\(dqqueued\(dq\fP\&. +.UNINDENT +.UNINDENT +.UNINDENT +.SS void Resume() +.INDENT 0.0 +.INDENT 3.5 +Resumes transference previously suspended with use of \fBSuspend()\fP +method. +.sp +Possible errors: +.INDENT 0.0 +.TP +.B org.bluez.obex.Error.NotAuthorized +.TP +.B org.bluez.obex.Error.NotInProgress +If transfer is still in with \fBStatus\fP \fB\(dqqueued\(dq\fP\&. +.UNINDENT +.UNINDENT +.UNINDENT +.SS Properties +.SS string Status [readonly] +.INDENT 0.0 +.INDENT 3.5 +Indicates the current status of the transfer. +.sp +Possible values: +.INDENT 0.0 +.TP +.B \(dqqueued\(dq +.TP +.B \(dqactive\(dq +.TP +.B \(dqsuspended\(dq +.TP +.B \(dqcomplete\(dq +.TP +.B \(dqerror\(dq +.UNINDENT +.UNINDENT +.UNINDENT +.SS object Session [readonly] +.INDENT 0.0 +.INDENT 3.5 +The object path of the session the transfer belongs to. +.UNINDENT +.UNINDENT +.SS string Name [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Name of the object being transferred. +.sp +Either Name or Type or both will be present. +.UNINDENT +.UNINDENT +.SS string Type [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Type of the object transferred being transferred. +.sp +Either Name or Type or both will be present. +.UNINDENT +.UNINDENT +.SS uint64 Time [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Time of the object being transferred if this is provided by the remote +party. +.UNINDENT +.UNINDENT +.SS uint64 Size [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Size of the object being transferred. +.sp +If the size is unknown, then this property will not be present. +.UNINDENT +.UNINDENT +.SS uint64 Transferred [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Number of bytes transferred. +.sp +For transfers with \fBStatus\fP set to \fB\(dqqueued\(dq\fP, this value will not +be present. +.UNINDENT +.UNINDENT +.SS string Filename [readonly, optional] +.INDENT 0.0 +.INDENT 3.5 +Complete name of the file being received or sent. +.sp +For incoming object push transaction, this will be the proposed default +location and name. It can be overwritten by the \fBAuthorizePush()\fP in +\fBorg.bluez.obex.Agent(5)\fP and will be then updated accordingly. +.UNINDENT +.UNINDENT +.\" Generated by docutils manpage writer. +. diff --git a/doc/org.bluez.obex.Transfer.rst b/doc/org.bluez.obex.Transfer.rst new file mode 100644 index 0000000000000000000000000000000000000000..733d82851f426bd2cff1e2e892961c04b2979a53 --- /dev/null +++ b/doc/org.bluez.obex.Transfer.rst @@ -0,0 +1,123 @@ +======================= +org.bluez.obex.Transfer +======================= + +------------------------------------------- +BlueZ D-Bus OBEX Transfer API documentation +------------------------------------------- + +:Version: BlueZ +:Date: October 2023 +:Manual section: 5 +:Manual group: Linux System Administration + +Interface +========= + +:Service: org.bluez.obex +:Interface: org.bluez.obex.Transfer1 +:Object path: [Session object path]/transfer{#} + +Methods +------- + +void Cancel() +````````````` + + Cancels the current transference. + + Possible errors: + + :org.bluez.obex.Error.NotAuthorized: + :org.bluez.obex.Error.InProgress: + :org.bluez.obex.Error.Failed: + +void Suspend() +`````````````` + + Suspends transference. + + Possible errors: + + :org.bluez.obex.Error.NotAuthorized: + :org.bluez.obex.Error.NotInProgress: + + If transfer is still in with **Status** **"queued"**. + +void Resume() +````````````` + + Resumes transference previously suspended with use of **Suspend()** + method. + + Possible errors: + + :org.bluez.obex.Error.NotAuthorized: + :org.bluez.obex.Error.NotInProgress: + + If transfer is still in with **Status** **"queued"**. + +Properties +---------- + +string Status [readonly] +```````````````````````` + + Indicates the current status of the transfer. + + Possible values: + + :"queued": + :"active": + :"suspended": + :"complete": + :"error": + +object Session [readonly] +````````````````````````` + + The object path of the session the transfer belongs to. + +string Name [readonly, optional] +```````````````````````````````` + + Name of the object being transferred. + + Either Name or Type or both will be present. + +string Type [readonly, optional] +```````````````````````````````` + + Type of the object transferred being transferred. + + Either Name or Type or both will be present. + +uint64 Time [readonly, optional] +```````````````````````````````` + + Time of the object being transferred if this is provided by the remote + party. + +uint64 Size [readonly, optional] +```````````````````````````````` + + Size of the object being transferred. + + If the size is unknown, then this property will not be present. + +uint64 Transferred [readonly, optional] +``````````````````````````````````````` + + Number of bytes transferred. + + For transfers with **Status** set to **"queued"**, this value will not + be present. + +string Filename [readonly, optional] +```````````````````````````````````` + + Complete name of the file being received or sent. + + For incoming object push transaction, this will be the proposed default + location and name. It can be overwritten by the **AuthorizePush()** in + **org.bluez.obex.Agent(5)** and will be then updated accordingly. diff --git a/doc/profile-api.txt b/doc/profile-api.txt deleted file mode 100644 index 183c6c11a7ba8eea1ed7df5ad6ae6c26da4f1776..0000000000000000000000000000000000000000 --- a/doc/profile-api.txt +++ /dev/null @@ -1,170 +0,0 @@ -BlueZ D-Bus Profile API description -*********************************** - - -Profile Manager hierarchy -========================= - -Service org.bluez -Interface org.bluez.ProfileManager1 -Object path /org/bluez - - void RegisterProfile(object profile, string uuid, dict options) - - This registers a profile implementation. - - If an application disconnects from the bus all - its registered profiles will be removed. - - Some predefined services: - - HFP AG UUID: 0000111f-0000-1000-8000-00805f9b34fb - - Default profile Version is 1.7, profile Features - is 0b001001 and RFCOMM channel is 13. - Authentication is required. - - HFP HS UUID: 0000111e-0000-1000-8000-00805f9b34fb - - Default profile Version is 1.7, profile Features - is 0b000000 and RFCOMM channel is 7. - Authentication is required. - - HSP AG UUID: 00001112-0000-1000-8000-00805f9b34fb - - Default profile Version is 1.2, RFCOMM channel - is 12 and Authentication is required. Does not - support any Features, option is ignored. - - HSP HS UUID: 00001108-0000-1000-8000-00805f9b34fb - - Default profile Version is 1.2, profile Features - is 0b0 and RFCOMM channel is 6. Authentication - is required. Features is one bit value, specify - capability of Remote Audio Volume Control - (by default turned off). - - Available options: - - string Name - - Human readable name for the profile - - string Service - - The primary service class UUID - (if different from the actual - profile UUID) - - string Role - - For asymmetric profiles that do not - have UUIDs available to uniquely - identify each side this - parameter allows specifying the - precise local role. - - Possible values: "client", "server" - - uint16 Channel - - RFCOMM channel number that is used - for client and server UUIDs. - - If applicable it will be used in the - SDP record as well. - - uint16 PSM - - PSM number that is used for client - and server UUIDs. - - If applicable it will be used in the - SDP record as well. - - boolean RequireAuthentication - - Pairing is required before connections - will be established. No devices will - be connected if not paired. - - boolean RequireAuthorization - - Request authorization before any - connection will be established. - - boolean AutoConnect - - In case of a client UUID this will - force connection of the RFCOMM or - L2CAP channels when a remote device - is connected. - - string ServiceRecord - - Provide a manual SDP record. - - uint16 Version - - Profile version (for SDP record) - - uint16 Features - - Profile features (for SDP record) - - Possible errors: org.bluez.Error.InvalidArguments - org.bluez.Error.AlreadyExists - - void UnregisterProfile(object profile) - - This unregisters the profile that has been previously - registered. The object path parameter must match the - same value that has been used on registration. - - Possible errors: org.bluez.Error.DoesNotExist - - -Profile hierarchy -================= - -Service unique name -Interface org.bluez.Profile1 -Object path freely definable - -Methods void Release() [noreply] - - This method gets called when the service daemon - unregisters the profile. A profile can use it to do - cleanup tasks. There is no need to unregister the - profile, because when this method gets called it has - already been unregistered. - - void NewConnection(object device, fd, dict fd_properties) - - This method gets called when a new service level - connection has been made and authorized. - - Common fd_properties: - - uint16 Version Profile version (optional) - uint16 Features Profile features (optional) - - Possible errors: org.bluez.Error.Rejected - org.bluez.Error.Canceled - - void RequestDisconnection(object device) - - This method gets called when a profile gets - disconnected. - - The file descriptor is no longer owned by the service - daemon and the profile implementation needs to take - care of cleaning up all connections. - - If multiple file descriptors are indicated via - NewConnection, it is expected that all of them - are disconnected before returning from this - method call. - - Possible errors: org.bluez.Error.Rejected - org.bluez.Error.Canceled diff --git a/doc/rfcomm.7 b/doc/rfcomm.7 new file mode 100644 index 0000000000000000000000000000000000000000..d69519d721ed5bd8bbb170c2a15eef6f645536f5 --- /dev/null +++ b/doc/rfcomm.7 @@ -0,0 +1,452 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "RFCOMM" "7" "May 2024" "BlueZ" "Linux System Administration" +.SH NAME +rfcomm \- RFCOMM protocol +.SH SYNOPSIS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +#include <sys/socket.h> +#include <bluetooth/bluetooth.h> +#include <bluetooth/rfcomm.h> + +rfcomm_socket = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); +.EE +.UNINDENT +.UNINDENT +.SH DESCRIPTION +.sp +The RFCOMM protocol provides emulation of serial ports over the L2CAP(7) +protocol. The protocol is based on the ETSI standard TS 07.10. +.sp +RFCOMM is a simple transport protocol, with additional provisions for emulating +the 9 circuits of RS\-232 (EIATIA\-232\-E) serial ports. +.SH SOCKET ADDRESS +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +struct sockaddr_rc { + sa_family_t rc_family; + unsigned short rc_bdaddr; + unsigned char rc_channel; +}; +.EE +.UNINDENT +.UNINDENT +.sp +Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +struct sockaddr_rc addr; + +memset(&addr, 0, sizeof(addr)); +addr.rc_family = AF_BLUETOOTH; +bacpy(&addr.rc_bdaddr, bdaddr); +addr.rc_channel = channel; +.EE +.UNINDENT +.UNINDENT +.SH SOCKET OPTIONS +.sp +The socket options listed below can be set by using \fBsetsockopt(2)\fP and read +with \fBgetsockopt(2)\fP with the socket level set to SOL_BLUETOOTH. +.SS BT_SECURITY (since Linux 2.6.30) +.sp +Channel security level, possible values: +.TS +box center; +l|l|l|l. +T{ +Value +T} T{ +Security Level +T} T{ +Link Key Type +T} T{ +Encryption +T} +_ +T{ +\fBBT_SECURITY_SDP\fP +T} T{ +0 (SDP Only) +T} T{ +None +T} T{ +Not required +T} +_ +T{ +\fBBT_SECURITY_LOW\fP +T} T{ +1 (Low) +T} T{ +Unauthenticated +T} T{ +Not required +T} +_ +T{ +\fBBT_SECURITY_MEDIUM\fP +T} T{ +2 (Medium \- default) +T} T{ +Unauthenticated +T} T{ +Desired +T} +_ +T{ +\fBBT_SECURITY_HIGH\fP +T} T{ +3 (High) +T} T{ +Authenticated +T} T{ +Required +T} +_ +T{ +\fBBT_SECURITY_FIPS\fP (since Linux 3.15) +T} T{ +4 (Secure Only) +T} T{ +Authenticated (P\-256 based Secure Simple Pairing and Secure Authentication) +T} T{ +Required +T} +.TE +.sp +Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +int level = BT_SECURITY_HIGH; +int err = setsockopt(rfcomm_socket, SOL_BLUETOOTH, BT_SECURITY, &level, + sizeof(level)); +if (err == \-1) { + perror(\(dqsetsockopt\(dq); + return 1; +} +.EE +.UNINDENT +.UNINDENT +.SS BT_DEFER_SETUP (since Linux 2.6.30) +.sp +Channel defer connection setup, this control if the connection procedure +needs to be authorized by userspace before responding which allows +authorization at profile level, possible values: +.TS +box center; +l|l|l. +T{ +Value +T} T{ +Description +T} T{ +Authorization +T} +_ +T{ +\fB0\fP +T} T{ +Disable (default) +T} T{ +Not required +T} +_ +T{ +\fB1\fP +T} T{ +Enable +T} T{ +Required +T} +.TE +.sp +Example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +int defer_setup = 1; +int err = setsockopt(rfcomm_socket, SOL_BLUETOOTH, BT_DEFER_SETUP, + &defer_setup, sizeof(defer_setup)); +if (err == \-1) { + perror(\(dqsetsockopt\(dq); + return err; +} + +err = listen(rfcomm_socket, 5); +if (err) { + perror(\(dqlisten\(dq); + return err; +} + +struct sockaddr_rc remote_addr = {0}; +socklen_t addr_len = sizeof(remote_addr); +int new_socket = accept(rfcomm_socket, (struct sockaddr*)&remote_addr, + &addr_len); +if (new_socket < 0) { + perror(\(dqaccept\(dq); + return new_socket; +} + +/* To complete the connection setup of new_socket read 1 byte */ +char c; +struct pollfd pfd; + +memset(&pfd, 0, sizeof(pfd)); +pfd.fd = new_socket; +pfd.events = POLLOUT; + +err = poll(&pfd, 1, 0); +if (err) { + perror(\(dqpoll\(dq); + return err; +} + +if (!(pfd.revents & POLLOUT)) { + err = read(sk, &c, 1); + if (err < 0) { + perror(\(dqread\(dq); + return err; + } +} +.EE +.UNINDENT +.UNINDENT +.SS BT_FLUSHABLE (since Linux 2.6.39) +.sp +Channel flushable flag, this control if the channel data can be flushed or +not, possible values: +.TS +box center; +l|l|l. +T{ +Define +T} T{ +Value +T} T{ +Description +T} +_ +T{ +\fBBT_FLUSHABLE_OFF\fP +T} T{ +0x00 (default) +T} T{ +Do not flush data +T} +_ +T{ +\fBBT_FLUSHABLE_ON\fP +T} T{ +0x01 +T} T{ +Flush data +T} +.TE +.SS BT_POWER (since Linux 3.1) +.sp +Channel power policy, this control if the channel shall force exit of sniff +mode or not, possible values: +.TS +box center; +l|l|l. +T{ +Define +T} T{ +Value +T} T{ +Description +T} +_ +T{ +\fBBT_POWER_FORCE_ACTIVE_OFF\fP +T} T{ +0x00 (default) +T} T{ +Don\(aqt force exit of sniff mode +T} +_ +T{ +\fBBT_POWER_FORCE_ACTIVE_ON\fP +T} T{ +0x01 +T} T{ +Force exit of sniff mode +T} +.TE +.SS BT_CHANNEL_POLICY (since Linux 3.10) +.sp +High\-speed (AMP) channel policy, possible values: +.TS +box center; +l|l|l. +T{ +Define +T} T{ +Value +T} T{ +Description +T} +_ +T{ +\fBBT_CHANNEL_POLICY_BREDR_ONLY\fP +T} T{ +0 (default) +T} T{ +BR/EDR only +T} +_ +T{ +\fBBT_CHANNEL_POLICY_BREDR_PREFERRED\fP +T} T{ +1 +T} T{ +BR/EDR Preferred +T} +_ +T{ +\fBBT_CHANNEL_POLICY_BREDR_PREFERRED\fP +T} T{ +2 +T} T{ +AMP Preferred +T} +.TE +.SS BT_PHY (since Linux 5.10) +.sp +Channel supported PHY(s), possible values: +.TS +box center; +l|l|l. +T{ +Define +T} T{ +Value +T} T{ +Description +T} +_ +T{ +\fBBT_PHY_BR_1M_1SLOT\fP +T} T{ +BIT 0 +T} T{ +BR 1Mbps 1SLOT +T} +_ +T{ +\fBBT_PHY_BR_1M_3SLOT\fP +T} T{ +BIT 1 +T} T{ +BR 1Mbps 3SLOT +T} +_ +T{ +\fBBT_PHY_BR_1M_5SLOT\fP +T} T{ +BIT 2 +T} T{ +BR 1Mbps 5SLOT +T} +_ +T{ +\fBBT_PHY_BR_2M_1SLOT\fP +T} T{ +BIT 3 +T} T{ +EDR 2Mbps 1SLOT +T} +_ +T{ +\fBBT_PHY_BR_2M_3SLOT\fP +T} T{ +BIT 4 +T} T{ +EDR 2Mbps 3SLOT +T} +_ +T{ +\fBBT_PHY_BR_2M_5SLOT\fP +T} T{ +BIT 5 +T} T{ +EDR 2Mbps 5SLOT +T} +_ +T{ +\fBBT_PHY_BR_3M_1SLOT\fP +T} T{ +BIT 6 +T} T{ +EDR 3Mbps 1SLOT +T} +_ +T{ +\fBBT_PHY_BR_3M_3SLOT\fP +T} T{ +BIT 7 +T} T{ +EDR 3Mbps 3SLOT +T} +_ +T{ +\fBBT_PHY_BR_3M_5SLOT\fP +T} T{ +BIT 8 +T} T{ +EDR 3Mbps 5SLOT +T} +.TE +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH SEE ALSO +.sp +socket(7), rctest(1) +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/doc/rfcomm.rst b/doc/rfcomm.rst new file mode 100644 index 0000000000000000000000000000000000000000..b20c7544b64ff622ba3a63b5553de9017d6bfba2 --- /dev/null +++ b/doc/rfcomm.rst @@ -0,0 +1,225 @@ +====== +rfcomm +====== + +--------------- +RFCOMM protocol +--------------- + +:Version: BlueZ +:Copyright: Free use of this software is granted under ther terms of the GNU + Lesser General Public Licenses (LGPL). +:Date: May 2024 +:Manual section: 7 +:Manual group: Linux System Administration + +SYNOPSIS +======== + +.. code-block:: + + #include <sys/socket.h> + #include <bluetooth/bluetooth.h> + #include <bluetooth/rfcomm.h> + + rfcomm_socket = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + +DESCRIPTION +=========== + +The RFCOMM protocol provides emulation of serial ports over the L2CAP(7) +protocol. The protocol is based on the ETSI standard TS 07.10. + +RFCOMM is a simple transport protocol, with additional provisions for emulating +the 9 circuits of RS-232 (EIATIA-232-E) serial ports. + +SOCKET ADDRESS +============== + +.. code-block:: + + struct sockaddr_rc { + sa_family_t rc_family; + unsigned short rc_bdaddr; + unsigned char rc_channel; + }; + +Example: + +.. code-block:: + + struct sockaddr_rc addr; + + memset(&addr, 0, sizeof(addr)); + addr.rc_family = AF_BLUETOOTH; + bacpy(&addr.rc_bdaddr, bdaddr); + addr.rc_channel = channel; + +SOCKET OPTIONS +============== + +The socket options listed below can be set by using **setsockopt(2)** and read +with **getsockopt(2)** with the socket level set to SOL_BLUETOOTH. + +BT_SECURITY (since Linux 2.6.30) +-------------------------------- + +Channel security level, possible values: + +.. csv-table:: + :header: "Value", "Security Level", "Link Key Type", "Encryption" + :widths: auto + + **BT_SECURITY_SDP**, 0 (SDP Only), None, Not required + **BT_SECURITY_LOW**, 1 (Low), Unauthenticated, Not required + **BT_SECURITY_MEDIUM**, 2 (Medium - default), Unauthenticated, Desired + **BT_SECURITY_HIGH**, 3 (High), Authenticated, Required + **BT_SECURITY_FIPS** (since Linux 3.15), 4 (Secure Only), Authenticated (P-256 based Secure Simple Pairing and Secure Authentication), Required + +Example: + +.. code-block:: + + int level = BT_SECURITY_HIGH; + int err = setsockopt(rfcomm_socket, SOL_BLUETOOTH, BT_SECURITY, &level, + sizeof(level)); + if (err == -1) { + perror("setsockopt"); + return 1; + } + +BT_DEFER_SETUP (since Linux 2.6.30) +----------------------------------- + +Channel defer connection setup, this control if the connection procedure +needs to be authorized by userspace before responding which allows +authorization at profile level, possible values: + +.. csv-table:: + :header: "Value", "Description", "Authorization" + :widths: auto + + **0**, Disable (default), Not required + **1**, Enable, Required + +Example: + +.. code-block:: + + int defer_setup = 1; + int err = setsockopt(rfcomm_socket, SOL_BLUETOOTH, BT_DEFER_SETUP, + &defer_setup, sizeof(defer_setup)); + if (err == -1) { + perror("setsockopt"); + return err; + } + + err = listen(rfcomm_socket, 5); + if (err) { + perror("listen"); + return err; + } + + struct sockaddr_rc remote_addr = {0}; + socklen_t addr_len = sizeof(remote_addr); + int new_socket = accept(rfcomm_socket, (struct sockaddr*)&remote_addr, + &addr_len); + if (new_socket < 0) { + perror("accept"); + return new_socket; + } + + /* To complete the connection setup of new_socket read 1 byte */ + char c; + struct pollfd pfd; + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = new_socket; + pfd.events = POLLOUT; + + err = poll(&pfd, 1, 0); + if (err) { + perror("poll"); + return err; + } + + if (!(pfd.revents & POLLOUT)) { + err = read(sk, &c, 1); + if (err < 0) { + perror("read"); + return err; + } + } + +BT_FLUSHABLE (since Linux 2.6.39) +--------------------------------- + +Channel flushable flag, this control if the channel data can be flushed or +not, possible values: + +.. csv-table:: + :header: "Define", "Value", "Description" + :widths: auto + + **BT_FLUSHABLE_OFF**, 0x00 (default), Do not flush data + **BT_FLUSHABLE_ON**, 0x01, Flush data + +BT_POWER (since Linux 3.1) +-------------------------- + +Channel power policy, this control if the channel shall force exit of sniff +mode or not, possible values: + +.. csv-table:: + :header: "Define", "Value", "Description" + :widths: auto + + **BT_POWER_FORCE_ACTIVE_OFF**, 0x00 (default), Don't force exit of sniff mode + **BT_POWER_FORCE_ACTIVE_ON**, 0x01, Force exit of sniff mode + +BT_CHANNEL_POLICY (since Linux 3.10) +------------------------------------ + +High-speed (AMP) channel policy, possible values: + +.. csv-table:: + :header: "Define", "Value", "Description" + :widths: auto + + **BT_CHANNEL_POLICY_BREDR_ONLY**, 0 (default), BR/EDR only + **BT_CHANNEL_POLICY_BREDR_PREFERRED**, 1, BR/EDR Preferred + **BT_CHANNEL_POLICY_BREDR_PREFERRED**, 2, AMP Preferred + +BT_PHY (since Linux 5.10) +------------------------- + +Channel supported PHY(s), possible values: + +.. csv-table:: + :header: "Define", "Value", "Description" + :widths: auto + + **BT_PHY_BR_1M_1SLOT**, BIT 0, BR 1Mbps 1SLOT + **BT_PHY_BR_1M_3SLOT**, BIT 1, BR 1Mbps 3SLOT + **BT_PHY_BR_1M_5SLOT**, BIT 2, BR 1Mbps 5SLOT + **BT_PHY_BR_2M_1SLOT**, BIT 3, EDR 2Mbps 1SLOT + **BT_PHY_BR_2M_3SLOT**, BIT 4, EDR 2Mbps 3SLOT + **BT_PHY_BR_2M_5SLOT**, BIT 5, EDR 2Mbps 5SLOT + **BT_PHY_BR_3M_1SLOT**, BIT 6, EDR 3Mbps 1SLOT + **BT_PHY_BR_3M_3SLOT**, BIT 7, EDR 3Mbps 3SLOT + **BT_PHY_BR_3M_5SLOT**, BIT 8, EDR 3Mbps 5SLOT + +RESOURCES +========= + +http://www.bluez.org + +REPORTING BUGS +============== + +linux-bluetooth@vger.kernel.org + +SEE ALSO +======== + +socket(7), rctest(1) diff --git a/doc/security-bugs.txt b/doc/security-bugs.txt deleted file mode 100644 index bd4b0d68f309c975a318138b4af180486015b66e..0000000000000000000000000000000000000000 --- a/doc/security-bugs.txt +++ /dev/null @@ -1,88 +0,0 @@ -Security bugs -============= - -BlueZ developers take security very seriously. As such, we'd like to know -when a security bug is found so that it can be fixed and disclosed as quickly -as possible. Please report security bugs to the BlueZ security team. - - -Contact -------- - -The BlueZ security team can be contacted by email at <security@bluez.org>. -This is a private list of security officers who will help verify the bug -report and develop and release a fix. If you already have a fix, please -include it with your report, as that can speed up the process considerably. - -As it is with any bug, the more information provided the easier it will -be to diagnose and fix. Any exploit code is very helpful and will not -be released without consent from the reporter unless it has already been -made public. - -Please send plain text emails without attachments where possible. - - -Disclosure and embargoed information ------------------------------------- - -The security list is not a disclosure channel. For that, see Coordination -below. - -Once a robust fix has been developed, the release process starts. Fixes -for publicly known bugs are released immediately. - -Although our preference is to release fixes for publicly undisclosed bugs -as soon as they become available, this may be postponed at the request of -the reporter or an affected party for up to 7 calendar days from the start -of the release process, with an exceptional extension to 14 calendar days -if it is agreed that the criticality of the bug requires more time. The -only valid reason for deferring the publication of a fix is to accommodate -the logistics of QA and large scale rollouts which require release -coordination. - -While embargoed information may be shared with trusted individuals in -order to develop a fix, such information will not be published alongside -the fix or on any other disclosure channel without the permission of the -reporter. This includes but is not limited to the original bug report -and followup discussions (if any), exploits, CVE information or the -identity of the reporter. - -In other words our only interest is in getting bugs fixed. All other -information submitted to the security list and any followup discussions -of the report are treated confidentially even after the embargo has been -lifted, in perpetuity. - - -Coordination ------------- - -Fixes for sensitive bugs, such as those that might lead to privilege -escalations, may need to be coordinated with the private -<linux-distros@vs.openwall.org> mailing list so that distribution vendors -are well prepared to issue a fixed package upon public disclosure of the -upstream fix. Distros will need some time to test the proposed patch and -will generally request at least a few days of embargo, and vendor update -publication prefers to happen Tuesday through Thursday. When appropriate, -the security team can assist with this coordination, or the reporter can -include linux-distros from the start. In this case, remember to prefix -the email Subject line with "[vs]" as described in the linux-distros wiki: -<http://oss-security.openwall.org/wiki/mailing-lists/distros#how-to-use-the-lists> - - -CVE assignment --------------- - -The security team does not normally assign CVEs, nor do we require them -for reports or fixes, as this can needlessly complicate the process and -may delay the bug handling. If a reporter wishes to have a CVE identifier -assigned ahead of public disclosure, they will need to contact the private -linux-distros list, described above. When such a CVE identifier is known -before a patch is provided, it is desirable to mention it in the commit -message if the reporter agrees. - - -Non-disclosure agreements -------------------------- - -The BlueZ security team is not a formal body and therefore unable to enter -any non-disclosure agreements. diff --git a/doc/test-runner.rst b/doc/test-runner.rst new file mode 100644 index 0000000000000000000000000000000000000000..423a9379c0ab688f28cd46135f960c4c4b4b6a81 --- /dev/null +++ b/doc/test-runner.rst @@ -0,0 +1,178 @@ +=========== +test-runner +=========== + +**test-runner** [*OPTIONS*] -- <test-name> + +DESCRIPTION +=========== + +**test-runner(1)** is used to test Kernel changes to the Bluetooth subsystem, +it lunches a virtual machine using qemu(1) and mounts the local filesystem +using virtio (9p). + +OPTIONS +======= + +:-a:--auto: Find tests and run them +:-b/--dbus: Start D-Bus system daemon +:-s/--dbus-session: Start D-Bus session daemon +:-d/--daemon: Start bluetoothd +:-m/--monitor: Start btmon +:-l/--emulator: Start btvirt +:-A/-audio[=path]: Start audio server +:-u/--unix[=path]: Provide serial device +:-q/--qemu=<path>: QEMU binary +:-k/--kernel=<image>: Kernel image (bzImage) +:-h/--help: Show help options + +Kernel +====== + +The test-runner tool requires a kernel that is at least build with these +minimal options for a successful boot. These options should be installed as +.config in the kernel source directory followed by: + +.. code-block:: + + make olddefconfig + +After that a default kernel with the required options can be built. More +option (like the Bluetooth subsystem) can be enabled on top of this. + +.. code-block:: + + CONFIG_VIRTIO=y + CONFIG_VIRTIO_PCI=y + + CONFIG_NET=y + CONFIG_INET=y + + CONFIG_NET_9P=y + CONFIG_NET_9P_VIRTIO=y + + CONFIG_9P_FS=y + CONFIG_9P_FS_POSIX_ACL=y + + CONFIG_SERIAL_8250=y + CONFIG_SERIAL_8250_CONSOLE=y + CONFIG_SERIAL_8250_PCI=yCONFIG_DEBUG_KERNEL=y + CONFIG_SERIAL_8250_NR_UARTS=4 + + CONFIG_TMPFS=y + CONFIG_TMPFS_POSIX_ACL=y + CONFIG_TMPFS_XATTR=y + + CONFIG_DEVTMPFS=y + CONFIG_DEBUG_FS=y + +Bluetooth +--------- + +.. code-block:: + + CONFIG_BT=y + CONFIG_BT_BREDR=y + CONFIG_BT_RFCOMM=y + CONFIG_BT_BNEP=y + CONFIG_BT_HIDP=y + CONFIG_BT_LE=y + + CONFIG_BT_HCIUART=y + CONFIG_BT_HCIUART_H4=y + CONFIG_BT_HCIVHCI=y + + CONFIG_CRYPTO_CMAC=y + CONFIG_CRYPTO_USER_API=y + CONFIG_CRYPTO_USER_API_HASH=y + CONFIG_CRYPTO_USER_API_SKCIPHER=y + + CONFIG_UNIX=y + + CONFIG_UHID=y + +Lock debuging +------------- + +To catch locking related issues the following set of kernel config +options may be useful: + +.. code-block:: + + CONFIG_DEBUG_KERNEL=y + CONFIG_LOCKDEP_SUPPORT=y + CONFIG_DEBUG_SPINLOCK=y + CONFIG_DEBUG_LOCK_ALLOC=y + CONFIG_DEBUG_ATOMIC_SLEEP=y + CONFIG_PROVE_LOCKING=y + CONFIG_PROVE_RCU=y + CONFIG_LOCKDEP=y + CONFIG_DEBUG_MUTEXES=y + CONFIG_KASAN=y + +EXAMPLES +======== + +Running mgmt-tester +------------------- + +.. code-block:: + + $ tools/test-runner -k /pathto/bzImage -- tools/mgmt-tester + +Running a specific test of mgmt-tester +-------------------------------------- + +.. code-block:: + + $ tools/test-runner -k /pathto/bzImage -- tools/mgmt-tester -s "<name>" + +Running bluetoothctl with emulated controller +--------------------------------------------- + +.. code-block:: + + $ tools/test-runner -l -d -k /pathto/bzImage -- client/bluetoothctl + [CHG] Controller 00:AA:01:00:00:00 Pairable: yes + [bluetooth]# + +Running bluetoothctl with emulated controller and audio support +--------------------------------------------------------------- + +.. code-block:: + + $ tools/test-runner -l -d -A -k /pathto/bzImage -- client/bluetoothctl + [CHG] Controller 00:AA:01:00:00:00 Pairable: yes + [bluetooth]# + [CHG] Controller 00:AA:01:00:00:00 Pairable: yes + [CHG] Controller 00:AA:01:00:00:00 Class: 0x00600000 (6291456) + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 0000110e-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 0000111f-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 00001200-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 0000110b-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 0000110a-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 0000110c-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 00001800-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 00001801-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 0000180a-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 0000111e-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 Class: 0x006c0000 (7077888) + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 0000110e-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 0000111f-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 00001200-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 0000110b-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 0000110a-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 0000110c-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 00001800-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 00001801-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 0000180a-0000-1000-8000-00805f9b34fb + [CHG] Controller 00:AA:01:00:00:00 UUIDs: 0000111e-0000-1000-8000-00805f9b34fb + +Running shell with host controller using btproxy +------------------------------------------------ + +.. code-block:: + + $ tools/btproxy -u [1] + $ tools/test-runner -u -d -k /pathto/bzImage -- /bin/bash [2] + diff --git a/doc/test-runner.txt b/doc/test-runner.txt deleted file mode 100644 index 019c231889c888bc343259a8ef284a915865453c..0000000000000000000000000000000000000000 --- a/doc/test-runner.txt +++ /dev/null @@ -1,82 +0,0 @@ -Notes for test-runner usage -*************************** - - -Kernel configuration -==================== - -The test-runner tool requires a kernel that is at least build with these -minimal options for a successful boot. - - CONFIG_VIRTIO=y - CONFIG_VIRTIO_PCI=y - - CONFIG_NET=y - CONFIG_INET=y - - CONFIG_NET_9P=y - CONFIG_NET_9P_VIRTIO=y - - CONFIG_9P_FS=y - CONFIG_9P_FS_POSIX_ACL=y - - CONFIG_SERIAL_8250=y - CONFIG_SERIAL_8250_CONSOLE=y - CONFIG_SERIAL_8250_PCI=y - CONFIG_SERIAL_8250_NR_UARTS=4 - - CONFIG_TMPFS=y - CONFIG_TMPFS_POSIX_ACL=y - CONFIG_TMPFS_XATTR=y - - CONFIG_DEVTMPFS=y - CONFIG_DEBUG_FS=y - -For Bluetooth functionality: - - CONFIG_BT=y - CONFIG_BT_BREDR=y - CONFIG_BT_RFCOMM=y - CONFIG_BT_BNEP=y - CONFIG_BT_HIDP=y - CONFIG_BT_LE=y - - CONFIG_BT_HCIUART=y - CONFIG_BT_HCIUART_H4=y - CONFIG_BT_HCIVHCI=y - - CONFIG_CRYPTO_CMAC=y - CONFIG_CRYPTO_USER_API=y - CONFIG_CRYPTO_USER_API_HASH=y - CONFIG_CRYPTO_USER_API_SKCIPHER=y - - CONFIG_UNIX=y - - CONFIG_UHID=y - -For Audio functionality: - CONFIG_SYSVIPC=y - CONFIG_SOUND=y - CONFIG_SND=y - CONFIG_SND_INTEL8X0=y - -These options should be installed as .config in the kernel source directory -followed by this command. - - make olddefconfig - -After that a default kernel with the required options can be built. More -option (like the Bluetooth subsystem) can be enabled on top of this. - -Lock debuging -------------- - -To catch locking related issues the following set of kernel config -options may be useful: - - CONFIG_LOCKDEP_SUPPORT=y - CONFIG_DEBUG_SPINLOCK=y - CONFIG_DEBUG_LOCK_ALLOC=y - CONFIG_PROVE_LOCKING=y - CONFIG_LOCKDEP=y - CONFIG_DEBUG_MUTEXES=y diff --git a/doc/tester.config b/doc/tester.config deleted file mode 100644 index 4429a72223fc4896a2be1032dd5230500a890324..0000000000000000000000000000000000000000 --- a/doc/tester.config +++ /dev/null @@ -1,56 +0,0 @@ -CONFIG_PCI=y -CONFIG_VIRTIO=y -CONFIG_VIRTIO_PCI=y - -CONFIG_NET=y -CONFIG_INET=y - -CONFIG_NET_9P=y -CONFIG_NET_9P_VIRTIO=y - -CONFIG_9P_FS=y -CONFIG_9P_FS_POSIX_ACL=y - -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_PCI=y -CONFIG_SERIAL_8250_NR_UARTS=4 - -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_TMPFS_XATTR=y - -CONFIG_DEVTMPFS=y -CONFIG_DEBUG_FS=y - -CONFIG_BT=y -CONFIG_BT_BREDR=y -CONFIG_BT_RFCOMM=y -CONFIG_BT_BNEP=y -CONFIG_BT_HIDP=y -CONFIG_BT_LE=y -CONFIG_BT_HS=y -CONFIG_BT_MSFTEXT=y -CONFIG_BT_AOSPEXT=y -CONFIG_BT_FEATURE_DEBUG=y - -CONFIG_BT_HCIUART=y -CONFIG_BT_HCIUART_H4=y -CONFIG_BT_HCIVHCI=y - -CONFIG_CRYPTO_CMAC=y -CONFIG_CRYPTO_USER_API=y -CONFIG_CRYPTO_USER_API_HASH=y -CONFIG_CRYPTO_USER_API_SKCIPHER=y - -CONFIG_UNIX=y - -CONFIG_UHID=y - -CONFIG_LOCKDEP_SUPPORT=y -CONFIG_DEBUG_SPINLOCK=y -CONFIG_DEBUG_LOCK_ALLOC=y -CONFIG_PROVE_LOCKING=y -CONFIG_LOCKDEP=y -CONFIG_DEBUG_MUTEXES=y -CONFIG_KASAN=y diff --git a/doc/thermometer-api.txt b/doc/thermometer-api.txt deleted file mode 100644 index c7c8a5dadee02adaf81455627e3ebd0a3a511523..0000000000000000000000000000000000000000 --- a/doc/thermometer-api.txt +++ /dev/null @@ -1,134 +0,0 @@ -BlueZ D-Bus Thermometer API description -*************************************** - - Santiago Carot-Nemesio <sancane@gmail.com> - -Health Thermometer Manager hierarchy -==================================== - -Service org.bluez -Interface org.bluez.ThermometerManager1 -Object path [variable prefix]/{hci0,hci1,...} - -Methods RegisterWatcher(object agent) - - Registers a watcher to monitor scanned measurements. - This agent will be notified about final temperature - measurements. - - Possible Errors: org.bluez.Error.InvalidArguments - - UnregisterWatcher(object agent) - - Unregisters a watcher. - - EnableIntermediateMeasurement(object agent) - - Enables intermediate measurement notifications - for this agent. Intermediate measurements will - be enabled only for thermometers which support it. - - Possible Errors: org.bluez.Error.InvalidArguments - - DisableIntermediateMeasurement(object agent) - - Disables intermediate measurement notifications - for this agent. It will disable notifications in - thermometers when the last agent removes the - watcher for intermediate measurements. - - Possible Errors: org.bluez.Error.InvalidArguments - org.bluez.Error.NotFound - -Health Thermometer Profile hierarchy -==================================== - -Service org.bluez -Interface org.bluez.Thermometer1 -Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX - - -Properties boolean Intermediate [readonly] - - True if the thermometer supports intermediate - measurement notifications. - - uint16 Interval (optional) [readwrite] - - The Measurement Interval defines the time (in - seconds) between measurements. This interval is - not related to the intermediate measurements and - must be defined into a valid range. Setting it - to zero means that no periodic measurements will - be taken. - - uint16 Maximum (optional) [readonly] - - Defines the maximum value allowed for the interval - between periodic measurements. - - uint16 Minimum (optional) [readonly] - - Defines the minimum value allowed for the interval - between periodic measurements. - - -Health Thermometer Watcher hierarchy -==================================== - -Service unique name -Interface org.bluez.ThermometerWatcher1 -Object path freely definable - -Methods void MeasurementReceived(dict measurement) - - This callback gets called when a measurement has been - scanned in the thermometer. - - Measurement: - - int16 Exponent: - int32 Mantissa: - - Exponent and Mantissa values as - extracted from float value defined by - IEEE-11073-20601. - - Measurement value is calculated as - (Mantissa) * (10^Exponent) - - For special cases Exponent is - set to 0 and Mantissa is set to - one of following values: - - +(2^23 - 1) NaN (invalid or - missing data) - -(2^23) NRes - +(2^23 - 2) +Infinity - -(2^23 - 2) -Infinity - - string Unit: - - Possible values: "celsius" or - "fahrenheit" - - uint64 Time (optional): - - Time of measurement, if - supported by device. - Expressed in seconds since epoch. - - string Type (optional): - - Only present if measurement type - is known. - - Possible values: "armpit", "body", - "ear", "finger", "intestines", - "mouth", "rectum", "toe", - "tympanum" - - string Measurement: - - Possible values: "final" or - "intermediate" diff --git a/ell/asn1-private.h b/ell/asn1-private.h new file mode 100644 index 0000000000000000000000000000000000000000..08f04baa693dec50931d7d82224b4ededf4228f7 --- /dev/null +++ b/ell/asn1-private.h @@ -0,0 +1,193 @@ +/* + * Embedded Linux library + * Copyright (C) 2017 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#define ASN1_ID(class, pc, tag) (((class) << 6) | ((pc) << 5) | (tag)) + +#define ASN1_CLASS_UNIVERSAL 0 +#define ASN1_CLASS_CONTEXT 2 + +#define ASN1_ID_SEQUENCE ASN1_ID(ASN1_CLASS_UNIVERSAL, 1, 0x10) +#define ASN1_ID_SET ASN1_ID(ASN1_CLASS_UNIVERSAL, 1, 0x11) +#define ASN1_ID_BOOLEAN ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x01) +#define ASN1_ID_INTEGER ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x02) +#define ASN1_ID_BIT_STRING ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x03) +#define ASN1_ID_OCTET_STRING ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x04) +#define ASN1_ID_NULL ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x05) +#define ASN1_ID_OID ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x06) +#define ASN1_ID_UTF8STRING ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x0c) +#define ASN1_ID_PRINTABLESTRING ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x13) +#define ASN1_ID_IA5STRING ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x16) +#define ASN1_ID_UTCTIME ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x17) +#define ASN1_ID_GENERALIZEDTIME ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x18) + +struct asn1_oid { + uint8_t asn1_len; + uint8_t asn1[11]; +}; + +#define asn1_oid_eq(oid1, oid2_len, oid2_string) \ + ((oid1)->asn1_len == (oid2_len) && \ + !memcmp((oid1)->asn1, (oid2_string), (oid2_len))) + +#if __STDC_VERSION__ <= 199409L +#define inline __inline__ +#endif + +static inline int asn1_parse_definite_length(const uint8_t **buf, + size_t *len) +{ + int n; + size_t result = 0; + + /* Decrease the buffer length left */ + if ((*len)-- < 1) + return -1; + + /* + * If short form length, move the pointer to start of data and + * return the data length. + */ + if (!(**buf & 0x80)) + return *(*buf)++; + + n = *(*buf)++ & 0x7f; + if ((size_t) n > *len) + return -1; + + *len -= n; + while (n--) + result = (result << 8) | *(*buf)++; + + return result; +} + +static inline void asn1_write_definite_length(uint8_t **buf, size_t len) +{ + int n; + + if (len < 0x80) { + *(*buf)++ = len; + return; + } + + for (n = 1; len >> (n * 8); n++); + *(*buf)++ = 0x80 | n; + + while (n--) + *(*buf)++ = len >> (n * 8); +} + +#define ASN1_CONTEXT_IMPLICIT(tag) (0x1000 | (tag)) +#define ASN1_CONTEXT_EXPLICIT(tag) (0x2000 | (tag)) + +/* + * Return the tag, length and value of the @index'th + * non-context-specific-tagged element in a DER SEQUENCE or one who's + * ASN1_CONTEXT_IMPLICIT(tag) matches @index or the inner element of + * the one who's ASN1_CONTEXT_EXPLICIT(tag) matches @index. + */ +static inline const uint8_t *asn1_der_find_elem(const uint8_t *buf, + size_t len_in, int index, + uint8_t *tag, size_t *len_out) +{ + int n = 0; + + while (1) { + int tlv_len; + + if (len_in < 2) + return NULL; + + *tag = *buf++; + len_in--; + + tlv_len = asn1_parse_definite_length((void *) &buf, &len_in); + if (tlv_len < 0 || (size_t) tlv_len > len_in) + return NULL; + + if (*tag >> 6 != ASN1_CLASS_CONTEXT) { + if (n++ == index) { + *len_out = tlv_len; + return buf; + } + } else if ((*tag & 0x1f) == (index & 0xfff)) { + /* Context-specific tag */ + if (index & 0x1000) { /* Implicit */ + *len_out = tlv_len; + return buf; + } else if (index & 0x2000) { /* Explicit */ + const uint8_t *outer = buf; + int inner_len; + + if (!(*tag & 0x20)) /* Primitive */ + return NULL; + + if (tlv_len < 2) + return NULL; + + *tag = *buf++; + + inner_len = asn1_parse_definite_length( + (void *) &buf, &len_in); + if (outer + tlv_len != buf + inner_len) + return NULL; + + *len_out = inner_len; + return buf; + } + } + + buf += tlv_len; + len_in -= tlv_len; + } +} + +/* Return an element in a DER SEQUENCE structure by path */ +static inline const uint8_t *asn1_der_find_elem_by_path(const uint8_t *buf, + size_t len_in, uint8_t tag, + size_t *len_out, ...) +{ + int index; + va_list vl; + + va_start(vl, len_out); + + index = va_arg(vl, int); + + while (index != -1) { + uint8_t elem_tag; + uint8_t expect_tag; + int prev_index = index; + + buf = asn1_der_find_elem(buf, len_in, index, + &elem_tag, &len_in); + if (!buf) { + va_end(vl); + return NULL; + } + + index = va_arg(vl, int); + + if (prev_index & 0x1000) + expect_tag = ASN1_ID(ASN1_CLASS_CONTEXT, + index != -1 ? 1 : + ((elem_tag >> 5) & 1), + prev_index & 0xfff); + else + expect_tag = (index == -1) ? tag : ASN1_ID_SEQUENCE; + + if (elem_tag != expect_tag) { + va_end(vl); + return NULL; + } + } + + va_end(vl); + + *len_out = len_in; + return buf; +} diff --git a/ell/base64.c b/ell/base64.c new file mode 100644 index 0000000000000000000000000000000000000000..bfd78579d05460a80560fba99d18af950175205c --- /dev/null +++ b/ell/base64.c @@ -0,0 +1,163 @@ +/* + * Embedded Linux library + * Copyright (C) 2015 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdint.h> + +#include "utf8.h" +#include "base64.h" +#include "private.h" +#include "useful.h" + +#include <stdio.h> + +LIB_EXPORT uint8_t *l_base64_decode(const char *in, size_t in_len, + size_t *n_written) +{ + const char *ptr, *in_end = in + in_len; + const char *base64_end = NULL; + uint8_t *out_buf, *out; + int base64_len = 0, pad_len = 0; + uint16_t reg = 0; + + for (ptr = in; ptr < in_end; ptr++) { + if (l_ascii_isspace(*ptr)) + /* Whitespace */ + continue; + else if (*ptr == '=') { + /* Final padding */ + if (!pad_len) + base64_end = ptr; + + pad_len++; + } else if (!pad_len && (l_ascii_isalnum(*ptr) || *ptr == '+' || + *ptr == '/')) + /* Base64 character */ + base64_len++; + else + /* Bad character */ + return NULL; + } + + if (ptr != in_end) + return NULL; + + if ((base64_len & 3) == 1) + /* Invalid length */ + return NULL; + + if (pad_len != align_len(base64_len, 4) - base64_len) + return NULL; + + /* No padding */ + if (!base64_end) + base64_end = ptr; + + *n_written = base64_len * 3 / 4; + out_buf = l_malloc(*n_written); + + out = out_buf; + base64_len = 0; + + for (ptr = in; ptr < base64_end; ptr++) { + if (l_ascii_isspace(*ptr)) + /* Whitespace */ + continue; + + /* Base64 character */ + reg <<= 6; + if (l_ascii_isupper(*ptr)) + reg |= *ptr - 'A' + 0; + else if (l_ascii_islower(*ptr)) + reg |= *ptr - 'a' + 26; + else if (l_ascii_isdigit(*ptr)) + reg |= *ptr - '0' + 52; + else if (*ptr == '+') + reg |= 62; + else if (*ptr == '/') + reg |= 63; + + if ((base64_len & 3) == 1) + *out++ = reg >> 4; + else if ((base64_len & 3) == 2) + *out++ = reg >> 2; + else if ((base64_len & 3) == 3) + *out++ = reg >> 0; + + base64_len++; + } + + return out_buf; +} + +LIB_EXPORT char *l_base64_encode(const uint8_t *in, size_t in_len, int columns) +{ + const uint8_t *in_end = in + in_len; + char *out_buf, *out; + size_t out_len; + uint32_t reg; + uint8_t idx; + int i, pad = 4; + int col = 0; + + /* For simplicity allow multiples of 4 only */ + if (columns & 3) + return NULL; + + out_len = (in_len + 2) / 3 * 4; + + if (columns && out_len) + out_len += (out_len - 4) / columns; + + out_buf = l_malloc(out_len + 1); + + out = out_buf; + + while (in < in_end) { + reg = *in++ << 16; + + if (in < in_end) + reg |= *in++ << 8; + else + pad--; + + if (in < in_end) + reg |= *in++ << 0; + else + pad--; + + if (columns && col == columns) { + *out++ = '\n'; + col = 0; + } + col += 4; + + for (i = 0; i < pad; i++) { + idx = (reg >> 18) & 63; + reg <<= 6; + + if (idx < 26) + *out++ = idx + 'A'; + else if (idx < 52) + *out++ = idx - 26 + 'a'; + else if (idx < 62) + *out++ = idx - 52 + '0'; + else + *out++ = (idx == 62) ? '+' : '/'; + } + } + + for (; pad < 4; pad++) + *out++ = '='; + + *out = '\0'; + + return out_buf; +} diff --git a/ell/base64.h b/ell/base64.h new file mode 100644 index 0000000000000000000000000000000000000000..9c1cc5eb3507a1735ef09d682f1cfefbb77bf624 --- /dev/null +++ b/ell/base64.h @@ -0,0 +1,23 @@ +/* + * Embedded Linux library + * Copyright (C) 2015 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_BASE64_H +#define __ELL_BASE64_H + +#ifdef __cplusplus +extern "C" { +#endif + +uint8_t *l_base64_decode(const char *in, size_t in_len, size_t *n_written); + +char *l_base64_encode(const uint8_t *in, size_t in_len, int columns); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_BASE64_H */ diff --git a/ell/cert-crypto.c b/ell/cert-crypto.c new file mode 100644 index 0000000000000000000000000000000000000000..b19f85c5bed1dfaf980789b9cc15a2f4fec936cb --- /dev/null +++ b/ell/cert-crypto.c @@ -0,0 +1,787 @@ +/* + * Embedded Linux library + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <unistd.h> +#include <stdarg.h> +#include <string.h> +#include <strings.h> + +#include "checksum.h" +#include "cipher.h" +#include "useful.h" +#include "utf8.h" +#include "asn1-private.h" +#include "private.h" +#include "missing.h" +#include "cert.h" +#include "cert-private.h" + +/* RFC8018 section 5.1 */ +LIB_EXPORT bool l_cert_pkcs5_pbkdf1(enum l_checksum_type type, + const char *password, + const uint8_t *salt, size_t salt_len, + unsigned int iter_count, + uint8_t *out_dk, size_t dk_len) +{ + size_t hash_len, t_len; + uint8_t t[20 + salt_len + strlen(password)]; + struct l_checksum *checksum; + + switch (type) { + case L_CHECKSUM_MD5: + hash_len = 16; + break; + case L_CHECKSUM_SHA1: + hash_len = 20; + break; + case L_CHECKSUM_NONE: + case L_CHECKSUM_MD4: + case L_CHECKSUM_SHA224: + case L_CHECKSUM_SHA256: + case L_CHECKSUM_SHA384: + case L_CHECKSUM_SHA512: + return false; + default: + return false; + } + + if (dk_len > hash_len) + return false; + + checksum = l_checksum_new(type); + if (!checksum) + return false; + + memcpy(t, password, strlen(password)); + memcpy(t + strlen(password), salt, salt_len); + t_len = strlen(password) + salt_len; + + while (iter_count) { + l_checksum_reset(checksum); + + if (!l_checksum_update(checksum, t, t_len)) + break; + + if (l_checksum_get_digest(checksum, t, hash_len) != + (ssize_t) hash_len) + break; + + t_len = hash_len; + iter_count--; + } + + l_checksum_free(checksum); + + if (!iter_count) + memcpy(out_dk, t, dk_len); + + explicit_bzero(t, sizeof(t)); + return !iter_count; +} + +/* RFC8018 section 5.2 */ +LIB_EXPORT bool l_cert_pkcs5_pbkdf2(enum l_checksum_type type, + const char *password, + const uint8_t *salt, size_t salt_len, + unsigned int iter_count, + uint8_t *out_dk, size_t dk_len) +{ + size_t h_len; + struct l_checksum *checksum; + unsigned int i; + + switch (type) { + case L_CHECKSUM_SHA1: + h_len = 20; + break; + case L_CHECKSUM_SHA224: + h_len = 28; + break; + case L_CHECKSUM_SHA256: + h_len = 32; + break; + case L_CHECKSUM_SHA384: + h_len = 48; + break; + case L_CHECKSUM_SHA512: + h_len = 64; + break; + case L_CHECKSUM_NONE: + case L_CHECKSUM_MD4: + case L_CHECKSUM_MD5: + return false; + default: + return false; + } + + checksum = l_checksum_new_hmac(type, password, strlen(password)); + if (!checksum) + return false; + + for (i = 1; dk_len; i++) { + unsigned int j, k; + uint8_t u[salt_len + 64]; + size_t u_len; + size_t block_len = h_len; + + if (block_len > dk_len) + block_len = dk_len; + + memset(out_dk, 0, block_len); + + memcpy(u, salt, salt_len); + l_put_be32(i, u + salt_len); + u_len = salt_len + 4; + + for (j = 0; j < iter_count; j++) { + l_checksum_reset(checksum); + + if (!l_checksum_update(checksum, u, u_len)) + break; + + if (l_checksum_get_digest(checksum, u, h_len) != + (ssize_t) h_len) + break; + + u_len = h_len; + + for (k = 0; k < block_len; k++) + out_dk[k] ^= u[k]; + } + + if (j < iter_count) + break; + + out_dk += block_len; + dk_len -= block_len; + } + + l_checksum_free(checksum); + + return !dk_len; +} + +/* RFC7292 Appendix B */ +uint8_t *cert_pkcs12_pbkdf(const char *password, + const struct cert_pkcs12_hash *hash, + const uint8_t *salt, size_t salt_len, + unsigned int iterations, uint8_t id, + size_t key_len) +{ + /* All lengths in bytes instead of bits */ + size_t passwd_len = password ? 2 * strlen(password) + 2 : 0; + uint8_t *bmpstring; + /* Documented as v(ceiling(s/v)), usually will just equal v */ + unsigned int s_len = (salt_len + hash->v - 1) & ~(hash->v - 1); + /* Documented as p(ceiling(s/p)), usually will just equal v */ + unsigned int p_len = password ? + (passwd_len + hash->v - 1) & ~(hash->v - 1) : 0; + uint8_t di[hash->v + s_len + p_len]; + uint8_t *ptr; + unsigned int j; + uint8_t *key; + unsigned int bytes; + struct l_checksum *h = l_checksum_new(hash->alg); + + if (!h) + return NULL; + + /* + * The BMPString encoding, in practice same as UCS-2, can end up + * at 2 * strlen(password) + 2 bytes or shorter depending on the + * characters used. Recalculate p_len after we know it. + * Important: The password must be valid UTF-8 here. + */ + if (p_len) { + if (!(bmpstring = l_utf8_to_ucs2be(password, &passwd_len))) { + l_checksum_free(h); + return NULL; + } + + p_len = (passwd_len + hash->v - 1) & ~(hash->v - 1); + } + + memset(di, id, hash->v); + ptr = di + hash->v; + + for (j = salt_len; j < s_len; j += salt_len, ptr += salt_len) + memcpy(ptr, salt, salt_len); + + if (s_len) { + memcpy(ptr, salt, s_len + salt_len - j); + ptr += s_len + salt_len - j; + } + +_Pragma("GCC diagnostic push") +_Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") + if (p_len) { + for (j = passwd_len; j < p_len; + j += passwd_len, ptr += passwd_len) + memcpy(ptr, bmpstring, passwd_len); + + memcpy(ptr, bmpstring, p_len + passwd_len - j); + + explicit_bzero(bmpstring, passwd_len); + l_free(bmpstring); + } +_Pragma("GCC diagnostic pop") + + key = l_malloc(key_len + hash->len); + + for (bytes = 0; bytes < key_len; bytes += hash->u) { + uint8_t b[hash->v]; + uint8_t *input = di; + unsigned int input_len = hash->v + s_len + p_len; + + for (j = 0; j < iterations; j++) { + if (!l_checksum_update(h, input, input_len) || + l_checksum_get_digest(h, + key + bytes, + hash->len) <= 0) { + l_checksum_free(h); + l_free(key); + return NULL; + } + + input = key + bytes; + input_len = hash->u; + l_checksum_reset(h); + } + + if (bytes + hash->u >= key_len) + break; + + for (j = 0; j < hash->v - hash->u; j += hash->u) + memcpy(b + j, input, hash->u); + + memcpy(b + j, input, hash->v - j); + + ptr = di + hash->v; + for (j = 0; j < s_len + p_len; j += hash->v, ptr += hash->v) { + unsigned int k; + uint16_t carry = 1; + + /* + * Not specified in the RFC7292 but implementations + * sum these octet strings as big-endian integers. + * We could use 64-bit additions here but the benefit + * may not compensate the cost of the byteswapping. + */ + for (k = hash->v - 1; k > 0; k--) { + carry = ptr[k] + b[k] + carry; + ptr[k] = carry; + carry >>= 8; + } + + ptr[k] += b[k] + carry; + explicit_bzero(&carry, sizeof(carry)); + } + + explicit_bzero(b, sizeof(b)); + } + + explicit_bzero(di, sizeof(di)); + l_checksum_free(h); + return key; +} + +/* RFC7292 Appendix A */ +static const struct cert_pkcs12_hash pkcs12_sha1_hash = { + .alg = L_CHECKSUM_SHA1, + .len = 20, + .u = 20, + .v = 64, + .oid = { 5, { 0x2b, 0x0e, 0x03, 0x02, 0x1a } }, +}; + +/* RFC8018 Section A.2 */ +static struct asn1_oid pkcs5_pbkdf2_oid = { + 9, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c } +}; + +/* RFC8018 Section A.4 */ +static struct asn1_oid pkcs5_pbes2_oid = { + 9, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0d } +}; + +/* RFC8018 Section A.3 */ +static const struct pkcs5_pbes1_encryption_oid { + enum l_checksum_type checksum_type; + enum l_cipher_type cipher_type; + struct asn1_oid oid; +} pkcs5_pbes1_encryption_oids[] = { + { /* pbeWithMD5AndDES-CBC */ + L_CHECKSUM_MD5, L_CIPHER_DES_CBC, + { 9, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x03 } }, + }, + { /* pbeWithSHA1AndDES-CBC */ + L_CHECKSUM_SHA1, L_CIPHER_DES_CBC, + { 9, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0a } }, + }, + /* MD2- and RC2-based schemes 1, 4, 6 and 11 not supported */ +}; + +/* RFC7292 Appendix C */ +static const struct pkcs12_encryption_oid { + enum l_cipher_type cipher_type; + unsigned int key_length; + unsigned int iv_length; + bool copy_k1; /* Expand the 2-Key 3DES key for 3-Key 3DES */ + bool is_block; + struct asn1_oid oid; +} pkcs12_encryption_oids[] = { + { /* pbeWithSHAAnd128BitRC4 */ + .cipher_type = L_CIPHER_ARC4, + .key_length = 16, + .oid = { 10, { + 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x0c, 0x01, 0x01, + } } + }, + { /* pbeWithSHAAnd40BitRC4 */ + .cipher_type = L_CIPHER_ARC4, + .key_length = 5, + .oid = { 10, { + 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x0c, 0x01, 0x02, + } } + }, + { /* pbeWithSHAAnd3-KeyTripleDES-CBC */ + .cipher_type = L_CIPHER_DES3_EDE_CBC, + .key_length = 24, + .iv_length = 8, + .is_block = true, + .oid = { 10, { + 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x0c, 0x01, 0x03, + } } + }, + { /* pbeWithSHAAnd2-KeyTripleDES-CBC */ + .cipher_type = L_CIPHER_DES3_EDE_CBC, + .key_length = 16, + .iv_length = 8, + .copy_k1 = true, + .is_block = true, + .oid = { 10, { + 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x0c, 0x01, 0x04, + } } + }, + { /* pbeWithSHAAnd128BitRC2-CBC */ + .cipher_type = L_CIPHER_RC2_CBC, + .key_length = 16, + .iv_length = 8, + .is_block = true, + .oid = { 10, { + 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x0c, 0x01, 0x05, + } } + }, + { /* pbeWithSHAAnd40BitRC2-CBC */ + .cipher_type = L_CIPHER_RC2_CBC, + .key_length = 5, + .iv_length = 8, + .is_block = true, + .oid = { 10, { + 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x0c, 0x01, 0x06, + } } + }, +}; + +static const struct pkcs5_digest_alg_oid { + enum l_checksum_type type; + struct asn1_oid oid; +} pkcs5_digest_alg_oids[] = { + { /* hmacWithSHA1 */ + L_CHECKSUM_SHA1, + { 8, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x07 } }, + }, + { /* hmacWithSHA224 */ + L_CHECKSUM_SHA224, + { 8, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x08 } }, + }, + { /* hmacWithSHA256 */ + L_CHECKSUM_SHA256, + { 8, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x09 } }, + }, + { /* hmacWithSHA384 */ + L_CHECKSUM_SHA384, + { 8, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x0a } }, + }, + { /* hmacWithSHA512 */ + L_CHECKSUM_SHA512, + { 8, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x0b } }, + }, + /* hmacWithSHA512-224 and hmacWithSHA512-256 not supported */ +}; + +static const struct pkcs5_enc_alg_oid { + enum l_cipher_type cipher_type; + uint8_t key_size, iv_size; + struct asn1_oid oid; +} pkcs5_enc_alg_oids[] = { + { /* desCBC */ + L_CIPHER_DES_CBC, 8, 8, + { 5, { 0x2b, 0x0e, 0x03, 0x02, 0x07 } }, + }, + { /* des-EDE3-CBC */ + L_CIPHER_DES3_EDE_CBC, 24, 8, + { 8, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x07 } }, + }, + /* RC2/RC5-based schemes 2 and 9 not supported */ + { /* aes128-CBC-PAD */ + L_CIPHER_AES_CBC, 16, 16, + { 9, { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02 } }, + }, + { /* aes192-CBC-PAD */ + L_CIPHER_AES_CBC, 24, 16, + { 9, { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x16 } }, + }, + { /* aes256-CBC-PAD */ + L_CIPHER_AES_CBC, 32, 16, + { 9, { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2a } }, + }, +}; + +static struct l_cipher *cipher_from_pkcs5_pbes2_params( + const uint8_t *pbes2_params, + size_t pbes2_params_len, + const char *password) +{ + uint8_t tag; + const uint8_t *kdf_sequence, *enc_sequence, *oid, *params, + *salt, *iter_count_buf, *key_len_buf, *prf_sequence; + size_t kdf_len, enc_len, params_len, salt_len, key_len, tmp_len; + unsigned int i, iter_count, pos; + enum l_checksum_type prf_alg = L_CHECKSUM_NONE; + const struct pkcs5_enc_alg_oid *enc_scheme = NULL; + uint8_t derived_key[64]; + struct l_cipher *cipher; + + /* RFC8018 section A.4 */ + + kdf_sequence = asn1_der_find_elem(pbes2_params, pbes2_params_len, 0, + &tag, &kdf_len); + if (!kdf_sequence || tag != ASN1_ID_SEQUENCE) + return NULL; + + enc_sequence = asn1_der_find_elem(pbes2_params, pbes2_params_len, 1, + &tag, &enc_len); + if (!enc_sequence || tag != ASN1_ID_SEQUENCE) + return NULL; + + if (asn1_der_find_elem(pbes2_params, pbes2_params_len, 2, + &tag, &tmp_len)) + return NULL; + + /* RFC8018 section A.2 */ + + oid = asn1_der_find_elem(kdf_sequence, kdf_len, 0, &tag, &tmp_len); + if (!oid || tag != ASN1_ID_OID) + return NULL; + + if (!asn1_oid_eq(&pkcs5_pbkdf2_oid, tmp_len, oid)) + return NULL; + + params = asn1_der_find_elem(kdf_sequence, kdf_len, 1, + &tag, ¶ms_len); + if (!params || tag != ASN1_ID_SEQUENCE) + return NULL; + + if (asn1_der_find_elem(kdf_sequence, kdf_len, 2, &tag, &tmp_len)) + return NULL; + + salt = asn1_der_find_elem(params, params_len, 0, &tag, &salt_len); + if (!salt || tag != ASN1_ID_OCTET_STRING || + salt_len < 1 || salt_len > 512) + return NULL; + + iter_count_buf = asn1_der_find_elem(params, params_len, 1, + &tag, &tmp_len); + if (!iter_count_buf || tag != ASN1_ID_INTEGER || + tmp_len < 1 || tmp_len > 4) + return NULL; + + iter_count = 0; + + while (tmp_len--) + iter_count = (iter_count << 8) | *iter_count_buf++; + + pos = 2; + key_len_buf = asn1_der_find_elem(params, params_len, pos, + &tag, &tmp_len); + if (key_len_buf && tag == ASN1_ID_INTEGER) { + if (tmp_len != 1) + return NULL; + + pos++; + key_len = 0; + + while (tmp_len--) + key_len = (key_len << 8) | *key_len_buf++; + } else + key_len = 0; + + prf_sequence = asn1_der_find_elem(params, params_len, pos, + &tag, &tmp_len); + if (prf_sequence && tag == ASN1_ID_SEQUENCE) { + pos++; + + oid = asn1_der_find_elem(prf_sequence, tmp_len, 0, + &tag, &tmp_len); + if (!oid || tag != ASN1_ID_OID) + return NULL; + + for (i = 0; i < L_ARRAY_SIZE(pkcs5_digest_alg_oids); i++) + if (asn1_oid_eq(&pkcs5_digest_alg_oids[i].oid, + tmp_len, oid)) + prf_alg = pkcs5_digest_alg_oids[i].type; + + if (prf_alg == L_CHECKSUM_NONE) + return NULL; + } else + prf_alg = L_CHECKSUM_SHA1; + + oid = asn1_der_find_elem(enc_sequence, enc_len, 0, &tag, &tmp_len); + if (!oid || tag != ASN1_ID_OID) + return NULL; + + for (i = 0; i < L_ARRAY_SIZE(pkcs5_enc_alg_oids); i++) { + if (asn1_oid_eq(&pkcs5_enc_alg_oids[i].oid, tmp_len, oid)) { + enc_scheme = &pkcs5_enc_alg_oids[i]; + break; + } + } + + if (!enc_scheme) + return NULL; + + params = asn1_der_find_elem(enc_sequence, enc_len, 1, + &tag, ¶ms_len); + if (!params) + return NULL; + + /* RFC8018 section B.2 */ + + /* + * Since we don't support the RC2/RC5 PBES2 ciphers, our parameters + * only have an obligatory OCTET STRING IV parameter and a fixed key + * length. + */ + if (tag != ASN1_ID_OCTET_STRING || params_len != enc_scheme->iv_size) + return NULL; + + if (key_len && enc_scheme->key_size != key_len) + return NULL; + + key_len = enc_scheme->key_size; + + if (asn1_der_find_elem(enc_sequence, enc_len, 2, &tag, &tmp_len)) + return NULL; + + /* RFC8018 section 6.2 */ + + if (!l_cert_pkcs5_pbkdf2(prf_alg, password, salt, salt_len, iter_count, + derived_key, key_len)) + return NULL; + + cipher = l_cipher_new(enc_scheme->cipher_type, derived_key, key_len); + if (cipher && !l_cipher_set_iv(cipher, params, enc_scheme->iv_size)) { + l_cipher_free(cipher); + cipher = NULL; + } + + explicit_bzero(derived_key, 16); + return cipher; +} + +static struct l_cipher *cipher_from_pkcs12_alg_id( + const struct pkcs12_encryption_oid *scheme, + const uint8_t *params, size_t params_len, + const char *password, bool *out_is_block) +{ + uint8_t tag; + const uint8_t *salt; + const uint8_t *iterations_data; + size_t salt_len; + size_t iterations_len; + unsigned int iterations; + uint8_t *key; + size_t key_len; + struct l_cipher *cipher; + + /* Same parameters as in PKCS#5 */ + salt = asn1_der_find_elem(params, params_len, 0, &tag, &salt_len); + if (!salt || tag != ASN1_ID_OCTET_STRING) + return NULL; + + iterations_data = asn1_der_find_elem(params, params_len, 1, + &tag, &iterations_len); + if (!iterations_data || tag != ASN1_ID_INTEGER || + iterations_len < 1 || iterations_len > 4) + return NULL; + + for (iterations = 0; iterations_len; iterations_len--) + iterations = (iterations << 8) | *iterations_data++; + + if (iterations < 1 || iterations > 8192) + return NULL; + + if (iterations_data != params + params_len) + return NULL; + + key_len = scheme->key_length; + key = cert_pkcs12_pbkdf(password, &pkcs12_sha1_hash, salt, salt_len, + iterations, 1, key_len); + if (!key) + return NULL; + + if (scheme->copy_k1) { + /* + * 2-Key 3DES is like L_CIPHER_DES3_EDE_CBC except the last + * of the 3 8-byte keys is not generated using a KDF and + * instead is a copy of the first key. In other words + * the first half of the 16-byte key material is appended + * at the end to produce the 24 bytes for DES3_EDE_CBC. + */ + uint8_t *key2 = l_malloc(24); + + memcpy(key2, key, 16); + memcpy(key2 + 16, key, 8); + explicit_bzero(key, key_len); + l_free(key); + key = key2; + key_len = 24; + } + + cipher = l_cipher_new(scheme->cipher_type, key, key_len); + explicit_bzero(key, key_len); + l_free(key); + + if (!cipher) + return NULL; + + if (scheme->iv_length) { + uint8_t *iv = cert_pkcs12_pbkdf(password, &pkcs12_sha1_hash, + salt, salt_len, iterations, 2, + scheme->iv_length); + + if (!iv || !l_cipher_set_iv(cipher, iv, scheme->iv_length)) { + l_cipher_free(cipher); + cipher = NULL; + } + + if (iv) + explicit_bzero(iv, scheme->iv_length); + + l_free(iv); + } + + if (out_is_block) + *out_is_block = scheme->is_block; + + return cipher; +} + +struct l_cipher *cert_cipher_from_pkcs_alg_id(const uint8_t *id_asn1, + size_t id_asn1_len, + const char *password, + bool *out_is_block) +{ + uint8_t tag; + const uint8_t *oid, *params, *salt, *iter_count_buf; + size_t oid_len, params_len, tmp_len; + unsigned int i, iter_count; + const struct pkcs5_pbes1_encryption_oid *pbes1_scheme = NULL; + uint8_t derived_key[16]; + struct l_cipher *cipher; + + oid = asn1_der_find_elem(id_asn1, id_asn1_len, 0, &tag, &oid_len); + if (!oid || tag != ASN1_ID_OID) + return NULL; + + params = asn1_der_find_elem(id_asn1, id_asn1_len, 1, &tag, ¶ms_len); + if (!params || tag != ASN1_ID_SEQUENCE) + return NULL; + + if (asn1_der_find_elem(id_asn1, id_asn1_len, 2, &tag, &tmp_len)) + return NULL; + + if (asn1_oid_eq(&pkcs5_pbes2_oid, oid_len, oid)) { + if (out_is_block) + *out_is_block = true; + + return cipher_from_pkcs5_pbes2_params(params, params_len, + password); + } + + /* RFC8018 section A.3 */ + + for (i = 0; i < L_ARRAY_SIZE(pkcs5_pbes1_encryption_oids); i++) { + if (asn1_oid_eq(&pkcs5_pbes1_encryption_oids[i].oid, + oid_len, oid)) { + pbes1_scheme = &pkcs5_pbes1_encryption_oids[i]; + break; + } + } + + /* Check if this is a PKCS#12 OID */ + if (!pbes1_scheme) { + for (i = 0; i < L_ARRAY_SIZE(pkcs12_encryption_oids); i++) + if (asn1_oid_eq(&pkcs12_encryption_oids[i].oid, + oid_len, oid)) + return cipher_from_pkcs12_alg_id( + &pkcs12_encryption_oids[i], + params, params_len, password, + out_is_block); + + return NULL; + } + + salt = asn1_der_find_elem(params, params_len, 0, &tag, &tmp_len); + if (!salt || tag != ASN1_ID_OCTET_STRING || tmp_len != 8) + return NULL; + + iter_count_buf = asn1_der_find_elem(params, params_len, 1, + &tag, &tmp_len); + if (!iter_count_buf || tag != ASN1_ID_INTEGER || + tmp_len < 1 || tmp_len > 4) + return NULL; + + iter_count = 0; + + while (tmp_len--) + iter_count = (iter_count << 8) | *iter_count_buf++; + + if (asn1_der_find_elem(params, params_len, 2, &tag, &tmp_len)) + return NULL; + + /* RFC8018 section 6.1 */ + + if (!l_cert_pkcs5_pbkdf1(pbes1_scheme->checksum_type, password, + salt, 8, iter_count, derived_key, 16)) + return NULL; + + cipher = l_cipher_new(pbes1_scheme->cipher_type, derived_key + 0, 8); + if (cipher && !l_cipher_set_iv(cipher, derived_key + 8, 8)) { + l_cipher_free(cipher); + cipher = NULL; + } + + explicit_bzero(derived_key, 16); + + if (out_is_block) + *out_is_block = true; + + return cipher; +} diff --git a/ell/cert-private.h b/ell/cert-private.h new file mode 100644 index 0000000000000000000000000000000000000000..c1b2e01b4c0c16413c2bd5afa7c3867023a79928 --- /dev/null +++ b/ell/cert-private.h @@ -0,0 +1,42 @@ +/* + * Embedded Linux library + * Copyright (C) 2018 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +struct asn1_oid; + +struct l_certchain *certchain_new_from_leaf(struct l_cert *leaf); +void certchain_link_issuer(struct l_certchain *chain, struct l_cert *ca); + +const uint8_t *cert_get_extension(struct l_cert *cert, + const struct asn1_oid *ext_id, + bool *out_critical, size_t *out_len); + +struct l_key *cert_key_from_pkcs8_private_key_info(const uint8_t *der, + size_t der_len); +struct l_key *cert_key_from_pkcs8_encrypted_private_key_info(const uint8_t *der, + size_t der_len, + const char *passphrase); +struct l_key *cert_key_from_pkcs1_rsa_private_key(const uint8_t *der, + size_t der_len); + +struct cert_pkcs12_hash { + enum l_checksum_type alg; + unsigned int len; + unsigned int u; + unsigned int v; + struct asn1_oid oid; +}; + +uint8_t *cert_pkcs12_pbkdf(const char *password, + const struct cert_pkcs12_hash *hash, + const uint8_t *salt, size_t salt_len, + unsigned int iterations, uint8_t id, + size_t key_len); + +struct l_cipher *cert_cipher_from_pkcs_alg_id(const uint8_t *id_asn1, + size_t id_asn1_len, + const char *password, + bool *out_is_block); diff --git a/ell/cert.c b/ell/cert.c new file mode 100644 index 0000000000000000000000000000000000000000..38bb01aa6a558898f33c8846f761a97012aa03d6 --- /dev/null +++ b/ell/cert.c @@ -0,0 +1,1954 @@ +/* + * Embedded Linux library + * Copyright (C) 2018 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <time.h> + +#include "private.h" +#include "useful.h" +#include "key.h" +#include "queue.h" +#include "asn1-private.h" +#include "cipher.h" +#include "pem-private.h" +#include "time.h" +#include "time-private.h" +#include "utf8.h" +#include "cert.h" +#include "cert-private.h" +#include "tls.h" +#include "tls-private.h" +#include "missing.h" + +#define X509_CERTIFICATE_POS 0 +#define X509_TBSCERTIFICATE_POS 0 +#define X509_TBSCERT_VERSION_POS ASN1_CONTEXT_EXPLICIT(0) +#define X509_TBSCERT_SERIAL_POS 0 +#define X509_TBSCERT_SIGNATURE_POS 1 +#define X509_ALGORITHM_ID_ALGORITHM_POS 0 +#define X509_ALGORITHM_ID_PARAMS_POS 1 +#define X509_TBSCERT_ISSUER_DN_POS 2 +#define X509_TBSCERT_VALIDITY_POS 3 +#define X509_TBSCERT_SUBJECT_DN_POS 4 +#define X509_TBSCERT_SUBJECT_KEY_POS 5 +#define X509_SUBJECT_KEY_ALGORITHM_POS 0 +#define X509_SUBJECT_KEY_VALUE_POS 1 +#define X509_TBSCERT_ISSUER_UID_POS ASN1_CONTEXT_IMPLICIT(1) +#define X509_TBSCERT_SUBJECT_UID_POS ASN1_CONTEXT_IMPLICIT(2) +#define X509_TBSCERT_EXTENSIONS_POS ASN1_CONTEXT_EXPLICIT(3) +#define X509_SIGNATURE_ALGORITHM_POS 1 +#define X509_SIGNATURE_VALUE_POS 2 + +struct l_cert { + enum l_cert_key_type pubkey_type; + struct l_cert *issuer; + struct l_cert *issued; + size_t asn1_len; + uint8_t asn1[]; +}; + +struct l_certchain { + struct l_cert *leaf; /* Bottom of the doubly-linked list */ + struct l_cert *ca; /* Top of the doubly-linked list */ +}; + +static const struct pkcs1_encryption_oid { + enum l_cert_key_type key_type; + struct asn1_oid oid; +} pkcs1_encryption_oids[] = { + { /* rsaEncryption */ + L_CERT_KEY_RSA, + { .asn1_len = 9, .asn1 = { + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 } + }, + }, + { /* ecPublicKey */ + L_CERT_KEY_ECC, + { .asn1_len = 7, .asn1 = { + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01 } + }, + }, +}; + +static bool cert_set_pubkey_type(struct l_cert *cert) +{ + const uint8_t *key_type; + size_t key_type_len; + int i; + + key_type = asn1_der_find_elem_by_path(cert->asn1, cert->asn1_len, + ASN1_ID_OID, &key_type_len, + X509_CERTIFICATE_POS, + X509_TBSCERTIFICATE_POS, + X509_TBSCERT_SUBJECT_KEY_POS, + X509_SUBJECT_KEY_ALGORITHM_POS, + X509_ALGORITHM_ID_ALGORITHM_POS, + -1); + if (!key_type) + return false; + + for (i = 0; i < (int) L_ARRAY_SIZE(pkcs1_encryption_oids); i++) + if (asn1_oid_eq(&pkcs1_encryption_oids[i].oid, + key_type_len, key_type)) + break; + + if (i == L_ARRAY_SIZE(pkcs1_encryption_oids)) + cert->pubkey_type = L_CERT_KEY_UNKNOWN; + else + cert->pubkey_type = pkcs1_encryption_oids[i].key_type; + + return true; +} + +LIB_EXPORT struct l_cert *l_cert_new_from_der(const uint8_t *buf, + size_t buf_len) +{ + const uint8_t *seq = buf; + size_t seq_len = buf_len; + size_t content_len; + struct l_cert *cert; + + /* Sanity check: outer element is a SEQUENCE */ + if (seq_len-- < 1 || *seq++ != ASN1_ID_SEQUENCE) + return NULL; + + /* Sanity check: the SEQUENCE spans the whole buffer */ + content_len = asn1_parse_definite_length(&seq, &seq_len); + if (content_len < 64 || content_len != seq_len) + return NULL; + + /* + * We could require the signature algorithm and the key algorithm + * to be one of our supported types here but instead we only + * require that when the user wants to verify this certificate or + * get the public key respectively. + */ + + cert = l_malloc(sizeof(struct l_cert) + buf_len); + cert->issuer = NULL; + cert->issued = NULL; + cert->asn1_len = buf_len; + memcpy(cert->asn1, buf, buf_len); + + /* Sanity check: structure is correct up to the Public Key Algorithm */ + if (!cert_set_pubkey_type(cert)) { + l_free(cert); + return NULL; + } + + return cert; +} + +LIB_EXPORT void l_cert_free(struct l_cert *cert) +{ + l_free(cert); +} + +LIB_EXPORT const uint8_t *l_cert_get_der_data(struct l_cert *cert, + size_t *out_len) +{ + if (unlikely(!cert)) + return NULL; + + *out_len = cert->asn1_len; + return cert->asn1; +} + +LIB_EXPORT const uint8_t *l_cert_get_dn(struct l_cert *cert, size_t *out_len) +{ + if (unlikely(!cert)) + return NULL; + + return asn1_der_find_elem_by_path(cert->asn1, cert->asn1_len, + ASN1_ID_SEQUENCE, out_len, + X509_CERTIFICATE_POS, + X509_TBSCERTIFICATE_POS, + X509_TBSCERT_SUBJECT_DN_POS, + -1); +} + +static uint64_t cert_parse_asn1_time(const uint8_t *data, size_t len, + uint8_t tag) +{ + struct tm tm = {}; + int tz_hours; + int tz_mins; + int century; + int msecs = 0; + time_t tt; + unsigned int i; + + for (i = 0; i < len && i < 15; i++) + if (unlikely(!l_ascii_isdigit(data[i]))) + break; + + if (tag == ASN1_ID_UTCTIME) { + if (unlikely(!L_IN_SET(i, 10, 12))) + return L_TIME_INVALID; + + century = 19; + } else if (tag == ASN1_ID_GENERALIZEDTIME) { + if (unlikely(!L_IN_SET(i, 10, 12, 14))) + return L_TIME_INVALID; + + century = (data[0] - '0') * 10 + (data[1] - '0'); + if (century < 19) + return L_TIME_INVALID; + + if (len >= i + 4 && data[i] == '.') { + if (unlikely(!l_ascii_isdigit(data[i + 1]) || + !l_ascii_isdigit(data[i + 2]) || + !l_ascii_isdigit(data[i + 3]))) + return L_TIME_INVALID; + + i++; + msecs += (data[i++] - '0') * 100; + msecs += (data[i++] - '0') * 10; + msecs += (data[i++] - '0'); + } + + data += 2; + len -= 2; + i -= 2; + } else + return L_TIME_INVALID; + + if (unlikely((len != i + 1 || data[i] != 'Z') && + (len != i + 5 || (data[i] != '+' && data[i] != '-')))) + return L_TIME_INVALID; + + tm.tm_year = (data[0] - '0') * 10 + (data[1] - '0'); + tm.tm_mon = (data[2] - '0') * 10 + (data[3] - '0'); + tm.tm_mday = (data[4] - '0') * 10 + (data[5] - '0'); + tm.tm_hour = (data[6] - '0') * 10 + (data[7] - '0'); + + if (unlikely(tm.tm_mon < 1 || tm.tm_mon > 12 || + tm.tm_mday < 1 || tm.tm_mday > 31 || + tm.tm_hour > 23)) + return L_TIME_INVALID; + + if (i >= 10) { + tm.tm_min = (data[8] - '0') * 10 + (data[9] - '0'); + if (unlikely(tm.tm_min > 59)) + return L_TIME_INVALID; + } + + if (i >= 12) { + tm.tm_sec = (data[10] - '0') * 10 + (data[11] - '0'); + if (unlikely(tm.tm_sec > 59)) + return L_TIME_INVALID; + } + + /* RFC5280 Section 4.1.2.5.1 */ + if (tag == ASN1_ID_UTCTIME && tm.tm_year < 50) + century = 20; + + tm.tm_year += (century - 19) * 100; + + /* Month number is 1-based in UTCTime and 0-based in struct tm */ + tm.tm_mon -= 1; + + tt = timegm(&tm); + if (unlikely(tt == (time_t) -1)) + return L_TIME_INVALID; + + if (len == i + 5) { + data += i; + + for (i = 1; i < 5; i++) + if (unlikely(!l_ascii_isdigit(data[i]))) + return L_TIME_INVALID; + + tz_hours = (data[1] - '0') * 10 + (data[2] - '0'); + tz_mins = (data[3] - '0') * 10 + (data[4] - '0'); + + if (unlikely(tz_hours > 14 || tz_mins > 59)) + return L_TIME_INVALID; + + /* The sign converts UTC to local so invert it */ + if (data[0] == '+') + tt -= tz_hours * 3600 + tz_mins * 60; + else + tt += tz_hours * 3600 + tz_mins * 60; + } + + return (uint64_t) tt * L_USEC_PER_SEC + msecs * L_USEC_PER_MSEC; +} + +LIB_EXPORT bool l_cert_get_valid_times(struct l_cert *cert, + uint64_t *out_not_before_time, + uint64_t *out_not_after_time) +{ + const uint8_t *validity; + const uint8_t *not_before; + const uint8_t *not_after; + size_t seq_size; + size_t not_before_size; + size_t not_after_size; + uint8_t not_before_tag; + uint8_t not_after_tag; + uint64_t not_before_time = 0; + uint64_t not_after_time = 0; + + if (unlikely(!cert)) + return false; + + validity = asn1_der_find_elem_by_path(cert->asn1, cert->asn1_len, + ASN1_ID_SEQUENCE, &seq_size, + X509_CERTIFICATE_POS, + X509_TBSCERTIFICATE_POS, + X509_TBSCERT_VALIDITY_POS, + -1); + if (unlikely(!validity)) + return false; + + not_before = asn1_der_find_elem(validity, seq_size, 0, ¬_before_tag, + ¬_before_size); + if (!not_before) + return false; + + seq_size -= not_before_size + (not_before - validity); + validity = not_before + not_before_size; + not_after = asn1_der_find_elem(validity, seq_size, 0, ¬_after_tag, + ¬_after_size); + if (!not_after) + return false; + + if (out_not_before_time) { + not_before_time = cert_parse_asn1_time(not_before, + not_before_size, + not_before_tag); + if (not_before_time == L_TIME_INVALID) + return false; + } + + if (out_not_after_time) { + /* + * RFC5280 Section 4.1.2.5: "To indicate that a certificate + * has no well-defined expiration date, the notAfter SHOULD + * be assigned the GeneralizedTime value of 99991231235959Z." + */ + if (not_after_size == 15 && + !memcmp(not_after, "99991231235959Z", 15)) + not_after_time = 0; + else { + not_after_time = cert_parse_asn1_time(not_after, + not_after_size, + not_after_tag); + if (not_after_time == L_TIME_INVALID) + return false; + } + } + + if (out_not_before_time) + *out_not_before_time = not_before_time; + + if (out_not_after_time) + *out_not_after_time = not_after_time; + + return true; +} + +const uint8_t *cert_get_extension(struct l_cert *cert, + const struct asn1_oid *ext_id, + bool *out_critical, size_t *out_len) +{ + const uint8_t *ext, *end; + size_t ext_len; + + if (unlikely(!cert)) + return NULL; + + ext = asn1_der_find_elem_by_path(cert->asn1, cert->asn1_len, + ASN1_ID_SEQUENCE, &ext_len, + X509_CERTIFICATE_POS, + X509_TBSCERTIFICATE_POS, + X509_TBSCERT_EXTENSIONS_POS, + -1); + if (unlikely(!ext)) + return NULL; + + end = ext + ext_len; + while (ext < end) { + const uint8_t *seq, *oid, *data; + uint8_t tag; + size_t len, oid_len, data_len; + bool critical; + + seq = asn1_der_find_elem(ext, end - ext, 0, &tag, &len); + if (unlikely(!seq || tag != ASN1_ID_SEQUENCE)) + return false; + + ext = seq + len; + + oid = asn1_der_find_elem(seq, len, 0, &tag, &oid_len); + if (unlikely(!oid || tag != ASN1_ID_OID)) + return false; + + if (!asn1_oid_eq(ext_id, oid_len, oid)) + continue; + + data = asn1_der_find_elem(seq, len, 1, &tag, &data_len); + critical = false; + + if (data && tag == ASN1_ID_BOOLEAN) { + if (data_len != 1) + return false; + + critical = *data != 0; /* Tolerate BER booleans */ + + data = asn1_der_find_elem(seq, len, 2, &tag, &data_len); + } + + if (unlikely(!data || tag != ASN1_ID_OCTET_STRING)) + return false; + + if (out_critical) + *out_critical = critical; + + if (out_len) + *out_len = data_len; + + return data; + } + + return NULL; +} + +LIB_EXPORT enum l_cert_key_type l_cert_get_pubkey_type(struct l_cert *cert) +{ + if (unlikely(!cert)) + return L_CERT_KEY_UNKNOWN; + + return cert->pubkey_type; +} + +/* + * Note: Returns a new l_key object to be freed by the caller. + */ +LIB_EXPORT struct l_key *l_cert_get_pubkey(struct l_cert *cert) +{ + if (unlikely(!cert)) + return NULL; + + /* Use kernel's ASN.1 certificate parser to find the key data for us */ + switch (cert->pubkey_type) { + case L_CERT_KEY_RSA: + return l_key_new(L_KEY_RSA, cert->asn1, cert->asn1_len); + case L_CERT_KEY_ECC: + return l_key_new(L_KEY_ECC, cert->asn1, cert->asn1_len); + case L_CERT_KEY_UNKNOWN: + break; + } + + return NULL; +} + +/* + * Note: takes ownership of the certificate. The certificate is + * assumed to be new and not linked into any certchain object. + */ +struct l_certchain *certchain_new_from_leaf(struct l_cert *leaf) +{ + struct l_certchain *chain; + + chain = l_new(struct l_certchain, 1); + chain->leaf = leaf; + chain->ca = leaf; + return chain; +} + +/* + * Note: takes ownership of the certificate. The certificate is + * assumed to be new and not linked into any certchain object. + */ +void certchain_link_issuer(struct l_certchain *chain, struct l_cert *ca) +{ + ca->issued = chain->ca; + chain->ca->issuer = ca; + chain->ca = ca; +} + +static struct l_cert *certchain_pop_ca(struct l_certchain *chain) +{ + struct l_cert *ca = chain->ca; + + if (!ca) + return NULL; + + if (ca->issued) { + chain->ca = ca->issued; + ca->issued->issuer = NULL; + ca->issued = NULL; + } else { + chain->ca = NULL; + chain->leaf = NULL; + } + + return ca; +} + +LIB_EXPORT void l_certchain_free(struct l_certchain *chain) +{ + while (chain && chain->ca) + l_cert_free(certchain_pop_ca(chain)); + + l_free(chain); +} + +LIB_EXPORT struct l_cert *l_certchain_get_leaf(struct l_certchain *chain) +{ + if (unlikely(!chain)) + return NULL; + + return chain->leaf; +} + +/* + * Call @cb for each certificate in the chain starting from the leaf + * certificate. Stop if a call returns @true. + */ +LIB_EXPORT void l_certchain_walk_from_leaf(struct l_certchain *chain, + l_cert_walk_cb_t cb, + void *user_data) +{ + struct l_cert *cert; + + if (unlikely(!chain)) + return; + + for (cert = chain->leaf; cert; cert = cert->issuer) + if (cb(cert, user_data)) + break; +} + +/* + * Call @cb for each certificate in the chain starting from the root + * certificate. Stop if a call returns @true. + */ +LIB_EXPORT void l_certchain_walk_from_ca(struct l_certchain *chain, + l_cert_walk_cb_t cb, + void *user_data) +{ + struct l_cert *cert; + + if (unlikely(!chain)) + return; + + for (cert = chain->ca; cert; cert = cert->issued) + if (cb(cert, user_data)) + break; +} + +static struct l_keyring *cert_set_to_keyring(struct l_cert **certs, char *error) +{ + struct l_keyring *ring; + int i = 1; + int count; + + ring = l_keyring_new(); + if (!ring) + return NULL; + + for (count = 0; certs[count]; count++); + + for (; *certs; certs++) { + struct l_cert *cert = *certs; + struct l_key *key = l_cert_get_pubkey(cert); + + if (!key) { + sprintf(error, "Can't get public key from certificate " + "%i / %i in certificate set", i, count); + goto cleanup; + } + + if (!l_keyring_link(ring, key)) { + l_key_free(key); + sprintf(error, "Can't link the public key from " + "certificate %i / %i to target keyring", + i, count); + goto cleanup; + } + + l_key_free_norevoke(key); + i++; + } + + return ring; + +cleanup: + l_keyring_free(ring); + return NULL; +} + +static bool cert_is_in_set(struct l_cert *cert, struct l_cert **set) +{ + for (; *set; set++) { + struct l_cert *cert2 = *set; + + if (cert == cert2) + return true; + + if (cert->asn1_len == cert2->asn1_len && + !memcmp(cert->asn1, cert2->asn1, + cert->asn1_len)) + return true; + } + + return false; +} + +static struct l_cert **cert_set_filter_by_validity(struct l_queue *set, + uint64_t now, + int *out_total, + int *out_valid) +{ + const struct l_queue_entry *entry; + _auto_(l_free) struct l_cert **valid; + + *out_total = l_queue_length(set); + *out_valid = 0; + valid = l_new(struct l_cert *, *out_total + 1); + + for (entry = l_queue_get_entries(set); entry; entry = entry->next) { + struct l_cert *cert = entry->data; + uint64_t not_before; + uint64_t not_after; + + if (!l_cert_get_valid_times(cert, ¬_before, ¬_after)) + return NULL; + + if (now < not_before || (not_after && now > not_after)) + continue; + + valid[(*out_valid)++] = cert; + } + + return l_steal_ptr(valid); +} + +static struct l_key *cert_try_link(struct l_cert *cert, struct l_keyring *ring) +{ + struct l_key *key; + + key = l_key_new(L_KEY_RSA, cert->asn1, cert->asn1_len); + if (!key) + return NULL; + + if (l_keyring_link(ring, key)) + return key; + + l_key_free(key); + return NULL; +} + +#define RETURN_ERROR(msg, args...) \ + do { \ + if (error) { \ + *error = error_buf; \ + snprintf(error_buf, sizeof(error_buf), msg, ## args); \ + } \ + return false; \ + } while (0) + +LIB_EXPORT bool l_certchain_verify(struct l_certchain *chain, + struct l_queue *ca_certs, + const char **error) +{ + struct l_keyring *ca_ring = NULL; + _auto_(l_keyring_free) struct l_keyring *verify_ring = NULL; + struct l_cert *cert; + struct l_key *prev_key = NULL; + int verified = 0; + int ca_match = 0; + int i; + static char error_buf[1024]; + int total = 0; + uint64_t now; + _auto_(l_free) struct l_cert **ca_certs_valid = NULL; + int ca_certs_total_count = 0; + int ca_certs_valid_count = 0; + + if (unlikely(!chain || !chain->leaf)) + RETURN_ERROR("Chain empty"); + + for (cert = chain->ca; cert; cert = cert->issued, total++); + + now = time_realtime_now(); + + for (cert = chain->ca, i = 0; cert; cert = cert->issued, i++) { + uint64_t not_before; + uint64_t not_after; + char time_str[100]; + + if (unlikely(!l_cert_get_valid_times(cert, ¬_before, + ¬_after))) + RETURN_ERROR("Can't parse validity in certificate " + "%i / %i", i + 1, total); + + if (unlikely(now < not_before)) { + time_t t = not_before / L_USEC_PER_SEC; + struct tm *tm = gmtime(&t); + + if (!tm || !strftime(time_str, sizeof(time_str), + "%a %F %T UTC", tm)) + strcpy(time_str, "<error>"); + + RETURN_ERROR("Certificate %i / %i not valid before %s", + i + 1, total, time_str); + } + + if (unlikely(not_after && now > not_after)) { + time_t t = not_after / L_USEC_PER_SEC; + struct tm *tm = gmtime(&t); + + if (!tm || !strftime(time_str, sizeof(time_str), + "%a %F %T UTC", tm)) + strcpy(time_str, "<error>"); + + RETURN_ERROR("Certificate %i / %i expired on %s", + i + 1, total, time_str); + } + } + + if (ca_certs) { + if (unlikely(l_queue_isempty(ca_certs))) + RETURN_ERROR("No trusted CA certificates"); + + ca_certs_valid = cert_set_filter_by_validity(ca_certs, now, + &ca_certs_total_count, + &ca_certs_valid_count); + if (unlikely(!ca_certs_valid)) + RETURN_ERROR("Can't parse validity in CA cert(s)"); + + if (unlikely(!ca_certs_valid_count)) + RETURN_ERROR("All trusted CA certs are expired or " + "not-yet-valid"); + + for (cert = chain->ca, i = 0; cert; cert = cert->issued, i++) + if (cert_is_in_set(cert, ca_certs_valid)) { + ca_match = i + 1; + break; + } + } + + verify_ring = l_keyring_new(); + if (!verify_ring) + RETURN_ERROR("Can't create verify keyring"); + + cert = chain->ca; + + /* + * For TLS compatibility the trusted root CA certificate is + * optionally present in the chain. + * + * RFC5246 7.4.2: + * "Because certificate validation requires that root keys be + * distributed independently, the self-signed certificate that + * specifies the root certificate authority MAY be omitted from + * the chain, under the assumption that the remote end must + * already possess it in order to validate it in any case." + * + * The following is an optimization to skip verifying the root + * cert in the chain if it is bitwise-identical to one of the + * trusted CA certificates. In that case we don't have to load + * all of the trusted certificates into the kernel, link them + * to @ca_ring or link @ca_ring to @verify_ring, instead we + * load the first certificate into @verify_ring before we set + * the restrict mode on it, same as when no trusted CAs are + * provided. + * + * Note this happens to work around a kernel issue preventing + * self-signed certificates missing the optional AKID extension + * from being linked to a restricted keyring. That issue would + * have affected us if the trusted CA set included such + * certificate and the same certificate was at the root of + * the chain. + */ + if (ca_certs && !ca_match) { + ca_ring = cert_set_to_keyring(ca_certs_valid, error_buf); + if (!ca_ring) { + if (error) + *error = error_buf; + return false; + } + + if (!l_keyring_link_nested(verify_ring, ca_ring)) { + l_keyring_free(ca_ring); + RETURN_ERROR("Can't link CA ring to verify ring"); + } + } else + prev_key = cert_try_link(cert, verify_ring); + + /* + * The top, unverified certificate(s) are linked to the keyring and + * we can now force verification of any new certificates linked. + */ + if (!l_keyring_restrict(verify_ring, L_KEYRING_RESTRICT_ASYM_CHAIN, + NULL)) { + l_key_free(prev_key); + l_keyring_free(ca_ring); + RETURN_ERROR("Can't restrict verify keyring"); + } + + if (ca_ring) { + /* + * Verify the first certificate outside of the loop, then + * revoke the trusted CAs' keys so that only the newly + * verified cert's public key remains in the ring. + */ + prev_key = cert_try_link(cert, verify_ring); + l_keyring_free(ca_ring); + } + + cert = cert->issued; + + /* Verify the rest of the chain */ + while (prev_key && cert) { + struct l_key *new_key = cert_try_link(cert, verify_ring); + + /* + * Free and revoke the issuer's public key again leaving only + * new_key in verify_ring to ensure the next certificate linked + * is signed by the owner of this key. + */ + l_key_free(prev_key); + prev_key = new_key; + cert = cert->issued; + verified++; + } + + if (!prev_key) { + char str1[100]; + char str2[100] = ""; + + if (ca_match) + snprintf(str1, sizeof(str1), "%i / %i matched a trusted" + " certificate, root not verified", + ca_match, total); + else + snprintf(str1, sizeof(str1), "root %sverified against " + "trusted CA(s)", + ca_certs && verified ? "" : "not "); + + if (ca_certs && !ca_match && !verified && + ca_certs_valid_count < ca_certs_total_count) + snprintf(str2, sizeof(str2), ", %i out of %i trused " + "CA(s) were expired or not-yet-valid", + ca_certs_total_count - + ca_certs_valid_count, + ca_certs_total_count); + + RETURN_ERROR("Linking certificate %i / %i failed, %s%s", + verified + 1, total, str1, str2); + } + + l_key_free(prev_key); + return true; +} + +struct l_key *cert_key_from_pkcs8_private_key_info(const uint8_t *der, + size_t der_len) +{ + return l_key_new(L_KEY_RSA, der, der_len); +} + +/* + * The passphrase, if given, must have been validated as UTF-8 unless the + * caller knows that PKCS#12 encryption algorithms are not used. + * Use l_utf8_validate. + */ +struct l_key *cert_key_from_pkcs8_encrypted_private_key_info(const uint8_t *der, + size_t der_len, + const char *passphrase) +{ + const uint8_t *key_info, *alg_id, *data; + uint8_t tag; + size_t key_info_len, alg_id_len, data_len, tmp_len; + struct l_cipher *alg; + uint8_t *decrypted; + struct l_key *pkey; + bool r; + bool is_block; + size_t decrypted_len; + + /* Technically this is BER, not limited to DER */ + key_info = asn1_der_find_elem(der, der_len, 0, &tag, &key_info_len); + if (!key_info || tag != ASN1_ID_SEQUENCE) + return NULL; + + alg_id = asn1_der_find_elem(key_info, key_info_len, 0, &tag, + &alg_id_len); + if (!alg_id || tag != ASN1_ID_SEQUENCE) + return NULL; + + data = asn1_der_find_elem(key_info, key_info_len, 1, &tag, &data_len); + if (!data || tag != ASN1_ID_OCTET_STRING || data_len < 8 || + (data_len & 7) != 0) + return NULL; + + if (asn1_der_find_elem(der, der_len, 2, &tag, &tmp_len)) + return NULL; + + alg = cert_cipher_from_pkcs_alg_id(alg_id, alg_id_len, passphrase, + &is_block); + if (!alg) + return NULL; + + decrypted = l_malloc(data_len); + + r = l_cipher_decrypt(alg, data, decrypted, data_len); + l_cipher_free(alg); + + if (!r) { + l_free(decrypted); + return NULL; + } + + decrypted_len = data_len; + + /* + * For block ciphers strip padding as defined in RFC8018 + * (for PKCS#5 v1) or RFC1423 / RFC5652 (for v2). + */ + if (is_block) { + uint8_t pad = decrypted[data_len - 1]; + + pkey = NULL; + + if (pad > data_len || pad > 16 || pad == 0) + goto cleanup; + + if (!l_secure_memeq(decrypted + data_len - pad, pad - 1U, pad)) + goto cleanup; + + decrypted_len -= pad; + } + + pkey = cert_key_from_pkcs8_private_key_info(decrypted, decrypted_len); + +cleanup: + explicit_bzero(decrypted, data_len); + l_free(decrypted); + return pkey; +} + +struct l_key *cert_key_from_pkcs1_rsa_private_key(const uint8_t *der, + size_t der_len) +{ + const uint8_t *data; + uint8_t tag; + size_t data_len; + const uint8_t *key_data; + size_t key_data_len; + int i; + uint8_t *private_key; + size_t private_key_len; + uint8_t *one_asymmetric_key; + uint8_t *ptr; + struct l_key *pkey; + + static const uint8_t version0[] = { + ASN1_ID_INTEGER, 0x01, 0x00 + }; + static const uint8_t pkcs1_rsa_encryption[] = { + ASN1_ID_SEQUENCE, 0x0d, + ASN1_ID_OID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x01, + ASN1_ID_NULL, 0x00, + }; + + /* + * Sanity check that it's a version 0 or 1 RSAPrivateKey structure + * with the 8 integers. + */ + key_data = asn1_der_find_elem(der, der_len, 0, &tag, &key_data_len); + if (!key_data || tag != ASN1_ID_SEQUENCE) + return NULL; + + data = asn1_der_find_elem(key_data, key_data_len, 0, &tag, + &data_len); + if (!data || tag != ASN1_ID_INTEGER || data_len != 1 || + (data[0] != 0x00 && data[0] != 0x01)) + return NULL; + + for (i = 1; i < 9; i++) { + data = asn1_der_find_elem(key_data, key_data_len, i, &tag, + &data_len); + if (!data || tag != ASN1_ID_INTEGER || data_len < 1) + return NULL; + } + + private_key = l_malloc(10 + der_len); + ptr = private_key; + *ptr++ = ASN1_ID_OCTET_STRING; + asn1_write_definite_length(&ptr, der_len); + memcpy(ptr, der, der_len); + ptr += der_len; + private_key_len = ptr - private_key; + + one_asymmetric_key = l_malloc(32 + private_key_len); + ptr = one_asymmetric_key; + *ptr++ = ASN1_ID_SEQUENCE; + asn1_write_definite_length(&ptr, sizeof(version0) + + sizeof(pkcs1_rsa_encryption) + + private_key_len); + memcpy(ptr, version0, sizeof(version0)); + ptr += sizeof(version0); + memcpy(ptr, pkcs1_rsa_encryption, sizeof(pkcs1_rsa_encryption)); + ptr += sizeof(pkcs1_rsa_encryption); + memcpy(ptr, private_key, private_key_len); + ptr += private_key_len; + explicit_bzero(private_key, private_key_len); + l_free(private_key); + + pkey = cert_key_from_pkcs8_private_key_info(one_asymmetric_key, + ptr - one_asymmetric_key); + explicit_bzero(one_asymmetric_key, ptr - one_asymmetric_key); + l_free(one_asymmetric_key); + + return pkey; +} + +static const uint8_t *cert_unpack_pkcs7_content_info(const uint8_t *container, + size_t container_len, int pos, + const struct asn1_oid *expected_oid, + struct asn1_oid *out_oid, + uint8_t *out_tag, size_t *out_len) +{ + const uint8_t *content_info; + size_t content_info_len; + const uint8_t *type; + size_t type_len; + const uint8_t *ret; + uint8_t tag; + + if (!(content_info = asn1_der_find_elem(container, container_len, pos, + &tag, &content_info_len)) || + tag != ASN1_ID_SEQUENCE) + return NULL; + + if (!(type = asn1_der_find_elem(content_info, content_info_len, 0, + &tag, &type_len)) || + tag != ASN1_ID_OID || + type_len > sizeof(out_oid->asn1)) + return NULL; + + if (expected_oid && !asn1_oid_eq(expected_oid, type_len, type)) + return NULL; + + if (!(ret = asn1_der_find_elem(content_info, content_info_len, + ASN1_CONTEXT_EXPLICIT(0), + out_tag, out_len)) || + ret + *out_len != content_info + content_info_len) + return NULL; + + if (out_oid) { + out_oid->asn1_len = type_len; + memcpy(out_oid->asn1, type, type_len); + } + + return ret; +} + +/* RFC5652 Section 8 */ +static uint8_t *cert_decrypt_pkcs7_encrypted_data(const uint8_t *data, + size_t data_len, + const char *password, + struct asn1_oid *out_oid, + size_t *out_len) +{ + const uint8_t *version; + size_t version_len; + const uint8_t *encrypted_info; + size_t encrypted_info_len; + const uint8_t *type; + size_t type_len; + const uint8_t *alg_id; + size_t alg_id_len; + const uint8_t *encrypted; + size_t encrypted_len; + uint8_t tag; + struct l_cipher *alg; + uint8_t *plaintext; + int i; + bool ok; + bool is_block; + + if (!(version = asn1_der_find_elem(data, data_len, 0, &tag, + &version_len)) || + tag != ASN1_ID_INTEGER || version_len != 1 || + !L_IN_SET(version[0], 0, 2)) + return NULL; + + if (!(encrypted_info = asn1_der_find_elem(data, data_len, 1, &tag, + &encrypted_info_len)) || + tag != ASN1_ID_SEQUENCE) + return NULL; + + if (!(type = asn1_der_find_elem(encrypted_info, encrypted_info_len, 0, + &tag, &type_len)) || + tag != ASN1_ID_OID || + type_len > sizeof(out_oid->asn1)) + return NULL; + + if (!(alg_id = asn1_der_find_elem(encrypted_info, encrypted_info_len, 1, + &tag, &alg_id_len)) || + tag != ASN1_ID_SEQUENCE) + return NULL; + + /* Not optional in our case, defined [0] IMPLICIT OCTET STRING */ + if (!(encrypted = asn1_der_find_elem(encrypted_info, encrypted_info_len, + ASN1_CONTEXT_IMPLICIT(0), + &tag, &encrypted_len)) || + tag != ASN1_ID(ASN1_CLASS_CONTEXT, 0, 0) || + encrypted_len < 8) + return NULL; + + if (!(alg = cert_cipher_from_pkcs_alg_id(alg_id, alg_id_len, password, + &is_block))) + return NULL; + + plaintext = l_malloc(encrypted_len); + ok = l_cipher_decrypt(alg, encrypted, plaintext, encrypted_len); + l_cipher_free(alg); + + if (!ok) { + l_free(plaintext); + return NULL; + } + + if (is_block) { + bool ok = true; + + /* Also validate the padding */ + if (encrypted_len < plaintext[encrypted_len - 1] || + plaintext[encrypted_len - 1] > 16) { + plaintext[encrypted_len - 1] = 1; + ok = false; + } + + for (i = 1; i < plaintext[encrypted_len - 1]; i++) + if (plaintext[encrypted_len - 1 - i] != + plaintext[encrypted_len - 1]) + ok = false; + + if (!ok) { + explicit_bzero(plaintext, encrypted_len); + l_free(plaintext); + return NULL; + } + + encrypted_len -= plaintext[encrypted_len - 1]; + } + + if (out_oid) { + out_oid->asn1_len = type_len; + memcpy(out_oid->asn1, type, type_len); + } + + *out_len = encrypted_len; + return plaintext; +} + +/* RFC7292 Appendix A. */ +static const struct cert_pkcs12_hash pkcs12_mac_algs[] = { + { + L_CHECKSUM_MD5, 16, 16, 64, + { 8, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0f, 0x02, 0x05 } } + }, + { + L_CHECKSUM_SHA1, 20, 20, 64, + { 5, { 0x2b, 0x0e, 0x03, 0x02, 0x1a } } + }, + { + L_CHECKSUM_SHA224, 28, 28, 64, + { 9, { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04 } } + }, + { + L_CHECKSUM_SHA256, 32, 32, 64, + { 9, { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 } } + }, + { + L_CHECKSUM_SHA384, 48, 48, 128, + { 9, { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 } } + }, + { + L_CHECKSUM_SHA512, 64, 64, 128, + { 9, { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 } } + }, + { + L_CHECKSUM_SHA512, 64, 28, 128, + { 9, { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05 } } + }, + { + L_CHECKSUM_SHA512, 64, 32, 128, + { 9, { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06 } } + }, +}; + +static const struct asn1_oid pkcs12_key_bag_oid = { + 11, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x01 } +}; + +static const struct asn1_oid pkcs12_pkcs8_shrouded_key_bag_oid = { + 11, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02 } +}; + +static const struct asn1_oid pkcs12_cert_bag_oid = { + 11, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x03 } +}; + +static const struct asn1_oid pkcs12_safe_contents_bag_oid = { + 11, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x06 } +}; + +static const struct asn1_oid pkcs9_x509_certificate_oid = { + 10, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x16, 0x01 } +}; + +/* RFC7292 Section 4.2.3 */ +static bool cert_parse_pkcs12_cert_bag(const uint8_t *data, size_t data_len, + struct l_certchain **out_certchain) +{ + const uint8_t *cert_bag; + size_t cert_bag_len; + const uint8_t *cert_id; + size_t cert_id_len; + const uint8_t *cert_value; + size_t cert_value_len; + uint8_t tag; + struct l_cert *cert; + + if (!(cert_bag = asn1_der_find_elem(data, data_len, 0, + &tag, &cert_bag_len)) || + tag != ASN1_ID_SEQUENCE) + return false; + + if (!(cert_id = asn1_der_find_elem(cert_bag, cert_bag_len, 0, + &tag, &cert_id_len)) || + tag != ASN1_ID_OID) + return false; + + if (!(cert_value = asn1_der_find_elem(cert_bag, cert_bag_len, + ASN1_CONTEXT_EXPLICIT(0), + &tag, &cert_value_len)) || + tag != ASN1_ID_OCTET_STRING || + cert_value + cert_value_len != data + data_len) + return false; + + /* Skip unsupported certificate types */ + if (!asn1_oid_eq(&pkcs9_x509_certificate_oid, cert_id_len, cert_id)) + return true; + + if (!(cert = l_cert_new_from_der(cert_value, cert_value_len))) + return false; + + if (!*out_certchain) + *out_certchain = certchain_new_from_leaf(cert); + else + certchain_link_issuer(*out_certchain, cert); + + return true; +} + +static bool cert_parse_pkcs12_safe_contents(const uint8_t *data, + size_t data_len, const char *password, + struct l_certchain **out_certchain, + struct l_key **out_privkey) +{ + const uint8_t *safe_contents; + size_t safe_contents_len; + uint8_t tag; + + if (!(safe_contents = asn1_der_find_elem(data, data_len, 0, &tag, + &safe_contents_len)) || + tag != ASN1_ID_SEQUENCE || + data + data_len != safe_contents + safe_contents_len) + return false; + + /* RFC7292 Section 4.2 */ + while (safe_contents_len) { + const uint8_t *safe_bag; + size_t safe_bag_len; + const uint8_t *bag_id; + size_t bag_id_len; + const uint8_t *bag_value; + int bag_value_len; + + /* RFC7292 Section 4.2 */ + if (!(safe_bag = asn1_der_find_elem(safe_contents, + safe_contents_len, 0, + &tag, &safe_bag_len)) || + tag != ASN1_ID_SEQUENCE) + return false; + + if (!(bag_id = asn1_der_find_elem(safe_bag, safe_bag_len, 0, + &tag, &bag_id_len)) || + tag != ASN1_ID_OID) + return false; + + /* + * The bagValue is EXPLICITly tagged but we don't want to + * unpack the inner TLV yet so don't use asn1_der_find_elem. + */ + safe_bag_len -= bag_id + bag_id_len - safe_bag; + safe_bag = bag_id + bag_id_len; + + if (safe_bag_len < 4) + return false; + + tag = *safe_bag++; + safe_bag_len--; + bag_value_len = asn1_parse_definite_length(&safe_bag, + &safe_bag_len); + bag_value = safe_bag; + + if (bag_value_len < 0 || bag_value_len > (int) safe_bag_len || + tag != ASN1_ID(ASN1_CLASS_CONTEXT, 1, 0)) + return false; + + /* PKCS#9 attributes ignored */ + + safe_contents_len -= (safe_bag + safe_bag_len - safe_contents); + safe_contents = safe_bag + safe_bag_len; + + if (asn1_oid_eq(&pkcs12_key_bag_oid, bag_id_len, bag_id)) { + if (!out_privkey || *out_privkey) + continue; + + *out_privkey = + cert_key_from_pkcs8_private_key_info(bag_value, + bag_value_len); + if (!*out_privkey) + return false; + } else if (asn1_oid_eq(&pkcs12_pkcs8_shrouded_key_bag_oid, + bag_id_len, bag_id)) { + if (!out_privkey || *out_privkey) + continue; + + *out_privkey = + cert_key_from_pkcs8_encrypted_private_key_info( + bag_value, + bag_value_len, + password); + if (!*out_privkey) + return false; + } else if (asn1_oid_eq(&pkcs12_cert_bag_oid, + bag_id_len, bag_id)) { + if (!out_certchain) + continue; + + if (!cert_parse_pkcs12_cert_bag(bag_value, bag_value_len, + out_certchain)) + return false; + } else if (asn1_oid_eq(&pkcs12_safe_contents_bag_oid, + bag_id_len, bag_id)) { + /* TODO: depth check */ + if (!(cert_parse_pkcs12_safe_contents(bag_value, + bag_value_len, + password, + out_certchain, + out_privkey))) + return false; + } + } + + return true; +} + +static bool cert_check_pkcs12_integrity(const uint8_t *mac_data, + size_t mac_data_len, + const uint8_t *auth_safe, + size_t auth_safe_len, + const char *password) +{ + const uint8_t *mac; + size_t mac_len; + const uint8_t *mac_salt; + size_t mac_salt_len; + const uint8_t *iterations_data; + size_t iterations_len; + unsigned int iterations; + const uint8_t *digest_alg; + size_t digest_alg_len; + const uint8_t *digest; + size_t digest_len; + const uint8_t *alg_id; + size_t alg_id_len; + const struct cert_pkcs12_hash *mac_hash; + L_AUTO_FREE_VAR(uint8_t *, key) = NULL; + struct l_checksum *hmac; + uint8_t hmac_val[64]; + uint8_t tag; + bool ok; + unsigned int i; + + if (!(mac = asn1_der_find_elem(mac_data, mac_data_len, 0, &tag, + &mac_len)) || + tag != ASN1_ID_SEQUENCE) + return false; + + if (!(mac_salt = asn1_der_find_elem(mac_data, mac_data_len, 1, &tag, + &mac_salt_len)) || + tag != ASN1_ID_OCTET_STRING || mac_salt_len > 1024) + return false; + + if (!(iterations_data = asn1_der_find_elem(mac_data, mac_data_len, 2, + &tag, + &iterations_len)) || + tag != ASN1_ID_INTEGER || iterations_len > 4) + return false; + + for (iterations = 0; iterations_len; iterations_len--) + iterations = (iterations << 8) | *iterations_data++; + + if (iterations < 1 || iterations > 8192) + return false; + + /* RFC2315 Section 9.4 */ + if (!(digest_alg = asn1_der_find_elem(mac, mac_len, 0, &tag, + &digest_alg_len)) || + tag != ASN1_ID_SEQUENCE) + return false; + + if (!(digest = asn1_der_find_elem(mac, mac_len, 1, &tag, + &digest_len)) || + tag != ASN1_ID_OCTET_STRING) + return false; + + if (!(alg_id = asn1_der_find_elem(digest_alg, digest_alg_len, + 0, &tag, &alg_id_len)) || + tag != ASN1_ID_OID) + return false; + + /* This is going to be used for both the MAC and its key derivation */ + for (i = 0; i < L_ARRAY_SIZE(pkcs12_mac_algs); i++) + if (asn1_oid_eq(&pkcs12_mac_algs[i].oid, alg_id_len, alg_id)) { + mac_hash = &pkcs12_mac_algs[i]; + break; + } + + if (i == L_ARRAY_SIZE(pkcs12_mac_algs) || digest_len != mac_hash->u) + return false; + + if (!(key = cert_pkcs12_pbkdf(password, mac_hash, + mac_salt, mac_salt_len, + iterations, 3, mac_hash->u))) + return false; + + hmac = l_checksum_new_hmac(mac_hash->alg, key, mac_hash->u); + explicit_bzero(key, mac_hash->u); + + if (!hmac) + return false; + + ok = l_checksum_update(hmac, auth_safe, auth_safe_len) && + l_checksum_get_digest(hmac, hmac_val, mac_hash->len) > 0; + l_checksum_free(hmac); + + if (!ok) + return false; + + /* + * SHA-512/224 and SHA-512/256 are not supported. We can truncate the + * output for key derivation but we can't do this inside the HMAC + * algorithms based on these hashes. We skip the MAC verification + * if one of these hashes is used (identified by .u != .len) + */ + if (mac_hash->u != mac_hash->len) + return true; + + return l_secure_memcmp(hmac_val, digest, digest_len) == 0; +} + +/* RFC5652 Section 4 */ +static const struct asn1_oid pkcs7_data_oid = { + 9, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01 } +}; + +/* RFC5652 Section 8 */ +static const struct asn1_oid pkcs7_encrypted_data_oid = { + 9, { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x06 } +}; + +static bool cert_parse_auth_safe_content(const uint8_t *data, size_t data_len, + uint8_t tag, + const struct asn1_oid *data_oid, + const char *password, + struct l_certchain **out_certchain, + struct l_key **out_privkey) +{ + if (asn1_oid_eq(&pkcs7_encrypted_data_oid, + data_oid->asn1_len, data_oid->asn1)) { + uint8_t *plaintext; + size_t plaintext_len; + struct asn1_oid oid; + bool ok; + + if (tag != ASN1_ID_SEQUENCE) + return false; + + /* + * This is same as PKCS#7 encryptedData but the ciphers + * used are from PKCS#12 (broken but still the default + * everywhere) and PKCS#5 (recommended). + */ + plaintext = cert_decrypt_pkcs7_encrypted_data(data, + data_len, + password, &oid, + &plaintext_len); + if (!plaintext) + return false; + + /* + * Since we only support PKCS#7 data and encryptedData + * types, and there's no point re-encrypting + * encryptedData, the plaintext must be a PKCS#7 + * "data". + */ + ok = asn1_oid_eq(&pkcs7_data_oid, + oid.asn1_len, oid.asn1) && + cert_parse_pkcs12_safe_contents(plaintext, + plaintext_len, + password, + out_certchain, + out_privkey); + explicit_bzero(plaintext, plaintext_len); + l_free(plaintext); + + if (!ok) + return false; + } else if (asn1_oid_eq(&pkcs7_data_oid, + data_oid->asn1_len, data_oid->asn1)) { + if (tag != ASN1_ID_OCTET_STRING) + return false; + + if (!cert_parse_pkcs12_safe_contents(data, data_len, + password, + out_certchain, + out_privkey)) + return false; + } + /* envelopedData support not needed */ + + return true; +} + +static bool cert_parse_pkcs12_pfx(const uint8_t *ptr, size_t len, + const char *password, + struct l_certchain **out_certchain, + struct l_key **out_privkey) +{ + const uint8_t *version; + size_t version_len; + const uint8_t *auth_safe; + size_t auth_safe_len; + const uint8_t *mac_data; + size_t mac_data_len; + const uint8_t *auth_safe_seq; + size_t auth_safe_seq_len; + uint8_t tag; + unsigned int i; + struct l_certchain *certchain = NULL; + struct l_key *privkey = NULL; + + /* RFC7292 Section 4 */ + if (!(version = asn1_der_find_elem(ptr, len, 0, &tag, &version_len)) || + tag != ASN1_ID_INTEGER) + return false; + + if (version_len != 1 || version[0] != 3) + return false; + + /* + * Since we only support the password-based integrity mode, the + * authSafe must be of PKCS#7 type "data" and not "signedData". + */ + if (!(auth_safe = cert_unpack_pkcs7_content_info(ptr, len, 1, + &pkcs7_data_oid, NULL, + &tag, + &auth_safe_len)) || + tag != ASN1_ID_OCTET_STRING) + return false; + + /* + * openssl can generate PFX structures without macData not signed + * with a public key so handle this case, otherwise the macData + * would not be optional. + */ + if (auth_safe + auth_safe_len == ptr + len) + goto integrity_check_done; + + if (!(mac_data = asn1_der_find_elem(ptr, len, 2, &tag, + &mac_data_len)) || + tag != ASN1_ID_SEQUENCE) + return false; + + if (!cert_check_pkcs12_integrity(mac_data, mac_data_len, + auth_safe, auth_safe_len, + password)) + return false; + +integrity_check_done: + if (!(auth_safe_seq = asn1_der_find_elem(auth_safe, auth_safe_len, 0, + &tag, &auth_safe_seq_len)) || + tag != ASN1_ID_SEQUENCE || + auth_safe + auth_safe_len != + auth_safe_seq + auth_safe_seq_len) + return false; + + i = 0; + while (1) { + struct asn1_oid data_oid; + const uint8_t *data; + size_t data_len; + + if (!(data = cert_unpack_pkcs7_content_info(auth_safe_seq, + auth_safe_seq_len, i++, + NULL, &data_oid, &tag, + &data_len))) + goto error; + + if (!cert_parse_auth_safe_content(data, data_len, tag, + &data_oid, password, + out_certchain ? + &certchain : NULL, + out_privkey ? + &privkey : NULL)) + goto error; + + if (data + data_len == auth_safe_seq + auth_safe_seq_len) + break; + } + + if (out_certchain) + *out_certchain = certchain; + + if (out_privkey) + *out_privkey = privkey; + + return true; + +error: + if (certchain) + l_certchain_free(certchain); + + if (privkey) + l_key_free(privkey); + + return false; +} + +static int cert_try_load_der_format(const uint8_t *content, size_t content_len, + const char *password, + struct l_certchain **out_certchain, + struct l_key **out_privkey, + bool *out_encrypted) +{ + const uint8_t *seq; + size_t seq_len; + size_t elem_len; + uint8_t tag; + + if (!(seq = asn1_der_find_elem(content, content_len, + 0, &tag, &seq_len))) + /* May not have been a DER file after all */ + return -ENOMSG; + + /* + * See if the first sub-element is another sequence, then, out of + * the formats that we currently support this can only be a raw + * certificate. If integer, it's going to be PKCS#12. If we wish + * to add any more formats we'll probably need to start guessing + * from the filename suffix. + */ + if (!asn1_der_find_elem(seq, seq_len,0, &tag, &elem_len)) + return -ENOMSG; + + if (tag == ASN1_ID_SEQUENCE) { + if (out_certchain) { + struct l_cert *cert; + + if (!(cert = l_cert_new_from_der(content, content_len))) + return -EINVAL; + + *out_certchain = certchain_new_from_leaf(cert); + + if (out_privkey) + *out_privkey = NULL; + + if (out_encrypted) + *out_encrypted = false; + + return 0; + } + + return -EINVAL; + } + + if (tag == ASN1_ID_INTEGER) { + /* + * Since we don't support public key-protected PKCS#12 + * modes, we always require the password at least for the + * integrity check. Strictly speaking encryption may not + * actually be in use. We also don't support files with + * different integrity and privacy passwords, they must + * be identical if privacy is enabled. + */ + if (out_encrypted) + *out_encrypted = true; + + if (!password) { + if (!out_encrypted) + return -EINVAL; + + if (out_certchain) + *out_certchain = NULL; + + if (out_privkey) + *out_privkey = NULL; + + return 0; + } + + if (cert_parse_pkcs12_pfx(seq, seq_len, password, + out_certchain, out_privkey)) + return 0; + else + return -EINVAL; + } + + return -ENOMSG; +} + +static bool cert_try_load_pem_format(const char *content, size_t content_len, + const char *password, + struct l_certchain **out_certchain, + struct l_key **out_privkey, + bool *out_encrypted) +{ + bool error = false; + bool done = false; + struct l_certchain *certchain = NULL; + struct l_key *privkey = NULL; + bool encrypted = false; + + while (!done && !error && content_len) { + uint8_t *der; + size_t der_len; + char *type_label; + char *headers; + const char *endp; + + if (!(der = pem_load_buffer(content, content_len, &type_label, + &der_len, &headers, &endp))) + break; + + content_len -= endp - content; + content = endp; + + if (out_certchain && L_IN_STRSET(type_label, "CERTIFICATE")) { + struct l_cert *cert; + + if (!(cert = l_cert_new_from_der(der, der_len))) { + error = true; + goto next; + } + + if (!certchain) + certchain = certchain_new_from_leaf(cert); + else + certchain_link_issuer(certchain, cert); + + goto next; + } + + /* Only use the first private key found */ + if (out_privkey && !privkey && L_IN_STRSET(type_label, + "PRIVATE KEY", + "ENCRYPTED PRIVATE KEY", + "RSA PRIVATE KEY")) { + privkey = pem_load_private_key(der, der_len, type_label, + password, headers, + &encrypted); + if (!privkey) { + if (certchain) { + l_certchain_free(certchain); + certchain = NULL; + } + + if (password) + error = true; + else + error = !encrypted || !out_encrypted; + + done = true; + } + + continue; + } + + /* Cisco/gnutls-type PEM-encoded PKCS#12, probably rare */ + if (L_IN_STRSET(type_label, "PKCS12")) { + encrypted = true; + + if (!password) { + if (certchain && out_privkey) { + l_certchain_free(certchain); + certchain = NULL; + } + + error = !out_encrypted; + done = true; + goto next; + } + + error = !cert_parse_pkcs12_pfx(der, der_len, password, + out_certchain ? + &certchain : NULL, + out_privkey ? + &privkey : NULL); + goto next; + } + +next: + explicit_bzero(der, der_len); + l_free(der); + l_free(type_label); + l_free(headers); + } + + if (error) { + if (certchain) + l_certchain_free(certchain); + + if (privkey) + l_key_free(privkey); + + return false; + } + + if (out_certchain) + *out_certchain = certchain; + + if (out_privkey) + *out_privkey = privkey; + + if (out_encrypted) + *out_encrypted = encrypted; + + return true; +} + +/* + * Look at a file, try to detect which of the few X.509 certificate and/or + * private key container formats it uses and load any certificates in it as + * a certificate chain object, and load the first private key as an l_key + * object. + * + * Currently supported are: + * PEM X.509 certificates + * PEM PKCS#8 encrypted and unencrypted private keys + * PEM legacy PKCS#1 encrypted and unencrypted private keys + * Raw X.509 certificates (.cer, .der, .crt) + * PKCS#12 certificates + * PKCS#12 encrypted private keys + * + * The raw format contains exactly one certificate, PEM and PKCS#12 files + * can contain any combination of certificates and private keys. + * + * The password must have been validated as UTF-8 (use l_utf8_validate) + * unless the caller knows that no PKCS#12-defined encryption algorithm + * or MAC is used. + * + * Returns false on "unrecoverable" errors, and *out_certchain, + * *out_privkey and *out_encrypted (if provided) are not modified. However + * when true is returned, *out_certchain and *out_privkey (if provided) may + * be set to NULL when nothing could be loaded only due to missing password, + * and *out_encrypted (if provided) will be set accordingly. It will also + * be set on success to indicate whether the password was used. + * *out_certchain and/or *out_privkey will also be NULL if the container + * was loaded but there were no certificates or private keys in it. + */ +LIB_EXPORT bool l_cert_load_container_file(const char *filename, + const char *password, + struct l_certchain **out_certchain, + struct l_key **out_privkey, + bool *out_encrypted) +{ + struct pem_file_info file; + bool error = true; + + if (unlikely(!filename)) + return false; + + if (pem_file_open(&file, filename) < 0) + return false; + + if (file.st.st_size < 1) + goto close; + + /* See if we have a DER sequence tag at the start */ + if (file.data[0] == ASN1_ID_SEQUENCE) { + int err; + + err = cert_try_load_der_format(file.data, file.st.st_size, + password, out_certchain, + out_privkey, out_encrypted); + if (!err) { + error = false; + goto close; + } + + if (err != -ENOMSG) + goto close; + + /* Try other formats */ + } + + /* + * For backwards compatibility try the TLS internal struct Certificate + * format as may be captured by PCAP (no future support guaranteed). + */ + if (out_certchain && !password && file.st.st_size && + tls_parse_certificate_list(file.data, file.st.st_size, + out_certchain) == 0) { + error = false; + + if (out_privkey) + *out_privkey = NULL; + + if (out_encrypted) + *out_encrypted = false; + + goto close; + } + + /* + * RFC 7486 allows whitespace and possibly other data before the + * PEM "encapsulation boundary" so rather than check if the start + * of the data looks like PEM, we fall back to this format if the + * data didn't look like anything else we knew about. Note this + * succeeds for empty files and files without any PEM markers, + * returning NULL chain and privkey. + */ + if (cert_try_load_pem_format((const char *) file.data, file.st.st_size, + password, out_certchain, out_privkey, + out_encrypted)) + error = false; + +close: + pem_file_close(&file); + return !error; +} diff --git a/ell/cert.h b/ell/cert.h new file mode 100644 index 0000000000000000000000000000000000000000..78b2e547e5a79e596df0c37209a11efac0722915 --- /dev/null +++ b/ell/cert.h @@ -0,0 +1,71 @@ +/* + * Embedded Linux library + * Copyright (C) 2018 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_CERT_H +#define __ELL_CERT_H + +#include <stddef.h> +#include <ell/cleanup.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct l_queue; +struct l_cert; +struct l_certchain; + +enum l_cert_key_type { + L_CERT_KEY_RSA, + L_CERT_KEY_ECC, + L_CERT_KEY_UNKNOWN, +}; + +typedef bool (*l_cert_walk_cb_t)(struct l_cert *cert, void *user_data); + +struct l_cert *l_cert_new_from_der(const uint8_t *buf, size_t buf_len); +void l_cert_free(struct l_cert *cert); +DEFINE_CLEANUP_FUNC(l_cert_free); + +const uint8_t *l_cert_get_der_data(struct l_cert *cert, size_t *out_len); +const uint8_t *l_cert_get_dn(struct l_cert *cert, size_t *out_len); +bool l_cert_get_valid_times(struct l_cert *cert, uint64_t *out_not_before_time, + uint64_t *out_not_after_time); +enum l_cert_key_type l_cert_get_pubkey_type(struct l_cert *cert); +struct l_key *l_cert_get_pubkey(struct l_cert *cert); + +void l_certchain_free(struct l_certchain *chain); +DEFINE_CLEANUP_FUNC(l_certchain_free); + +struct l_cert *l_certchain_get_leaf(struct l_certchain *chain); +void l_certchain_walk_from_leaf(struct l_certchain *chain, + l_cert_walk_cb_t cb, void *user_data); +void l_certchain_walk_from_ca(struct l_certchain *chain, + l_cert_walk_cb_t cb, void *user_data); + +bool l_certchain_verify(struct l_certchain *chain, struct l_queue *ca_certs, + const char **error); + +bool l_cert_load_container_file(const char *filename, const char *password, + struct l_certchain **out_certchain, + struct l_key **out_privkey, + bool *out_encrypted); + +bool l_cert_pkcs5_pbkdf1(enum l_checksum_type type, const char *password, + const uint8_t *salt, size_t salt_len, + unsigned int iter_count, + uint8_t *out_dk, size_t dk_len); +bool l_cert_pkcs5_pbkdf2(enum l_checksum_type type, const char *password, + const uint8_t *salt, size_t salt_len, + unsigned int iter_count, + uint8_t *out_dk, size_t dk_len); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_CERT_H */ diff --git a/ell/checksum.c b/ell/checksum.c new file mode 100644 index 0000000000000000000000000000000000000000..74defdd4e15d8721d45fd798af02280e58b509ba --- /dev/null +++ b/ell/checksum.c @@ -0,0 +1,445 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <stdio.h> + +#include "useful.h" +#include "checksum.h" +#include "private.h" + +#ifndef HAVE_LINUX_IF_ALG_H +#ifndef HAVE_LINUX_TYPES_H +typedef uint8_t __u8; +typedef uint16_t __u16; +typedef uint32_t __u32; +#else +#include <linux/types.h> +#endif + +#ifndef AF_ALG +#define AF_ALG 38 +#define PF_ALG AF_ALG +#endif + +struct sockaddr_alg { + __u16 salg_family; + __u8 salg_type[14]; + __u32 salg_feat; + __u32 salg_mask; + __u8 salg_name[64]; +}; + +/* Socket options */ +#define ALG_SET_KEY 1 + +#else +#include <linux/if_alg.h> +#endif + +#ifndef SOL_ALG +#define SOL_ALG 279 +#endif + +struct checksum_info { + const char *name; + uint8_t digest_len; + bool supported; +}; + +static struct checksum_info checksum_algs[] = { + [L_CHECKSUM_MD4] = { .name = "md4", .digest_len = 16 }, + [L_CHECKSUM_MD5] = { .name = "md5", .digest_len = 16 }, + [L_CHECKSUM_SHA1] = { .name = "sha1", .digest_len = 20 }, + [L_CHECKSUM_SHA256] = { .name = "sha256", .digest_len = 32 }, + [L_CHECKSUM_SHA384] = { .name = "sha384", .digest_len = 48 }, + [L_CHECKSUM_SHA512] = { .name = "sha512", .digest_len = 64 }, +}; + +static struct checksum_info checksum_cmac_aes_alg = + { .name = "cmac(aes)", .digest_len = 16 }; + +static struct checksum_info checksum_hmac_algs[] = { + [L_CHECKSUM_MD4] = { .name = "hmac(md4)", .digest_len = 16 }, + [L_CHECKSUM_MD5] = { .name = "hmac(md5)", .digest_len = 16 }, + [L_CHECKSUM_SHA1] = { .name = "hmac(sha1)", .digest_len = 20 }, + [L_CHECKSUM_SHA256] = { .name = "hmac(sha256)", .digest_len = 32 }, + [L_CHECKSUM_SHA384] = { .name = "hmac(sha384)", .digest_len = 48 }, + [L_CHECKSUM_SHA512] = { .name = "hmac(sha512)", .digest_len = 64 }, +}; + +static const struct { + struct checksum_info *list; + size_t n; +} checksum_info_table[] = { + { checksum_algs, L_ARRAY_SIZE(checksum_algs) }, + { &checksum_cmac_aes_alg, 1 }, + { checksum_hmac_algs, L_ARRAY_SIZE(checksum_hmac_algs) }, + {} +}; + +/** + * SECTION:checksum + * @short_description: Checksum handling + * + * Checksum handling + */ + +#define is_valid_index(array, i) ((i) >= 0 && (i) < L_ARRAY_SIZE(array)) + +/** + * l_checksum: + * + * Opaque object representing the checksum. + */ +struct l_checksum { + int sk; + const struct checksum_info *alg_info; +}; + +static int create_alg(const char *alg) +{ + struct sockaddr_alg salg; + int sk; + + sk = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); + if (sk < 0) + return -1; + + memset(&salg, 0, sizeof(salg)); + salg.salg_family = AF_ALG; + strcpy((char *) salg.salg_type, "hash"); + strcpy((char *) salg.salg_name, alg); + + if (bind(sk, (struct sockaddr *) &salg, sizeof(salg)) < 0) { + close(sk); + return -1; + } + + return sk; +} + +static struct l_checksum *checksum_new_common(const char *alg, int sockopt, + const void *data, size_t len, + struct checksum_info *info) +{ + struct l_checksum *checksum; + int fd; + + fd = create_alg(alg); + if (fd < 0) + return NULL; + + if (data) { + if (setsockopt(fd, SOL_ALG, sockopt, data, len) < 0) { + close(fd); + return NULL; + } + } + + checksum = l_new(struct l_checksum, 1); + checksum->sk = accept4(fd, NULL, 0, SOCK_CLOEXEC); + close(fd); + + if (checksum->sk < 0) { + l_free(checksum); + return NULL; + } + + checksum->alg_info = info; + return checksum; +} + +/** + * l_checksum_new: + * @type: checksum type + * + * Creates new #l_checksum, using the checksum algorithm @type. + * + * Returns: a newly allocated #l_checksum object. + **/ +LIB_EXPORT struct l_checksum *l_checksum_new(enum l_checksum_type type) +{ + if (!is_valid_index(checksum_algs, type) || !checksum_algs[type].name) + return NULL; + + return checksum_new_common(checksum_algs[type].name, 0, NULL, 0, + &checksum_algs[type]); +} + +LIB_EXPORT struct l_checksum *l_checksum_new_cmac_aes(const void *key, + size_t key_len) +{ + return checksum_new_common("cmac(aes)", ALG_SET_KEY, key, key_len, + &checksum_cmac_aes_alg); +} + +LIB_EXPORT struct l_checksum *l_checksum_new_hmac(enum l_checksum_type type, + const void *key, size_t key_len) +{ + if (!is_valid_index(checksum_hmac_algs, type) || + !checksum_hmac_algs[type].name) + return NULL; + + return checksum_new_common(checksum_hmac_algs[type].name, + ALG_SET_KEY, key, key_len, + &checksum_hmac_algs[type]); +} + +/** + * l_checksum_clone: + * @checksum: parent checksum object + * + * Creates a new checksum with an independent copy of parent @checksum's + * state. l_checksum_get_digest can then be called on the parent or the + * clone without affecting the state of the other object. + **/ +LIB_EXPORT struct l_checksum *l_checksum_clone(struct l_checksum *checksum) +{ + struct l_checksum *clone; + + if (unlikely(!checksum)) + return NULL; + + clone = l_new(struct l_checksum, 1); + clone->sk = accept4(checksum->sk, NULL, 0, SOCK_CLOEXEC); + + if (clone->sk < 0) { + l_free(clone); + return NULL; + } + + clone->alg_info = checksum->alg_info; + return clone; +} + +/** + * l_checksum_free: + * @checksum: checksum object + * + * Frees the memory allocated for @checksum. + **/ +LIB_EXPORT void l_checksum_free(struct l_checksum *checksum) +{ + if (unlikely(!checksum)) + return; + + close(checksum->sk); + l_free(checksum); +} + +/** + * l_checksum_reset: + * @checksum: checksum object + * + * Resets the internal state of @checksum. + **/ +LIB_EXPORT void l_checksum_reset(struct l_checksum *checksum) +{ + if (unlikely(!checksum)) + return; + + send(checksum->sk, NULL, 0, 0); +} + +/** + * l_checksum_update: + * @checksum: checksum object + * @data: data pointer + * @len: length of data + * + * Updates checksum from @data pointer with @len bytes. + * + * Returns: true if the operation succeeded, false otherwise. + **/ +LIB_EXPORT bool l_checksum_update(struct l_checksum *checksum, + const void *data, size_t len) +{ + ssize_t written; + + if (unlikely(!checksum)) + return false; + + written = send(checksum->sk, data, len, MSG_MORE); + if (written < 0) + return false; + + return true; +} + +/** + * l_checksum_updatev: + * @checksum: checksum object + * @iov: iovec pointer + * @iov_len: Number of iovec entries + * + * This is a iovec based version of l_checksum_update; it updates the checksum + * based on contents of @iov and @iov_len. + * + * Returns: true if the operation succeeded, false otherwise. + **/ +LIB_EXPORT bool l_checksum_updatev(struct l_checksum *checksum, + const struct iovec *iov, size_t iov_len) +{ + struct msghdr msg; + ssize_t written; + + if (unlikely(!checksum)) + return false; + + if (unlikely(!iov) || unlikely(!iov_len)) + return false; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = (struct iovec *) iov; + msg.msg_iovlen = iov_len; + + written = sendmsg(checksum->sk, &msg, MSG_MORE); + if (written < 0) + return false; + + return true; +} + +/** + * l_checksum_get_digest: + * @checksum: checksum object + * @digest: output data buffer + * @len: length of output buffer + * + * Writes the digest from @checksum as raw binary data into the provided + * buffer or, if the buffer is shorter, the initial @len bytes of the digest + * data. + * + * Returns: Number of bytes written, or negative value if an error occurred. + **/ +LIB_EXPORT ssize_t l_checksum_get_digest(struct l_checksum *checksum, + void *digest, size_t len) +{ + ssize_t result; + + if (unlikely(!checksum)) + return -EINVAL; + + if (unlikely(!digest)) + return -EFAULT; + + if (unlikely(!len)) + return -EINVAL; + + result = recv(checksum->sk, digest, len, 0); + if (result < 0) + return -errno; + + if ((size_t) result < len && result < checksum->alg_info->digest_len) + return -EIO; + + return result; +} + +/** + * l_checksum_get_string: + * @checksum: checksum object + * + * Gets the digest from @checksum as hex encoded string. + * + * Returns: a newly allocated hex string + **/ +LIB_EXPORT char *l_checksum_get_string(struct l_checksum *checksum) +{ + unsigned char digest[64]; + + if (unlikely(!checksum)) + return NULL; + + l_checksum_get_digest(checksum, digest, sizeof(digest)); + + return l_util_hexstring(digest, checksum->alg_info->digest_len); +} + +static void init_supported() +{ + static bool initialized = false; + struct sockaddr_alg salg; + int sk; + unsigned int i, j; + + if (likely(initialized)) + return; + + initialized = true; + + sk = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); + if (sk < 0) + return; + + memset(&salg, 0, sizeof(salg)); + salg.salg_family = AF_ALG; + strcpy((char *) salg.salg_type, "hash"); + + for (i = 0; checksum_info_table[i].list; i++) + for (j = 0; j < checksum_info_table[i].n; j++) { + struct checksum_info *info; + + info = &checksum_info_table[i].list[j]; + if (!info->name) + continue; + + strcpy((char *) salg.salg_name, info->name); + + if (bind(sk, (struct sockaddr *) &salg, + sizeof(salg)) < 0) + continue; + + info->supported = true; + } + + close(sk); +} + +LIB_EXPORT bool l_checksum_is_supported(enum l_checksum_type type, + bool check_hmac) +{ + const struct checksum_info *list; + + init_supported(); + + if (!check_hmac) { + if (!is_valid_index(checksum_algs, type)) + return false; + + list = checksum_algs; + } else { + if (!is_valid_index(checksum_hmac_algs, type)) + return false; + + list = checksum_hmac_algs; + } + + return list[type].supported; +} + +LIB_EXPORT bool l_checksum_cmac_aes_supported() +{ + init_supported(); + + return checksum_cmac_aes_alg.supported; +} + +LIB_EXPORT ssize_t l_checksum_digest_length(enum l_checksum_type type) +{ + return is_valid_index(checksum_algs, type) ? + checksum_algs[type].digest_len : 0; +} diff --git a/ell/checksum.h b/ell/checksum.h new file mode 100644 index 0000000000000000000000000000000000000000..cc03b035df6587bd55ba2ff543e923adab9b6480 --- /dev/null +++ b/ell/checksum.h @@ -0,0 +1,60 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_CHECKSUM_H +#define __ELL_CHECKSUM_H + +#include <stdbool.h> +#include <stdint.h> +#include <sys/uio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct l_checksum; + +enum l_checksum_type { + L_CHECKSUM_NONE, + L_CHECKSUM_MD4, + L_CHECKSUM_MD5, + L_CHECKSUM_SHA1, + L_CHECKSUM_SHA224, + L_CHECKSUM_SHA256, + L_CHECKSUM_SHA384, + L_CHECKSUM_SHA512, +}; + +struct l_checksum *l_checksum_new(enum l_checksum_type type); +struct l_checksum *l_checksum_new_cmac_aes(const void *key, size_t key_len); +struct l_checksum *l_checksum_new_hmac(enum l_checksum_type type, + const void *key, size_t key_len); +struct l_checksum *l_checksum_clone(struct l_checksum *checksum); + +void l_checksum_free(struct l_checksum *checksum); + +void l_checksum_reset(struct l_checksum *checksum); + +bool l_checksum_update(struct l_checksum *checksum, + const void *data, size_t len); +bool l_checksum_updatev(struct l_checksum *checksum, + const struct iovec *iov, + size_t iov_len); +ssize_t l_checksum_get_digest(struct l_checksum *checksum, + void *digest, size_t len); +char *l_checksum_get_string(struct l_checksum *checksum); + +bool l_checksum_is_supported(enum l_checksum_type type, bool check_hmac); +bool l_checksum_cmac_aes_supported(void); + +ssize_t l_checksum_digest_length(enum l_checksum_type type); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_CHECKSUM_H */ diff --git a/ell/cipher.c b/ell/cipher.c new file mode 100644 index 0000000000000000000000000000000000000000..a1c0e255a92f43305e55836a109d3ffafaed0b6e --- /dev/null +++ b/ell/cipher.c @@ -0,0 +1,1102 @@ +/* + * Embedded Linux library + * Copyright (C) 2015 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <unistd.h> +#include <stdbool.h> +#include <stdint.h> +#include <errno.h> +#include <sys/socket.h> +#include <alloca.h> + +#include "useful.h" +#include "cipher.h" +#include "private.h" +#include "random.h" +#include "missing.h" + +#ifndef HAVE_LINUX_IF_ALG_H +#ifndef HAVE_LINUX_TYPES_H +typedef uint8_t __u8; +typedef uint16_t __u16; +typedef uint32_t __u32; +#else +#include <linux/types.h> +#endif + +#ifndef AF_ALG +#define AF_ALG 38 +#define PF_ALG AF_ALG +#endif + +struct sockaddr_alg { + __u16 salg_family; + __u8 salg_type[14]; + __u32 salg_feat; + __u32 salg_mask; + __u8 salg_name[64]; +}; + +struct af_alg_iv { + __u32 ivlen; + __u8 iv[0]; +}; + +/* Socket options */ +#define ALG_SET_KEY 1 +#define ALG_SET_IV 2 +#define ALG_SET_OP 3 + +/* Operations */ +#define ALG_OP_DECRYPT 0 +#define ALG_OP_ENCRYPT 1 +#else +#include <linux/if_alg.h> +#endif + +#ifndef SOL_ALG +#define SOL_ALG 279 +#endif + +#ifndef ALG_SET_AEAD_ASSOCLEN +#define ALG_SET_AEAD_ASSOCLEN 4 +#endif + +#ifndef ALG_SET_AEAD_AUTHSIZE +#define ALG_SET_AEAD_AUTHSIZE 5 +#endif + +#define is_valid_type(type) ((type) <= L_CIPHER_RC2_CBC) + +static uint32_t supported_ciphers; +static uint32_t supported_aead_ciphers; + +struct l_cipher { + int type; + const struct local_impl *local; + union { + int sk; + void *local_data; + }; +}; + +struct l_aead_cipher { + int type; + int sk; +}; + +struct local_impl { + void *(*cipher_new)(enum l_cipher_type, + const void *key, size_t key_length); + void (*cipher_free)(void *data); + bool (*set_iv)(void *data, const uint8_t *iv, size_t iv_length); + ssize_t (*operate)(void *data, __u32 operation, + const struct iovec *in, size_t in_cnt, + const struct iovec *out, size_t out_cnt); +}; + +static int create_alg(const char *alg_type, const char *alg_name, + const void *key, size_t key_length, size_t tag_length) +{ + struct sockaddr_alg salg; + int sk; + int ret; + + sk = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); + if (sk < 0) + return -errno; + + memset(&salg, 0, sizeof(salg)); + salg.salg_family = AF_ALG; + strcpy((char *) salg.salg_type, alg_type); + strcpy((char *) salg.salg_name, alg_name); + + if (bind(sk, (struct sockaddr *) &salg, sizeof(salg)) < 0) { + close(sk); + return -1; + } + + if (setsockopt(sk, SOL_ALG, ALG_SET_KEY, key, key_length) < 0) { + close(sk); + return -1; + } + + if (tag_length && setsockopt(sk, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, + tag_length)) { + close(sk); + return -1; + } + + ret = accept4(sk, NULL, 0, SOCK_CLOEXEC); + close(sk); + + return ret; +} + +static const char *cipher_type_to_name(enum l_cipher_type type) +{ + switch (type) { + case L_CIPHER_AES: + return "ecb(aes)"; + case L_CIPHER_AES_CBC: + return "cbc(aes)"; + case L_CIPHER_AES_CTR: + return "ctr(aes)"; + case L_CIPHER_ARC4: + return NULL; + case L_CIPHER_DES: + return "ecb(des)"; + case L_CIPHER_DES_CBC: + return "cbc(des)"; + case L_CIPHER_DES3_EDE_CBC: + return "cbc(des3_ede)"; + case L_CIPHER_RC2_CBC: + return NULL; + } + + return NULL; +} + +static const struct local_impl local_arc4; +static const struct local_impl local_rc2_cbc; + +static const struct local_impl *local_impl_ciphers[] = { + [L_CIPHER_ARC4] = &local_arc4, + [L_CIPHER_RC2_CBC] = &local_rc2_cbc, +}; + +#define HAVE_LOCAL_IMPLEMENTATION(type) \ + ((type) < L_ARRAY_SIZE(local_impl_ciphers) && \ + local_impl_ciphers[(type)]) + +LIB_EXPORT struct l_cipher *l_cipher_new(enum l_cipher_type type, + const void *key, + size_t key_length) +{ + struct l_cipher *cipher; + const char *alg_name; + + if (unlikely(!key)) + return NULL; + + if (!is_valid_type(type)) + return NULL; + + cipher = l_new(struct l_cipher, 1); + cipher->type = type; + alg_name = cipher_type_to_name(type); + + if (HAVE_LOCAL_IMPLEMENTATION(type)) { + cipher->local = local_impl_ciphers[type]; + cipher->local_data = cipher->local->cipher_new(type, + key, key_length); + + if (!cipher->local_data) + goto error_free; + + return cipher; + } + + cipher->sk = create_alg("skcipher", alg_name, key, key_length, 0); + if (cipher->sk < 0) + goto error_free; + + return cipher; + +error_free: + l_free(cipher); + return NULL; +} + +static const char *aead_cipher_type_to_name(enum l_aead_cipher_type type) +{ + switch (type) { + case L_AEAD_CIPHER_AES_CCM: + return "ccm(aes)"; + case L_AEAD_CIPHER_AES_GCM: + return "gcm(aes)"; + } + + return NULL; +} + +LIB_EXPORT struct l_aead_cipher *l_aead_cipher_new(enum l_aead_cipher_type type, + const void *key, + size_t key_length, + size_t tag_length) +{ + struct l_aead_cipher *cipher; + const char *alg_name; + + if (unlikely(!key)) + return NULL; + + if (type != L_AEAD_CIPHER_AES_CCM && type != L_AEAD_CIPHER_AES_GCM) + return NULL; + + cipher = l_new(struct l_aead_cipher, 1); + cipher->type = type; + alg_name = aead_cipher_type_to_name(type); + + cipher->sk = create_alg("aead", alg_name, key, key_length, tag_length); + if (cipher->sk >= 0) + return cipher; + + l_free(cipher); + return NULL; +} + +LIB_EXPORT void l_cipher_free(struct l_cipher *cipher) +{ + if (unlikely(!cipher)) + return; + + if (cipher->local) + cipher->local->cipher_free(cipher->local_data); + else + close(cipher->sk); + + l_free(cipher); +} + +LIB_EXPORT void l_aead_cipher_free(struct l_aead_cipher *cipher) +{ + if (unlikely(!cipher)) + return; + + close(cipher->sk); + + l_free(cipher); +} + +static ssize_t operate_cipher(int sk, __u32 operation, + const void *in, size_t in_len, + const void *ad, size_t ad_len, + const void *iv, size_t iv_len, + void *out, size_t out_len) +{ + char *c_msg_buf; + size_t c_msg_size; + struct msghdr msg; + struct cmsghdr *c_msg; + struct iovec iov[2]; + ssize_t result; + + c_msg_size = CMSG_SPACE(sizeof(operation)); + c_msg_size += ad_len ? CMSG_SPACE(sizeof(uint32_t)) : 0; + c_msg_size += iv_len ? + CMSG_SPACE(sizeof(struct af_alg_iv) + iv_len) : 0; + + c_msg_buf = alloca(c_msg_size); + + memset(c_msg_buf, 0, c_msg_size); + memset(&msg, 0, sizeof(msg)); + + msg.msg_iov = iov; + + msg.msg_control = c_msg_buf; + msg.msg_controllen = c_msg_size; + + c_msg = CMSG_FIRSTHDR(&msg); + c_msg->cmsg_level = SOL_ALG; + c_msg->cmsg_type = ALG_SET_OP; + c_msg->cmsg_len = CMSG_LEN(sizeof(operation)); + memcpy(CMSG_DATA(c_msg), &operation, sizeof(operation)); + + if (ad_len) { + uint32_t *ad_data; + + c_msg = CMSG_NXTHDR(&msg, c_msg); + c_msg->cmsg_level = SOL_ALG; + c_msg->cmsg_type = ALG_SET_AEAD_ASSOCLEN; + c_msg->cmsg_len = CMSG_LEN(sizeof(*ad_data)); + ad_data = (void *) CMSG_DATA(c_msg); + *ad_data = ad_len; + + iov[0].iov_base = (void *) ad; + iov[0].iov_len = ad_len; + + msg.msg_iovlen = 1; + + if (in) { + iov[1].iov_base = (void *) in; + iov[1].iov_len = in_len; + msg.msg_iovlen = 2; + } + } else { + iov[0].iov_base = (void *) in; + iov[0].iov_len = in_len; + msg.msg_iovlen = 1; + } + + if (iv_len) { + struct af_alg_iv *algiv; + + c_msg = CMSG_NXTHDR(&msg, c_msg); + c_msg->cmsg_level = SOL_ALG; + c_msg->cmsg_type = ALG_SET_IV; + c_msg->cmsg_len = CMSG_LEN(sizeof(*algiv) + iv_len); + + algiv = (void *)CMSG_DATA(c_msg); + algiv->ivlen = iv_len; + memcpy(algiv->iv, iv, iv_len); + } + + result = sendmsg(sk, &msg, 0); + if (result < 0) + return -errno; + + if (ad_len) { + /* + * When AEAD additional data is passed to sendmsg() for + * use in computing the tag, those bytes also appear at + * the beginning of the encrypt or decrypt results. Rather + * than force the caller to pad their result buffer with + * the correct number of bytes for the additional data, + * the necessary space is allocated here and then the + * duplicate AAD is discarded. + */ + iov[0].iov_base = l_malloc(ad_len); + iov[0].iov_len = ad_len; + iov[1].iov_base = (void *) out; + iov[1].iov_len = out_len; + msg.msg_iovlen = 2; + + msg.msg_control = NULL; + msg.msg_controllen = 0; + + result = recvmsg(sk, &msg, 0); + + if (result >= (ssize_t) ad_len) + result -= ad_len; + else if (result > 0) + result = 0; + + l_free(iov[0].iov_base); + } else { + result = read(sk, out, out_len); + } + + if (result < 0) + return -errno; + + return result; +} + +static ssize_t operate_cipherv(int sk, __u32 operation, + const struct iovec *in, size_t in_cnt, + const struct iovec *out, size_t out_cnt) +{ + char *c_msg_buf; + size_t c_msg_size; + struct msghdr msg; + struct cmsghdr *c_msg; + ssize_t result; + + c_msg_size = CMSG_SPACE(sizeof(operation)); + c_msg_buf = alloca(c_msg_size); + + memset(c_msg_buf, 0, c_msg_size); + memset(&msg, 0, sizeof(msg)); + + msg.msg_iov = (struct iovec *) in; + msg.msg_iovlen = in_cnt; + + msg.msg_control = c_msg_buf; + msg.msg_controllen = c_msg_size; + + c_msg = CMSG_FIRSTHDR(&msg); + c_msg->cmsg_level = SOL_ALG; + c_msg->cmsg_type = ALG_SET_OP; + c_msg->cmsg_len = CMSG_LEN(sizeof(operation)); + memcpy(CMSG_DATA(c_msg), &operation, sizeof(operation)); + + result = sendmsg(sk, &msg, 0); + if (result < 0) + return -errno; + + result = readv(sk, out, out_cnt); + + if (result < 0) + return -errno; + + return result; +} + +LIB_EXPORT bool l_cipher_encrypt(struct l_cipher *cipher, + const void *in, void *out, size_t len) +{ + if (unlikely(!cipher)) + return false; + + if (unlikely(!in) || unlikely(!out)) + return false; + + if (cipher->local) { + struct iovec in_iov = { (void *) in, len }; + struct iovec out_iov = { out, len }; + + return cipher->local->operate(cipher->local_data, + ALG_OP_ENCRYPT, + &in_iov, 1, &out_iov, 1) >= 0; + } + + return operate_cipher(cipher->sk, ALG_OP_ENCRYPT, in, len, + NULL, 0, NULL, 0, out, len) >= 0; +} + +LIB_EXPORT bool l_cipher_encryptv(struct l_cipher *cipher, + const struct iovec *in, size_t in_cnt, + const struct iovec *out, size_t out_cnt) +{ + if (unlikely(!cipher)) + return false; + + if (unlikely(!in) || unlikely(!out)) + return false; + + if (cipher->local) + return cipher->local->operate(cipher->local_data, + ALG_OP_ENCRYPT, + in, in_cnt, out, out_cnt) >= 0; + + return operate_cipherv(cipher->sk, ALG_OP_ENCRYPT, in, in_cnt, + out, out_cnt) >= 0; +} + +LIB_EXPORT bool l_cipher_decrypt(struct l_cipher *cipher, + const void *in, void *out, size_t len) +{ + if (unlikely(!cipher)) + return false; + + if (unlikely(!in) || unlikely(!out)) + return false; + + if (cipher->local) { + struct iovec in_iov = { (void *) in, len }; + struct iovec out_iov = { out, len }; + + return cipher->local->operate(cipher->local_data, + ALG_OP_DECRYPT, + &in_iov, 1, &out_iov, 1) >= 0; + } + + return operate_cipher(cipher->sk, ALG_OP_DECRYPT, in, len, + NULL, 0, NULL, 0, out, len) >= 0; +} + +LIB_EXPORT bool l_cipher_decryptv(struct l_cipher *cipher, + const struct iovec *in, size_t in_cnt, + const struct iovec *out, size_t out_cnt) +{ + if (unlikely(!cipher)) + return false; + + if (unlikely(!in) || unlikely(!out)) + return false; + + if (cipher->local) + return cipher->local->operate(cipher->local_data, + ALG_OP_DECRYPT, + in, in_cnt, out, out_cnt) >= 0; + + return operate_cipherv(cipher->sk, ALG_OP_DECRYPT, in, in_cnt, + out, out_cnt) >= 0; +} + +LIB_EXPORT bool l_cipher_set_iv(struct l_cipher *cipher, const uint8_t *iv, + size_t iv_length) +{ + char c_msg_buf[CMSG_SPACE(4 + iv_length)]; + struct msghdr msg; + struct cmsghdr *c_msg; + uint32_t len = iv_length; + + if (unlikely(!cipher)) + return false; + + if (cipher->local) { + if (!cipher->local->set_iv) + return false; + + return cipher->local->set_iv(cipher->local_data, iv, iv_length); + } + + memset(&c_msg_buf, 0, sizeof(c_msg_buf)); + memset(&msg, 0, sizeof(struct msghdr)); + + msg.msg_control = c_msg_buf; + msg.msg_controllen = sizeof(c_msg_buf); + + c_msg = CMSG_FIRSTHDR(&msg); + c_msg->cmsg_level = SOL_ALG; + c_msg->cmsg_type = ALG_SET_IV; + c_msg->cmsg_len = CMSG_LEN(4 + iv_length); + memcpy(CMSG_DATA(c_msg) + 0, &len, 4); + memcpy(CMSG_DATA(c_msg) + 4, iv, iv_length); + + msg.msg_iov = NULL; + msg.msg_iovlen = 0; + + if (sendmsg(cipher->sk, &msg, MSG_MORE) < 0) + return false; + + return true; +} + +#define CCM_IV_SIZE 16 + +static size_t l_aead_cipher_get_ivlen(struct l_aead_cipher *cipher) +{ + switch (cipher->type) { + case L_AEAD_CIPHER_AES_CCM: + return CCM_IV_SIZE; + case L_AEAD_CIPHER_AES_GCM: + return 12; + } + + return 0; +} + +/* RFC3610 Section 2.3 */ +static ssize_t build_ccm_iv(const void *nonce, uint8_t nonce_len, + uint8_t (*iv)[CCM_IV_SIZE]) +{ + const size_t iv_overhead = 2; + int lprime = 15 - nonce_len - 1; + + if (unlikely(nonce_len + iv_overhead > CCM_IV_SIZE || lprime > 7)) + return -EINVAL; + + (*iv)[0] = lprime; + memcpy(*iv + 1, nonce, nonce_len); + memset(*iv + 1 + nonce_len, 0, lprime + 1); + + return CCM_IV_SIZE; +} + +LIB_EXPORT bool l_aead_cipher_encrypt(struct l_aead_cipher *cipher, + const void *in, size_t in_len, + const void *ad, size_t ad_len, + const void *nonce, size_t nonce_len, + void *out, size_t out_len) +{ + uint8_t ccm_iv[CCM_IV_SIZE]; + const uint8_t *iv; + ssize_t iv_len; + + if (unlikely(!cipher)) + return false; + + if (unlikely(!in && !ad) || unlikely(!out)) + return false; + + if (unlikely(!in && in_len) || unlikely(!ad && ad_len)) + return false; + + if (cipher->type == L_AEAD_CIPHER_AES_CCM) { + iv_len = build_ccm_iv(nonce, nonce_len, &ccm_iv); + if (unlikely(iv_len < 0)) + return false; + + iv = ccm_iv; + } else { + if (unlikely(nonce_len != l_aead_cipher_get_ivlen(cipher))) + return false; + + iv = nonce; + iv_len = nonce_len; + } + + return operate_cipher(cipher->sk, ALG_OP_ENCRYPT, in, in_len, + ad, ad_len, iv, iv_len, out, out_len) == + (ssize_t)out_len; +} + +LIB_EXPORT bool l_aead_cipher_decrypt(struct l_aead_cipher *cipher, + const void *in, size_t in_len, + const void *ad, size_t ad_len, + const void *nonce, size_t nonce_len, + void *out, size_t out_len) +{ + uint8_t ccm_iv[CCM_IV_SIZE]; + const uint8_t *iv; + ssize_t iv_len; + + if (unlikely(!cipher)) + return false; + + if (unlikely(!in) || unlikely(!out)) + return false; + + if (cipher->type == L_AEAD_CIPHER_AES_CCM) { + iv_len = build_ccm_iv(nonce, nonce_len, &ccm_iv); + if (unlikely(iv_len < 0)) + return false; + + iv = ccm_iv; + } else { + if (unlikely(nonce_len != l_aead_cipher_get_ivlen(cipher))) + return false; + + iv = nonce; + iv_len = nonce_len; + } + + return operate_cipher(cipher->sk, ALG_OP_DECRYPT, in, in_len, + ad, ad_len, iv, iv_len, out, out_len) == + (ssize_t)out_len; +} + +static void init_supported() +{ + static bool initialized = false; + struct sockaddr_alg salg; + int sk; + enum l_cipher_type c; + enum l_aead_cipher_type a; + + if (likely(initialized)) + return; + + initialized = true; + + for (c = 0; c < L_ARRAY_SIZE(local_impl_ciphers); c++) + if (HAVE_LOCAL_IMPLEMENTATION(c)) + supported_ciphers |= 1 << c; + + sk = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); + if (sk < 0) + return; + + memset(&salg, 0, sizeof(salg)); + salg.salg_family = AF_ALG; + strcpy((char *) salg.salg_type, "skcipher"); + + for (c = L_CIPHER_AES; c <= L_CIPHER_DES3_EDE_CBC; c++) { + const char *name = cipher_type_to_name(c); + + if (!name) + continue; + strcpy((char *) salg.salg_name, name); + + if (bind(sk, (struct sockaddr *) &salg, sizeof(salg)) < 0) + continue; + + supported_ciphers |= 1 << c; + } + + strcpy((char *) salg.salg_type, "aead"); + + for (a = L_AEAD_CIPHER_AES_CCM; a <= L_AEAD_CIPHER_AES_GCM; a++) { + strcpy((char *) salg.salg_name, aead_cipher_type_to_name(a)); + + if (bind(sk, (struct sockaddr *) &salg, sizeof(salg)) < 0) + continue; + + supported_aead_ciphers |= 1 << a; + } + + close(sk); +} + +LIB_EXPORT bool l_cipher_is_supported(enum l_cipher_type type) +{ + if (!is_valid_type(type)) + return false; + + init_supported(); + + return supported_ciphers & (1 << type); +} + +LIB_EXPORT bool l_aead_cipher_is_supported(enum l_aead_cipher_type type) +{ + if (type != L_AEAD_CIPHER_AES_CCM && type != L_AEAD_CIPHER_AES_GCM) + return false; + + init_supported(); + + return supported_aead_ciphers & (1 << type); +} + +/* ARC4 implementation copyright (c) 2001 Niels Möller */ + +static void arc4_set_key(uint8_t *S, const uint8_t *key, size_t key_length) +{ + unsigned int i; + uint8_t j; + + for (i = 0; i < 256; i++) + S[i] = i; + + for (i = j = 0; i < 256; i++) { + j += S[i] + key[i % key_length]; + SWAP(S[i], S[j]); + } +} + +struct arc4_state { + struct arc4_state_ctx { + uint8_t S[256]; + uint8_t i; + uint8_t j; + } ctx[2]; +}; + +static void *local_arc4_new(enum l_cipher_type type, + const void *key, size_t key_length) +{ + struct arc4_state *s; + + if (unlikely(key_length == 0 || key_length > 256)) + return NULL; + + s = l_new(struct arc4_state, 1); + arc4_set_key(s->ctx[0].S, key, key_length); + s->ctx[1] = s->ctx[0]; + return s; +} + +static void local_arc4_free(void *data) +{ + explicit_bzero(data, sizeof(struct arc4_state)); + l_free(data); +} + +static ssize_t local_arc4_operate(void *data, __u32 operation, + const struct iovec *in, size_t in_cnt, + const struct iovec *out, size_t out_cnt) +{ + struct arc4_state *s = data; + struct iovec cur_in; + struct iovec cur_out; + struct arc4_state_ctx *ctx = + &s->ctx[operation == ALG_OP_ENCRYPT ? 1 : 0]; + + if (!in_cnt || !out_cnt) + return 0; + + cur_in = *in; + cur_out = *out; + + while (1) { + while (!cur_in.iov_len) { + cur_in = *in++; + + if (!--in_cnt) + return 0; + } + + while (!cur_out.iov_len) { + cur_out = *out++; + + if (!--out_cnt) + return 0; + } + + ctx->j += ctx->S[++ctx->i]; + SWAP(ctx->S[ctx->i], ctx->S[ctx->j]); + *(uint8_t *) cur_out.iov_base++ = + *(uint8_t *) cur_in.iov_base++ ^ + ctx->S[(ctx->S[ctx->i] + ctx->S[ctx->j]) & 0xff]; + cur_in.iov_len--; + cur_out.iov_len--; + } +} + +static const struct local_impl local_arc4 = { + local_arc4_new, + local_arc4_free, + NULL, + local_arc4_operate, +}; + +struct rc2_state { + union { + uint16_t xkey[64]; + uint8_t xkey8[128]; + }; + struct rc2_state_ctx { + union { + uint16_t x[4]; + uint64_t x64; + }; + } ctx[2]; +}; + +/* Simplified from the 1996 public-domain implementation */ +static void rc2_keyschedule(struct rc2_state *s, + const uint8_t *key, size_t key_len, + size_t bits) +{ + static const uint8_t permute[256] = { + 217,120,249,196, 25,221,181,237, 40,233,253,121, 74,160,216,157, + 198,126, 55,131, 43,118, 83,142, 98, 76,100,136, 68,139,251,162, + 23,154, 89,245,135,179, 79, 19, 97, 69,109,141, 9,129,125, 50, + 189,143, 64,235,134,183,123, 11,240,149, 33, 34, 92,107, 78,130, + 84,214,101,147,206, 96,178, 28,115, 86,192, 20,167,140,241,220, + 18,117,202, 31, 59,190,228,209, 66, 61,212, 48,163, 60,182, 38, + 111,191, 14,218, 70,105, 7, 87, 39,242, 29,155,188,148, 67, 3, + 248, 17,199,246,144,239, 62,231, 6,195,213, 47,200,102, 30,215, + 8,232,234,222,128, 82,238,247,132,170,114,172, 53, 77,106, 42, + 150, 26,210,113, 90, 21, 73,116, 75,159,208, 94, 4, 24,164,236, + 194,224, 65,110, 15, 81,203,204, 36,145,175, 80,161,244,112, 57, + 153,124, 58,133, 35,184,180,122,252, 2, 54, 91, 37, 85,151, 49, + 45, 93,250,152,227,138,146,174, 5,223, 41, 16,103,108,186,201, + 211, 0,230,207,225,158,168, 44, 99, 22, 1, 63, 88,226,137,169, + 13, 56, 52, 27,171, 51,255,176,187, 72, 12, 95,185,177,205, 46, + 197,243,219, 71,229,165,156,119, 10,166, 32,104,254,127,193,173 + }; + uint8_t x; + unsigned int i; + + memcpy(&s->xkey8, key, key_len); + + /* Step 1: expand input key to 128 bytes */ + x = s->xkey8[key_len - 1]; + + for (i = 0; key_len < 128; key_len++, i++) + s->xkey8[key_len] = x = permute[(x + s->xkey8[i]) & 255]; + + /* Step 2: reduce effective key size to "bits" */ + key_len = (bits + 7) >> 3; + i = 128 - key_len; + s->xkey8[i] = x = permute[s->xkey8[i] & (255 >> (7 & -bits))]; + + while (i--) + s->xkey8[i] = x = permute[x ^ s->xkey8[i + key_len]]; + + /* Step 3: copy to xkey in little-endian order */ + for (i = 0; i < 64; i++) + s->xkey[i] = L_CPU_TO_LE16(s->xkey[i]); +} + +static uint64_t rc2_operate(struct rc2_state *s, uint64_t in, __u32 operation) +{ + int i; + union { + uint16_t x16[4]; + uint64_t x64; + } x; + + x.x64 = in; + + if (operation == ALG_OP_ENCRYPT) { + const uint16_t *xkey = s->xkey; + + for (i = 0; i < 16; i++) { + x.x16[0] += (x.x16[1] & ~x.x16[3]) + + (x.x16[2] & x.x16[3]) + *xkey++; + x.x16[0] = (x.x16[0] << 1) | (x.x16[0] >> 15); + x.x16[1] += (x.x16[2] & ~x.x16[0]) + + (x.x16[3] & x.x16[0]) + *xkey++; + x.x16[1] = (x.x16[1] << 2) | (x.x16[1] >> 14); + x.x16[2] += (x.x16[3] & ~x.x16[1]) + + (x.x16[0] & x.x16[1]) + *xkey++; + x.x16[2] = (x.x16[2] << 3) | (x.x16[2] >> 13); + x.x16[3] += (x.x16[0] & ~x.x16[2]) + + (x.x16[1] & x.x16[2]) + *xkey++; + x.x16[3] = (x.x16[3] << 5) | (x.x16[3] >> 11); + + if (i == 4 || i == 10) { + x.x16[0] += s->xkey[x.x16[3] & 63]; + x.x16[1] += s->xkey[x.x16[0] & 63]; + x.x16[2] += s->xkey[x.x16[1] & 63]; + x.x16[3] += s->xkey[x.x16[2] & 63]; + } + } + } else { + const uint16_t *xkey = s->xkey + 63; + + for (i = 0; i < 16; i++) { + x.x16[3] = (x.x16[3] << 11) | (x.x16[3] >> 5); + x.x16[3] -= (x.x16[0] & ~x.x16[2]) + + (x.x16[1] & x.x16[2]) + *xkey--; + x.x16[2] = (x.x16[2] << 13) | (x.x16[2] >> 3); + x.x16[2] -= (x.x16[3] & ~x.x16[1]) + + (x.x16[0] & x.x16[1]) + *xkey--; + x.x16[1] = (x.x16[1] << 14) | (x.x16[1] >> 2); + x.x16[1] -= (x.x16[2] & ~x.x16[0]) + + (x.x16[3] & x.x16[0]) + *xkey--; + x.x16[0] = (x.x16[0] << 15) | (x.x16[0] >> 1); + x.x16[0] -= (x.x16[1] & ~x.x16[3]) + + (x.x16[2] & x.x16[3]) + *xkey--; + + if (i == 4 || i == 10) { + x.x16[3] -= s->xkey[x.x16[2] & 63]; + x.x16[2] -= s->xkey[x.x16[1] & 63]; + x.x16[1] -= s->xkey[x.x16[0] & 63]; + x.x16[0] -= s->xkey[x.x16[3] & 63]; + } + } + } + + return x.x64; +} + +static void *local_rc2_cbc_new(enum l_cipher_type type, + const void *key, size_t key_length) +{ + struct rc2_state *s; + + if (unlikely(key_length == 0 || key_length > 128)) + return NULL; + + /* + * The key length and the effective "strength" bits are separate + * parameters but they match in our current use cases. + */ + s = l_new(struct rc2_state, 1); + rc2_keyschedule(s, key, key_length, key_length * 8); + return s; +} + +static void local_rc2_cbc_free(void *data) +{ + explicit_bzero(data, sizeof(struct rc2_state)); + l_free(data); +} + +static bool local_rc2_cbc_set_iv(void *data, + const uint8_t *iv, size_t iv_length) +{ + struct rc2_state *s = data; + + if (unlikely(iv_length != 8)) + return false; + + s->ctx[0].x[0] = l_get_le16(iv + 0); + s->ctx[0].x[1] = l_get_le16(iv + 2); + s->ctx[0].x[2] = l_get_le16(iv + 4); + s->ctx[0].x[3] = l_get_le16(iv + 6); + s->ctx[1].x64 = s->ctx[0].x64; + return true; +} + +static ssize_t local_rc2_cbc_operate(void *data, __u32 operation, + const struct iovec *in, size_t in_cnt, + const struct iovec *out, size_t out_cnt) +{ + struct rc2_state *s = data; + struct iovec cur_in = {}; + struct iovec cur_out = {}; + struct rc2_state_ctx *ctx = + &s->ctx[operation == ALG_OP_ENCRYPT ? 1 : 0]; + +#define CONSUME_IN(bytes, eof_ok) \ + cur_in.iov_len -= (bytes); \ + while (!cur_in.iov_len) { \ + if (!in_cnt) { \ + if (eof_ok) \ + break; \ + else \ + return -1; \ + } \ + \ + cur_in = *in++; \ + in_cnt--; \ + } + +#define CONSUME_OUT(bytes) \ + cur_out.iov_len -= (bytes); \ + while (!cur_out.iov_len) { \ + if (!out_cnt) \ + return 0; \ + \ + cur_out = *out++; \ + out_cnt--; \ + } + + CONSUME_IN(0, true) + CONSUME_OUT(0) + + while (cur_in.iov_len) { + union { + uint16_t x16[4]; + uint64_t x64; + } inblk; + + if (cur_in.iov_len >= 8) { +#define CUR_IN16 (*(uint16_t **) &cur_in.iov_base) + inblk.x16[0] = l_get_le16(CUR_IN16++); + inblk.x16[1] = l_get_le16(CUR_IN16++); + inblk.x16[2] = l_get_le16(CUR_IN16++); + inblk.x16[3] = l_get_le16(CUR_IN16++); + CONSUME_IN(8, true) + } else { + inblk.x16[0] = *(uint8_t *) cur_in.iov_base++; + CONSUME_IN(1, false) + inblk.x16[0] |= (*(uint8_t *) cur_in.iov_base++) << 8; + CONSUME_IN(1, false) + inblk.x16[1] = *(uint8_t *) cur_in.iov_base++; + CONSUME_IN(1, false) + inblk.x16[1] |= (*(uint8_t *) cur_in.iov_base++) << 8; + CONSUME_IN(1, false) + inblk.x16[2] = *(uint8_t *) cur_in.iov_base++; + CONSUME_IN(1, false) + inblk.x16[2] |= (*(uint8_t *) cur_in.iov_base++) << 8; + CONSUME_IN(1, false) + inblk.x16[3] = *(uint8_t *) cur_in.iov_base++; + CONSUME_IN(1, false) + inblk.x16[3] |= (*(uint8_t *) cur_in.iov_base++) << 8; + CONSUME_IN(1, true) + } + + if (operation == ALG_OP_ENCRYPT) + ctx->x64 = rc2_operate(s, inblk.x64 ^ ctx->x64, + operation); + else + ctx->x64 ^= rc2_operate(s, inblk.x64, operation); + + if (cur_out.iov_len >= 8) { +#define CUR_OUT16 (*(uint16_t **) &cur_out.iov_base) + l_put_le16(ctx->x[0], CUR_OUT16++); + l_put_le16(ctx->x[1], CUR_OUT16++); + l_put_le16(ctx->x[2], CUR_OUT16++); + l_put_le16(ctx->x[3], CUR_OUT16++); + CONSUME_OUT(8) + } else { + *(uint8_t *) cur_out.iov_base++ = ctx->x[0]; + CONSUME_OUT(1) + *(uint8_t *) cur_out.iov_base++ = ctx->x[0] >> 8; + CONSUME_OUT(1) + *(uint8_t *) cur_out.iov_base++ = ctx->x[1]; + CONSUME_OUT(1) + *(uint8_t *) cur_out.iov_base++ = ctx->x[1] >> 8; + CONSUME_OUT(1) + *(uint8_t *) cur_out.iov_base++ = ctx->x[2]; + CONSUME_OUT(1) + *(uint8_t *) cur_out.iov_base++ = ctx->x[2] >> 8; + CONSUME_OUT(1) + *(uint8_t *) cur_out.iov_base++ = ctx->x[3]; + CONSUME_OUT(1) + *(uint8_t *) cur_out.iov_base++ = ctx->x[3] >> 8; + CONSUME_OUT(1) + } + + /* Save ciphertext as IV for next CBC block */ + if (operation == ALG_OP_DECRYPT) + ctx->x64 = inblk.x64; + + inblk.x64 = 0; + } + + return 0; +} + +static const struct local_impl local_rc2_cbc = { + local_rc2_cbc_new, + local_rc2_cbc_free, + local_rc2_cbc_set_iv, + local_rc2_cbc_operate, +}; diff --git a/ell/cipher.h b/ell/cipher.h new file mode 100644 index 0000000000000000000000000000000000000000..dc581a0e185c8c5ed32848919447213a2ba9f308 --- /dev/null +++ b/ell/cipher.h @@ -0,0 +1,80 @@ +/* + * Embedded Linux library + * Copyright (C) 2015 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_CIPHER_H +#define __ELL_CIPHER_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct l_cipher; + +enum l_cipher_type { + L_CIPHER_AES = 0, + L_CIPHER_AES_CBC, + L_CIPHER_AES_CTR, + L_CIPHER_ARC4, + L_CIPHER_DES, + L_CIPHER_DES_CBC, + L_CIPHER_DES3_EDE_CBC, + L_CIPHER_RC2_CBC, +}; + +struct l_cipher *l_cipher_new(enum l_cipher_type type, + const void *key, size_t key_length); + +void l_cipher_free(struct l_cipher *cipher); + +bool l_cipher_encrypt(struct l_cipher *cipher, + const void *in, void *out, size_t len); +bool l_cipher_encryptv(struct l_cipher *cipher, + const struct iovec *in, size_t in_cnt, + const struct iovec *out, size_t out_cnt); + +bool l_cipher_decrypt(struct l_cipher *cipher, + const void *in, void *out, size_t len); +bool l_cipher_decryptv(struct l_cipher *cipher, + const struct iovec *in, size_t in_cnt, + const struct iovec *out, size_t out_cnt); + +bool l_cipher_set_iv(struct l_cipher *cipher, const uint8_t *iv, + size_t iv_length); + +struct l_aead_cipher; + +enum l_aead_cipher_type { + L_AEAD_CIPHER_AES_CCM = 0, + L_AEAD_CIPHER_AES_GCM, +}; + +struct l_aead_cipher *l_aead_cipher_new(enum l_aead_cipher_type type, + const void *key, size_t key_length, + size_t tag_length); + +void l_aead_cipher_free(struct l_aead_cipher *cipher); + +bool l_aead_cipher_encrypt(struct l_aead_cipher *cipher, + const void *in, size_t in_len, + const void *ad, size_t ad_len, + const void *nonce, size_t nonce_len, + void *out, size_t out_len); + +bool l_aead_cipher_decrypt(struct l_aead_cipher *cipher, + const void *in, size_t in_len, + const void *ad, size_t ad_len, + const void *nonce, size_t nonce_len, + void *out, size_t out_len); + +bool l_cipher_is_supported(enum l_cipher_type type); +bool l_aead_cipher_is_supported(enum l_aead_cipher_type type); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_CIPHER_H */ diff --git a/ell/cleanup.h b/ell/cleanup.h new file mode 100644 index 0000000000000000000000000000000000000000..ac9f5a894b248d0dacb5b1258aa3c584ceac837e --- /dev/null +++ b/ell/cleanup.h @@ -0,0 +1,15 @@ +/* + * Embedded Linux library + * Copyright (C) 2021 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#pragma once + +#define __L_AUTODESTRUCT(func) \ + __attribute((cleanup(_l_ ## func ## _cleanup))) + +#define DEFINE_CLEANUP_FUNC(func) \ + inline __attribute__((always_inline)) \ + void _l_ ## func ## _cleanup(void *p) { func(*(void **) p); } diff --git a/ell/dbus-client.c b/ell/dbus-client.c new file mode 100644 index 0000000000000000000000000000000000000000..e29c6fae3288fae9d35da90a8d705d22dad51377 --- /dev/null +++ b/ell/dbus-client.c @@ -0,0 +1,722 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * Copyright (C) 2017 Codecoup + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "dbus.h" +#include "dbus-client.h" +#include "queue.h" +#include "useful.h" +#include "private.h" + +struct l_dbus_client { + struct l_dbus *dbus; + unsigned int watch; + unsigned int added_watch; + unsigned int removed_watch; + char *service; + uint32_t objects_call; + + l_dbus_watch_func_t connect_cb; + void *connect_cb_data; + l_dbus_destroy_func_t connect_cb_data_destroy; + + l_dbus_watch_func_t disconnect_cb; + void *disconnect_cb_data; + l_dbus_destroy_func_t disconnect_cb_data_destroy; + + l_dbus_client_ready_func_t ready_cb; + void *ready_cb_data; + l_dbus_destroy_func_t ready_cb_data_destroy; + + l_dbus_client_proxy_func_t proxy_added_cb; + l_dbus_client_proxy_func_t proxy_removed_cb; + l_dbus_client_property_function_t properties_changed_cb; + void *proxy_cb_data; + l_dbus_destroy_func_t proxy_cb_data_destroy; + + struct l_queue *proxies; +}; + +struct proxy_property { + char *name; + struct l_dbus_message *msg; +}; + +struct l_dbus_proxy { + struct l_dbus_client *client; + char *interface; + char *path; + uint32_t properties_watch; + bool ready; + + struct l_queue *properties; + struct l_queue *pending_calls; +}; + +LIB_EXPORT const char *l_dbus_proxy_get_path(struct l_dbus_proxy *proxy) +{ + if (unlikely(!proxy)) + return NULL; + + return proxy->path; +} + +LIB_EXPORT const char *l_dbus_proxy_get_interface(struct l_dbus_proxy *proxy) +{ + if (unlikely(!proxy)) + return NULL; + + return proxy->interface; +} + +static bool property_match_by_name(const void *a, const void *b) +{ + const struct proxy_property *prop = a; + const char *name = b; + + return !strcmp(prop->name, name); +} + +static struct proxy_property *find_property(struct l_dbus_proxy *proxy, + const char *name) +{ + return l_queue_find(proxy->properties, property_match_by_name, name); +} + +static struct proxy_property *get_property(struct l_dbus_proxy *proxy, + const char *name) +{ + struct proxy_property *prop; + + prop = find_property(proxy, name); + if (prop) + return prop; + + prop = l_new(struct proxy_property, 1); + prop->name = l_strdup(name); + + l_queue_push_tail(proxy->properties, prop); + + return prop; +} + +LIB_EXPORT bool l_dbus_proxy_get_property(struct l_dbus_proxy *proxy, + const char *name, + const char *signature, ...) +{ + struct proxy_property *prop; + va_list args; + bool res; + + if (unlikely(!proxy)) + return false; + + prop = find_property(proxy, name); + if (!prop) + return false; + + va_start(args, signature); + res = l_dbus_message_get_arguments_valist(prop->msg, signature, args); + va_end(args); + + return res; +} + +static void property_free(void *data) +{ + struct proxy_property *prop = data; + + if (prop->msg) + l_dbus_message_unref(prop->msg); + + l_free(prop->name); + l_free(prop); +} + +static void cancel_pending_calls(struct l_dbus_proxy *proxy) +{ + const struct l_queue_entry *entry; + + for (entry = l_queue_get_entries(proxy->pending_calls); entry; + entry = entry->next) { + uint32_t call_id = L_PTR_TO_UINT(entry->data); + + l_dbus_cancel(proxy->client->dbus, call_id); + } +} + +static void dbus_proxy_destroy(struct l_dbus_proxy *proxy) +{ + if (unlikely(!proxy)) + return; + + if (proxy->properties_watch) + l_dbus_remove_signal_watch(proxy->client->dbus, + proxy->properties_watch); + + cancel_pending_calls(proxy); + l_queue_destroy(proxy->pending_calls, NULL); + l_queue_destroy(proxy->properties, property_free); + l_free(proxy->interface); + l_free(proxy->path); + l_free(proxy); +} + +struct method_call_request +{ + struct l_dbus_proxy *proxy; + uint32_t call_id; + l_dbus_message_func_t setup; + l_dbus_client_proxy_result_func_t result; + void *user_data; + l_dbus_destroy_func_t destroy; +}; + +static void method_call_request_free(void *user_data) +{ + struct method_call_request *req = user_data; + + l_queue_remove(req->proxy->pending_calls, L_UINT_TO_PTR(req->call_id)); + + if (req->destroy) + req->destroy(req->user_data); + + l_free(req); +} + +static void method_call_setup(struct l_dbus_message *message, void *user_data) +{ + struct method_call_request *req = user_data; + + if (req->setup) + req->setup(message, req->user_data); + else + l_dbus_message_set_arguments(message, ""); +} + +static void method_call_reply(struct l_dbus_message *message, void *user_data) +{ + struct method_call_request *req = user_data; + + if (req->result) + req->result(req->proxy, message, req->user_data); +} + +LIB_EXPORT bool l_dbus_proxy_set_property(struct l_dbus_proxy *proxy, + l_dbus_client_proxy_result_func_t result, + void *user_data, l_dbus_destroy_func_t destroy, + const char *name, const char *signature, ...) +{ + struct l_dbus_client *client = proxy->client; + struct l_dbus_message_builder *builder; + struct method_call_request *req; + struct l_dbus_message *message; + struct proxy_property *prop; + va_list args; + + if (unlikely(!proxy)) + return false; + + prop = find_property(proxy, name); + if (!prop) + return false; + + if (strcmp(l_dbus_message_get_signature(prop->msg), signature)) + return false; + + message = l_dbus_message_new_method_call(client->dbus, client->service, + proxy->path, + L_DBUS_INTERFACE_PROPERTIES, + "Set"); + if (!message) + return false; + + builder = l_dbus_message_builder_new(message); + if (!builder) { + l_dbus_message_unref(message); + return false; + } + + l_dbus_message_builder_append_basic(builder, 's', proxy->interface); + l_dbus_message_builder_append_basic(builder, 's', name); + + l_dbus_message_builder_enter_variant(builder, signature); + + va_start(args, signature); + l_dbus_message_builder_append_from_valist(builder, signature, args); + va_end(args); + + l_dbus_message_builder_leave_variant(builder); + + l_dbus_message_builder_finalize(builder); + l_dbus_message_builder_destroy(builder); + + req = l_new(struct method_call_request, 1); + req->proxy = proxy; + req->result = result; + req->user_data = user_data; + req->destroy = destroy; + + req->call_id = l_dbus_send_with_reply(client->dbus, message, + method_call_reply, req, + method_call_request_free); + if (!req->call_id) { + l_free(req); + return false; + } + + l_queue_push_tail(proxy->pending_calls, L_UINT_TO_PTR(req->call_id)); + + return true; +} + +LIB_EXPORT uint32_t l_dbus_proxy_method_call(struct l_dbus_proxy *proxy, + const char *method, + l_dbus_message_func_t setup, + l_dbus_client_proxy_result_func_t reply, + void *user_data, + l_dbus_destroy_func_t destroy) +{ + struct method_call_request *req; + + if (unlikely(!proxy)) + return 0; + + req = l_new(struct method_call_request, 1); + req->proxy = proxy; + req->setup = setup; + req->result = reply; + req->user_data = user_data; + req->destroy = destroy; + + req->call_id = l_dbus_method_call(proxy->client->dbus, + proxy->client->service, + proxy->path, proxy->interface, + method, method_call_setup, + method_call_reply, req, + method_call_request_free); + if (!req->call_id) { + l_free(req); + return 0; + } + + l_queue_push_tail(proxy->pending_calls, L_UINT_TO_PTR(req->call_id)); + + return req->call_id; +} + +static void proxy_update_property(struct l_dbus_proxy *proxy, + const char *name, + struct l_dbus_message_iter *property) +{ + struct l_dbus_message_builder *builder; + struct proxy_property *prop = get_property(proxy, name); + + l_dbus_message_unref(prop->msg); + + if (!property) { + prop->msg = NULL; + goto done; + } + + prop->msg = l_dbus_message_new_signal(proxy->client->dbus, proxy->path, + proxy->interface, name); + if (!prop->msg) + return; + + builder = l_dbus_message_builder_new(prop->msg); + l_dbus_message_builder_append_from_iter(builder, property); + l_dbus_message_builder_finalize(builder); + l_dbus_message_builder_destroy(builder); + +done: + if (proxy->client->properties_changed_cb && proxy->ready) + proxy->client->properties_changed_cb(proxy, name, prop->msg, + proxy->client->proxy_cb_data); +} + +static void proxy_invalidate_properties(struct l_dbus_proxy *proxy, + struct l_dbus_message_iter* props) +{ + const char *name; + + while (l_dbus_message_iter_next_entry(props, &name)) + proxy_update_property(proxy, name, NULL); +} + +static void proxy_update_properties(struct l_dbus_proxy *proxy, + struct l_dbus_message_iter* props) +{ + struct l_dbus_message_iter variant; + const char *name; + + while (l_dbus_message_iter_next_entry(props, &name, &variant)) + proxy_update_property(proxy, name, &variant); +} + +static void properties_changed_callback(struct l_dbus_message *message, + void *user_data) +{ + struct l_dbus_proxy *proxy = user_data; + const char *interface; + struct l_dbus_message_iter changed; + struct l_dbus_message_iter invalidated; + + if (!l_dbus_message_get_arguments(message, "sa{sv}as", &interface, + &changed, &invalidated)) + return; + + proxy_update_properties(proxy, &changed); + proxy_invalidate_properties(proxy, &invalidated); +} + +static struct l_dbus_proxy *dbus_proxy_new(struct l_dbus_client *client, + const char *path, const char *interface) +{ + struct l_dbus_proxy *proxy = l_new(struct l_dbus_proxy, 1); + + proxy->properties_watch = l_dbus_add_signal_watch(client->dbus, + client->service, path, + L_DBUS_INTERFACE_PROPERTIES, + "PropertiesChanged", + L_DBUS_MATCH_ARGUMENT(0), + interface, L_DBUS_MATCH_NONE, + properties_changed_callback, + proxy); + if (!proxy->properties_watch) { + l_free(proxy); + return NULL; + } + + proxy->client = client; + proxy->interface = l_strdup(interface); + proxy->path = l_strdup(path); + proxy->properties = l_queue_new(); + proxy->pending_calls = l_queue_new(); + + l_queue_push_tail(client->proxies, proxy); + + return proxy; +} + +static bool is_ignorable(const char *interface) +{ + static const struct { + const char *interface; + } interfaces_to_ignore[] = { + { L_DBUS_INTERFACE_OBJECT_MANAGER }, + { L_DBUS_INTERFACE_INTROSPECTABLE }, + { L_DBUS_INTERFACE_PROPERTIES }, + }; + size_t i; + + for (i = 0; i < L_ARRAY_SIZE(interfaces_to_ignore); i++) + if (!strcmp(interfaces_to_ignore[i].interface, interface)) + return true; + + return false; +} + +static struct l_dbus_proxy *find_proxy(struct l_dbus_client *client, + const char *path, const char *interface) +{ + const struct l_queue_entry *entry; + + for (entry = l_queue_get_entries(client->proxies); entry; + entry = entry->next) { + struct l_dbus_proxy *proxy = entry->data; + + if (!strcmp(proxy->interface, interface) && + !strcmp(proxy->path, path)) + return proxy; + } + + return NULL; +} + +static void parse_interface(struct l_dbus_client *client, const char *path, + const char *interface, + struct l_dbus_message_iter *properties) +{ + struct l_dbus_proxy *proxy; + + if (is_ignorable(interface)) + return; + + proxy = find_proxy(client, path, interface); + if (!proxy) + proxy = dbus_proxy_new(client, path, interface); + + if (!proxy) + return; + + proxy_update_properties(proxy, properties); + + if (!proxy->ready) { + proxy->ready = true; + + if (client->proxy_added_cb) + client->proxy_added_cb(proxy, client->proxy_cb_data); + } +} + +static void parse_object(struct l_dbus_client *client, const char *path, + struct l_dbus_message_iter *object) +{ + const char *interface; + struct l_dbus_message_iter properties; + + if (!path) + return; + + while (l_dbus_message_iter_next_entry(object, &interface, &properties)) + parse_interface(client, path, interface, &properties); +} + +static void interfaces_added_callback(struct l_dbus_message *message, + void *user_data) +{ + struct l_dbus_client *client = user_data; + struct l_dbus_message_iter object; + const char *path; + + if (!l_dbus_message_get_arguments(message, "oa{sa{sv}}", &path, + &object)) + return; + + parse_object(client, path, &object); +} + +static void interfaces_removed_callback(struct l_dbus_message *message, + void *user_data) +{ + struct l_dbus_client *client = user_data; + struct l_dbus_message_iter interfaces; + const char *interface; + const char *path; + + if (!l_dbus_message_get_arguments(message, "oas", &path, &interfaces)) + return; + + while (l_dbus_message_iter_next_entry(&interfaces, &interface)) { + struct l_dbus_proxy *proxy; + + proxy = find_proxy(client, path, interface); + if (!proxy) + continue; + + l_queue_remove(proxy->client->proxies, proxy); + + if (client->proxy_removed_cb) + client->proxy_removed_cb(proxy, client->proxy_cb_data); + + dbus_proxy_destroy(proxy); + } +} + +static void get_managed_objects_reply(struct l_dbus_message *message, + void *user_data) +{ + struct l_dbus_client *client = user_data; + struct l_dbus_message_iter objects; + struct l_dbus_message_iter object; + const char *path; + + client->objects_call = 0; + + if (l_dbus_message_is_error(message)) + return; + + if (!l_dbus_message_get_arguments(message, "a{oa{sa{sv}}}", &objects)) + return; + + while (l_dbus_message_iter_next_entry(&objects, &path, &object)) + parse_object(client, path, &object); + + client->added_watch = l_dbus_add_signal_watch(client->dbus, + client->service, "/", + L_DBUS_INTERFACE_OBJECT_MANAGER, + "InterfacesAdded", + L_DBUS_MATCH_NONE, + interfaces_added_callback, + client); + + client->removed_watch = l_dbus_add_signal_watch(client->dbus, + client->service, "/", + L_DBUS_INTERFACE_OBJECT_MANAGER, + "InterfacesRemoved", + L_DBUS_MATCH_NONE, + interfaces_removed_callback, + client); + + if (client->ready_cb) + client->ready_cb(client, client->ready_cb_data); +} + +static void service_appeared_callback(struct l_dbus *dbus, void *user_data) +{ + struct l_dbus_client *client = user_data; + + /* TODO should we allow to set different root? */ + client->objects_call = l_dbus_method_call(dbus, client->service, "/", + L_DBUS_INTERFACE_OBJECT_MANAGER, + "GetManagedObjects", NULL, + get_managed_objects_reply, + client, NULL); + + if (client->connect_cb) + client->connect_cb(client->dbus, client->connect_cb_data); +} + +static void service_disappeared_callback(struct l_dbus *dbus, void *user_data) +{ + struct l_dbus_client *client = user_data; + + if (client->disconnect_cb) + client->disconnect_cb(client->dbus, client->disconnect_cb_data); + + l_queue_clear(client->proxies, + (l_queue_destroy_func_t)dbus_proxy_destroy); +} + +LIB_EXPORT struct l_dbus_client *l_dbus_client_new(struct l_dbus *dbus, + const char *service, const char *path) +{ + struct l_dbus_client *client = l_new(struct l_dbus_client, 1); + + client->dbus = dbus; + + client->watch = l_dbus_add_service_watch(dbus, service, + service_appeared_callback, + service_disappeared_callback, + client, NULL); + + if (!client->watch) { + l_free(client); + return NULL; + } + + client->service = l_strdup(service); + client->proxies = l_queue_new(); + + return client; +} + +LIB_EXPORT void l_dbus_client_destroy(struct l_dbus_client *client) +{ + if (unlikely(!client)) + return; + + if (client->watch) + l_dbus_remove_signal_watch(client->dbus, client->watch); + + if (client->added_watch) + l_dbus_remove_signal_watch(client->dbus, client->added_watch); + + if (client->removed_watch) + l_dbus_remove_signal_watch(client->dbus, client->removed_watch); + + if (client->connect_cb_data_destroy) + client->connect_cb_data_destroy(client->connect_cb_data); + + if (client->disconnect_cb_data_destroy) + client->disconnect_cb_data_destroy(client->disconnect_cb_data); + + if (client->ready_cb_data_destroy) + client->ready_cb_data_destroy(client->ready_cb_data); + + if (client->proxy_cb_data_destroy) + client->proxy_cb_data_destroy(client->proxy_cb_data); + + if (client->objects_call) + l_dbus_cancel(client->dbus, client->objects_call); + + l_queue_destroy(client->proxies, + (l_queue_destroy_func_t)dbus_proxy_destroy); + + l_free(client->service); + l_free(client); +} + +LIB_EXPORT bool l_dbus_client_set_connect_handler(struct l_dbus_client *client, + l_dbus_watch_func_t function, + void *user_data, + l_dbus_destroy_func_t destroy) +{ + if (unlikely(!client)) + return false; + + if (client->connect_cb_data_destroy) + client->connect_cb_data_destroy(client->connect_cb_data); + + client->connect_cb = function; + client->connect_cb_data = user_data; + client->connect_cb_data_destroy = destroy; + + return true; +} + +LIB_EXPORT bool l_dbus_client_set_disconnect_handler(struct l_dbus_client *client, + l_dbus_watch_func_t function, + void *user_data, + l_dbus_destroy_func_t destroy) +{ + if (unlikely(!client)) + return false; + + if(client->disconnect_cb_data_destroy) + client->disconnect_cb_data_destroy(client->disconnect_cb_data); + + client->disconnect_cb = function; + client->disconnect_cb_data = user_data; + client->disconnect_cb_data_destroy = destroy; + + return true; +} + +LIB_EXPORT bool l_dbus_client_set_ready_handler(struct l_dbus_client *client, + l_dbus_client_ready_func_t function, + void *user_data, + l_dbus_destroy_func_t destroy) +{ + if (unlikely(!client)) + return false; + + if (client->ready_cb_data_destroy) + client->ready_cb_data_destroy(client->ready_cb_data); + + client->ready_cb = function; + client->ready_cb_data = user_data; + client->ready_cb_data_destroy = destroy; + + return true; +} + +LIB_EXPORT bool l_dbus_client_set_proxy_handlers(struct l_dbus_client *client, + l_dbus_client_proxy_func_t proxy_added, + l_dbus_client_proxy_func_t proxy_removed, + l_dbus_client_property_function_t property_changed, + void *user_data, l_dbus_destroy_func_t destroy) +{ + if (unlikely(!client)) + return false; + + if (client->proxy_cb_data_destroy) + client->proxy_cb_data_destroy(client->proxy_cb_data); + + client->proxy_added_cb = proxy_added; + client->proxy_removed_cb = proxy_removed; + client->properties_changed_cb = property_changed; + client->proxy_cb_data = user_data; + client->proxy_cb_data_destroy = destroy; + + return true; +} diff --git a/ell/dbus-client.h b/ell/dbus-client.h new file mode 100644 index 0000000000000000000000000000000000000000..b8128611e3f72be9a6364603adc3c47d2ccabef6 --- /dev/null +++ b/ell/dbus-client.h @@ -0,0 +1,83 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * Copyright (C) 2017 Codecoup + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_DBUS_CLIENT_H +#define __ELL_DBUS_CLIENT_H + +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct l_dbus; +struct l_dbus_message; +struct l_dbus_client; +struct l_dbus_proxy; + +typedef void (*l_dbus_client_ready_func_t)(struct l_dbus_client *client, + void *user_data); +typedef void (*l_dbus_client_proxy_func_t) (struct l_dbus_proxy *proxy, + void *user_data); +typedef void (*l_dbus_client_proxy_result_func_t) (struct l_dbus_proxy *proxy, + struct l_dbus_message *result, + void *user_data); +typedef void (*l_dbus_client_property_function_t) (struct l_dbus_proxy *proxy, + const char *name, + struct l_dbus_message *msg, + void *user_data); + +struct l_dbus_client *l_dbus_client_new(struct l_dbus *dbus, + const char *service, const char *path); +void l_dbus_client_destroy(struct l_dbus_client *client); + +bool l_dbus_client_set_connect_handler(struct l_dbus_client *client, + l_dbus_watch_func_t function, + void *user_data, + l_dbus_destroy_func_t destroy); + +bool l_dbus_client_set_disconnect_handler(struct l_dbus_client *client, + l_dbus_watch_func_t function, + void *user_data, + l_dbus_destroy_func_t destroy); + +bool l_dbus_client_set_ready_handler(struct l_dbus_client *client, + l_dbus_client_ready_func_t function, + void *user_data, + l_dbus_destroy_func_t destroy); + +bool l_dbus_client_set_proxy_handlers(struct l_dbus_client *client, + l_dbus_client_proxy_func_t proxy_added, + l_dbus_client_proxy_func_t proxy_removed, + l_dbus_client_property_function_t property_changed, + void *user_data, l_dbus_destroy_func_t destroy); + +const char *l_dbus_proxy_get_path(struct l_dbus_proxy *proxy); + +const char *l_dbus_proxy_get_interface(struct l_dbus_proxy *proxy); + +bool l_dbus_proxy_get_property(struct l_dbus_proxy *proxy, const char *name, + const char *signature, ...); + +bool l_dbus_proxy_set_property(struct l_dbus_proxy *proxy, + l_dbus_client_proxy_result_func_t result, + void *user_data, l_dbus_destroy_func_t destroy, + const char *name, const char *signature, ...); + +uint32_t l_dbus_proxy_method_call(struct l_dbus_proxy *proxy, + const char *method, + l_dbus_message_func_t setup, + l_dbus_client_proxy_result_func_t reply, + void *user_data, + l_dbus_destroy_func_t destroy); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_DBUS_CLIENT_H */ diff --git a/ell/dbus-filter.c b/ell/dbus-filter.c new file mode 100644 index 0000000000000000000000000000000000000000..7853c2b087a3a0bbbd8df17c69846b6d524a5a69 --- /dev/null +++ b/ell/dbus-filter.c @@ -0,0 +1,414 @@ +/* + * Embedded Linux library + * Copyright (C) 2016 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <stdlib.h> +#include <stdio.h> + +#include "util.h" +#include "queue.h" +#include "hashmap.h" +#include "string.h" +#include "dbus.h" +#include "dbus-private.h" +#include "gvariant-private.h" +#include "private.h" +#include "useful.h" + +#define NODE_TYPE_CALLBACK L_DBUS_MATCH_NONE + +struct filter_node { + enum l_dbus_match_type type; + union { + struct { + char *value; + struct filter_node *children; + bool remote_rule; + } match; + struct { + l_dbus_message_func_t func; + void *user_data; + } callback; + }; + unsigned int id; + struct filter_node *next; +}; + +struct _dbus_filter { + struct l_dbus *dbus; + struct filter_node *root; + unsigned int signal_id; + unsigned int last_id; + const struct _dbus_filter_ops *driver; + struct _dbus_name_cache *name_cache; +}; + +static void filter_subtree_free(struct filter_node *node) +{ + struct filter_node *child, *next; + + if (node->type == NODE_TYPE_CALLBACK) { + l_free(node); + return; + } + + next = node->match.children; + + l_free(node->match.value); + l_free(node); + + while (next) { + child = next; + next = child->next; + + filter_subtree_free(child); + } +} + +static void dbus_filter_destroy(void *data) +{ + struct _dbus_filter *filter = data; + + if (filter->root) + filter_subtree_free(filter->root); + + l_free(filter); +} + +static void filter_dispatch_match_recurse(struct _dbus_filter *filter, + struct filter_node *node, + struct l_dbus_message *message) +{ + const char *value = NULL; + const char *alt_value = NULL; + struct filter_node *child; + + switch ((int) node->type) { + case NODE_TYPE_CALLBACK: + node->callback.func(message, node->callback.user_data); + return; + + case L_DBUS_MATCH_SENDER: + value = l_dbus_message_get_sender(message); + break; + + case L_DBUS_MATCH_TYPE: + value = _dbus_message_get_type_as_string(message); + break; + + case L_DBUS_MATCH_PATH: + value = l_dbus_message_get_path(message); + break; + + case L_DBUS_MATCH_INTERFACE: + value = l_dbus_message_get_interface(message); + break; + + case L_DBUS_MATCH_MEMBER: + value = l_dbus_message_get_member(message); + break; + + case L_DBUS_MATCH_ARG0...(L_DBUS_MATCH_ARG0 + 63): + value = _dbus_message_get_nth_string_argument(message, + node->type - L_DBUS_MATCH_ARG0); + break; + } + + if (!value) + return; + + if (node->type == L_DBUS_MATCH_SENDER && filter->name_cache) + alt_value = _dbus_name_cache_lookup(filter->name_cache, + node->match.value); + + if (strcmp(value, node->match.value) && + (!alt_value || strcmp(value, alt_value))) + return; + + for (child = node->match.children; child; child = child->next) + filter_dispatch_match_recurse(filter, child, message); +} + +void _dbus_filter_dispatch(struct l_dbus_message *message, void *user_data) +{ + struct _dbus_filter *filter = user_data; + + filter_dispatch_match_recurse(filter, filter->root, message); +} + +struct _dbus_filter *_dbus_filter_new(struct l_dbus *dbus, + const struct _dbus_filter_ops *driver, + struct _dbus_name_cache *name_cache) +{ + struct _dbus_filter *filter; + + filter = l_new(struct _dbus_filter, 1); + + filter->dbus = dbus; + filter->driver = driver; + filter->name_cache = name_cache; + + if (!filter->driver->skip_register) + filter->signal_id = l_dbus_register(dbus, _dbus_filter_dispatch, + filter, + dbus_filter_destroy); + + return filter; +} + +void _dbus_filter_free(struct _dbus_filter *filter) +{ + if (!filter) + return; + + if (!filter->driver->skip_register) + l_dbus_unregister(filter->dbus, filter->signal_id); + else + dbus_filter_destroy(filter); +} + +static int condition_compare(const void *a, const void *b) +{ + const struct _dbus_filter_condition *condition_a = a, *condition_b = b; + + return condition_a->type - condition_b->type; +} + +static bool remove_recurse(struct _dbus_filter *filter, + struct filter_node **node, unsigned int id) +{ + struct filter_node *tmp; + + for (; *node; node = &(*node)->next) { + if ((*node)->type == NODE_TYPE_CALLBACK && (*node)->id == id) + break; + + if ((*node)->type != NODE_TYPE_CALLBACK && + remove_recurse(filter, &(*node)->match.children, + id)) + break; + } + + if (!*node) + return false; + + if ((*node)->type == NODE_TYPE_CALLBACK || !(*node)->match.children) { + tmp = *node; + *node = tmp->next; + + if (tmp->match.remote_rule) + filter->driver->remove_match(filter->dbus, tmp->id); + + if (tmp->type == L_DBUS_MATCH_SENDER && filter->name_cache && + !_dbus_parse_unique_name(tmp->match.value, + NULL)) + _dbus_name_cache_remove(filter->name_cache, + tmp->match.value); + + filter_subtree_free(tmp); + } + + return true; +} + +unsigned int _dbus_filter_add_rule(struct _dbus_filter *filter, + const struct _dbus_filter_condition *rule, + int rule_len, + l_dbus_message_func_t signal_func, + void *user_data) +{ + struct filter_node **node_ptr = &filter->root; + struct filter_node *node; + struct filter_node *parent = filter->root; + bool remote_rule = false; + struct _dbus_filter_condition sorted[rule_len]; + struct _dbus_filter_condition *unused; + struct _dbus_filter_condition *condition; + struct _dbus_filter_condition *end = sorted + rule_len; + + memcpy(sorted, rule, sizeof(sorted)); + qsort(sorted, rule_len, sizeof(*condition), condition_compare); + + /* + * Find or create a path in the tree with a node for each + * condition in the rule, loop until all conditions have been + * used. + */ + unused = sorted; + while (unused < end) { + /* + * Find a child of the node that matches any unused + * condition. Note there could be multiple matches, we're + * happy with the first we can find. + */ + while (*node_ptr) { + node = *node_ptr; + + for (condition = unused; condition < end; condition++) { + if (condition->type > node->type) { + condition = end; + break; + } + + if (condition->type < node->type || + condition->type == + L_DBUS_MATCH_NONE) + continue; + + if (!strcmp(node->match.value, + condition->value)) + break; + } + + if (condition < end) + break; + + node_ptr = &node->next; + } + + /* Add a node */ + if (!*node_ptr) { + condition = unused; + + node = l_new(struct filter_node, 1); + node->type = condition->type; + node->match.value = l_strdup(condition->value); + + *node_ptr = node; + + if (node->type == L_DBUS_MATCH_SENDER && + filter->name_cache && + !_dbus_parse_unique_name( + node->match.value, + NULL)) + _dbus_name_cache_add(filter->name_cache, + node->match.value); + + } + +_Pragma("GCC diagnostic push") +_Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") + /* + * Mark the condition used. We do this by setting + * condition->type to an invalid value unless it is the + * first condition left in which case we can push the + * rule start. Another option is to always push the rule + * start and memmove the still unused conditions by one + * if necessary. + */ + condition->type = L_DBUS_MATCH_NONE; + while (unused < end && unused[0].type == L_DBUS_MATCH_NONE) + unused++; + + node_ptr = &node->match.children; + + parent = node; + + /* + * Only have to call AddMatch if none of the parent nodes + * have yet created an AddMatch rule on the server. + */ + remote_rule |= node->match.remote_rule; +_Pragma("GCC diagnostic pop") + } + + node = l_new(struct filter_node, 1); + node->type = NODE_TYPE_CALLBACK; + node->callback.func = signal_func; + node->callback.user_data = user_data; + node->id = ++filter->last_id; + node->next = *node_ptr; + + *node_ptr = node; + + if (!remote_rule) { + if (!filter->driver->add_match(filter->dbus, node->id, + rule, rule_len)) + goto err; + +_Pragma("GCC diagnostic push") +_Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") + parent->id = node->id; + parent->match.remote_rule = true; +_Pragma("GCC diagnostic pop") + } + + return node->id; + +err: + /* Remove all the nodes we may have added */ + node->id = (unsigned int) -1; + remove_recurse(filter, &filter->root, node->id); + + return 0; +} + +bool _dbus_filter_remove_rule(struct _dbus_filter *filter, unsigned int id) +{ + return remove_recurse(filter, &filter->root, id); +} + +char *_dbus_filter_rule_to_str(const struct _dbus_filter_condition *rule, + int rule_len) +{ + struct l_string *str = l_string_new(63); + char *key, arg_buf[6]; + const char *value, *endp; + + for (; rule_len; rule++, rule_len--) { + switch ((int) rule->type) { + case L_DBUS_MATCH_SENDER: + key = "sender"; + break; + case L_DBUS_MATCH_TYPE: + key = "type"; + break; + case L_DBUS_MATCH_PATH: + key = "path"; + break; + case L_DBUS_MATCH_INTERFACE: + key = "interface"; + break; + case L_DBUS_MATCH_MEMBER: + key = "member"; + break; + case L_DBUS_MATCH_ARG0...(L_DBUS_MATCH_ARG0 + 63): + key = arg_buf; + snprintf(arg_buf, sizeof(arg_buf), "arg%i", + rule->type - L_DBUS_MATCH_ARG0); + break; + default: + l_string_free(str); + return NULL; + } + + l_string_append(str, key); + l_string_append(str, "='"); + + /* We only need to escape single-quotes in the values */ + value = rule->value; + + while ((endp = strchr(value, '\''))) { + l_string_append_fixed(str, value, endp - value); + l_string_append(str, "'\\''"); + + value = endp + 1; + } + + l_string_append(str, value); + l_string_append_c(str, '\''); + + if (rule_len > 1) + l_string_append_c(str, ','); + } + + return l_string_unwrap(str); +} diff --git a/ell/dbus-message.c b/ell/dbus-message.c new file mode 100644 index 0000000000000000000000000000000000000000..d85f7f853f6f6c4b55955a37eb79e3c3c681f4dd --- /dev/null +++ b/ell/dbus-message.c @@ -0,0 +1,1974 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> + +#include "util.h" +#include "private.h" +#include "useful.h" +#include "dbus.h" +#include "dbus-private.h" +#include "gvariant-private.h" + +#define DBUS_MESSAGE_LITTLE_ENDIAN ('l') +#define DBUS_MESSAGE_BIG_ENDIAN ('B') + +#define DBUS_MESSAGE_PROTOCOL_VERSION 1 + +#define DBUS_MESSAGE_FLAG_NO_REPLY_EXPECTED 0x01 +#define DBUS_MESSAGE_FLAG_NO_AUTO_START 0x02 + +#define DBUS_MESSAGE_FIELD_PATH 1 +#define DBUS_MESSAGE_FIELD_INTERFACE 2 +#define DBUS_MESSAGE_FIELD_MEMBER 3 +#define DBUS_MESSAGE_FIELD_ERROR_NAME 4 +#define DBUS_MESSAGE_FIELD_REPLY_SERIAL 5 +#define DBUS_MESSAGE_FIELD_DESTINATION 6 +#define DBUS_MESSAGE_FIELD_SENDER 7 +#define DBUS_MESSAGE_FIELD_SIGNATURE 8 +#define DBUS_MESSAGE_FIELD_UNIX_FDS 9 + +#define DBUS_MAX_NESTING 32 + +struct l_dbus_message { + int refcount; + void *header; + size_t header_size; + size_t header_end; + char *signature; + void *body; + size_t body_size; + char *path; + char *interface; + char *member; + char *error_name; + uint32_t reply_serial; + char *destination; + char *sender; + int fds[16]; + uint32_t num_fds; + + bool sealed : 1; + bool signature_free : 1; +}; + +struct l_dbus_message_builder { + struct l_dbus_message *message; + struct dbus_builder *builder; + struct builder_driver *driver; +}; + +static inline bool _dbus_message_is_gvariant(struct l_dbus_message *msg) +{ + struct dbus_header *hdr = msg->header; + + return hdr->version == 2; +} + +void *_dbus_message_get_header(struct l_dbus_message *msg, size_t *out_size) +{ + if (out_size) + *out_size = msg->header_size; + + return msg->header; +} + +void *_dbus_message_get_body(struct l_dbus_message *msg, size_t *out_size) +{ + if (out_size) + *out_size = msg->body_size; + + return msg->body; +} + +/* Get a buffer containing the final message contents except the header */ +void *_dbus_message_get_footer(struct l_dbus_message *msg, size_t *out_size) +{ + size_t size; + + if (_dbus_message_is_gvariant(msg)) { + size = _gvariant_message_finalize(msg->header_end, + msg->body, msg->body_size, + msg->signature); + size -= msg->header_size; + } else + size = msg->body_size; + + if (out_size) + *out_size = size; + + return msg->body; +} + +int *_dbus_message_get_fds(struct l_dbus_message *msg, uint32_t *num_fds) +{ + *num_fds = msg->num_fds; + + return msg->fds; +} + +void _dbus_message_set_serial(struct l_dbus_message *msg, uint32_t serial) +{ + struct dbus_header *hdr = msg->header; + + hdr->dbus1.serial = serial; +} + +uint32_t _dbus_message_get_serial(struct l_dbus_message *msg) +{ + struct dbus_header *hdr = msg->header; + + return hdr->dbus1.serial; +} + +LIB_EXPORT bool l_dbus_message_set_no_reply(struct l_dbus_message *msg, bool on) +{ + struct dbus_header *hdr; + + if (unlikely(!msg)) + return false; + + hdr = msg->header; + + if (on) + hdr->flags |= DBUS_MESSAGE_FLAG_NO_REPLY_EXPECTED; + else + hdr->flags &= ~DBUS_MESSAGE_FLAG_NO_REPLY_EXPECTED; + + return true; +} + +LIB_EXPORT bool l_dbus_message_get_no_reply(struct l_dbus_message *msg) +{ + struct dbus_header *hdr; + + if (unlikely(!msg)) + return false; + + hdr = msg->header; + + if (hdr->flags & DBUS_MESSAGE_FLAG_NO_REPLY_EXPECTED) + return true; + + return false; +} + +LIB_EXPORT bool l_dbus_message_set_no_autostart(struct l_dbus_message *msg, + bool on) +{ + struct dbus_header *hdr; + + if (unlikely(!msg)) + return false; + + hdr = msg->header; + + if (on) + hdr->flags |= DBUS_MESSAGE_FLAG_NO_AUTO_START; + else + hdr->flags &= ~DBUS_MESSAGE_FLAG_NO_AUTO_START; + + return true; +} + +LIB_EXPORT bool l_dbus_message_get_no_autostart(struct l_dbus_message *msg) +{ + struct dbus_header *hdr; + + if (unlikely(!msg)) + return false; + + hdr = msg->header; + + if (hdr->flags & DBUS_MESSAGE_FLAG_NO_AUTO_START) + return true; + + return false; + +} + +static struct l_dbus_message *message_new_common(uint8_t type, uint8_t flags, + uint8_t version) +{ + struct l_dbus_message *message; + struct dbus_header *hdr; + + message = l_new(struct l_dbus_message, 1); + message->refcount = 1; + + /* + * We allocate the header with the initial 12 bytes (up to the field + * length) so that we can store the basic information here. For + * GVariant we need 16 bytes. + */ + message->header_size = version == 1 ? 12 : 16; + message->header_end = message->header_size; + message->header = l_realloc(NULL, message->header_size); + + hdr = message->header; + hdr->endian = DBUS_NATIVE_ENDIAN; + hdr->message_type = type; + hdr->flags = flags; + hdr->version = version; + + return message; +} + +struct l_dbus_message *_dbus_message_new_method_call(uint8_t version, + const char *destination, + const char *path, + const char *interface, + const char *method) +{ + struct l_dbus_message *message; + + message = message_new_common(DBUS_MESSAGE_TYPE_METHOD_CALL, 0, version); + + message->destination = l_strdup(destination); + message->path = l_strdup(path); + message->interface = l_strdup(interface); + message->member = l_strdup(method); + + return message; +} + +LIB_EXPORT struct l_dbus_message *l_dbus_message_new_method_call( + struct l_dbus *dbus, + const char *destination, + const char *path, + const char *interface, + const char *method) +{ + uint8_t version; + + if (unlikely(!dbus)) + return NULL; + + version = _dbus_get_version(dbus); + + return _dbus_message_new_method_call(version, destination, path, + interface, method); +} + +struct l_dbus_message *_dbus_message_new_signal(uint8_t version, + const char *path, + const char *interface, + const char *name) +{ + struct l_dbus_message *message; + + message = message_new_common(DBUS_MESSAGE_TYPE_SIGNAL, + DBUS_MESSAGE_FLAG_NO_REPLY_EXPECTED, + version); + + message->path = l_strdup(path); + message->interface = l_strdup(interface); + message->member = l_strdup(name); + + return message; +} + +LIB_EXPORT struct l_dbus_message *l_dbus_message_new_signal(struct l_dbus *dbus, + const char *path, + const char *interface, + const char *name) +{ + uint8_t version; + + if (unlikely(!dbus)) + return NULL; + + version = _dbus_get_version(dbus); + + return _dbus_message_new_signal(version, path, interface, name); +} + +LIB_EXPORT struct l_dbus_message *l_dbus_message_new_method_return( + struct l_dbus_message *method_call) +{ + struct l_dbus_message *message; + struct dbus_header *hdr = method_call->header; + const char *sender; + + message = message_new_common(DBUS_MESSAGE_TYPE_METHOD_RETURN, + DBUS_MESSAGE_FLAG_NO_REPLY_EXPECTED, + hdr->version); + + if (!l_dbus_message_get_no_reply(method_call)) + message->reply_serial = _dbus_message_get_serial(method_call); + + sender = l_dbus_message_get_sender(method_call); + if (sender) + message->destination = l_strdup(sender); + + return message; +} + +struct l_dbus_message *_dbus_message_new_error(uint8_t version, + uint32_t reply_serial, + const char *destination, + const char *name, + const char *error) +{ + struct l_dbus_message *reply; + + if (!_dbus_valid_interface(name)) + return NULL; + + reply = message_new_common(DBUS_MESSAGE_TYPE_ERROR, + DBUS_MESSAGE_FLAG_NO_REPLY_EXPECTED, + version); + + reply->error_name = l_strdup(name); + reply->destination = l_strdup(destination); + reply->reply_serial = reply_serial; + + if (!l_dbus_message_set_arguments(reply, "s", error)) { + l_dbus_message_unref(reply); + return NULL; + } + + return reply; +} + +LIB_EXPORT struct l_dbus_message *l_dbus_message_new_error_valist( + struct l_dbus_message *method_call, + const char *name, + const char *format, va_list args) +{ + char str[1024]; + struct dbus_header *hdr = method_call->header; + uint32_t reply_serial = 0; + + vsnprintf(str, sizeof(str), format, args); + + if (!l_dbus_message_get_no_reply(method_call)) + reply_serial = _dbus_message_get_serial(method_call); + + return _dbus_message_new_error(hdr->version, reply_serial, + l_dbus_message_get_sender(method_call), + name, str); +} + +LIB_EXPORT struct l_dbus_message *l_dbus_message_new_error( + struct l_dbus_message *method_call, + const char *name, + const char *format, ...) +{ + va_list args; + struct l_dbus_message *reply; + + va_start(args, format); + reply = l_dbus_message_new_error_valist(method_call, name, + format, args); + va_end(args); + + return reply; +} + +LIB_EXPORT struct l_dbus_message *l_dbus_message_ref(struct l_dbus_message *message) +{ + if (unlikely(!message)) + return NULL; + + __atomic_fetch_add(&message->refcount, 1, __ATOMIC_SEQ_CST); + + return message; +} + +LIB_EXPORT void l_dbus_message_unref(struct l_dbus_message *message) +{ + unsigned int i; + + if (unlikely(!message)) + return; + + if (__atomic_sub_fetch(&message->refcount, 1, __ATOMIC_SEQ_CST)) + return; + + for (i = 0; i < message->num_fds; i++) + close(message->fds[i]); + + if (!message->sealed) { + l_free(message->destination); + l_free(message->path); + l_free(message->interface); + l_free(message->member); + l_free(message->error_name); + l_free(message->sender); + } + + if (message->signature_free) + l_free(message->signature); + + l_free(message->header); + l_free(message->body); + l_free(message); +} + +const char *_dbus_message_get_nth_string_argument( + struct l_dbus_message *message, int n) +{ + struct l_dbus_message_iter iter; + const char *signature, *value; + void *body; + size_t size; + char type; + bool (*skip_entry)(struct l_dbus_message_iter *); + bool (*get_basic)(struct l_dbus_message_iter *, char, void *); + + signature = l_dbus_message_get_signature(message); + body = _dbus_message_get_body(message, &size); + + if (!signature) + return NULL; + + if (_dbus_message_is_gvariant(message)) { + if (!_gvariant_iter_init(&iter, message, signature, NULL, + body, size)) + return NULL; + + skip_entry = _gvariant_iter_skip_entry; + get_basic = _gvariant_iter_next_entry_basic; + } else { + _dbus1_iter_init(&iter, message, signature, NULL, body, size); + + skip_entry = _dbus1_iter_skip_entry; + get_basic = _dbus1_iter_next_entry_basic; + } + + while (n--) + if (!skip_entry(&iter)) + return NULL; + + if (!iter.sig_start) + return NULL; + + type = iter.sig_start[iter.sig_pos]; + if (!strchr("sog", type)) + return NULL; + + if (!get_basic(&iter, type, &value)) + return NULL; + + return value; +} + +static bool message_iter_next_entry_valist(struct l_dbus_message_iter *orig, + va_list args) +{ + static const char *simple_types = "sogybnqiuxtd"; + struct l_dbus_message_iter *iter = orig; + const char *signature = orig->sig_start + orig->sig_pos; + const char *end; + struct l_dbus_message_iter *sub_iter; + struct l_dbus_message_iter stack[DBUS_MAX_NESTING]; + unsigned int indent = 0; + uint32_t uint32_val; + int fd; + void *arg; + bool (*get_basic)(struct l_dbus_message_iter *, char ,void *); + bool (*enter_struct)(struct l_dbus_message_iter *, + struct l_dbus_message_iter *); + bool (*enter_array)(struct l_dbus_message_iter *, + struct l_dbus_message_iter *); + bool (*enter_variant)(struct l_dbus_message_iter *, + struct l_dbus_message_iter *); + + if (_dbus_message_is_gvariant(orig->message)) { + get_basic = _gvariant_iter_next_entry_basic; + enter_struct = _gvariant_iter_enter_struct; + enter_array = _gvariant_iter_enter_array; + enter_variant = _gvariant_iter_enter_variant; + } else { + get_basic = _dbus1_iter_next_entry_basic; + enter_struct = _dbus1_iter_enter_struct; + enter_array = _dbus1_iter_enter_array; + enter_variant = _dbus1_iter_enter_variant; + } + + while (signature < orig->sig_start + orig->sig_len) { + if (strchr(simple_types, *signature)) { + arg = va_arg(args, void *); + if (!get_basic(iter, *signature, arg)) + return false; + + signature += 1; + continue; + } + + switch (*signature) { + case 'h': + if (!get_basic(iter, 'h', &uint32_val)) + return false; + + if (uint32_val < iter->message->num_fds) + fd = fcntl(iter->message->fds[uint32_val], + F_DUPFD_CLOEXEC, 3); + else + fd = -1; + + *va_arg(args, int *) = fd; + signature += 1; + break; + case '(': + case '{': + signature += 1; + indent += 1; + + if (indent > DBUS_MAX_NESTING) + return false; + + if (!enter_struct(iter, &stack[indent - 1])) + return false; + + iter = &stack[indent - 1]; + + break; + case ')': + case '}': + /* + * Sanity check in case of an unmatched paren/brace + * that isn't caught elsewhere. + */ + if (unlikely(indent == 0)) + return false; + + signature += 1; + indent -= 1; + + if (indent == 0) + iter = orig; + else + iter = &stack[indent - 1]; + break; + case 'a': + sub_iter = va_arg(args, void *); + + if (!enter_array(iter, sub_iter)) + return false; + + end = _dbus_signature_end(signature + 1); + signature = end + 1; + break; + case 'v': + sub_iter = va_arg(args, void *); + + if (!enter_variant(iter, sub_iter)) + return false; + + signature += 1; + break; + default: + return false; + } + } + + return true; +} + +static inline bool message_iter_next_entry(struct l_dbus_message_iter *iter, + ...) +{ + va_list args; + bool result; + + va_start(args, iter); + result = message_iter_next_entry_valist(iter, args); + va_end(args); + + return result; +} + +static bool get_header_field_from_iter_valist(struct l_dbus_message *message, + uint8_t type, char data_type, + va_list args) +{ + struct l_dbus_message_iter header; + struct l_dbus_message_iter array, iter; + uint8_t endian, message_type, flags, version; + uint32_t body_length, serial; + bool found; + + if (!message->sealed) + return false; + + if (_dbus_message_is_gvariant(message)) { + uint64_t field_type; + + if (!_gvariant_iter_init(&header, message, "a(tv)", NULL, + message->header + 16, + message->header_end - 16)) + return false; + + if (!_gvariant_iter_enter_array(&header, &array)) + return false; + + while ((found = message_iter_next_entry(&array, + &field_type, &iter))) + if (field_type == type) + break; + } else { + uint8_t field_type; + + _dbus1_iter_init(&header, message, "yyyyuua(yv)", NULL, + message->header, message->header_size); + + if (!message_iter_next_entry(&header, &endian, + &message_type, &flags, &version, + &body_length, &serial, &array)) + return false; + + while ((found = message_iter_next_entry(&array, + &field_type, &iter))) + if (field_type == type) + break; + } + + if (!found) + return false; + + if (iter.sig_start[iter.sig_pos] != data_type) + return false; + + return message_iter_next_entry_valist(&iter, args); +} + +static inline bool get_header_field(struct l_dbus_message *message, + uint8_t type, int data_type, ...) +{ + va_list args; + bool result; + + va_start(args, data_type); + result = get_header_field_from_iter_valist(message, type, data_type, + args); + va_end(args); + + return result; +} + +static bool valid_header(const struct dbus_header *hdr) +{ + if (hdr->endian != DBUS_MESSAGE_LITTLE_ENDIAN && + hdr->endian != DBUS_MESSAGE_BIG_ENDIAN) + return false; + + if (hdr->message_type < DBUS_MESSAGE_TYPE_METHOD_CALL || + hdr->message_type > DBUS_MESSAGE_TYPE_SIGNAL) + return false; + + if (hdr->version != 1 && hdr->version != 2) + return false; + + if (hdr->version == 1) { + if (hdr->dbus1.serial == 0) + return false; + } + + return true; +} + +unsigned int _dbus_message_unix_fds_from_header(const void *data, size_t size) +{ + struct l_dbus_message message; + uint32_t unix_fds; + + message.header = (uint8_t *) data; + message.header_size = size; + message.body_size = 0; + message.sealed = true; + + if (!get_header_field(&message, DBUS_MESSAGE_FIELD_UNIX_FDS, + 'u', &unix_fds)) + return 0; + + return unix_fds; +} + +struct l_dbus_message *dbus_message_from_blob(const void *data, size_t size, + int fds[], uint32_t num_fds) +{ + const struct dbus_header *hdr = data; + struct l_dbus_message *message; + size_t body_pos; + unsigned int i; + + if (unlikely(size < DBUS_HEADER_SIZE)) + return NULL; + + message = l_new(struct l_dbus_message, 1); + + message->refcount = 1; + + if (hdr->version == 1) { + message->header_size = align_len(DBUS_HEADER_SIZE + + hdr->dbus1.field_length, 8); + message->body_size = hdr->dbus1.body_length; + + if (message->header_size + message->body_size < size) + goto free; + + body_pos = message->header_size; + } else { + struct l_dbus_message_iter iter; + struct l_dbus_message_iter header, variant, body; + + /* + * GVariant message structure as per + * https://wiki.gnome.org/Projects/GLib/GDBus/Version2 + * is "(yyyyuta{tv}v)". As noted this is equivalent to + * some other types, this one lets us get iterators for + * the header and the body in the fewest steps. + */ + if (!_gvariant_iter_init(&iter, message, "(yyyyuta{tv})v", + NULL, data, size)) + goto free; + + if (!_gvariant_iter_enter_struct(&iter, &header)) + goto free; + + if (!_gvariant_iter_enter_variant(&iter, &variant)) + goto free; + + if (!_gvariant_iter_enter_struct(&variant, &body)) + goto free; + + message->header_size = align_len(header.len - header.pos, 8); + message->body_size = body.len - body.pos; + message->signature = l_strndup(body.sig_start + body.sig_pos, + body.sig_len - body.sig_pos); + message->signature_free = true; + message->header_end = header.len; + body_pos = body.data + body.pos - data; + } + + message->header = l_malloc(message->header_size); + message->body = l_malloc(message->body_size); + + memcpy(message->header, data, message->header_size); + memcpy(message->body, data + body_pos, message->body_size); + + message->sealed = true; + + /* If the field is absent message->signature will remain NULL */ + if (hdr->version == 1) + get_header_field(message, DBUS_MESSAGE_FIELD_SIGNATURE, + 'g', &message->signature); + + if (num_fds) { + uint32_t unix_fds, orig_fds = num_fds; + + if (!get_header_field(message, DBUS_MESSAGE_FIELD_UNIX_FDS, + 'u', &unix_fds)) + goto free; + + if (num_fds > unix_fds) + num_fds = unix_fds; + + if (num_fds > L_ARRAY_SIZE(message->fds)) + num_fds = L_ARRAY_SIZE(message->fds); + + for (i = num_fds; i < orig_fds; i++) + close(fds[i]); + + message->num_fds = num_fds; + memcpy(message->fds, fds, num_fds * sizeof(int)); + } + + return message; + +free: + l_dbus_message_unref(message); + + return NULL; +} + +struct l_dbus_message *dbus_message_build(void *header, size_t header_size, + void *body, size_t body_size, + int fds[], uint32_t num_fds) +{ + const struct dbus_header *hdr = header; + struct l_dbus_message *message; + unsigned int i; + + if (unlikely(header_size < DBUS_HEADER_SIZE)) + return NULL; + + if (unlikely(!valid_header(hdr))) + return NULL; + + /* + * With GVariant we need to know the signature, use + * dbus_message_from_blob instead. + */ + if (unlikely(hdr->version != 1)) + return NULL; + + message = l_new(struct l_dbus_message, 1); + + message->refcount = 1; + message->header_size = header_size; + message->header = header; + message->body_size = body_size; + message->body = body; + message->sealed = true; + + if (num_fds) { + uint32_t unix_fds, orig_fds = num_fds; + + if (!get_header_field(message, DBUS_MESSAGE_FIELD_UNIX_FDS, + 'u', &unix_fds)) { + l_free(message); + return NULL; + } + + if (num_fds > unix_fds) + num_fds = unix_fds; + + if (num_fds > L_ARRAY_SIZE(message->fds)) + num_fds = L_ARRAY_SIZE(message->fds); + + for (i = num_fds; i < orig_fds; i++) + close(fds[i]); + + message->num_fds = num_fds; + memcpy(message->fds, fds, num_fds * sizeof(int)); + } + + /* If the field is absent message->signature will remain NULL */ + get_header_field(message, DBUS_MESSAGE_FIELD_SIGNATURE, 'g', + &message->signature); + + return message; +} + +bool dbus_message_compare(struct l_dbus_message *message, + const void *data, size_t size) +{ + struct l_dbus_message *other; + bool ret = false; + + other = dbus_message_from_blob(data, size, NULL, 0); + + if (message->signature) { + if (!other->signature) + goto done; + + if (strcmp(message->signature, other->signature)) + goto done; + } else { + if (other->signature) + goto done; + } + + if (message->body_size != other->body_size) + goto done; + + if (message->header_size != other->header_size) + goto done; + + ret = !memcmp(message->body, other->body, message->body_size); + +done: + l_dbus_message_unref(other); + + return ret; +} + +struct builder_driver { + bool (*append_basic)(struct dbus_builder *, char, const void *); + bool (*enter_struct)(struct dbus_builder *, const char *); + bool (*leave_struct)(struct dbus_builder *); + bool (*enter_dict)(struct dbus_builder *, const char *); + bool (*leave_dict)(struct dbus_builder *); + bool (*enter_array)(struct dbus_builder *, const char *); + bool (*leave_array)(struct dbus_builder *); + bool (*enter_variant)(struct dbus_builder *, const char *); + bool (*leave_variant)(struct dbus_builder *); + char *(*finish)(struct dbus_builder *, void **, size_t *); + bool (*mark)(struct dbus_builder *); + bool (*rewind)(struct dbus_builder *); + struct dbus_builder *(*new)(void *, size_t); + void (*free)(struct dbus_builder *); +}; + +static struct builder_driver dbus1_driver = { + .append_basic = _dbus1_builder_append_basic, + .enter_struct = _dbus1_builder_enter_struct, + .leave_struct = _dbus1_builder_leave_struct, + .enter_dict = _dbus1_builder_enter_dict, + .leave_dict = _dbus1_builder_leave_dict, + .enter_variant = _dbus1_builder_enter_variant, + .leave_variant = _dbus1_builder_leave_variant, + .enter_array = _dbus1_builder_enter_array, + .leave_array = _dbus1_builder_leave_array, + .finish = _dbus1_builder_finish, + .mark = _dbus1_builder_mark, + .rewind = _dbus1_builder_rewind, + .new = _dbus1_builder_new, + .free = _dbus1_builder_free, +}; + +static struct builder_driver gvariant_driver = { + .append_basic = _gvariant_builder_append_basic, + .enter_struct = _gvariant_builder_enter_struct, + .leave_struct = _gvariant_builder_leave_struct, + .enter_dict = _gvariant_builder_enter_dict, + .leave_dict = _gvariant_builder_leave_dict, + .enter_variant = _gvariant_builder_enter_variant, + .leave_variant = _gvariant_builder_leave_variant, + .enter_array = _gvariant_builder_enter_array, + .leave_array = _gvariant_builder_leave_array, + .finish = _gvariant_builder_finish, + .mark = _gvariant_builder_mark, + .rewind = _gvariant_builder_rewind, + .new = _gvariant_builder_new, + .free = _gvariant_builder_free, +}; + +static void add_field(struct dbus_builder *builder, + struct builder_driver *driver, + uint8_t field, const char *type, const void *value) +{ + if (driver == &gvariant_driver) { + uint64_t long_field = field; + + driver->enter_struct(builder, "tv"); + driver->append_basic(builder, 't', &long_field); + } else { + driver->enter_struct(builder, "yv"); + driver->append_basic(builder, 'y', &field); + } + driver->enter_variant(builder, type); + driver->append_basic(builder, type[0], value); + driver->leave_variant(builder); + driver->leave_struct(builder); +} + +static void build_header(struct l_dbus_message *message, const char *signature) +{ + struct dbus_builder *builder; + struct builder_driver *driver; + char *generated_signature; + size_t header_size; + bool gvariant; + + gvariant = _dbus_message_is_gvariant(message); + + if (gvariant) + driver = &gvariant_driver; + else + driver = &dbus1_driver; + + builder = driver->new(message->header, message->header_size); + + driver->enter_array(builder, gvariant ? "(tv)" : "(yv)"); + + if (message->path) { + add_field(builder, driver, DBUS_MESSAGE_FIELD_PATH, + "o", message->path); + l_free(message->path); + message->path = NULL; + } + + if (message->member) { + add_field(builder, driver, DBUS_MESSAGE_FIELD_MEMBER, + "s", message->member); + l_free(message->member); + message->member = NULL; + } + + if (message->interface) { + add_field(builder, driver, DBUS_MESSAGE_FIELD_INTERFACE, + "s", message->interface); + l_free(message->interface); + message->interface = NULL; + } + + if (message->destination) { + add_field(builder, driver, DBUS_MESSAGE_FIELD_DESTINATION, + "s", message->destination); + l_free(message->destination); + message->destination = NULL; + } + + if (message->error_name != 0) { + add_field(builder, driver, DBUS_MESSAGE_FIELD_ERROR_NAME, + "s", message->error_name); + l_free(message->error_name); + message->error_name = NULL; + } + + if (message->reply_serial != 0) { + if (gvariant) { + uint64_t reply_serial = message->reply_serial; + + add_field(builder, driver, + DBUS_MESSAGE_FIELD_REPLY_SERIAL, + "t", &reply_serial); + } else { + add_field(builder, driver, + DBUS_MESSAGE_FIELD_REPLY_SERIAL, + "u", &message->reply_serial); + } + + message->reply_serial = 0; + } + + if (message->sender) { + add_field(builder, driver, DBUS_MESSAGE_FIELD_SENDER, + "s", message->sender); + l_free(message->sender); + message->sender = NULL; + } + + if (signature[0] != '\0' && !gvariant) + add_field(builder, driver, DBUS_MESSAGE_FIELD_SIGNATURE, + "g", signature); + + if (message->num_fds) + add_field(builder, driver, DBUS_MESSAGE_FIELD_UNIX_FDS, + "u", &message->num_fds); + + driver->leave_array(builder); + + generated_signature = driver->finish(builder, &message->header, + &header_size); + l_free(generated_signature); + + driver->free(builder); + + if (!_dbus_message_is_gvariant(message)) { + struct dbus_header *hdr = message->header; + + hdr->dbus1.body_length = message->body_size; + } + + /* We must align the end of the header to an 8-byte boundary */ + message->header_size = align_len(header_size, 8); + message->header = l_realloc(message->header, message->header_size); + memset(message->header + header_size, 0, + message->header_size - header_size); + message->header_end = header_size; +} + +struct container { + char type; + const char *sig_start; + const char *sig_end; + unsigned int n_items; +}; + +static bool append_arguments(struct l_dbus_message *message, + const char *signature, va_list args) +{ + struct l_dbus_message_builder *builder; + bool ret; + + builder = l_dbus_message_builder_new(message); + if (!builder) + return false; + + if (!l_dbus_message_builder_append_from_valist(builder, signature, + args)) { + l_dbus_message_builder_destroy(builder); + return false; + } + + l_dbus_message_builder_finalize(builder); + + ret = strcmp(signature, builder->message->signature) == 0; + + l_dbus_message_builder_destroy(builder); + + return ret; +} + +LIB_EXPORT bool l_dbus_message_get_error(struct l_dbus_message *message, + const char **name, const char **text) +{ + struct dbus_header *hdr; + const char *str; + + if (unlikely(!message)) + return false; + + hdr = message->header; + + if (hdr->message_type != DBUS_MESSAGE_TYPE_ERROR) + return false; + + if (!message->signature) + return false; + + if (message->signature[0] != 's') + return false; + + str = _dbus_message_get_nth_string_argument(message, 0); + if (!str) + return false; + + if (!message->error_name) + get_header_field(message, DBUS_MESSAGE_FIELD_ERROR_NAME, 's', + &message->error_name); + + if (name) + *name = message->error_name; + + if (text) + *text = str; + + return true; +} + +LIB_EXPORT bool l_dbus_message_is_error(struct l_dbus_message *message) +{ + struct dbus_header *hdr; + + if (unlikely(!message)) + return false; + + hdr = message->header; + return hdr->message_type == DBUS_MESSAGE_TYPE_ERROR; +} + +LIB_EXPORT bool l_dbus_message_get_arguments_valist( + struct l_dbus_message *message, + const char *signature, va_list args) +{ + struct l_dbus_message_iter iter; + + if (unlikely(!message)) + return false; + + if (!message->signature) { + /* An empty signature is valid */ + if (!signature || *signature == '\0') + return true; + + return false; + } + + if (!signature || strcmp(message->signature, signature)) + return false; + + if (_dbus_message_is_gvariant(message)) { + if (!_gvariant_iter_init(&iter, message, message->signature, + NULL, message->body, + message->body_size)) + return false; + } else + _dbus1_iter_init(&iter, message, message->signature, NULL, + message->body, message->body_size); + + return message_iter_next_entry_valist(&iter, args); +} + +LIB_EXPORT bool l_dbus_message_get_arguments(struct l_dbus_message *message, + const char *signature, ...) +{ + va_list args; + bool result; + + va_start(args, signature); + result = l_dbus_message_get_arguments_valist(message, signature, args); + va_end(args); + + return result; +} + +LIB_EXPORT bool l_dbus_message_set_arguments(struct l_dbus_message *message, + const char *signature, ...) +{ + va_list args; + bool result; + + if (unlikely(!message)) + return false; + + if (unlikely(message->sealed)) + return false; + + if (!signature) + return true; + + va_start(args, signature); + result = append_arguments(message, signature, args); + va_end(args); + + return result; +} + +LIB_EXPORT bool l_dbus_message_set_arguments_valist( + struct l_dbus_message *message, + const char *signature, va_list args) +{ + bool result; + + if (unlikely(!message)) + return false; + + if (!signature) + return true; + + result = append_arguments(message, signature, args); + + return result; +} + +LIB_EXPORT const char *l_dbus_message_get_path(struct l_dbus_message *message) +{ + if (unlikely(!message)) + return NULL; + + if (!message->path && message->sealed) + get_header_field(message, DBUS_MESSAGE_FIELD_PATH, 'o', + &message->path); + + return message->path; +} + +LIB_EXPORT const char *l_dbus_message_get_interface(struct l_dbus_message *message) +{ + if (unlikely(!message)) + return NULL; + + if (!message->interface && message->sealed) + get_header_field(message, DBUS_MESSAGE_FIELD_INTERFACE, 's', + &message->interface); + + return message->interface; +} + +LIB_EXPORT const char *l_dbus_message_get_member(struct l_dbus_message *message) +{ + if (unlikely(!message)) + return NULL; + + if (!message->member && message->sealed) + get_header_field(message, DBUS_MESSAGE_FIELD_MEMBER, 's', + &message->member); + + return message->member; +} + +LIB_EXPORT const char *l_dbus_message_get_destination(struct l_dbus_message *message) +{ + if (unlikely(!message)) + return NULL; + + if (!message->destination && message->sealed) + get_header_field(message, DBUS_MESSAGE_FIELD_DESTINATION, 's', + &message->destination); + + return message->destination; +} + +LIB_EXPORT const char *l_dbus_message_get_sender(struct l_dbus_message *message) +{ + if (unlikely(!message)) + return NULL; + + if (!message->sender && message->sealed) + get_header_field(message, DBUS_MESSAGE_FIELD_SENDER, 's', + &message->sender); + + return message->sender; +} + +LIB_EXPORT const char *l_dbus_message_get_signature( + struct l_dbus_message *message) +{ + if (unlikely(!message)) + return NULL; + + return message->signature; +} + +uint32_t _dbus_message_get_reply_serial(struct l_dbus_message *message) +{ + if (unlikely(!message)) + return 0; + + if (message->reply_serial == 0 && message->sealed) { + if (_dbus_message_is_gvariant(message)) { + uint64_t reply_serial = 0; + + get_header_field(message, + DBUS_MESSAGE_FIELD_REPLY_SERIAL, 't', + &reply_serial); + + message->reply_serial = reply_serial; + } else + get_header_field(message, + DBUS_MESSAGE_FIELD_REPLY_SERIAL, 'u', + &message->reply_serial); + } + + return message->reply_serial; +} + +enum dbus_message_type _dbus_message_get_type(struct l_dbus_message *message) +{ + struct dbus_header *header; + + header = message->header; + return header->message_type; +} + +const char * _dbus_message_get_type_as_string(struct l_dbus_message *message) +{ + struct dbus_header *header; + + header = message->header; + + switch (header->message_type) { + case DBUS_MESSAGE_TYPE_METHOD_CALL: + return "method_call"; + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + return "method_return"; + case DBUS_MESSAGE_TYPE_ERROR: + return "error"; + case DBUS_MESSAGE_TYPE_SIGNAL: + return "signal"; + } + + return NULL; +} + +uint8_t _dbus_message_get_endian(struct l_dbus_message *message) +{ + struct dbus_header *header = message->header; + + return header->endian; +} + +uint8_t _dbus_message_get_version(struct l_dbus_message *message) +{ + struct dbus_header *header = message->header; + + return header->version; +} + +LIB_EXPORT bool l_dbus_message_iter_next_entry(struct l_dbus_message_iter *iter, + ...) +{ + va_list args; + bool result; + + if (unlikely(!iter)) + return false; + + va_start(args, iter); + result = message_iter_next_entry_valist(iter, args); + va_end(args); + + return result; +} + +LIB_EXPORT bool l_dbus_message_iter_get_variant( + struct l_dbus_message_iter *iter, + const char *signature, ...) +{ + va_list args; + bool result; + + if (unlikely(!iter)) + return false; + + if (!iter->sig_start || strlen(signature) != iter->sig_len || + memcmp(iter->sig_start, signature, iter->sig_len)) + return false; + + va_start(args, signature); + result = message_iter_next_entry_valist(iter, args); + va_end(args); + + return result; +} + +LIB_EXPORT bool l_dbus_message_iter_get_fixed_array( + struct l_dbus_message_iter *iter, + void *out, uint32_t *n_elem) +{ + if (unlikely(!iter)) + return false; + + if (_dbus_message_is_gvariant(iter->message)) + return false; + + return _dbus1_iter_get_fixed_array(iter, out, n_elem); +} + +void _dbus_message_set_sender(struct l_dbus_message *message, + const char *sender) +{ + if (!_dbus_message_is_gvariant(message)) + return; + + l_free(message->sender); + + message->sender = l_strdup(sender); +} + +void _dbus_message_set_destination(struct l_dbus_message *message, + const char *destination) +{ + if (!_dbus_message_is_gvariant(message)) + return; + + l_free(message->destination); + + message->destination = l_strdup(destination); +} + +LIB_EXPORT struct l_dbus_message_builder *l_dbus_message_builder_new( + struct l_dbus_message *message) +{ + struct l_dbus_message_builder *ret; + + if (unlikely(!message)) + return NULL; + + if (message->sealed) + return NULL; + + ret = l_new(struct l_dbus_message_builder, 1); + ret->message = l_dbus_message_ref(message); + + if (_dbus_message_is_gvariant(message)) + ret->driver = &gvariant_driver; + else + ret->driver = &dbus1_driver; + + ret->builder = ret->driver->new(NULL, 0); + + return ret; +} + +LIB_EXPORT void l_dbus_message_builder_destroy( + struct l_dbus_message_builder *builder) +{ + if (unlikely(!builder)) + return; + + builder->driver->free(builder->builder); + l_dbus_message_unref(builder->message); + + l_free(builder); +} + +LIB_EXPORT bool l_dbus_message_builder_append_basic( + struct l_dbus_message_builder *builder, + char type, const void *value) +{ + if (unlikely(!builder)) + return false; + + return builder->driver->append_basic(builder->builder, type, value); +} + +LIB_EXPORT bool l_dbus_message_builder_enter_container( + struct l_dbus_message_builder *builder, + char container_type, + const char *signature) +{ + if (unlikely(!builder)) + return false; + + switch (container_type) { + case DBUS_CONTAINER_TYPE_ARRAY: + return builder->driver->enter_array(builder->builder, + signature); + case DBUS_CONTAINER_TYPE_DICT_ENTRY: + return builder->driver->enter_dict(builder->builder, signature); + case DBUS_CONTAINER_TYPE_STRUCT: + return builder->driver->enter_struct(builder->builder, + signature); + case DBUS_CONTAINER_TYPE_VARIANT: + return builder->driver->enter_variant(builder->builder, + signature); + default: + break; + } + + return false; +} + +LIB_EXPORT bool l_dbus_message_builder_leave_container( + struct l_dbus_message_builder *builder, + char container_type) +{ + if (unlikely(!builder)) + return false; + + switch (container_type) { + case DBUS_CONTAINER_TYPE_ARRAY: + return builder->driver->leave_array(builder->builder); + case DBUS_CONTAINER_TYPE_DICT_ENTRY: + return builder->driver->leave_dict(builder->builder); + case DBUS_CONTAINER_TYPE_STRUCT: + return builder->driver->leave_struct(builder->builder); + case DBUS_CONTAINER_TYPE_VARIANT: + return builder->driver->leave_variant(builder->builder); + default: + break; + } + + return false; +} + +LIB_EXPORT bool l_dbus_message_builder_enter_struct( + struct l_dbus_message_builder *builder, + const char *signature) +{ + return l_dbus_message_builder_enter_container(builder, 'r', signature); +} + +LIB_EXPORT bool l_dbus_message_builder_leave_struct( + struct l_dbus_message_builder *builder) +{ + return l_dbus_message_builder_leave_container(builder, 'r'); +} + +LIB_EXPORT bool l_dbus_message_builder_enter_array( + struct l_dbus_message_builder *builder, + const char *signature) +{ + return l_dbus_message_builder_enter_container(builder, 'a', signature); +} + +LIB_EXPORT bool l_dbus_message_builder_leave_array( + struct l_dbus_message_builder *builder) +{ + return l_dbus_message_builder_leave_container(builder, 'a'); +} + +LIB_EXPORT bool l_dbus_message_builder_enter_dict( + struct l_dbus_message_builder *builder, + const char *signature) +{ + return l_dbus_message_builder_enter_container(builder, 'e', signature); +} + +LIB_EXPORT bool l_dbus_message_builder_leave_dict( + struct l_dbus_message_builder *builder) +{ + return l_dbus_message_builder_leave_container(builder, 'e'); +} + +LIB_EXPORT bool l_dbus_message_builder_enter_variant( + struct l_dbus_message_builder *builder, + const char *signature) +{ + return l_dbus_message_builder_enter_container(builder, 'v', signature); +} + +LIB_EXPORT bool l_dbus_message_builder_leave_variant( + struct l_dbus_message_builder *builder) +{ + return l_dbus_message_builder_leave_container(builder, 'v'); +} + +/** + * l_dbus_message_builder_append_from_iter: + * @builder: message builder to receive a new value + * @from: message iterator to have its position moved by one value + * + * Copy one value from a message iterator onto a message builder. The + * value's signature is also copied. + * + * Returns: whether the value was correctly copied. On failure both + * the @from iterator and the @builder may have their positions + * moved to somewhere within the new value if it's of a + * container type. + **/ +LIB_EXPORT bool l_dbus_message_builder_append_from_iter( + struct l_dbus_message_builder *builder, + struct l_dbus_message_iter *from) +{ + static const char *simple_types = "sogybnqiuxtd"; + char type = from->sig_start[from->sig_pos]; + char container_type; + char signature[256]; + struct l_dbus_message_iter iter; + void *basic_ptr; + uint64_t basic; + uint32_t uint32_val; + bool (*get_basic)(struct l_dbus_message_iter *, char, void *); + bool (*enter_func)(struct l_dbus_message_iter *, + struct l_dbus_message_iter *); + bool (*enter_struct)(struct l_dbus_message_iter *, + struct l_dbus_message_iter *); + bool (*enter_array)(struct l_dbus_message_iter *, + struct l_dbus_message_iter *); + bool (*enter_variant)(struct l_dbus_message_iter *, + struct l_dbus_message_iter *); + + if (_dbus_message_is_gvariant(from->message)) { + get_basic = _gvariant_iter_next_entry_basic; + enter_struct = _gvariant_iter_enter_struct; + enter_array = _gvariant_iter_enter_array; + enter_variant = _gvariant_iter_enter_variant; + } else { + get_basic = _dbus1_iter_next_entry_basic; + enter_struct = _dbus1_iter_enter_struct; + enter_array = _dbus1_iter_enter_array; + enter_variant = _dbus1_iter_enter_variant; + } + + if (strchr(simple_types, type)) { + if (strchr("sog", type)) { + if (!get_basic(from, type, &basic_ptr)) + return false; + } else { + basic_ptr = &basic; + + if (!get_basic(from, type, basic_ptr)) + return false; + } + + if (!l_dbus_message_builder_append_basic(builder, type, + basic_ptr)) + return false; + + return true; + } + + switch (type) { + case 'h': + if (!get_basic(from, type, &uint32_val)) + return false; + + if (!l_dbus_message_builder_append_basic(builder, type, + &builder->message->num_fds)) + return false; + + if (builder->message->num_fds < + L_ARRAY_SIZE(builder->message->fds)) { + int fd; + + if (uint32_val < from->message->num_fds) + fd = fcntl(from->message->fds[uint32_val], + F_DUPFD_CLOEXEC, 3); + else + fd = -1; + + builder->message->fds[builder->message->num_fds++] = fd; + } + + return true; + case '(': + enter_func = enter_struct; + container_type = DBUS_CONTAINER_TYPE_STRUCT; + break; + case '{': + enter_func = enter_struct; + container_type = DBUS_CONTAINER_TYPE_DICT_ENTRY; + break; + case 'a': + enter_func = enter_array; + container_type = DBUS_CONTAINER_TYPE_ARRAY; + break; + case 'v': + enter_func = enter_variant; + container_type = DBUS_CONTAINER_TYPE_VARIANT; + break; + default: + return false; + } + + if (!enter_func(from, &iter)) + return false; + + memcpy(signature, iter.sig_start, iter.sig_len); + signature[iter.sig_len] = '\0'; + + if (!l_dbus_message_builder_enter_container(builder, + container_type, signature)) + return false; + + if (container_type == DBUS_CONTAINER_TYPE_ARRAY) + while(l_dbus_message_builder_append_from_iter(builder, &iter)); + else + while (iter.sig_pos < iter.sig_len) + if (!l_dbus_message_builder_append_from_iter(builder, + &iter)) + return false; + + if (!l_dbus_message_builder_leave_container(builder, + container_type)) + return false; + + return true; +} + +LIB_EXPORT bool l_dbus_message_builder_append_from_valist( + struct l_dbus_message_builder *builder, + const char *signature, va_list args) +{ + struct builder_driver *driver; + char subsig[256]; + const char *sigend; + /* Nesting requires an extra stack entry for the base level */ + struct container stack[DBUS_MAX_NESTING + 1]; + unsigned int stack_index = 0; + + if (unlikely(!builder)) + return false; + + driver = builder->driver; + + stack[stack_index].type = DBUS_CONTAINER_TYPE_STRUCT; + stack[stack_index].sig_start = signature; + stack[stack_index].sig_end = signature + strlen(signature); + stack[stack_index].n_items = 0; + + while (stack_index != 0 || stack[0].sig_start != stack[0].sig_end) { + const char *s; + const char *str; + + if (stack[stack_index].type == DBUS_CONTAINER_TYPE_ARRAY && + stack[stack_index].n_items == 0) + stack[stack_index].sig_start = + stack[stack_index].sig_end; + + if (stack[stack_index].sig_start == + stack[stack_index].sig_end) { + bool ret; + + /* + * Sanity check in case of an invalid signature that + * isn't caught elsewhere. + */ + if (unlikely(stack_index == 0)) + return false; + + switch (stack[stack_index].type) { + case DBUS_CONTAINER_TYPE_STRUCT: + ret = driver->leave_struct(builder->builder); + break; + case DBUS_CONTAINER_TYPE_DICT_ENTRY: + ret = driver->leave_dict(builder->builder); + break; + case DBUS_CONTAINER_TYPE_VARIANT: + ret = driver->leave_variant(builder->builder); + break; + case DBUS_CONTAINER_TYPE_ARRAY: + ret = driver->leave_array(builder->builder); + break; + default: + ret = false; + } + + if (!ret) + return false; + + stack_index -= 1; + continue; + } + + s = stack[stack_index].sig_start; + + if (stack[stack_index].type != DBUS_CONTAINER_TYPE_ARRAY) + stack[stack_index].sig_start += 1; + else + stack[stack_index].n_items -= 1; + + switch (*s) { + case 'o': + case 's': + case 'g': + str = va_arg(args, const char *); + + if (!driver->append_basic(builder->builder, *s, str)) + return false; + break; + case 'b': + case 'y': + { + uint8_t y = (uint8_t) va_arg(args, int); + + if (!driver->append_basic(builder->builder, *s, &y)) + return false; + + break; + } + case 'n': + case 'q': + { + uint16_t n = (uint16_t) va_arg(args, int); + + if (!driver->append_basic(builder->builder, *s, &n)) + return false; + + break; + } + case 'i': + case 'u': + { + uint32_t u = va_arg(args, uint32_t); + + if (!driver->append_basic(builder->builder, *s, &u)) + return false; + + break; + } + case 'h': + { + int fd = va_arg(args, int); + struct l_dbus_message *message = builder->message; + + if (!driver->append_basic(builder->builder, *s, + &message->num_fds)) + return false; + + if (message->num_fds < L_ARRAY_SIZE(message->fds)) + message->fds[message->num_fds++] = + fcntl(fd, F_DUPFD_CLOEXEC, 3); + + break; + } + case 'x': + case 't': + { + uint64_t x = va_arg(args, uint64_t); + + if (!driver->append_basic(builder->builder, *s, &x)) + return false; + break; + } + case 'd': + { + double d = va_arg(args, double); + + if (!driver->append_basic(builder->builder, *s, &d)) + return false; + break; + } + case '(': + case '{': + if (stack_index == DBUS_MAX_NESTING) + return false; + + sigend = _dbus_signature_end(s); + memcpy(subsig, s + 1, sigend - s - 1); + subsig[sigend - s - 1] = '\0'; + + if (*s == '(' && !driver->enter_struct(builder->builder, + subsig)) + return false; + + if (*s == '{' && !driver->enter_dict(builder->builder, + subsig)) + return false; + + if (stack[stack_index].type != + DBUS_CONTAINER_TYPE_ARRAY) + stack[stack_index].sig_start = sigend + 1; + + stack_index += 1; + stack[stack_index].sig_start = s + 1; + stack[stack_index].sig_end = sigend; + stack[stack_index].n_items = 0; + stack[stack_index].type = *s == '(' ? + DBUS_CONTAINER_TYPE_STRUCT : + DBUS_CONTAINER_TYPE_DICT_ENTRY; + + break; + case 'v': + if (stack_index == DBUS_MAX_NESTING) + return false; + + str = va_arg(args, const char *); + + if (!str) + return false; + + if (!driver->enter_variant(builder->builder, str)) + return false; + + stack_index += 1; + stack[stack_index].type = DBUS_CONTAINER_TYPE_VARIANT; + stack[stack_index].sig_start = str; + stack[stack_index].sig_end = str + strlen(str); + stack[stack_index].n_items = 0; + + break; + case 'a': + if (stack_index == DBUS_MAX_NESTING) + return false; + + sigend = _dbus_signature_end(s + 1) + 1; + memcpy(subsig, s + 1, sigend - s - 1); + subsig[sigend - s - 1] = '\0'; + + if (!driver->enter_array(builder->builder, subsig)) + return false; + + if (stack[stack_index].type != + DBUS_CONTAINER_TYPE_ARRAY) + stack[stack_index].sig_start = sigend; + + stack_index += 1; + stack[stack_index].sig_start = s + 1; + stack[stack_index].sig_end = sigend; + stack[stack_index].n_items = va_arg(args, unsigned int); + stack[stack_index].type = DBUS_CONTAINER_TYPE_ARRAY; + + break; + default: + return false; + } + } + + return true; +} + +LIB_EXPORT struct l_dbus_message *l_dbus_message_builder_finalize( + struct l_dbus_message_builder *builder) +{ + char *generated_signature; + + if (unlikely(!builder)) + return NULL; + + generated_signature = builder->driver->finish(builder->builder, + &builder->message->body, + &builder->message->body_size); + + build_header(builder->message, generated_signature); + builder->message->sealed = true; + builder->message->signature = generated_signature; + builder->message->signature_free = true; + + return builder->message; +} + +bool _dbus_message_builder_mark(struct l_dbus_message_builder *builder) +{ + if (unlikely(!builder)) + return false; + + return builder->driver->mark(builder->builder); +} + +bool _dbus_message_builder_rewind(struct l_dbus_message_builder *builder) +{ + if (unlikely(!builder)) + return false; + + return builder->driver->rewind(builder->builder); +} diff --git a/ell/dbus-name-cache.c b/ell/dbus-name-cache.c new file mode 100644 index 0000000000000000000000000000000000000000..d26e8a56a091ac1e0a13b199cf2031ef8efaa8e9 --- /dev/null +++ b/ell/dbus-name-cache.c @@ -0,0 +1,298 @@ +/* + * Embedded Linux library + * Copyright (C) 2016 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <stdlib.h> +#include <stdio.h> + +#include "util.h" +#include "hashmap.h" +#include "idle.h" +#include "dbus.h" +#include "dbus-private.h" + +struct _dbus_name_cache { + struct l_dbus *bus; + struct l_hashmap *names; + const struct _dbus_name_ops *driver; + unsigned int last_watch_id; + struct l_idle *watch_remove_work; +}; + +struct service_watch { + l_dbus_watch_func_t connect_func; + l_dbus_watch_func_t disconnect_func; + l_dbus_destroy_func_t destroy; + void *user_data; + unsigned int id; + struct service_watch *next; +}; + +struct name_cache_entry { + int ref_count; + char *unique_name; + struct service_watch *watches; +}; + +struct _dbus_name_cache *_dbus_name_cache_new(struct l_dbus *bus, + const struct _dbus_name_ops *driver) +{ + struct _dbus_name_cache *cache; + + cache = l_new(struct _dbus_name_cache, 1); + + cache->bus = bus; + cache->driver = driver; + + return cache; +} + +static void service_watch_destroy(void *data) +{ + struct service_watch *watch = data; + + if (watch->destroy) + watch->destroy(watch->user_data); + + l_free(watch); +} + +static void name_cache_entry_destroy(void *data) +{ + struct name_cache_entry *entry = data; + struct service_watch *watch; + + while (entry->watches) { + watch = entry->watches; + entry->watches = watch->next; + + service_watch_destroy(watch); + } + + l_free(entry->unique_name); + + l_free(entry); +} + +void _dbus_name_cache_free(struct _dbus_name_cache *cache) +{ + if (!cache) + return; + + if (cache->watch_remove_work) + l_idle_remove(cache->watch_remove_work); + + l_hashmap_destroy(cache->names, name_cache_entry_destroy); + + l_free(cache); +} + +bool _dbus_name_cache_add(struct _dbus_name_cache *cache, const char *name) +{ + struct name_cache_entry *entry; + + if (!_dbus_valid_bus_name(name)) + return false; + + if (!cache->names) + cache->names = l_hashmap_string_new(); + + entry = l_hashmap_lookup(cache->names, name); + + if (!entry) { + entry = l_new(struct name_cache_entry, 1); + + l_hashmap_insert(cache->names, name, entry); + + cache->driver->get_name_owner(cache->bus, name); + } + + entry->ref_count++; + + return true; +} + +bool _dbus_name_cache_remove(struct _dbus_name_cache *cache, const char *name) +{ + struct name_cache_entry *entry; + + entry = l_hashmap_lookup(cache->names, name); + + if (!entry) + return false; + + if (--entry->ref_count) + return true; + + l_hashmap_remove(cache->names, name); + + name_cache_entry_destroy(entry); + + return true; +} + +const char *_dbus_name_cache_lookup(struct _dbus_name_cache *cache, + const char *name) +{ + struct name_cache_entry *entry; + + entry = l_hashmap_lookup(cache->names, name); + + if (!entry) + return NULL; + + return entry->unique_name; +} + +void _dbus_name_cache_notify(struct _dbus_name_cache *cache, + const char *name, const char *owner) +{ + struct name_cache_entry *entry; + struct service_watch *watch; + bool prev_connected, connected; + + if (!cache) + return; + + entry = l_hashmap_lookup(cache->names, name); + + if (!entry) + return; + + prev_connected = !!entry->unique_name; + connected = owner && *owner != '\0'; + + l_free(entry->unique_name); + + entry->unique_name = connected ? l_strdup(owner) : NULL; + + /* + * This check also means we notify all watchers who have a connected + * callback when we first learn that the service is in fact connected. + */ + if (connected == prev_connected) + return; + + for (watch = entry->watches; watch; watch = watch->next) + if (connected && watch->connect_func) + watch->connect_func(cache->bus, watch->user_data); + else if (!connected && watch->disconnect_func) + watch->disconnect_func(cache->bus, watch->user_data); +} + +unsigned int _dbus_name_cache_add_watch(struct _dbus_name_cache *cache, + const char *name, + l_dbus_watch_func_t connect_func, + l_dbus_watch_func_t disconnect_func, + void *user_data, + l_dbus_destroy_func_t destroy) +{ + struct name_cache_entry *entry; + struct service_watch *watch; + + if (!_dbus_name_cache_add(cache, name)) + return 0; + + watch = l_new(struct service_watch, 1); + watch->id = ++cache->last_watch_id; + watch->connect_func = connect_func; + watch->disconnect_func = disconnect_func; + watch->user_data = user_data; + watch->destroy = destroy; + + entry = l_hashmap_lookup(cache->names, name); + + watch->next = entry->watches; + entry->watches = watch; + + if (entry->unique_name && connect_func) + watch->connect_func(cache->bus, watch->user_data); + + return watch->id; +} + +static bool service_watch_remove(const void *key, void *value, void *user_data) +{ + struct name_cache_entry *entry = value; + struct service_watch **watch, *tmp; + + for (watch = &entry->watches; *watch;) { + if ((*watch)->id) { + watch = &(*watch)->next; + continue; + } + + tmp = *watch; + *watch = tmp->next; + + service_watch_destroy(tmp); + + entry->ref_count--; + } + + if (entry->ref_count) + return false; + + name_cache_entry_destroy(entry); + + return true; +} + +static void service_watch_remove_all(struct l_idle *idle, void *user_data) +{ + struct _dbus_name_cache *cache = user_data; + + l_idle_remove(cache->watch_remove_work); + cache->watch_remove_work = NULL; + + l_hashmap_foreach_remove(cache->names, service_watch_remove, cache); +} + +static void service_watch_mark(const void *key, void *value, void *user_data) +{ + struct name_cache_entry *entry = value; + struct service_watch *watch; + unsigned int *id = user_data; + + if (!*id) + return; + + for (watch = entry->watches; watch; watch = watch->next) + if (watch->id == *id) { + watch->id = 0; + watch->connect_func = NULL; + watch->disconnect_func = NULL; + + if (watch->destroy) { + watch->destroy(watch->user_data); + watch->destroy = NULL; + } + + *id = 0; + break; + } +} + +bool _dbus_name_cache_remove_watch(struct _dbus_name_cache *cache, + unsigned int id) +{ + l_hashmap_foreach(cache->names, service_watch_mark, &id); + + if (id) + return false; + + if (!cache->watch_remove_work) + cache->watch_remove_work = l_idle_create( + service_watch_remove_all, + cache, NULL); + + return true; +} diff --git a/ell/dbus-private.h b/ell/dbus-private.h new file mode 100644 index 0000000000000000000000000000000000000000..0c064100f251ecad1eb7a23df17cb403abba95a9 --- /dev/null +++ b/ell/dbus-private.h @@ -0,0 +1,297 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include <endian.h> + +enum dbus_message_type { + DBUS_MESSAGE_TYPE_METHOD_CALL = 1, + DBUS_MESSAGE_TYPE_METHOD_RETURN = 2, + DBUS_MESSAGE_TYPE_ERROR = 3, + DBUS_MESSAGE_TYPE_SIGNAL = 4, +}; + +enum dbus_container_type { + DBUS_CONTAINER_TYPE_ARRAY = 'a', + DBUS_CONTAINER_TYPE_STRUCT = 'r', + DBUS_CONTAINER_TYPE_VARIANT = 'v', + DBUS_CONTAINER_TYPE_DICT_ENTRY = 'e', +}; + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define DBUS_NATIVE_ENDIAN 'l' +#elif __BYTE_ORDER == __BIG_ENDIAN +#define DBUS_NATIVE_ENDIAN 'B' +#else +#error "Unknown byte order" +#endif + +struct dbus_header { + uint8_t endian; + uint8_t message_type; + uint8_t flags; + uint8_t version; + + union { + struct { + uint32_t body_length; + uint32_t serial; + uint32_t field_length; + } __attribute__ ((packed)) dbus1; + }; +} __attribute__ ((packed)); +#define DBUS_HEADER_SIZE 16 + +struct dbus_builder; +struct l_string; +struct l_dbus_interface; +struct _dbus_method; +struct _dbus_signal; +struct _dbus_property; +struct l_dbus_message_iter; +struct l_dbus_message; +struct l_dbus; +struct _dbus_filter; +struct _dbus_filter_condition; +struct _dbus_filter_ops; + +void _dbus1_iter_init(struct l_dbus_message_iter *iter, + struct l_dbus_message *message, + const char *sig_start, const char *sig_end, + const void *data, size_t len); +bool _dbus1_iter_next_entry_basic(struct l_dbus_message_iter *iter, char type, + void *out); +bool _dbus1_iter_get_fixed_array(struct l_dbus_message_iter *iter, + void *out, uint32_t *n_elem); +bool _dbus1_iter_enter_struct(struct l_dbus_message_iter *iter, + struct l_dbus_message_iter *structure); +bool _dbus1_iter_enter_variant(struct l_dbus_message_iter *iter, + struct l_dbus_message_iter *variant); +bool _dbus1_iter_enter_array(struct l_dbus_message_iter *iter, + struct l_dbus_message_iter *array); +bool _dbus1_iter_skip_entry(struct l_dbus_message_iter *iter); + +struct dbus_builder *_dbus1_builder_new(void *body, size_t body_size); +void _dbus1_builder_free(struct dbus_builder *builder); +bool _dbus1_builder_append_basic(struct dbus_builder *builder, + char type, const void *value); +bool _dbus1_builder_enter_struct(struct dbus_builder *builder, + const char *signature); +bool _dbus1_builder_leave_struct(struct dbus_builder *builder); +bool _dbus1_builder_enter_dict(struct dbus_builder *builder, + const char *signature); +bool _dbus1_builder_leave_dict(struct dbus_builder *builder); +bool _dbus1_builder_enter_variant(struct dbus_builder *builder, + const char *signature); +bool _dbus1_builder_leave_variant(struct dbus_builder *builder); +bool _dbus1_builder_enter_array(struct dbus_builder *builder, + const char *signature); +bool _dbus1_builder_leave_array(struct dbus_builder *builder); +char *_dbus1_builder_finish(struct dbus_builder *builder, + void **body, size_t *body_size); +bool _dbus1_builder_mark(struct dbus_builder *builder); +bool _dbus1_builder_rewind(struct dbus_builder *builder); + +void *_dbus_message_get_body(struct l_dbus_message *msg, size_t *out_size); +void *_dbus_message_get_header(struct l_dbus_message *msg, size_t *out_size); +void *_dbus_message_get_footer(struct l_dbus_message *msg, size_t *out_size); +int *_dbus_message_get_fds(struct l_dbus_message *msg, uint32_t *num_fds); +void _dbus_message_set_serial(struct l_dbus_message *msg, uint32_t serial); +uint32_t _dbus_message_get_serial(struct l_dbus_message *msg); +uint32_t _dbus_message_get_reply_serial(struct l_dbus_message *message); + +void _dbus_message_set_sender(struct l_dbus_message *message, + const char *sender); +void _dbus_message_set_destination(struct l_dbus_message *message, + const char *destination); + +enum dbus_message_type _dbus_message_get_type(struct l_dbus_message *message); +const char * _dbus_message_get_type_as_string(struct l_dbus_message *message); +uint8_t _dbus_message_get_version(struct l_dbus_message *message); +uint8_t _dbus_message_get_endian(struct l_dbus_message *message); +const char *_dbus_message_get_nth_string_argument( + struct l_dbus_message *message, int n); + +struct l_dbus_message *_dbus_message_new_method_call(uint8_t version, + const char *destination, + const char *path, + const char *interface, + const char *method); +struct l_dbus_message *_dbus_message_new_signal(uint8_t version, + const char *path, + const char *interface, + const char *name); +struct l_dbus_message *_dbus_message_new_error(uint8_t version, + uint32_t reply_serial, + const char *destination, + const char *name, + const char *error); + +struct l_dbus_message *dbus_message_from_blob(const void *data, size_t size, + int fds[], uint32_t num_fds); +struct l_dbus_message *dbus_message_build(void *header, size_t header_size, + void *body, size_t body_size, + int fds[], uint32_t num_fds); +bool dbus_message_compare(struct l_dbus_message *message, + const void *data, size_t size); + +bool _dbus_message_builder_mark(struct l_dbus_message_builder *builder); +bool _dbus_message_builder_rewind(struct l_dbus_message_builder *builder); + +unsigned int _dbus_message_unix_fds_from_header(const void *data, size_t size); + +const char *_dbus_signature_end(const char *signature); + +bool _dbus_valid_object_path(const char *path); +bool _dbus_valid_signature(const char *sig); +int _dbus_num_children(const char *sig); +bool _dbus_valid_interface(const char *interface); +bool _dbus_valid_method(const char *method); +bool _dbus_parse_unique_name(const char *name, uint64_t *out_id); +bool _dbus_valid_bus_name(const char *bus_name); + +bool _dbus1_header_is_valid(void *data, size_t size); + +void _dbus_method_introspection(struct _dbus_method *info, + struct l_string *buf); +void _dbus_signal_introspection(struct _dbus_signal *info, + struct l_string *buf); +void _dbus_property_introspection(struct _dbus_property *info, + struct l_string *buf); +void _dbus_interface_introspection(struct l_dbus_interface *interface, + struct l_string *buf); + +struct l_dbus_interface *_dbus_interface_new(const char *name); +void _dbus_interface_free(struct l_dbus_interface *interface); + +struct _dbus_method *_dbus_interface_find_method(struct l_dbus_interface *i, + const char *method); +struct _dbus_signal *_dbus_interface_find_signal(struct l_dbus_interface *i, + const char *signal); +struct _dbus_property *_dbus_interface_find_property(struct l_dbus_interface *i, + const char *property); + +struct _dbus_object_tree *_dbus_object_tree_new(void); +void _dbus_object_tree_free(struct _dbus_object_tree *tree); + +struct object_node *_dbus_object_tree_makepath(struct _dbus_object_tree *tree, + const char *path); +struct object_node *_dbus_object_tree_lookup(struct _dbus_object_tree *tree, + const char *path); +void _dbus_object_tree_prune_node(struct object_node *node); + +struct object_node *_dbus_object_tree_new_object(struct _dbus_object_tree *tree, + const char *path, + void *user_data, + void (*destroy) (void *)); +bool _dbus_object_tree_object_destroy(struct _dbus_object_tree *tree, + const char *path); + +bool _dbus_object_tree_register_interface(struct _dbus_object_tree *tree, + const char *interface, + void (*setup_func)(struct l_dbus_interface *), + void (*destroy) (void *), + bool old_style_properties); +bool _dbus_object_tree_unregister_interface(struct _dbus_object_tree *tree, + const char *interface); + +bool _dbus_object_tree_add_interface(struct _dbus_object_tree *tree, + const char *path, const char *interface, + void *user_data); +bool _dbus_object_tree_remove_interface(struct _dbus_object_tree *tree, + const char *path, + const char *interface); +void *_dbus_object_tree_get_interface_data(struct _dbus_object_tree *tree, + const char *path, + const char *interface); +bool _dbus_object_tree_set_interface_data(struct _dbus_object_tree *tree, + const char *path, + const char *interface, + void *user_data); + +void _dbus_object_tree_introspect(struct _dbus_object_tree *tree, + const char *path, struct l_string *buf); +bool _dbus_object_tree_dispatch(struct _dbus_object_tree *tree, + struct l_dbus *dbus, + struct l_dbus_message *message); +struct l_dbus_message *_dbus_object_tree_get_objects( + struct _dbus_object_tree *tree, + struct l_dbus *dbus, + const char *path, + struct l_dbus_message *message); + +bool _dbus_object_tree_property_changed(struct l_dbus *dbus, + const char *path, + const char *interface_name, + const char *property_name); + +void _dbus_object_tree_signals_flush(struct l_dbus *dbus, const char *path); + +typedef void (*_dbus_name_owner_change_func_t)(const char *name, + uint64_t old_owner, + uint64_t new_owner, + void *user_data); + +uint8_t _dbus_get_version(struct l_dbus *dbus); +int _dbus_get_fd(struct l_dbus *dbus); +struct _dbus_object_tree *_dbus_get_tree(struct l_dbus *dbus); + +struct _dbus_name_ops { + bool (*get_name_owner)(struct l_dbus *bus, const char *name); +}; + +struct _dbus_name_cache; + +struct _dbus_name_cache *_dbus_name_cache_new(struct l_dbus *bus, + const struct _dbus_name_ops *driver); +void _dbus_name_cache_free(struct _dbus_name_cache *cache); + +bool _dbus_name_cache_add(struct _dbus_name_cache *cache, const char *name); +bool _dbus_name_cache_remove(struct _dbus_name_cache *cache, const char *name); +const char *_dbus_name_cache_lookup(struct _dbus_name_cache *cache, + const char *name); + +void _dbus_name_cache_notify(struct _dbus_name_cache *cache, + const char *name, const char *owner); + +unsigned int _dbus_name_cache_add_watch(struct _dbus_name_cache *cache, + const char *name, + l_dbus_watch_func_t connect_func, + l_dbus_watch_func_t disconnect_func, + void *user_data, + l_dbus_destroy_func_t destroy); +bool _dbus_name_cache_remove_watch(struct _dbus_name_cache *cache, + unsigned int id); + +struct _dbus_filter_condition { + enum l_dbus_match_type type; + const char *value; +}; + +struct _dbus_filter_ops { + bool skip_register; + bool (*add_match)(struct l_dbus *bus, unsigned int id, + const struct _dbus_filter_condition *rule, + int rule_len); + bool (*remove_match)(struct l_dbus *bus, unsigned int id); +}; + +struct _dbus_filter *_dbus_filter_new(struct l_dbus *dbus, + const struct _dbus_filter_ops *driver, + struct _dbus_name_cache *name_cache); +void _dbus_filter_free(struct _dbus_filter *filter); + +unsigned int _dbus_filter_add_rule(struct _dbus_filter *filter, + const struct _dbus_filter_condition *rule, + int rule_len, + l_dbus_message_func_t signal_func, + void *user_data); +bool _dbus_filter_remove_rule(struct _dbus_filter *filter, unsigned int id); + +char *_dbus_filter_rule_to_str(const struct _dbus_filter_condition *rule, + int rule_len); + +void _dbus_filter_dispatch(struct l_dbus_message *message, void *user_data); diff --git a/ell/dbus-service.c b/ell/dbus-service.c new file mode 100644 index 0000000000000000000000000000000000000000..0300bfe323b6606d1e55ad52caedc51834001643 --- /dev/null +++ b/ell/dbus-service.c @@ -0,0 +1,2159 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#include "useful.h" +#include "queue.h" +#include "string.h" +#include "hashmap.h" +#include "dbus.h" +#include "dbus-service.h" +#include "dbus-private.h" +#include "private.h" +#include "idle.h" + +#define XML_ID "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" +#define XML_DTD "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" +#define XML_HEAD "<!DOCTYPE node PUBLIC \""XML_ID"\"\n\""XML_DTD"\">\n" + +static const char *static_introspectable = + "\t<interface name=\"org.freedesktop.DBus.Introspectable\">\n" + "\t\t<method name=\"Introspect\">\n" + "\t\t\t<arg name=\"xml\" type=\"s\" direction=\"out\"/>\n" + "\t\t</method>\n\t</interface>\n"; + +struct _dbus_method { + l_dbus_interface_method_cb_t cb; + uint32_t flags; + unsigned char name_len; + char metainfo[]; +}; + +struct _dbus_signal { + uint32_t flags; + unsigned char name_len; + char metainfo[]; +}; + +struct _dbus_property { + l_dbus_property_get_cb_t getter; + l_dbus_property_set_cb_t setter; + uint32_t flags; + unsigned char name_len; + char metainfo[]; +}; + +struct l_dbus_interface { + struct l_queue *methods; + struct l_queue *signals; + struct l_queue *properties; + bool handle_old_style_properties; + void (*instance_destroy)(void *); + char name[]; +}; + +struct child_node { + struct object_node *node; + struct child_node *next; + char subpath[]; +}; + +struct interface_instance { + struct l_dbus_interface *interface; + void *user_data; +}; + +struct object_node { + struct object_node *parent; + struct l_queue *instances; + struct child_node *children; + void *user_data; + void (*destroy) (void *); +}; + +struct object_manager { + char *path; + struct l_dbus *dbus; + struct l_queue *announce_added; + struct l_queue *announce_removed; +}; + +struct interface_add_record { + char *path; + struct object_node *object; + struct l_queue *instances; +}; + +struct interface_remove_record { + char *path; + struct object_node *object; + struct l_queue *interface_names; +}; + +struct property_change_record { + char *path; + struct object_node *object; + struct interface_instance *instance; + struct l_queue *properties; +}; + +struct _dbus_object_tree { + struct l_hashmap *interfaces; + struct l_hashmap *objects; + struct object_node *root; + struct l_queue *object_managers; + struct l_queue *property_changes; + struct l_idle *emit_signals_work; + bool flushing; +}; + +void _dbus_method_introspection(struct _dbus_method *info, + struct l_string *buf) +{ + const char *sig; + const char *end; + const char *pname; + unsigned int offset = info->name_len + 1; + + l_string_append_printf(buf, "\t\t<method name=\"%s\">\n", + info->metainfo); + + sig = info->metainfo + offset; + offset += strlen(sig) + 1; + + for (; *sig; sig++) { + end = _dbus_signature_end(sig); + pname = info->metainfo + offset; + + l_string_append_printf(buf, "\t\t\t<arg name=\"%s\" " + "type=\"%.*s\" direction=\"in\"/>\n", + pname, (int) (end - sig + 1), sig); + sig = end; + offset += strlen(pname) + 1; + } + + sig = info->metainfo + offset; + offset += strlen(sig) + 1; + + for (; *sig; sig++) { + end = _dbus_signature_end(sig); + pname = info->metainfo + offset; + + l_string_append_printf(buf, "\t\t\t<arg name=\"%s\" " + "type=\"%.*s\" direction=\"out\"/>\n", + pname, (int) (end - sig + 1), sig); + sig = end; + offset += strlen(pname) + 1; + } + + if (info->flags & L_DBUS_METHOD_FLAG_DEPRECATED) + l_string_append(buf, "\t\t\t<annotation name=\"" + "org.freedesktop.DBus.Deprecated\" " + "value=\"true\"/>\n"); + + if (info->flags & L_DBUS_METHOD_FLAG_NOREPLY) + l_string_append(buf, "\t\t\t<annotation name=\"" + "org.freedesktop.DBus.Method.NoReply\" " + "value=\"true\"/>\n"); + + l_string_append(buf, "\t\t</method>\n"); +} + +void _dbus_signal_introspection(struct _dbus_signal *info, + struct l_string *buf) +{ + const char *sig; + const char *end; + const char *pname; + unsigned int offset = info->name_len + 1; + + l_string_append_printf(buf, "\t\t<signal name=\"%s\">\n", + info->metainfo); + + sig = info->metainfo + offset; + offset += strlen(sig) + 1; + + for (; *sig; sig++) { + end = _dbus_signature_end(sig); + pname = info->metainfo + offset; + + l_string_append_printf(buf, "\t\t\t<arg name=\"%s\" " + "type=\"%.*s\"/>\n", + pname, (int) (end - sig + 1), sig); + sig = end; + offset += strlen(pname) + 1; + } + + if (info->flags & L_DBUS_SIGNAL_FLAG_DEPRECATED) + l_string_append(buf, "\t\t\t<annotation name=\"" + "org.freedesktop.DBus.Deprecated\" " + "value=\"true\"/>\n"); + + l_string_append(buf, "\t\t</signal>\n"); +} + +void _dbus_property_introspection(struct _dbus_property *info, + struct l_string *buf) +{ + unsigned int offset = info->name_len + 1; + const char *signature = info->metainfo + offset; + + l_string_append_printf(buf, "\t\t<property name=\"%s\" type=\"%s\" ", + info->metainfo, signature); + + if (info->setter) + l_string_append(buf, "access=\"readwrite\""); + else + l_string_append(buf, "access=\"read\""); + + if (info->flags & L_DBUS_METHOD_FLAG_DEPRECATED) { + l_string_append(buf, ">\n"); + l_string_append(buf, "\t\t\t<annotation name=\"" + "org.freedesktop.DBus.Deprecated\" " + "value=\"true\"/>\n"); + l_string_append(buf, "\t\t</property>\n"); + } else + l_string_append(buf, "/>\n"); +} + +void _dbus_interface_introspection(struct l_dbus_interface *interface, + struct l_string *buf) +{ + l_string_append_printf(buf, "\t<interface name=\"%s\">\n", + interface->name); + + l_queue_foreach(interface->methods, + (l_queue_foreach_func_t) _dbus_method_introspection, buf); + l_queue_foreach(interface->signals, + (l_queue_foreach_func_t) _dbus_signal_introspection, buf); + l_queue_foreach(interface->properties, + (l_queue_foreach_func_t) _dbus_property_introspection, buf); + + l_string_append(buf, "\t</interface>\n"); +} + +#define COPY_PARAMS(dest, signature, args) \ + do { \ + const char *pname; \ + const char *sig; \ + dest = stpcpy(dest, signature) + 1; \ + for (sig = signature; *sig; sig++) { \ + sig = _dbus_signature_end(sig); \ + pname = va_arg(args, const char *); \ + dest = stpcpy(dest, pname) + 1; \ + } \ + } while(0) + +#define SIZE_PARAMS(signature, args) \ + ({ \ + unsigned int len = strlen(signature) + 1; \ + const char *pname; \ + const char *sig; \ + for (sig = signature; *sig; sig++) { \ + sig = _dbus_signature_end(sig); \ + if (!sig) { \ + len = 0; \ + break; \ + } \ + pname = va_arg(args, const char *); \ + len += strlen(pname) + 1; \ + } \ + len; \ + }) + +LIB_EXPORT bool l_dbus_interface_method(struct l_dbus_interface *interface, + const char *name, uint32_t flags, + l_dbus_interface_method_cb_t cb, + const char *return_sig, + const char *param_sig, ...) +{ + va_list args; + unsigned int return_info_len; + unsigned int param_info_len; + struct _dbus_method *info; + char *p; + + if (!_dbus_valid_method(name)) + return false; + + if (unlikely(!return_sig || !param_sig)) + return false; + + if (return_sig[0] && !_dbus_valid_signature(return_sig)) + return false; + + if (param_sig[0] && !_dbus_valid_signature(param_sig)) + return false; + + /* Pre-calculate the needed meta-info length */ + va_start(args, param_sig); + + return_info_len = SIZE_PARAMS(return_sig, args); + param_info_len = SIZE_PARAMS(param_sig, args); + + va_end(args); + + if (!return_info_len || !param_info_len) + return false; + + info = l_malloc(sizeof(*info) + return_info_len + + param_info_len + strlen(name) + 1); + info->cb = cb; + info->flags = flags; + info->name_len = strlen(name); + strcpy(info->metainfo, name); + + va_start(args, param_sig); + + /* + * We store param signature + parameter names first, to speed up + * lookups during the message dispatch procedures. + */ + p = info->metainfo + info->name_len + param_info_len + 1; + COPY_PARAMS(p, return_sig, args); + + p = info->metainfo + info->name_len + 1; + COPY_PARAMS(p, param_sig, args); + + va_end(args); + + l_queue_push_tail(interface->methods, info); + + return true; +} + +LIB_EXPORT bool l_dbus_interface_signal(struct l_dbus_interface *interface, + const char *name, uint32_t flags, + const char *signature, ...) +{ + va_list args; + unsigned int metainfo_len; + struct _dbus_signal *info; + char *p; + + if (!_dbus_valid_method(name)) + return false; + + if (unlikely(!signature)) + return false; + + if (signature[0] && !_dbus_valid_signature(signature)) + return false; + + /* Pre-calculate the needed meta-info length */ + va_start(args, signature); + metainfo_len = SIZE_PARAMS(signature, args); + va_end(args); + + if (!metainfo_len) + return false; + + metainfo_len += strlen(name) + 1; + + info = l_malloc(sizeof(*info) + metainfo_len); + info->flags = flags; + info->name_len = strlen(name); + + p = stpcpy(info->metainfo, name) + 1; + + va_start(args, signature); + COPY_PARAMS(p, signature, args); + va_end(args); + + l_queue_push_tail(interface->signals, info); + + return true; +} + +LIB_EXPORT bool l_dbus_interface_property(struct l_dbus_interface *interface, + const char *name, uint32_t flags, + const char *signature, + l_dbus_property_get_cb_t getter, + l_dbus_property_set_cb_t setter) +{ + unsigned int metainfo_len; + struct _dbus_property *info; + char *p; + + if (!_dbus_valid_method(name)) + return false; + + if (unlikely(!signature || !getter)) + return false; + + if (_dbus_num_children(signature) != 1) + return false; + + /* Pre-calculate the needed meta-info length */ + metainfo_len = strlen(name) + 1; + metainfo_len += strlen(signature) + 1; + + info = l_malloc(sizeof(*info) + metainfo_len); + info->flags = flags; + info->name_len = strlen(name); + info->getter = getter; + info->setter = setter; + + p = stpcpy(info->metainfo, name) + 1; + strcpy(p, signature); + + l_queue_push_tail(interface->properties, info); + + return true; +} + +struct l_dbus_interface *_dbus_interface_new(const char *name) +{ + struct l_dbus_interface *interface; + + interface = l_malloc(sizeof(*interface) + strlen(name) + 1); + + interface->methods = l_queue_new(); + interface->signals = l_queue_new(); + interface->properties = l_queue_new(); + + strcpy(interface->name, name); + + return interface; +} + +void _dbus_interface_free(struct l_dbus_interface *interface) +{ + l_queue_destroy(interface->methods, l_free); + l_queue_destroy(interface->signals, l_free); + l_queue_destroy(interface->properties, l_free); + + l_free(interface); +} + +static bool match_method(const void *a, const void *b) +{ + const struct _dbus_method *method = a; + const char *name = b; + + if (!strcmp(method->metainfo, name)) + return true; + + return false; +} + +struct _dbus_method *_dbus_interface_find_method(struct l_dbus_interface *i, + const char *method) +{ + return l_queue_find(i->methods, match_method, (char *) method); +} + +static bool match_signal(const void *a, const void *b) +{ + const struct _dbus_signal *signal = a; + const char *name = b; + + if (!strcmp(signal->metainfo, name)) + return true; + + return false; +} + +struct _dbus_signal *_dbus_interface_find_signal(struct l_dbus_interface *i, + const char *signal) +{ + return l_queue_find(i->signals, match_signal, (char *) signal); +} + +static bool match_property(const void *a, const void *b) +{ + const struct _dbus_property *property = a; + const char *name = b; + + if (!strcmp(property->metainfo, name)) + return true; + + return false; +} + +struct _dbus_property *_dbus_interface_find_property(struct l_dbus_interface *i, + const char *property) +{ + return l_queue_find(i->properties, match_property, (char *) property); +} + +static void interface_instance_free(struct interface_instance *instance) +{ + if (instance->interface->instance_destroy) + instance->interface->instance_destroy(instance->user_data); + + l_free(instance); +} + +static bool match_interface_instance(const void *a, const void *b) +{ + const struct interface_instance *instance = a; + const char *name = b; + + if (!strcmp(instance->interface->name, name)) + return true; + + return false; +} + +static bool match_interface_instance_ptr(const void *a, const void *b) +{ + const struct interface_instance *instance = a; + + return instance->interface == b; +} + +static void interface_add_record_free(void *data) +{ + struct interface_add_record *rec = data; + + l_free(rec->path); + l_queue_destroy(rec->instances, NULL); + l_free(rec); +} + +static void interface_removed_record_free(void *data) +{ + struct interface_remove_record *rec = data; + + l_free(rec->path); + l_queue_destroy(rec->interface_names, l_free); + l_free(rec); +} + +static void property_change_record_free(void *data) +{ + struct property_change_record *rec = data; + + l_free(rec->path); + l_queue_destroy(rec->properties, NULL); + l_free(rec); +} + +static void properties_setup_func(struct l_dbus_interface *); +static void object_manager_setup_func(struct l_dbus_interface *); + +struct _dbus_object_tree *_dbus_object_tree_new() +{ + struct _dbus_object_tree *tree; + + tree = l_new(struct _dbus_object_tree, 1); + + tree->interfaces = l_hashmap_new(); + l_hashmap_set_hash_function(tree->interfaces, l_str_hash); + l_hashmap_set_compare_function(tree->interfaces, + (l_hashmap_compare_func_t)strcmp); + + tree->objects = l_hashmap_string_new(); + + tree->root = l_new(struct object_node, 1); + + tree->property_changes = l_queue_new(); + + _dbus_object_tree_register_interface(tree, L_DBUS_INTERFACE_PROPERTIES, + properties_setup_func, NULL, + false); + + tree->object_managers = l_queue_new(); + + _dbus_object_tree_register_interface(tree, + L_DBUS_INTERFACE_OBJECT_MANAGER, + object_manager_setup_func, NULL, + false); + + return tree; +} + +static void subtree_free(struct object_node *node) +{ + struct child_node *child; + + while (node->children) { + child = node->children; + node->children = child->next; + + subtree_free(child->node); + l_free(child); + } + + l_queue_destroy(node->instances, + (l_queue_destroy_func_t) interface_instance_free); + + if (node->destroy) + node->destroy(node->user_data); + + l_free(node); +} + +static void object_manager_free(void *data) +{ + struct object_manager *manager = data; + + l_free(manager->path); + l_queue_destroy(manager->announce_added, interface_add_record_free); + l_queue_destroy(manager->announce_removed, + interface_removed_record_free); + l_free(manager); +} + +void _dbus_object_tree_free(struct _dbus_object_tree *tree) +{ + subtree_free(tree->root); + + l_hashmap_destroy(tree->interfaces, + (l_hashmap_destroy_func_t) _dbus_interface_free); + l_hashmap_destroy(tree->objects, NULL); + + l_queue_destroy(tree->object_managers, object_manager_free); + + l_queue_destroy(tree->property_changes, property_change_record_free); + + if (tree->emit_signals_work) + l_idle_remove(tree->emit_signals_work); + + l_free(tree); +} + +static struct object_node *makepath_recurse(struct object_node *node, + const char *path) +{ + const char *end; + struct child_node *child; + + if (*path == '\0') + return node; + + path += 1; + end = strchrnul(path, '/'); + child = node->children; + + while (child) { + if (!strncmp(child->subpath, path, end - path) && + child->subpath[end - path] == '\0') + goto done; + + child = child->next; + } + + child = l_malloc(sizeof(*child) + end - path + 1); + child->node = l_new(struct object_node, 1); + child->node->parent = node; + memcpy(child->subpath, path, end - path); + child->subpath[end-path] = '\0'; + child->next = node->children; + node->children = child; + +done: + return makepath_recurse(child->node, end); +} + +struct object_node *_dbus_object_tree_makepath(struct _dbus_object_tree *tree, + const char *path) +{ + if (path[0] == '/' && path[1] == '\0') + return tree->root; + + return makepath_recurse(tree->root, path); +} + +static struct object_node *lookup_recurse(struct object_node *node, + const char *path) +{ + const char *end; + struct child_node *child; + + if (*path == '\0') + return node; + + path += 1; + end = strchrnul(path, '/'); + child = node->children; + + while (child) { + if (!strncmp(child->subpath, path, end - path) && + child->subpath[end - path] == '\0') + return lookup_recurse(child->node, end); + + child = child->next; + } + + return NULL; +} + +struct object_node *_dbus_object_tree_lookup(struct _dbus_object_tree *tree, + const char *path) +{ + if (path[0] == '/' && path[1] == '\0') + return tree->root; + + return lookup_recurse(tree->root, path); +} + +void _dbus_object_tree_prune_node(struct object_node *node) +{ + struct object_node *parent = node->parent; + struct child_node *p = NULL, *c; + + while (parent) { + for (c = parent->children, p = NULL; c; p = c, c = c->next) { + if (c->node != node) + continue; + + if (p) + p->next = c->next; + else + parent->children = c->next; + + subtree_free(c->node); + l_free(c); + + break; + } + + if (parent->children != NULL) + return; + + if (parent->instances) + return; + + node = parent; + parent = node->parent; + } +} + +struct object_node *_dbus_object_tree_new_object(struct _dbus_object_tree *tree, + const char *path, + void *user_data, + void (*destroy) (void *)) +{ + struct object_node *node; + + if (!_dbus_valid_object_path(path)) + return NULL; + + if (l_hashmap_lookup(tree->objects, path)) + return NULL; + + node = _dbus_object_tree_makepath(tree, path); + node->user_data = user_data; + node->destroy = destroy; + + /* + * Registered objects in the tree are marked by being present in the + * tree->objects hash and having non-null node->instances. Remaining + * nodes are intermediate path elements added and removed + * automatically. + */ + node->instances = l_queue_new(); + + l_hashmap_insert(tree->objects, path, node); + + return node; +} + +bool _dbus_object_tree_object_destroy(struct _dbus_object_tree *tree, + const char *path) +{ + struct object_node *node; + const struct l_queue_entry *entry; + const struct interface_instance *instance; + + node = l_hashmap_lookup(tree->objects, path); + if (!node) + return false; + + while ((entry = l_queue_get_entries(node->instances))) { + instance = entry->data; + + if (!_dbus_object_tree_remove_interface(tree, path, + instance->interface->name)) + return false; + } + + l_hashmap_remove(tree->objects, path); + + l_queue_destroy(node->instances, NULL); + node->instances = NULL; + + if (node->destroy) { + node->destroy(node->user_data); + node->destroy = NULL; + } + + if (!node->children) + _dbus_object_tree_prune_node(node); + + return true; +} + +static bool get_properties_dict(struct l_dbus *dbus, + struct l_dbus_message *message, + struct l_dbus_message_builder *builder, + const struct l_dbus_interface *interface, + void *user_data) +{ + const struct l_queue_entry *entry; + const struct _dbus_property *property; + const char *signature; + + l_dbus_message_builder_enter_array(builder, "{sv}"); + _dbus_message_builder_mark(builder); + + for (entry = l_queue_get_entries(interface->properties); entry; + entry = entry->next) { + property = entry->data; + signature = property->metainfo + strlen(property->metainfo) + 1; + + l_dbus_message_builder_enter_dict(builder, "sv"); + l_dbus_message_builder_append_basic(builder, 's', + property->metainfo); + l_dbus_message_builder_enter_variant(builder, signature); + + if (!property->getter(dbus, message, builder, user_data)) { + if (!_dbus_message_builder_rewind(builder)) + return false; + + continue; + } + + l_dbus_message_builder_leave_variant(builder); + l_dbus_message_builder_leave_dict(builder); + _dbus_message_builder_mark(builder); + } + + l_dbus_message_builder_leave_array(builder); + + return true; +} + +static struct l_dbus_message *build_interfaces_removed_signal( + const struct object_manager *manager, + const struct interface_remove_record *rec) +{ + struct l_dbus_message *signal; + struct l_dbus_message_builder *builder; + const struct l_queue_entry *entry; + + signal = l_dbus_message_new_signal(manager->dbus, manager->path, + L_DBUS_INTERFACE_OBJECT_MANAGER, + "InterfacesRemoved"); + + builder = l_dbus_message_builder_new(signal); + + l_dbus_message_builder_append_basic(builder, 'o', rec->path); + l_dbus_message_builder_enter_array(builder, "s"); + + for (entry = l_queue_get_entries(rec->interface_names); entry; + entry = entry->next) + l_dbus_message_builder_append_basic(builder, 's', entry->data); + + l_dbus_message_builder_leave_array(builder); + l_dbus_message_builder_finalize(builder); + l_dbus_message_builder_destroy(builder); + + return signal; +} + +static struct l_dbus_message *build_interfaces_added_signal( + const struct object_manager *manager, + const struct interface_add_record *rec) +{ + struct l_dbus_message *signal; + struct l_dbus_message_builder *builder; + const struct l_queue_entry *entry; + const struct interface_instance *instance; + + signal = l_dbus_message_new_signal(manager->dbus, manager->path, + L_DBUS_INTERFACE_OBJECT_MANAGER, + "InterfacesAdded"); + + builder = l_dbus_message_builder_new(signal); + + l_dbus_message_builder_append_basic(builder, 'o', rec->path); + l_dbus_message_builder_enter_array(builder, "{sa{sv}}"); + + for (entry = l_queue_get_entries(rec->instances); entry; + entry = entry->next) { + instance = entry->data; + + l_dbus_message_builder_enter_dict(builder, "sa{sv}"); + l_dbus_message_builder_append_basic(builder, 's', + instance->interface->name); + + if (!get_properties_dict(manager->dbus, signal, builder, + instance->interface, + instance->user_data)) { + l_dbus_message_builder_destroy(builder); + l_dbus_message_unref(signal); + + return NULL; + } + + l_dbus_message_builder_leave_dict(builder); + } + + l_dbus_message_builder_leave_array(builder); + l_dbus_message_builder_finalize(builder); + l_dbus_message_builder_destroy(builder); + + return signal; +} + +static struct l_dbus_message *build_old_property_changed_signal( + struct l_dbus *dbus, + const struct property_change_record *rec, + const struct _dbus_property *property) +{ + struct l_dbus_message *signal; + struct l_dbus_message_builder *builder; + const char *signature; + + signature = property->metainfo + strlen(property->metainfo) + 1; + + signal = l_dbus_message_new_signal(dbus, rec->path, + rec->instance->interface->name, + "PropertyChanged"); + + builder = l_dbus_message_builder_new(signal); + + l_dbus_message_builder_append_basic(builder, 's', property->metainfo); + l_dbus_message_builder_enter_variant(builder, signature); + + if (!property->getter(dbus, signal, builder, + rec->instance->user_data)) { + l_dbus_message_builder_destroy(builder); + l_dbus_message_unref(signal); + + return NULL; + } + + l_dbus_message_builder_leave_variant(builder); + + l_dbus_message_builder_finalize(builder); + l_dbus_message_builder_destroy(builder); + + return signal; +} + +static struct l_dbus_message *build_properties_changed_signal( + struct l_dbus *dbus, + const struct property_change_record *rec) +{ + struct l_dbus_message *signal; + struct l_dbus_message_builder *builder; + const struct l_queue_entry *entry; + const struct _dbus_property *property; + const char *signature; + struct l_queue *invalidated; + + signal = l_dbus_message_new_signal(dbus, rec->path, + L_DBUS_INTERFACE_PROPERTIES, + "PropertiesChanged"); + + builder = l_dbus_message_builder_new(signal); + + invalidated = l_queue_new(); + + l_dbus_message_builder_append_basic(builder, 's', + rec->instance->interface->name); + l_dbus_message_builder_enter_array(builder, "{sv}"); + + for (entry = l_queue_get_entries(rec->properties); entry; + entry = entry->next) { + property = entry->data; + signature = property->metainfo + strlen(property->metainfo) + 1; + + _dbus_message_builder_mark(builder); + + l_dbus_message_builder_enter_dict(builder, "sv"); + l_dbus_message_builder_append_basic(builder, 's', + property->metainfo); + l_dbus_message_builder_enter_variant(builder, signature); + + if (!property->getter(dbus, signal, builder, + rec->instance->user_data)) { + if (!_dbus_message_builder_rewind(builder)) { + l_dbus_message_unref(signal); + signal = NULL; + + goto done; + } + + l_queue_push_tail(invalidated, (void *) property); + + continue; + } + + l_dbus_message_builder_leave_variant(builder); + l_dbus_message_builder_leave_dict(builder); + } + + l_dbus_message_builder_leave_array(builder); + l_dbus_message_builder_enter_array(builder, "s"); + + while ((property = l_queue_pop_head(invalidated))) + l_dbus_message_builder_append_basic(builder, 's', + property->metainfo); + + l_dbus_message_builder_leave_array(builder); + l_dbus_message_builder_finalize(builder); + +done: + l_dbus_message_builder_destroy(builder); + + l_queue_destroy(invalidated, NULL); + + return signal; +} + +struct emit_signals_data { + struct l_dbus *dbus; + struct object_manager *manager; + struct object_node *node; +}; + +static bool emit_interfaces_removed(void *data, void *user_data) +{ + struct interface_remove_record *rec = data; + struct emit_signals_data *es = user_data; + struct l_dbus_message *signal; + + if (es->node && rec->object != es->node) + return false; + + signal = build_interfaces_removed_signal(es->manager, rec); + interface_removed_record_free(rec); + + if (signal) + l_dbus_send(es->manager->dbus, signal); + + return true; +} + +static bool emit_interfaces_added(void *data, void *user_data) +{ + struct interface_add_record *rec = data; + struct emit_signals_data *es = user_data; + struct l_dbus_message *signal; + + if (es->node && rec->object != es->node) + return false; + + signal = build_interfaces_added_signal(es->manager, rec); + interface_add_record_free(rec); + + if (signal) + l_dbus_send(es->manager->dbus, signal); + + return true; +} + +static bool emit_properties_changed(void *data, void *user_data) +{ + struct property_change_record *rec = data; + struct emit_signals_data *es = user_data; + struct l_dbus_message *signal; + const struct l_queue_entry *entry; + + if (es->node && rec->object != es->node) + return false; + + if (rec->instance->interface->handle_old_style_properties) + for (entry = l_queue_get_entries(rec->properties); + entry; entry = entry->next) { + signal = build_old_property_changed_signal(es->dbus, + rec, entry->data); + if (signal) + l_dbus_send(es->dbus, signal); + } + + if (l_queue_find(rec->object->instances, match_interface_instance, + L_DBUS_INTERFACE_PROPERTIES)) { + signal = build_properties_changed_signal(es->dbus, rec); + if (signal) + l_dbus_send(es->dbus, signal); + } + + property_change_record_free(rec); + + return true; +} + +void _dbus_object_tree_signals_flush(struct l_dbus *dbus, const char *path) +{ + struct _dbus_object_tree *tree = _dbus_get_tree(dbus); + const struct l_queue_entry *entry; + struct emit_signals_data data; + bool all_done = true; + + if (!tree->emit_signals_work || tree->flushing) + return; + + tree->flushing = true; + + data.dbus = dbus; + data.node = path ? _dbus_object_tree_lookup(tree, path) : NULL; + + for (entry = l_queue_get_entries(tree->object_managers); entry; + entry = entry->next) { + data.manager = entry->data; + + l_queue_foreach_remove(data.manager->announce_removed, + emit_interfaces_removed, &data); + + if (!l_queue_isempty(data.manager->announce_removed)) + all_done = false; + + l_queue_foreach_remove(data.manager->announce_added, + emit_interfaces_added, &data); + + if (!l_queue_isempty(data.manager->announce_added)) + all_done = false; + } + + l_queue_foreach_remove(tree->property_changes, + emit_properties_changed, &data); + + if (!l_queue_isempty(tree->property_changes)) + all_done = false; + + if (all_done) { + l_idle_remove(tree->emit_signals_work); + tree->emit_signals_work = NULL; + } + + tree->flushing = false; +} + +static void emit_signals(struct l_idle *idle, void *user_data) +{ + struct l_dbus *dbus = user_data; + + _dbus_object_tree_signals_flush(dbus, NULL); +} + +static void schedule_emit_signals(struct l_dbus *dbus) +{ + struct _dbus_object_tree *tree = _dbus_get_tree(dbus); + + if (tree->emit_signals_work) + return; + + tree->emit_signals_work = l_idle_create(emit_signals, dbus, NULL); +} + +static bool match_property_changes_instance(const void *a, const void *b) +{ + const struct property_change_record *rec = a; + + return rec->instance == b; +} + +static bool match_pointer(const void *a, const void *b) +{ + return a == b; +} + +bool _dbus_object_tree_property_changed(struct l_dbus *dbus, + const char *path, + const char *interface_name, + const char *property_name) +{ + struct property_change_record *rec; + struct object_node *object; + struct interface_instance *instance; + struct _dbus_property *property; + struct _dbus_object_tree *tree = _dbus_get_tree(dbus); + + object = l_hashmap_lookup(tree->objects, path); + if (!object) + return false; + + instance = l_queue_find(object->instances, match_interface_instance, + interface_name); + if (!instance) + return false; + + property = _dbus_interface_find_property(instance->interface, + property_name); + if (!property) + return false; + + rec = l_queue_find(tree->property_changes, + match_property_changes_instance, instance); + + if (rec) { + if (l_queue_find(rec->properties, match_pointer, property)) + return true; + } else { + rec = l_new(struct property_change_record, 1); + rec->path = l_strdup(path); + rec->object = object; + rec->instance = instance; + rec->properties = l_queue_new(); + + l_queue_push_tail(tree->property_changes, rec); + } + + l_queue_push_tail(rec->properties, property); + + schedule_emit_signals(dbus); + + return true; +} + +static void pending_property_set_done_common(struct l_dbus *dbus, + struct l_dbus_message *message, + struct l_dbus_message *reply, + bool auto_emit) +{ + const char *member; + const char *interface_name; + const char *property_name; + struct l_dbus_message_iter variant; + + if (!reply) { + reply = l_dbus_message_new_method_return(message); + l_dbus_message_set_arguments(reply, ""); + } + + l_dbus_send(dbus, l_dbus_message_ref(reply)); + + member = l_dbus_message_get_member(message); + if (!strcmp(member, "SetProperty")) { + if (!l_dbus_message_get_arguments(message, "sv", + &property_name, &variant)) + goto done; + + interface_name = l_dbus_message_get_interface(message); + } else if (strcmp(member, "Set") || + !l_dbus_message_get_arguments(message, "ssv", + &interface_name, + &property_name, + &variant)) + goto done; + + if (auto_emit) + _dbus_object_tree_property_changed(dbus, + l_dbus_message_get_path(message), + interface_name, property_name); +done: + l_dbus_message_unref(message); + l_dbus_message_unref(reply); +} + +static void pending_property_set_done_emit(struct l_dbus *dbus, + struct l_dbus_message *message, + struct l_dbus_message *reply) +{ + pending_property_set_done_common(dbus, message, reply, true); +} + +static void pending_property_set_done(struct l_dbus *dbus, + struct l_dbus_message *message, + struct l_dbus_message *reply) +{ + pending_property_set_done_common(dbus, message, reply, false); +} + +static struct l_dbus_message *old_set_property(struct l_dbus *dbus, + struct l_dbus_message *message, + void *user_data) +{ + struct l_dbus_interface *interface; + const char *property_name; + const struct _dbus_property *property; + struct l_dbus_message_iter variant; + struct _dbus_object_tree *tree = _dbus_get_tree(dbus); + struct l_dbus_message *reply; + l_dbus_property_complete_cb_t complete_cb; + + interface = l_hashmap_lookup(tree->interfaces, + l_dbus_message_get_interface(message)); + /* If we got here the interface must exist */ + + if (!l_dbus_message_get_arguments(message, "sv", &property_name, + &variant)) + return l_dbus_message_new_error(message, + "org.freedesktop.DBus.Error." + "InvalidArgs", + "Invalid arguments"); + + property = _dbus_interface_find_property(interface, property_name); + if (!property) + return l_dbus_message_new_error(message, + "org.freedesktop.DBus.Error." + "InvalidArgs", + "Unknown Property %s", + property_name); + + if (!property->setter) + return l_dbus_message_new_error(message, + "org.freedesktop.DBus.Error." + "InvalidArgs", + "Property %s is read-only", + property_name); + + if (property->flags & L_DBUS_PROPERTY_FLAG_AUTO_EMIT) + complete_cb = pending_property_set_done_emit; + else + complete_cb = pending_property_set_done; + + reply = property->setter(dbus, l_dbus_message_ref(message), &variant, + complete_cb, user_data); + + if (reply) + complete_cb(dbus, message, reply); + + return NULL; +} + +static struct l_dbus_message *old_get_properties(struct l_dbus *dbus, + struct l_dbus_message *message, + void *user_data) +{ + const struct l_dbus_interface *interface; + struct l_dbus_message *reply; + struct l_dbus_message_builder *builder; + struct _dbus_object_tree *tree = _dbus_get_tree(dbus); + + interface = l_hashmap_lookup(tree->interfaces, + l_dbus_message_get_interface(message)); + /* If we got here the interface must exist */ + + reply = l_dbus_message_new_method_return(message); + builder = l_dbus_message_builder_new(reply); + + if (!get_properties_dict(dbus, message, builder, interface, + user_data)) { + l_dbus_message_unref(reply); + + reply = l_dbus_message_new_error(message, + "org.freedesktop.DBus.Error." + "Failed", + "Getting properties failed"); + } else + l_dbus_message_builder_finalize(builder); + + l_dbus_message_builder_destroy(builder); + + return reply; +} + +bool _dbus_object_tree_register_interface(struct _dbus_object_tree *tree, + const char *interface, + void (*setup_func)(struct l_dbus_interface *), + void (*destroy) (void *), + bool old_style_properties) +{ + struct l_dbus_interface *dbi; + + if (!_dbus_valid_interface(interface)) + return false; + + /* + * Check to make sure we do not have this interface already + * registered + */ + dbi = l_hashmap_lookup(tree->interfaces, interface); + if (dbi) + return false; + + dbi = _dbus_interface_new(interface); + dbi->instance_destroy = destroy; + dbi->handle_old_style_properties = old_style_properties; + + /* Add our methods first so we don't have to check for conflicts. */ + if (old_style_properties) { + l_dbus_interface_method(dbi, "SetProperty", 0, + old_set_property, "", "sv", + "name", "value"); + l_dbus_interface_method(dbi, "GetProperties", 0, + old_get_properties, "a{sv}", "", + "properties"); + + l_dbus_interface_signal(dbi, "PropertyChanged", 0, "sv", + "name", "value"); + } + + setup_func(dbi); + + l_hashmap_insert(tree->interfaces, dbi->name, dbi); + + return true; +} + +struct interface_check { + struct _dbus_object_tree *tree; + const char *interface; +}; + +static void check_interface_used(const void *key, void *value, void *user_data) +{ + const char *path = key; + struct object_node *node = value; + struct interface_check *state = user_data; + + if (!l_queue_find(node->instances, match_interface_instance, + (char *) state->interface)) + return; + + _dbus_object_tree_remove_interface(state->tree, path, state->interface); +} + +bool _dbus_object_tree_unregister_interface(struct _dbus_object_tree *tree, + const char *interface_name) +{ + struct l_dbus_interface *interface; + struct interface_check state = { tree, interface_name }; + + interface = l_hashmap_lookup(tree->interfaces, interface_name); + if (!interface) + return false; + + /* Check that the interface is not in use */ + l_hashmap_foreach(tree->objects, check_interface_used, &state); + + l_hashmap_remove(tree->interfaces, interface_name); + + _dbus_interface_free(interface); + + return true; +} + +static void collect_instances(struct object_node *node, + const char *path, + struct l_queue *announce) +{ + const struct l_queue_entry *entry; + struct interface_add_record *change_rec; + const struct child_node *child; + + if (!node->instances) + goto recurse; + + change_rec = l_new(struct interface_add_record, 1); + change_rec->path = l_strdup(path); + change_rec->object = node; + change_rec->instances = l_queue_new(); + + for (entry = l_queue_get_entries(node->instances); entry; + entry = entry->next) + l_queue_push_tail(change_rec->instances, entry->data); + + l_queue_push_tail(announce, change_rec); + +recurse: + if (!strcmp(path, "/")) + path = ""; + + for (child = node->children; child; child = child->next) { + char *child_path; + + child_path = l_strdup_printf("%s/%s", path, child->subpath); + + collect_instances(child->node, child_path, announce); + + l_free(child_path); + } +} + +static bool match_interfaces_added_object(const void *a, const void *b) +{ + const struct interface_add_record *rec = a; + + return rec->object == b; +} + +static bool match_interfaces_removed_object(const void *a, const void *b) +{ + const struct interface_remove_record *rec = a; + + return rec->object == b; +} + +bool _dbus_object_tree_add_interface(struct _dbus_object_tree *tree, + const char *path, const char *interface, + void *user_data) +{ + struct object_node *object; + struct l_dbus_interface *dbi; + struct interface_instance *instance; + const struct l_queue_entry *entry; + struct object_manager *manager; + size_t path_len; + struct interface_add_record *change_rec; + + dbi = l_hashmap_lookup(tree->interfaces, interface); + if (!dbi) + return false; + + object = l_hashmap_lookup(tree->objects, path); + if (!object) { + object = _dbus_object_tree_new_object(tree, path, NULL, NULL); + + if (!object) + return false; + } + + /* + * Check to make sure we do not have this interface already + * registered for this object + */ + if (l_queue_find(object->instances, match_interface_instance_ptr, dbi)) + return false; + + instance = l_new(struct interface_instance, 1); + instance->interface = dbi; + instance->user_data = user_data; + + l_queue_push_tail(object->instances, instance); + + for (entry = l_queue_get_entries(tree->object_managers); entry; + entry = entry->next) { + manager = entry->data; + path_len = strlen(manager->path); + + if (strncmp(path, manager->path, path_len) || + (path[path_len] != '\0' && + path[path_len] != '/' && path_len > 1)) + continue; + + change_rec = l_queue_find(manager->announce_added, + match_interfaces_added_object, + object); + if (!change_rec) { + change_rec = l_new(struct interface_add_record, 1); + change_rec->path = l_strdup(path); + change_rec->object = object; + change_rec->instances = l_queue_new(); + + l_queue_push_tail(manager->announce_added, change_rec); + } + + /* No need to check for duplicates here */ + l_queue_push_tail(change_rec->instances, instance); + + schedule_emit_signals(manager->dbus); + } + + if (!strcmp(interface, L_DBUS_INTERFACE_OBJECT_MANAGER)) { + manager = l_new(struct object_manager, 1); + manager->path = l_strdup(path); + manager->dbus = instance->user_data; + manager->announce_added = l_queue_new(); + manager->announce_removed = l_queue_new(); + + l_queue_push_tail(tree->object_managers, manager); + + /* Emit InterfacesAdded for interfaces added before OM */ + collect_instances(object, path, manager->announce_added); + + if (manager->dbus && !l_queue_isempty(manager->announce_added)) + schedule_emit_signals(manager->dbus); + } + + return true; +} + +static struct interface_instance *_dbus_object_tree_find_interface( + struct _dbus_object_tree *tree, + const char *path, + const char *interface) +{ + struct object_node *object; + + object = l_hashmap_lookup(tree->objects, path); + if (!object) + return NULL; + + return l_queue_find(object->instances, match_interface_instance, + interface); +} + +void *_dbus_object_tree_get_interface_data(struct _dbus_object_tree *tree, + const char *path, + const char *interface) +{ + struct interface_instance *instance; + + instance = _dbus_object_tree_find_interface(tree, path, interface); + if (!instance) + return NULL; + + return instance->user_data; +} + +bool _dbus_object_tree_set_interface_data(struct _dbus_object_tree *tree, + const char *path, + const char *interface, + void *user_data) +{ + struct interface_instance *instance; + + instance = _dbus_object_tree_find_interface(tree, path, interface); + if (!instance) + return false; + + instance->user_data = user_data; + + return true; +} + +static bool match_object_manager_path(const void *a, const void *b) +{ + const struct object_manager *manager = a; + + return !strcmp(manager->path, b); +} + +bool _dbus_object_tree_remove_interface(struct _dbus_object_tree *tree, + const char *path, const char *interface) +{ + struct object_node *node; + struct interface_instance *instance; + const struct l_queue_entry *entry; + struct object_manager *manager; + size_t path_len; + struct interface_add_record *interfaces_added_rec; + struct interface_remove_record *interfaces_removed_rec; + struct property_change_record *property_change_rec; + + node = l_hashmap_lookup(tree->objects, path); + if (!node) + return false; + + instance = l_queue_remove_if(node->instances, + match_interface_instance, (char *) interface); + if (!instance) + return false; + + if (!strcmp(interface, L_DBUS_INTERFACE_OBJECT_MANAGER)) { + manager = l_queue_remove_if(tree->object_managers, + match_object_manager_path, + (char *) path); + + if (manager) + object_manager_free(manager); + } + + for (entry = l_queue_get_entries(tree->object_managers); entry; + entry = entry->next) { + manager = entry->data; + path_len = strlen(manager->path); + + if (strncmp(path, manager->path, path_len) || + (path[path_len] != '\0' && + path[path_len] != '/' && path_len > 1)) + continue; + + interfaces_added_rec = l_queue_find(manager->announce_added, + match_interfaces_added_object, + node); + if (interfaces_added_rec && l_queue_remove( + interfaces_added_rec->instances, + instance)) { + if (l_queue_isempty(interfaces_added_rec->instances)) { + l_queue_remove(manager->announce_added, + interfaces_added_rec); + interface_add_record_free(interfaces_added_rec); + } + + continue; + } + + interfaces_removed_rec = l_queue_find(manager->announce_removed, + match_interfaces_removed_object, + node); + if (!interfaces_removed_rec) { + interfaces_removed_rec = + l_new(struct interface_remove_record, 1); + interfaces_removed_rec->path = l_strdup(path); + interfaces_removed_rec->object = node; + interfaces_removed_rec->interface_names = + l_queue_new(); + l_queue_push_tail(manager->announce_removed, + interfaces_removed_rec); + } + + /* No need to check for duplicates here */ + l_queue_push_tail(interfaces_removed_rec->interface_names, + l_strdup(interface)); + + schedule_emit_signals(manager->dbus); + } + + property_change_rec = l_queue_remove_if(tree->property_changes, + match_property_changes_instance, + instance); + if (property_change_rec) + property_change_record_free(property_change_rec); + + interface_instance_free(instance); + + return true; +} + +static void generate_interface_instance(void *data, void *user) +{ + struct interface_instance *instance = data; + struct l_string *buf = user; + + _dbus_interface_introspection(instance->interface, buf); +} + +void _dbus_object_tree_introspect(struct _dbus_object_tree *tree, + const char *path, struct l_string *buf) +{ + struct object_node *node; + struct child_node *child; + bool path_is_object = true; + + node = l_hashmap_lookup(tree->objects, path); + if (!node) { + path_is_object = false; + node = _dbus_object_tree_lookup(tree, path); + } + + l_string_append(buf, XML_HEAD); + l_string_append(buf, "<node>\n"); + + if (node) { + /* + * We emit org.freedesktop.DBus.Introspectable only in case the + * object node corresponds to a registered object, i.e. + * exposes anything other than: + * - org.freedesktop.DBus.Introspectable + * - org.freedesktop.DBus.Peer + * - org.freedesktop.DBus.Properties + */ + if (path_is_object) + l_string_append(buf, static_introspectable); + + l_queue_foreach(node->instances, + generate_interface_instance, buf); + + for (child = node->children; child; child = child->next) + l_string_append_printf(buf, "\t<node name=\"%s\"/>\n", + child->subpath); + } + + l_string_append(buf, "</node>\n"); +} + +bool _dbus_object_tree_dispatch(struct _dbus_object_tree *tree, + struct l_dbus *dbus, + struct l_dbus_message *message) +{ + const char *path; + const char *interface; + const char *member; + const char *msg_sig; + const char *sig; + struct object_node *node; + struct interface_instance *instance; + struct _dbus_method *method; + struct l_dbus_message *reply; + + path = l_dbus_message_get_path(message); + interface = l_dbus_message_get_interface(message); + member = l_dbus_message_get_member(message); + msg_sig = l_dbus_message_get_signature(message); + + /* + * Nothing in the spec explicitly forbids this, but handling of such + * messages is left up to the implementation. + * + * TODO: Another route is to go looking for a matching method under this + * object and call it. + */ + if (!interface) + return false; + + if (!msg_sig) + msg_sig = ""; + + if (!strcmp(interface, "org.freedesktop.DBus.Introspectable") && + !strcmp(member, "Introspect") && + !strcmp(msg_sig, "")) { + struct l_string *buf; + char *xml; + + buf = l_string_new(0); + _dbus_object_tree_introspect(tree, path, buf); + xml = l_string_unwrap(buf); + + reply = l_dbus_message_new_method_return(message); + l_dbus_message_set_arguments(reply, "s", xml); + l_dbus_send(dbus, reply); + + l_free(xml); + + return true; + } + + node = l_hashmap_lookup(tree->objects, path); + if (!node) + return false; + + instance = l_queue_find(node->instances, + match_interface_instance, (char *) interface); + if (!instance) + return false; + + method = _dbus_interface_find_method(instance->interface, member); + if (!method) + return false; + + sig = method->metainfo + method->name_len + 1; + + if (strcmp(msg_sig, sig)) + return false; + + reply = method->cb(dbus, message, instance->user_data); + if (reply) + l_dbus_send(dbus, reply); + + return true; +} + +LIB_EXPORT bool l_dbus_property_changed(struct l_dbus *dbus, const char *path, + const char *interface, + const char *property) +{ + return _dbus_object_tree_property_changed(dbus, path, interface, + property); +} + +static struct l_dbus_message *properties_get(struct l_dbus *dbus, + struct l_dbus_message *message, + void *user_data) +{ + const struct interface_instance *instance; + const char *interface_name, *property_name, *signature; + const struct _dbus_property *property; + struct _dbus_object_tree *tree = _dbus_get_tree(dbus); + const struct object_node *object; + struct l_dbus_message *reply; + struct l_dbus_message_builder *builder; + + if (!l_dbus_message_get_arguments(message, "ss", &interface_name, + &property_name)) + return l_dbus_message_new_error(message, + "org.freedesktop.DBus.Error." + "InvalidArgs", + "Invalid arguments"); + + object = l_hashmap_lookup(tree->objects, + l_dbus_message_get_path(message)); + /* If we got here the object must exist */ + + instance = l_queue_find(object->instances, + match_interface_instance, + (char *) interface_name); + if (!instance) + return l_dbus_message_new_error(message, + "org.freedesktop.DBus.Error." + "InvalidArgs", + "Object has no interface %s", + interface_name); + + property = _dbus_interface_find_property(instance->interface, + property_name); + if (!property) + return l_dbus_message_new_error(message, + "org.freedesktop.DBus.Error." + "InvalidArgs", + "Unknown Property %s", + property_name); + + + reply = l_dbus_message_new_method_return(message); + builder = l_dbus_message_builder_new(reply); + + signature = property->metainfo + strlen(property->metainfo) + 1; + + l_dbus_message_builder_enter_variant(builder, signature); + + if (property->getter(dbus, message, builder, instance->user_data)) { + l_dbus_message_builder_leave_variant(builder); + l_dbus_message_builder_finalize(builder); + } else { + l_dbus_message_unref(reply); + + reply = l_dbus_message_new_error(message, + "org.freedesktop.DBus.Error." + "Failed", + "Getting property value " + "failed"); + } + + l_dbus_message_builder_destroy(builder); + + return reply; +} + +static struct l_dbus_message *properties_set(struct l_dbus *dbus, + struct l_dbus_message *message, + void *user_data) +{ + struct l_dbus_interface *interface; + const struct interface_instance *instance; + const char *interface_name, *property_name; + const struct _dbus_property *property; + struct l_dbus_message_iter variant; + struct _dbus_object_tree *tree = _dbus_get_tree(dbus); + const struct object_node *object; + struct l_dbus_message *reply; + l_dbus_property_complete_cb_t complete_cb; + + if (!l_dbus_message_get_arguments(message, "ssv", &interface_name, + &property_name, &variant)) + return l_dbus_message_new_error(message, + "org.freedesktop.DBus.Error." + "InvalidArgs", + "Invalid arguments"); + + interface = l_hashmap_lookup(tree->interfaces, interface_name); + if (!interface) + return l_dbus_message_new_error(message, + "org.freedesktop.DBus.Error." + "InvalidArgs", + "Unknown Interface %s", + interface_name); + + property = _dbus_interface_find_property(interface, property_name); + if (!property) + return l_dbus_message_new_error(message, + "org.freedesktop.DBus.Error." + "InvalidArgs", + "Unknown Property %s", + property_name); + + if (!property->setter) + return l_dbus_message_new_error(message, + "org.freedesktop.DBus.Error." + "InvalidArgs", + "Property %s is read-only", + property_name); + + object = l_hashmap_lookup(tree->objects, + l_dbus_message_get_path(message)); + /* If we got here the object must exist */ + + instance = l_queue_find(object->instances, + match_interface_instance_ptr, interface); + if (!instance) + return l_dbus_message_new_error(message, + "org.freedesktop.DBus.Error." + "InvalidArgs", + "Object has no interface %s", + interface_name); + + if (property->flags & L_DBUS_PROPERTY_FLAG_AUTO_EMIT) + complete_cb = pending_property_set_done_emit; + else + complete_cb = pending_property_set_done; + + reply = property->setter(dbus, l_dbus_message_ref(message), &variant, + complete_cb, instance->user_data); + + if (reply) + complete_cb(dbus, message, reply); + + return NULL; +} + +static struct l_dbus_message *properties_get_all(struct l_dbus *dbus, + struct l_dbus_message *message, + void *user_data) +{ + const struct interface_instance *instance; + const char *interface_name; + struct _dbus_object_tree *tree = _dbus_get_tree(dbus); + const struct object_node *object; + struct l_dbus_message *reply; + struct l_dbus_message_builder *builder; + + if (!l_dbus_message_get_arguments(message, "s", &interface_name)) + return l_dbus_message_new_error(message, + "org.freedesktop.DBus.Error." + "InvalidArgs", + "Invalid arguments"); + + object = l_hashmap_lookup(tree->objects, + l_dbus_message_get_path(message)); + /* If we got here the object must exist */ + + instance = l_queue_find(object->instances, + match_interface_instance, + (char *) interface_name); + if (!instance) + return l_dbus_message_new_error(message, + "org.freedesktop.DBus.Error." + "InvalidArgs", + "Object has no interface %s", + interface_name); + + reply = l_dbus_message_new_method_return(message); + builder = l_dbus_message_builder_new(reply); + + if (!get_properties_dict(dbus, message, builder, instance->interface, + instance->user_data)) { + l_dbus_message_unref(reply); + + reply = l_dbus_message_new_error(message, + "org.freedesktop.DBus.Error." + "Failed", + "Getting property values " + "failed"); + } else + l_dbus_message_builder_finalize(builder); + + l_dbus_message_builder_destroy(builder); + + return reply; +} + +static void properties_setup_func(struct l_dbus_interface *interface) +{ + l_dbus_interface_method(interface, "Get", 0, + properties_get, "v", "ss", + "value", "interface_name", "property_name"); + l_dbus_interface_method(interface, "Set", 0, + properties_set, "", "ssv", + "interface_name", "property_name", "value"); + l_dbus_interface_method(interface, "GetAll", 0, + properties_get_all, "a{sv}", "s", + "props", "interface_name"); + + l_dbus_interface_signal(interface, "PropertiesChanged", 0, "sa{sv}as", + "interface_name", "changed_properties", + "invalidated_properties"); +} + +static bool collect_objects(struct l_dbus *dbus, struct l_dbus_message *message, + struct l_dbus_message_builder *builder, + const struct object_node *node, + const char *path) +{ + const struct l_queue_entry *entry; + const struct child_node *child; + char *child_path; + const struct interface_instance *instance; + bool r; + + if (!node->instances) + goto recurse; + + l_dbus_message_builder_enter_dict(builder, "oa{sa{sv}}"); + l_dbus_message_builder_append_basic(builder, 'o', path); + l_dbus_message_builder_enter_array(builder, "{sa{sv}}"); + + for (entry = l_queue_get_entries(node->instances); entry; + entry = entry->next) { + instance = entry->data; + + l_dbus_message_builder_enter_dict(builder, "sa{sv}"); + l_dbus_message_builder_append_basic(builder, 's', + instance->interface->name); + + if (!get_properties_dict(dbus, message, builder, + instance->interface, + instance->user_data)) + return false; + + l_dbus_message_builder_leave_dict(builder); + } + + l_dbus_message_builder_leave_array(builder); + l_dbus_message_builder_leave_dict(builder); + +recurse: + if (!strcmp(path, "/")) + path = ""; + + for (child = node->children; child; child = child->next) { + child_path = l_strdup_printf("%s/%s", path, child->subpath); + + r = collect_objects(dbus, message, builder, + child->node, child_path); + + l_free(child_path); + + if (!r) + return false; + } + + return true; +} + +struct l_dbus_message *_dbus_object_tree_get_objects( + struct _dbus_object_tree *tree, + struct l_dbus *dbus, + const char *path, + struct l_dbus_message *message) +{ + const struct object_node *node; + struct l_dbus_message *reply; + struct l_dbus_message_builder *builder; + + node = l_hashmap_lookup(tree->objects, path); + + reply = l_dbus_message_new_method_return(message); + builder = l_dbus_message_builder_new(reply); + + l_dbus_message_builder_enter_array(builder, "{oa{sa{sv}}}"); + + if (!collect_objects(dbus, message, builder, node, path)) { + l_dbus_message_builder_destroy(builder); + l_dbus_message_unref(reply); + + return l_dbus_message_new_error(message, + "org.freedesktop.DBus.Error." + "Failed", + "Getting property values " + "failed"); + } + + l_dbus_message_builder_leave_array(builder); + + l_dbus_message_builder_finalize(builder); + l_dbus_message_builder_destroy(builder); + + return reply; +} + +static struct l_dbus_message *get_managed_objects(struct l_dbus *dbus, + struct l_dbus_message *message, + void *user_data) +{ + struct _dbus_object_tree *tree = _dbus_get_tree(dbus); + const char *path = l_dbus_message_get_path(message); + + return _dbus_object_tree_get_objects(tree, dbus, path, message); +} + +static void object_manager_setup_func(struct l_dbus_interface *interface) +{ + l_dbus_interface_method(interface, "GetManagedObjects", 0, + get_managed_objects, "a{oa{sa{sv}}}", "", + "objpath_interfaces_and_properties"); + + l_dbus_interface_signal(interface, "InterfacesAdded", 0, "oa{sa{sv}}", + "object_path", "interfaces_and_properties"); + l_dbus_interface_signal(interface, "InterfacesRemoved", 0, "oas", + "object_path", "interfaces"); +} diff --git a/ell/dbus-service.h b/ell/dbus-service.h new file mode 100644 index 0000000000000000000000000000000000000000..5ef9710c808539fdb02ad12c9d7a651864627a8a --- /dev/null +++ b/ell/dbus-service.h @@ -0,0 +1,79 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_SERVICE_H +#define __ELL_SERVICE_H + +#include <stdint.h> +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct l_dbus; +struct l_dbus_interface; +struct l_dbus_message; + +enum l_dbus_method_flag { + L_DBUS_METHOD_FLAG_DEPRECATED = 1, + L_DBUS_METHOD_FLAG_NOREPLY = 2, + L_DBUS_METHOD_FLAG_ASYNC = 4, +}; + +enum l_dbus_signal_flag { + L_DBUS_SIGNAL_FLAG_DEPRECATED = 1, +}; + +enum l_dbus_property_flag { + L_DBUS_PROPERTY_FLAG_DEPRECATED = 1, + L_DBUS_PROPERTY_FLAG_AUTO_EMIT = 2, +}; + +typedef struct l_dbus_message *(*l_dbus_interface_method_cb_t) (struct l_dbus *, + struct l_dbus_message *message, + void *user_data); + +typedef void (*l_dbus_property_complete_cb_t) (struct l_dbus *, + struct l_dbus_message *, + struct l_dbus_message *error); + +typedef struct l_dbus_message *(*l_dbus_property_set_cb_t) (struct l_dbus *, + struct l_dbus_message *message, + struct l_dbus_message_iter *new_value, + l_dbus_property_complete_cb_t complete, + void *user_data); + +typedef bool (*l_dbus_property_get_cb_t) (struct l_dbus *, + struct l_dbus_message *message, + struct l_dbus_message_builder *builder, + void *user_data); + +bool l_dbus_interface_method(struct l_dbus_interface *interface, + const char *name, uint32_t flags, + l_dbus_interface_method_cb_t cb, + const char *return_sig, const char *param_sig, + ...); + +bool l_dbus_interface_signal(struct l_dbus_interface *interface, + const char *name, uint32_t flags, + const char *signature, ...); + +bool l_dbus_interface_property(struct l_dbus_interface *interface, + const char *name, uint32_t flags, + const char *signature, + l_dbus_property_get_cb_t getter, + l_dbus_property_set_cb_t setter); + +bool l_dbus_property_changed(struct l_dbus *dbus, const char *path, + const char *interface, const char *property); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_DBUS_SERVICE_H */ diff --git a/ell/dbus-util.c b/ell/dbus-util.c new file mode 100644 index 0000000000000000000000000000000000000000..3de81833468d620596298f09f45a2f0446dbfa6b --- /dev/null +++ b/ell/dbus-util.c @@ -0,0 +1,1299 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <stdbool.h> +#include <stdint.h> +#include <stddef.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +#include "dbus.h" +#include "private.h" +#include "useful.h" +#include "dbus-private.h" +#include "string.h" +#include "queue.h" +#include "utf8.h" + +#define DBUS_MAX_INTERFACE_LEN 255 +#define DBUS_MAX_METHOD_LEN 255 + +static const char *simple_types = "sogybnqiuxtdh"; + +static int get_alignment(const char type) +{ + switch (type) { + case 'b': + return 4; + case 'y': + return 1; + case 'n': + case 'q': + return 2; + case 'u': + case 'i': + return 4; + case 'x': + case 't': + case 'd': + return 8; + case 's': + case 'o': + return 4; + case 'g': + return 1; + case 'a': + return 4; + case '(': + case '{': + return 8; + case 'v': + return 1; + case 'h': + return 4; + default: + return 0; + } +} + +static int get_basic_size(const char type) +{ + switch (type) { + case 'b': + return 4; + case 'y': + return 1; + case 'n': + case 'q': + return 2; + case 'i': + case 'u': + return 4; + case 'x': + case 't': + return 8; + case 'd': + return 8; + case 'h': + return 4; + default: + return 0; + } +} + +static inline bool is_valid_character(const char c, bool bus_name) +{ + if (c >= 'a' && c <= 'z') + return true; + + if (c >= 'A' && c <= 'Z') + return true; + + if (c >= '0' && c <= '9') + return true; + + if (c == '_') + return true; + + if (c == '-' && bus_name) + return true; + + return false; +} + +bool _dbus_valid_object_path(const char *path) +{ + unsigned int i; + char c = '\0'; + + if (path == NULL) + return false; + + if (path[0] == '\0') + return false; + + if (path[0] && !path[1] && path[0] == '/') + return true; + + if (path[0] != '/') + return false; + + for (i = 0; path[i]; i++) { + if (path[i] == '/' && c == '/') + return false; + + c = path[i]; + + if (is_valid_character(path[i], false) || path[i] == '/') + continue; + + return false; + } + + if (path[i-1] == '/') + return false; + + return true; +} + +static const char *validate_next_type(const char *sig) +{ + char s = *sig; + + if (s == '\0') + return NULL; + + if (strchr(simple_types, s) || s == 'v') + return sig + 1; + + switch (s) { + case 'a': + s = *++sig; + + if (s == '{') { + s = *++sig; + + /* Dictionary keys can only be simple types */ + if (!strchr(simple_types, s)) + return NULL; + + sig = validate_next_type(sig + 1); + + if (!sig) + return NULL; + + if (*sig != '}') + return NULL; + + return sig + 1; + } + + return validate_next_type(sig); + + case '(': + sig++; + + do + sig = validate_next_type(sig); + while (sig && *sig != ')'); + + if (!sig) + return NULL; + + return sig + 1; + } + + return NULL; +} + +static bool valid_dict_signature(const char *sig) +{ + char s = *sig; + + if (s != '{') + return false; + + s = *++sig; + + if (!strchr(simple_types, s)) + return false; + + sig = validate_next_type(sig + 1); + if (!sig) + return false; + + if (sig[0] != '}') + return false; + + if (sig[1] != '\0') + return false; + + return true; +} + +bool _dbus_valid_signature(const char *sig) +{ + const char *s = sig; + + do { + s = validate_next_type(s); + + if (!s) + return false; + } while (*s); + + return true; +} + +int _dbus_num_children(const char *sig) +{ + const char *s = sig; + int num_children = 0; + + do { + s = validate_next_type(s); + + if (!s) + return -1; + + num_children += 1; + } while (*s); + + return num_children; +} + +static bool valid_member_name(const char *start, const char *end, + bool bus_name) +{ + const char *p; + + if ((end - start) < 1) + return false; + + if (*start >= '0' && *start <= '9') + return false; + + for (p = start; p < end; p++) + if (!is_valid_character(*p, bus_name)) + return false; + + return true; +} + +bool _dbus_valid_method(const char *method) +{ + unsigned int i; + + if (!method) + return false; + + if (method[0] == '\0' || strlen(method) > DBUS_MAX_METHOD_LEN) + return false; + + if (method[0] >= '0' && method[0] <= '9') + return false; + + for (i = 0; method[i]; i++) + if (!is_valid_character(method[i], false)) + return false; + + return true; +} + +bool _dbus_valid_interface(const char *interface) +{ + const char *sep; + + if (!interface) + return false; + + if (interface[0] == '\0' || strlen(interface) > DBUS_MAX_INTERFACE_LEN) + return false; + + sep = strchrnul(interface, '.'); + if (*sep == '\0') + return false; + + while (true) { + if (!valid_member_name(interface, sep, false)) + return false; + + if (*sep == '\0') + break; + + interface = sep + 1; + sep = strchrnul(interface, '.'); + } + + return true; +} + +bool _dbus_parse_unique_name(const char *name, uint64_t *out_id) +{ + char *endp = NULL; + uint64_t r; + + if (!l_str_has_prefix(name, ":1.")) + return false; + + name += 3; + + /* + * Disallow '+' or '-' at the beginning of the string + * must have at least one digit + */ + if (!l_ascii_isdigit(*name)) + return false; + + errno = 0; + r = strtoull(name, &endp, 10); + if (!endp || *endp || errno) + return false; + + if (out_id) + *out_id = r; + + return true; +} + +bool _dbus_valid_bus_name(const char *bus_name) +{ + const char *sep; + + if (!bus_name) + return false; + + if (bus_name[0] == '\0' || strlen(bus_name) > DBUS_MAX_INTERFACE_LEN) + return false; + + if (_dbus_parse_unique_name(bus_name, NULL)) + return true; + + sep = strchrnul(bus_name, '.'); + if (*sep == '\0') + return false; + + while (true) { + if (!valid_member_name(bus_name, sep, true)) + return false; + + if (*sep == '\0') + break; + + bus_name = sep + 1; + sep = strchrnul(bus_name, '.'); + } + + return true; +} + +const char *_dbus_signature_end(const char *signature) +{ + const char *ptr = signature; + unsigned int indent = 0; + char expect; + + switch (*signature) { + case '(': + expect = ')'; + break; + case '{': + expect = '}'; + break; + case 'a': + return _dbus_signature_end(signature + 1); + default: + return signature; + } + + for (ptr = signature; *ptr != '\0'; ptr++) { + if (*ptr == *signature) + indent++; + else if (*ptr == expect) + if (!--indent) + return ptr; + } + + return NULL; +} + +bool _dbus1_header_is_valid(void *data, size_t size) +{ + struct dbus_header *hdr; + size_t header_len; + + if (size < sizeof(struct dbus_header)) + return false; + + hdr = data; + + if (hdr->endian != DBUS_NATIVE_ENDIAN) + header_len = bswap_32(hdr->dbus1.field_length); + else + header_len = hdr->dbus1.field_length; + + header_len += sizeof(struct dbus_header); + return size >= header_len; +} + +static inline void dbus1_iter_init_internal(struct l_dbus_message_iter *iter, + struct l_dbus_message *message, + enum dbus_container_type type, + const char *sig_start, + const char *sig_end, + const void *data, size_t len, + size_t pos) +{ + size_t sig_len; + + iter->message = message; + + if (sig_end) + sig_len = sig_end - sig_start; + else + sig_len = strlen(sig_start); + + iter->sig_start = sig_start; + iter->sig_len = sig_len; + iter->sig_pos = 0; + iter->data = data; + iter->len = pos + len; + iter->pos = pos; + iter->container_type = type; +} + +void _dbus1_iter_init(struct l_dbus_message_iter *iter, + struct l_dbus_message *message, + const char *sig_start, const char *sig_end, + const void *data, size_t len) +{ + dbus1_iter_init_internal(iter, message, DBUS_CONTAINER_TYPE_STRUCT, + sig_start, sig_end, data, len, 0); +} + +static const char *calc_len_next_item(const char *signature, const void *data, + size_t data_pos, size_t data_len, + size_t *out_len) +{ + unsigned int alignment; + size_t pos; + size_t len; + const char *sig_end; + const char *var_sig; + + alignment = get_alignment(*signature); + if (alignment == 0) + return NULL; + + pos = align_len(data_pos, alignment); + if (pos > data_len) + return NULL; + + switch (*signature) { + case 'o': + case 's': + if (pos + 5 > data_len) + return NULL; + + pos += l_get_u32(data + pos) + 5; + break; + case 'g': + if (pos + 2 > data_len) + return NULL; + + pos += l_get_u8(data + pos) + 2; + break; + case 'y': + pos += 1; + break; + case 'n': + case 'q': + pos += 2; + break; + case 'b': + case 'i': + case 'u': + case 'h': + pos += 4; + break; + case 'x': + case 't': + case 'd': + pos += 8; + break; + case 'a': + if (pos + 4 > data_len) + return NULL; + + len = l_get_u32(data + pos); + pos += 4; + + alignment = get_alignment(signature[1]); + pos = align_len(pos, alignment); + pos += len; + + sig_end = _dbus_signature_end(signature) + 1; + goto done; + case '(': + sig_end = signature + 1; + + while (*sig_end != ')') { + sig_end = calc_len_next_item(sig_end, data, pos, + data_len, &len); + + if (!sig_end) + return NULL; + + pos += len; + } + + sig_end += 1; + goto done; + case '{': + sig_end = calc_len_next_item(signature + 1, data, pos, + data_len, &len); + + if (!sig_end) + return NULL; + + pos += len; + + sig_end = calc_len_next_item(sig_end, data, pos, + data_len, &len); + + if (!sig_end) + return NULL; + + pos += len; + sig_end += 1; + goto done; + case 'v': + if (!calc_len_next_item("g", data, pos, data_len, &len)) + return NULL; + + var_sig = data + pos + 1; + pos += len; + + if (!calc_len_next_item(var_sig, data, pos, data_len, &len)) + return NULL; + + pos += len; + break; + default: + return NULL; + } + + sig_end = signature + 1; + +done: + if (pos > data_len) + return NULL; + + *out_len = pos - data_pos; + return sig_end; +} + +bool _dbus1_iter_next_entry_basic(struct l_dbus_message_iter *iter, + char type, void *out) +{ + const char *str_val; + uint8_t uint8_val; + uint16_t uint16_val; + uint32_t uint32_val; + uint64_t uint64_val; + int16_t int16_val; + int32_t int32_val; + int64_t int64_val; + size_t pos; + + if (iter->pos >= iter->len) + return false; + + pos = align_len(iter->pos, get_alignment(type)); + + switch (type) { + case 'o': + case 's': + if (pos + 5 > iter->len) + return false; + uint32_val = l_get_u32(iter->data + pos); + str_val = iter->data + pos + 4; + *(const void **) out = str_val; + iter->pos = pos + uint32_val + 5; + break; + case 'g': + if (pos + 2 > iter->len) + return false; + uint8_val = l_get_u8(iter->data + pos); + str_val = iter->data + pos + 1; + *(const void **) out = str_val; + iter->pos = pos + uint8_val + 2; + break; + case 'b': + if (pos + 4 > iter->len) + return false; + uint32_val = l_get_u32(iter->data + pos); + *(bool *) out = !!uint32_val; + iter->pos = pos + 4; + break; + case 'y': + if (pos + 1 > iter->len) + return false; + uint8_val = l_get_u8(iter->data + pos); + *(uint8_t *) out = uint8_val; + iter->pos = pos + 1; + break; + case 'n': + if (pos + 2 > iter->len) + return false; + int16_val = l_get_s16(iter->data + pos); + *(int16_t *) out = int16_val; + iter->pos = pos + 2; + break; + case 'q': + if (pos + 2 > iter->len) + return false; + uint16_val = l_get_u16(iter->data + pos); + *(uint16_t *) out = uint16_val; + iter->pos = pos + 2; + break; + case 'i': + if (pos + 4 > iter->len) + return false; + int32_val = l_get_s32(iter->data + pos); + *(int32_t *) out = int32_val; + iter->pos = pos + 4; + break; + case 'u': + case 'h': + if (pos + 4 > iter->len) + return false; + uint32_val = l_get_u32(iter->data + pos); + *(uint32_t *) out = uint32_val; + iter->pos = pos + 4; + break; + case 'x': + if (pos + 8 > iter->len) + return false; + int64_val = l_get_s64(iter->data + pos); + *(int64_t *) out= int64_val; + iter->pos = pos + 8; + break; + case 't': + case 'd': + if (pos + 8 > iter->len) + return false; + uint64_val = l_get_u64(iter->data + pos); + *(uint64_t *) out = uint64_val; + iter->pos = pos + 8; + break; + default: + return false; + } + + if (iter->container_type != DBUS_CONTAINER_TYPE_ARRAY) + iter->sig_pos += 1; + + return true; +} + +bool _dbus1_iter_get_fixed_array(struct l_dbus_message_iter *iter, + void *out, uint32_t *n_elem) +{ + char type; + uint32_t size; + + if (iter->container_type != DBUS_CONTAINER_TYPE_ARRAY) + return false; + + type = iter->sig_start[iter->sig_pos]; + size = get_basic_size(type); + + /* Fail if the array is not a fixed size or contains file descriptors */ + if (!size || type == 'h') + return false; + + /* + * enter_array should already align us to our container type, so + * there is no need to align pos here + */ + *(const void **) out = iter->data + iter->pos; + *n_elem = (iter->len - iter->pos) / size; + + return true; +} + +bool _dbus1_iter_enter_struct(struct l_dbus_message_iter *iter, + struct l_dbus_message_iter *structure) +{ + size_t len; + size_t pos; + const char *sig_start; + const char *sig_end; + bool is_dict = iter->sig_start[iter->sig_pos] == '{'; + bool is_struct = iter->sig_start[iter->sig_pos] == '('; + + if (!is_dict && !is_struct) + return false; + + pos = align_len(iter->pos, 8); + if (pos >= iter->len) + return false; + + sig_start = iter->sig_start + iter->sig_pos + 1; + sig_end = _dbus_signature_end(iter->sig_start + iter->sig_pos); + + if (!calc_len_next_item(iter->sig_start + iter->sig_pos, + iter->data, pos, iter->len, &len)) + return false; + + dbus1_iter_init_internal(structure, iter->message, + DBUS_CONTAINER_TYPE_STRUCT, + sig_start, sig_end, iter->data, + len, pos); + + if (iter->container_type != DBUS_CONTAINER_TYPE_ARRAY) + iter->sig_pos += sig_end - sig_start + 2; + + iter->pos = pos + len; + + return true; +} + +bool _dbus1_iter_enter_variant(struct l_dbus_message_iter *iter, + struct l_dbus_message_iter *variant) +{ + size_t pos; + uint8_t sig_len; + size_t len; + const char *sig_start; + + if (iter->sig_start[iter->sig_pos] != 'v') + return false; + + pos = align_len(iter->pos, 1); + if (pos + 2 > iter->len) + return false; + + sig_len = l_get_u8(iter->data + pos); + sig_start = iter->data + pos + 1; + + if (!calc_len_next_item(sig_start, iter->data, pos + sig_len + 2, + iter->len, &len)) + return false; + + dbus1_iter_init_internal(variant, iter->message, + DBUS_CONTAINER_TYPE_VARIANT, + sig_start, NULL, iter->data, + len, pos + sig_len + 2); + + if (iter->container_type != DBUS_CONTAINER_TYPE_ARRAY) + iter->sig_pos += 1; + + iter->pos = pos + sig_len + 2 + len; + + return true; +} + +bool _dbus1_iter_enter_array(struct l_dbus_message_iter *iter, + struct l_dbus_message_iter *array) +{ + size_t pos; + size_t len; + const char *sig_start; + const char *sig_end; + + if (iter->sig_start[iter->sig_pos] != 'a') + return false; + + sig_start = iter->sig_start + iter->sig_pos + 1; + sig_end = _dbus_signature_end(sig_start) + 1; + + pos = align_len(iter->pos, 4); + if (pos + 4 > iter->len) + return false; + + len = l_get_u32(iter->data + pos); + pos += 4; + + pos = align_len(pos, get_alignment(*sig_start)); + dbus1_iter_init_internal(array, iter->message, + DBUS_CONTAINER_TYPE_ARRAY, + sig_start, sig_end, + iter->data, len, pos); + + if (iter->container_type != DBUS_CONTAINER_TYPE_ARRAY) + iter->sig_pos += sig_end - sig_start + 1; + + iter->pos = pos + len; + + return true; +} + +bool _dbus1_iter_skip_entry(struct l_dbus_message_iter *iter) +{ + size_t len; + const char *sig_end; + + sig_end = calc_len_next_item(iter->sig_start + iter->sig_pos, + iter->data, iter->pos, iter->len, &len); + if (!sig_end) + return false; + + iter->pos += len; + iter->sig_pos = sig_end - iter->sig_start; + + return true; +} + +struct dbus_builder { + struct l_string *signature; + void *body; + size_t body_size; + size_t body_pos; + struct l_queue *containers; + struct { + struct container *container; + int sig_end; + size_t body_pos; + } mark; +}; + +struct container { + size_t start; + enum dbus_container_type type; + char signature[256]; + uint8_t sigindex; +}; + +static struct container *container_new(enum dbus_container_type type, + const char *signature, size_t start) +{ + struct container *ret; + + ret = l_new(struct container, 1); + + ret->type = type; + strcpy(ret->signature, signature); + ret->start = start; + + return ret; +} + +static void container_free(struct container *container) +{ + l_free(container); +} + +static inline size_t grow_body(struct dbus_builder *builder, + size_t len, unsigned int alignment) +{ + size_t size = align_len(builder->body_pos, alignment); + + if (size + len > builder->body_size) { + builder->body = l_realloc(builder->body, size + len); + builder->body_size = size + len; + } + + if (size - builder->body_pos > 0) + memset(builder->body + builder->body_pos, 0, + size - builder->body_pos); + + builder->body_pos = size + len; + + return size; +} + +struct dbus_builder *_dbus1_builder_new(void *body, size_t body_size) +{ + struct dbus_builder *builder; + struct container *root; + + builder = l_new(struct dbus_builder, 1); + builder->signature = l_string_new(63); + + builder->containers = l_queue_new(); + root = container_new(DBUS_CONTAINER_TYPE_STRUCT, "", 0); + l_queue_push_head(builder->containers, root); + + builder->body = body; + builder->body_size = body_size; + builder->body_pos = body_size; + + builder->mark.container = root; + builder->mark.sig_end = 0; + builder->mark.body_pos = 0; + + return builder; +} + +void _dbus1_builder_free(struct dbus_builder *builder) +{ + if (unlikely(!builder)) + return; + + l_string_free(builder->signature); + l_queue_destroy(builder->containers, + (l_queue_destroy_func_t) container_free); + l_free(builder->body); + + l_free(builder); +} + +bool _dbus1_builder_append_basic(struct dbus_builder *builder, + char type, const void *value) +{ + struct container *container = l_queue_peek_head(builder->containers); + size_t start; + unsigned int alignment; + size_t len; + + if (unlikely(!builder)) + return false; + + if (unlikely(!strchr(simple_types, type))) + return false; + + alignment = get_alignment(type); + if (!alignment) + return false; + + if (l_queue_length(builder->containers) == 1) + l_string_append_c(builder->signature, type); + else if (container->signature[container->sigindex] != type) + return false; + + len = get_basic_size(type); + + if (len) { + uint32_t b; + + start = grow_body(builder, len, alignment); + + if (type == 'b') { + b = *(bool *)value; + memcpy(builder->body + start, &b, len); + } else + memcpy(builder->body + start, value, len); + + if (container->type != DBUS_CONTAINER_TYPE_ARRAY) + container->sigindex += 1; + + return true; + } + + len = strlen(value); + + if (type == 'g') { + start = grow_body(builder, len + 2, 1); + l_put_u8(len, builder->body + start); + strcpy(builder->body + start + 1, value); + } else { + start = grow_body(builder, len + 5, 4); + l_put_u32(len, builder->body + start); + strcpy(builder->body + start + 4, value); + } + + if (container->type != DBUS_CONTAINER_TYPE_ARRAY) + container->sigindex += 1; + + return true; +} + +static bool enter_struct_dict_common(struct dbus_builder *builder, + const char *signature, + enum dbus_container_type type, + const char open, + const char close) +{ + size_t qlen = l_queue_length(builder->containers); + struct container *container = l_queue_peek_head(builder->containers); + size_t start; + + if (qlen == 1) { + if (l_string_length(builder->signature) + + strlen(signature) + 2 > 255) + return false; + } else { + /* Verify Signatures Match */ + char expect[256]; + const char *start; + const char *end; + + start = container->signature + container->sigindex; + end = _dbus_signature_end(start); + + if (*start != open || *end != close) + return false; + + memcpy(expect, start + 1, end - start - 1); + expect[end - start - 1] = '\0'; + + if (strcmp(expect, signature)) + return false; + } + + start = grow_body(builder, 0, 8); + + container = container_new(type, signature, start); + l_queue_push_head(builder->containers, container); + + return true; +} + +bool _dbus1_builder_enter_struct(struct dbus_builder *builder, + const char *signature) +{ + if (!_dbus_valid_signature(signature)) + return false; + + return enter_struct_dict_common(builder, signature, + DBUS_CONTAINER_TYPE_STRUCT, '(', ')'); +} + +bool _dbus1_builder_enter_dict(struct dbus_builder *builder, + const char *signature) +{ + if (_dbus_num_children(signature) != 2) + return false; + + if (!strchr(simple_types, signature[0])) + return false; + + return enter_struct_dict_common(builder, signature, + DBUS_CONTAINER_TYPE_DICT_ENTRY, + '{', '}'); +} + +static bool leave_struct_dict_common(struct dbus_builder *builder, + enum dbus_container_type type, + const char open, + const char close) +{ + struct container *container = l_queue_peek_head(builder->containers); + size_t qlen = l_queue_length(builder->containers); + struct container *parent; + + if (unlikely(qlen <= 1)) + return false; + + if (unlikely(container->type != type)) + return false; + + l_queue_pop_head(builder->containers); + qlen -= 1; + parent = l_queue_peek_head(builder->containers); + + if (qlen == 1) + l_string_append_printf(builder->signature, "%c%s%c", + open, + container->signature, + close); + else if (parent->type != DBUS_CONTAINER_TYPE_ARRAY) + parent->sigindex += strlen(container->signature) + 2; + + container_free(container); + + return true; +} + +bool _dbus1_builder_leave_struct(struct dbus_builder *builder) +{ + return leave_struct_dict_common(builder, DBUS_CONTAINER_TYPE_STRUCT, + '(', ')'); +} + +bool _dbus1_builder_leave_dict(struct dbus_builder *builder) +{ + return leave_struct_dict_common(builder, + DBUS_CONTAINER_TYPE_DICT_ENTRY, + '{', '}'); +} + +bool _dbus1_builder_enter_variant(struct dbus_builder *builder, + const char *signature) +{ + size_t qlen = l_queue_length(builder->containers); + struct container *container = l_queue_peek_head(builder->containers); + size_t start; + size_t siglen; + + if (_dbus_num_children(signature) != 1) + return false; + + if (qlen == 1) { + if (l_string_length(builder->signature) + 1 > 255) + return false; + } else if (container->signature[container->sigindex] != 'v') + return false; + + siglen = strlen(signature); + start = grow_body(builder, siglen + 2, 1); + l_put_u8(siglen, builder->body + start); + strcpy(builder->body + start + 1, signature); + + container = container_new(DBUS_CONTAINER_TYPE_VARIANT, + signature, start); + l_queue_push_head(builder->containers, container); + + return true; +} + +bool _dbus1_builder_leave_variant(struct dbus_builder *builder) +{ + struct container *container = l_queue_peek_head(builder->containers); + size_t qlen = l_queue_length(builder->containers); + struct container *parent; + + if (unlikely(qlen <= 1)) + return false; + + if (unlikely(container->type != DBUS_CONTAINER_TYPE_VARIANT)) + return false; + + l_queue_pop_head(builder->containers); + qlen -= 1; + parent = l_queue_peek_head(builder->containers); + + if (qlen == 1) + l_string_append_c(builder->signature, 'v'); + else if (parent->type != DBUS_CONTAINER_TYPE_ARRAY) + parent->sigindex += 1; + + container_free(container); + + return true; +} + +bool _dbus1_builder_enter_array(struct dbus_builder *builder, + const char *signature) +{ + size_t qlen = l_queue_length(builder->containers); + struct container *container = l_queue_peek_head(builder->containers); + size_t start; + int alignment; + + if (_dbus_num_children(signature) != 1 && + !valid_dict_signature(signature)) + return false; + + if (qlen == 1) { + if (l_string_length(builder->signature) + + strlen(signature) + 1 > 255) + return false; + } else { + /* Verify Signatures Match */ + char expect[256]; + const char *start; + const char *end; + + start = container->signature + container->sigindex; + end = validate_next_type(start); + + if (*start != 'a') + return false; + + memcpy(expect, start + 1, end - start - 1); + expect[end - start - 1] = '\0'; + + if (strcmp(expect, signature)) + return false; + } + + /* First grow the body enough to cover preceding length */ + start = grow_body(builder, 4, 4); + + /* Now align to element alignment */ + alignment = get_alignment(*signature); + grow_body(builder, 0, alignment); + + container = container_new(DBUS_CONTAINER_TYPE_ARRAY, signature, start); + l_queue_push_head(builder->containers, container); + + return true; +} + +bool _dbus1_builder_leave_array(struct dbus_builder *builder) +{ + struct container *container = l_queue_peek_head(builder->containers); + size_t qlen = l_queue_length(builder->containers); + struct container *parent; + size_t alignment; + size_t array_start; + + if (unlikely(qlen <= 1)) + return false; + + if (unlikely(container->type != DBUS_CONTAINER_TYPE_ARRAY)) + return false; + + l_queue_pop_head(builder->containers); + qlen -= 1; + parent = l_queue_peek_head(builder->containers); + + if (qlen == 1) + l_string_append_printf(builder->signature, "a%s", + container->signature); + else if (parent->type != DBUS_CONTAINER_TYPE_ARRAY) + parent->sigindex += strlen(container->signature) + 1; + + /* Update array length */ + alignment = get_alignment(container->signature[0]); + array_start = align_len(container->start + 4, alignment); + + l_put_u32(builder->body_pos - array_start, + builder->body + container->start); + + container_free(container); + + return true; +} + +bool _dbus1_builder_mark(struct dbus_builder *builder) +{ + struct container *container = l_queue_peek_head(builder->containers); + + builder->mark.container = container; + + if (l_queue_length(builder->containers) == 1) + builder->mark.sig_end = l_string_length(builder->signature); + else + builder->mark.sig_end = container->sigindex; + + builder->mark.body_pos = builder->body_pos; + + return true; +} + +bool _dbus1_builder_rewind(struct dbus_builder *builder) +{ + struct container *container; + + while ((container = l_queue_peek_head(builder->containers)) != + builder->mark.container) { + container_free(container); + l_queue_pop_head(builder->containers); + } + + builder->body_pos = builder->mark.body_pos; + + if (l_queue_length(builder->containers) == 1) + l_string_truncate(builder->signature, builder->mark.sig_end); + else + container->sigindex = builder->mark.sig_end; + + return true; +} + +char *_dbus1_builder_finish(struct dbus_builder *builder, + void **body, size_t *body_size) +{ + char *signature; + + if (unlikely(!builder)) + return NULL; + + if (unlikely(l_queue_length(builder->containers) != 1)) + return NULL; + + signature = l_string_unwrap(builder->signature); + builder->signature = NULL; + + *body = builder->body; + *body_size = builder->body_pos; + builder->body = NULL; + builder->body_size = 0; + + return signature; +} diff --git a/ell/dbus.c b/ell/dbus.c new file mode 100644 index 0000000000000000000000000000000000000000..bd6e1b8c3e883fc0b88419bf1d87b79315ebb29f --- /dev/null +++ b/ell/dbus.c @@ -0,0 +1,1932 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <netdb.h> +#include <errno.h> + +#include "util.h" +#include "io.h" +#include "idle.h" +#include "queue.h" +#include "hashmap.h" +#include "dbus.h" +#include "private.h" +#include "useful.h" +#include "dbus-private.h" + +#define DEFAULT_SYSTEM_BUS_ADDRESS "unix:path=/var/run/dbus/system_bus_socket" + +#define DBUS_SERVICE_DBUS "org.freedesktop.DBus" + +#define DBUS_PATH_DBUS "/org/freedesktop/DBus" + +#define DBUS_MAXIMUM_MATCH_RULE_LENGTH 1024 + +enum auth_state { + WAITING_FOR_OK, + WAITING_FOR_AGREE_UNIX_FD, + SETUP_DONE +}; + +struct l_dbus_ops { + char version; + bool (*send_message)(struct l_dbus *bus, + struct l_dbus_message *message); + struct l_dbus_message *(*recv_message)(struct l_dbus *bus); + void (*free)(struct l_dbus *bus); + struct _dbus_name_ops name_ops; + struct _dbus_filter_ops filter_ops; + uint32_t (*name_acquire)(struct l_dbus *dbus, const char *name, + bool allow_replacement, bool replace_existing, + bool queue, l_dbus_name_acquire_func_t callback, + void *user_data); +}; + +struct l_dbus { + struct l_io *io; + char *guid; + bool negotiate_unix_fd; + bool support_unix_fd; + bool is_ready; + char *unique_name; + unsigned int next_id; + uint32_t next_serial; + struct l_queue *message_queue; + struct l_hashmap *message_list; + struct l_hashmap *signal_list; + l_dbus_ready_func_t ready_handler; + l_dbus_destroy_func_t ready_destroy; + void *ready_data; + l_dbus_disconnect_func_t disconnect_handler; + l_dbus_destroy_func_t disconnect_destroy; + void *disconnect_data; + l_dbus_debug_func_t debug_handler; + l_dbus_destroy_func_t debug_destroy; + void *debug_data; + struct _dbus_object_tree *tree; + struct _dbus_name_cache *name_cache; + struct _dbus_filter *filter; + bool name_notify_enabled; + + const struct l_dbus_ops *driver; +}; + +struct l_dbus_classic { + struct l_dbus super; + void *auth_command; + enum auth_state auth_state; + bool skip_hello; + struct l_hashmap *match_strings; + int *fd_buf; + unsigned int num_fds; +}; + +struct message_callback { + uint32_t serial; + struct l_dbus_message *message; + l_dbus_message_func_t callback; + l_dbus_destroy_func_t destroy; + void *user_data; +}; + +struct signal_callback { + unsigned int id; + l_dbus_message_func_t callback; + l_dbus_destroy_func_t destroy; + void *user_data; +}; + +static void message_queue_destroy(void *data) +{ + struct message_callback *callback = data; + + l_dbus_message_unref(callback->message); + + if (callback->destroy) + callback->destroy(callback->user_data); + + l_free(callback); +} + +static void message_list_destroy(void *value) +{ + message_queue_destroy(value); +} + +static void signal_list_destroy(void *value) +{ + struct signal_callback *callback = value; + + if (callback->destroy) + callback->destroy(callback->user_data); + + l_free(callback); +} + +static bool message_write_handler(struct l_io *io, void *user_data) +{ + struct l_dbus *dbus = user_data; + struct l_dbus_message *message; + struct message_callback *callback; + const void *header, *body; + size_t header_size, body_size; + + callback = l_queue_pop_head(dbus->message_queue); + if (!callback) + return false; + + message = callback->message; + if (_dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL && + callback->callback == NULL) + l_dbus_message_set_no_reply(message, true); + + _dbus_message_set_serial(message, callback->serial); + + if (!dbus->driver->send_message(dbus, message)) { + message_queue_destroy(callback); + return false; + } + + header = _dbus_message_get_header(message, &header_size); + body = _dbus_message_get_body(message, &body_size); + l_util_hexdump_two(false, header, header_size, body, body_size, + dbus->debug_handler, dbus->debug_data); + + if (callback->callback == NULL) { + message_queue_destroy(callback); + goto done; + } + + l_hashmap_insert(dbus->message_list, + L_UINT_TO_PTR(callback->serial), callback); + +done: + if (l_queue_isempty(dbus->message_queue)) + return false; + + /* Only continue sending messges if the connection is ready */ + return dbus->is_ready; +} + +static void handle_method_return(struct l_dbus *dbus, + struct l_dbus_message *message) +{ + struct message_callback *callback; + uint32_t reply_serial; + + reply_serial = _dbus_message_get_reply_serial(message); + if (reply_serial == 0) + return; + + callback = l_hashmap_remove(dbus->message_list, + L_UINT_TO_PTR(reply_serial)); + if (!callback) + return; + + if (callback->callback) + callback->callback(message, callback->user_data); + + message_queue_destroy(callback); +} + +static void handle_error(struct l_dbus *dbus, struct l_dbus_message *message) +{ + struct message_callback *callback; + uint32_t reply_serial; + + reply_serial = _dbus_message_get_reply_serial(message); + if (reply_serial == 0) + return; + + callback = l_hashmap_remove(dbus->message_list, + L_UINT_TO_PTR(reply_serial)); + if (!callback) + return; + + if (callback->callback) + callback->callback(message, callback->user_data); + + message_queue_destroy(callback); +} + +static void process_signal(const void *key, void *value, void *user_data) +{ + struct signal_callback *callback = value; + struct l_dbus_message *message = user_data; + + if (callback->callback) + callback->callback(message, callback->user_data); +} + +static void handle_signal(struct l_dbus *dbus, struct l_dbus_message *message) +{ + l_hashmap_foreach(dbus->signal_list, process_signal, message); +} + +static bool message_read_handler(struct l_io *io, void *user_data) +{ + struct l_dbus *dbus = user_data; + struct l_dbus_message *message; + const void *header, *body; + size_t header_size, body_size; + enum dbus_message_type msgtype; + + message = dbus->driver->recv_message(dbus); + if (!message) + return true; + + header = _dbus_message_get_header(message, &header_size); + body = _dbus_message_get_body(message, &body_size); + l_util_hexdump_two(true, header, header_size, body, body_size, + dbus->debug_handler, dbus->debug_data); + + msgtype = _dbus_message_get_type(message); + + switch (msgtype) { + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + handle_method_return(dbus, message); + break; + case DBUS_MESSAGE_TYPE_ERROR: + handle_error(dbus, message); + break; + case DBUS_MESSAGE_TYPE_SIGNAL: + handle_signal(dbus, message); + break; + case DBUS_MESSAGE_TYPE_METHOD_CALL: + if (!_dbus_object_tree_dispatch(dbus->tree, dbus, message)) { + struct l_dbus_message *error; + + error = l_dbus_message_new_error(message, + "org.freedesktop.DBus.Error.NotFound", + "No matching method found"); + l_dbus_send(dbus, error); + } + + break; + } + + l_dbus_message_unref(message); + + return true; +} + +static uint32_t send_message(struct l_dbus *dbus, bool priority, + struct l_dbus_message *message, + l_dbus_message_func_t function, + void *user_data, l_dbus_destroy_func_t destroy) +{ + struct message_callback *callback; + enum dbus_message_type type; + const char *path; + + type = _dbus_message_get_type(message); + + if ((type == DBUS_MESSAGE_TYPE_METHOD_RETURN || + type == DBUS_MESSAGE_TYPE_ERROR) && + _dbus_message_get_reply_serial(message) == 0) { + l_dbus_message_unref(message); + return 0; + } + + /* Default empty signature for method return messages */ + if (type == DBUS_MESSAGE_TYPE_METHOD_RETURN && + !l_dbus_message_get_signature(message)) + l_dbus_message_set_arguments(message, ""); + + callback = l_new(struct message_callback, 1); + + callback->serial = dbus->next_serial++; + callback->message = message; + callback->callback = function; + callback->destroy = destroy; + callback->user_data = user_data; + + if (priority) { + l_queue_push_head(dbus->message_queue, callback); + + l_io_set_write_handler(dbus->io, message_write_handler, + dbus, NULL); + + return callback->serial; + } + + path = l_dbus_message_get_path(message); + if (path) + _dbus_object_tree_signals_flush(dbus, path); + + l_queue_push_tail(dbus->message_queue, callback); + + if (dbus->is_ready) + l_io_set_write_handler(dbus->io, message_write_handler, + dbus, NULL); + + return callback->serial; +} + +static void bus_ready(struct l_dbus *dbus) +{ + dbus->is_ready = true; + + if (dbus->ready_handler) + dbus->ready_handler(dbus->ready_data); + + l_io_set_read_handler(dbus->io, message_read_handler, dbus, NULL); + + /* Check for messages added before the connection was ready */ + if (l_queue_isempty(dbus->message_queue)) + return; + + l_io_set_write_handler(dbus->io, message_write_handler, dbus, NULL); +} + +static void hello_callback(struct l_dbus_message *message, void *user_data) +{ + struct l_dbus *dbus = user_data; + const char *signature; + const char *unique_name; + + signature = l_dbus_message_get_signature(message); + if (!signature || strcmp(signature, "s")) { + close(l_io_get_fd(dbus->io)); + return; + } + + if (!l_dbus_message_get_arguments(message, "s", &unique_name)) { + close(l_io_get_fd(dbus->io)); + return; + } + + dbus->unique_name = l_strdup(unique_name); + + bus_ready(dbus); +} + +static bool auth_write_handler(struct l_io *io, void *user_data) +{ + struct l_dbus_classic *classic = user_data; + struct l_dbus *dbus = &classic->super; + ssize_t written, len; + int fd; + + fd = l_io_get_fd(io); + + if (!classic->auth_command) + return false; + + len = strlen(classic->auth_command); + if (!len) + return false; + + written = L_TFR(send(fd, classic->auth_command, len, 0)); + if (written < 0) + return false; + + l_util_hexdump(false, classic->auth_command, written, + dbus->debug_handler, dbus->debug_data); + + if (written < len) { + memmove(classic->auth_command, classic->auth_command + written, + len + 1 - written); + return true; + } + + l_free(classic->auth_command); + classic->auth_command = NULL; + + if (classic->auth_state == SETUP_DONE) { + struct l_dbus_message *message; + + if (classic->skip_hello) { + bus_ready(dbus); + return true; + } + + l_io_set_read_handler(dbus->io, message_read_handler, + dbus, NULL); + + message = l_dbus_message_new_method_call(dbus, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + L_DBUS_INTERFACE_DBUS, + "Hello"); + l_dbus_message_set_arguments(message, ""); + + send_message(dbus, true, message, hello_callback, dbus, NULL); + + return true; + } + + return false; +} + +static bool auth_read_handler(struct l_io *io, void *user_data) +{ + struct l_dbus_classic *classic = user_data; + struct l_dbus *dbus = &classic->super; + char buffer[64]; + char *ptr, *end; + ssize_t offset, len; + int fd; + + fd = l_io_get_fd(io); + + ptr = buffer; + offset = 0; + + while (1) { + len = L_TFR(recv(fd, ptr + offset, + sizeof(buffer) - offset, + MSG_DONTWAIT)); + if (len < 0) { + if (errno != EAGAIN) + return false; + + break; + } + + offset += len; + } + + ptr = buffer; + len = offset; + + if (!ptr || len < 3) + return true; + + end = strstr(ptr, "\r\n"); + if (!end) + return true; + + if (end - ptr + 2 != len) + return true; + + l_util_hexdump(true, ptr, len, dbus->debug_handler, dbus->debug_data); + + *end = '\0'; + + switch (classic->auth_state) { + case WAITING_FOR_OK: + if (!strncmp(ptr, "OK ", 3)) { + enum auth_state state; + const char *command; + + if (dbus->negotiate_unix_fd) { + command = "NEGOTIATE_UNIX_FD\r\n"; + state = WAITING_FOR_AGREE_UNIX_FD; + } else { + command = "BEGIN\r\n"; + state = SETUP_DONE; + } + + l_free(dbus->guid); + dbus->guid = l_strdup(ptr + 3); + + classic->auth_command = l_strdup(command); + classic->auth_state = state; + break; + } else if (!strncmp(ptr, "REJECTED ", 9)) { + static const char *command = "AUTH ANONYMOUS\r\n"; + + dbus->negotiate_unix_fd = true; + + classic->auth_command = l_strdup(command); + classic->auth_state = WAITING_FOR_OK; + } + break; + + case WAITING_FOR_AGREE_UNIX_FD: + if (!strncmp(ptr, "AGREE_UNIX_FD", 13)) { + static const char *command = "BEGIN\r\n"; + + dbus->support_unix_fd = true; + + classic->auth_command = l_strdup(command); + classic->auth_state = SETUP_DONE; + break; + } else if (!strncmp(ptr, "ERROR", 5)) { + static const char *command = "BEGIN\r\n"; + + dbus->support_unix_fd = false; + + classic->auth_command = l_strdup(command); + classic->auth_state = SETUP_DONE; + break; + } + break; + + case SETUP_DONE: + break; + } + + l_io_set_write_handler(io, auth_write_handler, dbus, NULL); + + return true; +} + +static void disconnect_handler(struct l_io *io, void *user_data) +{ + struct l_dbus *dbus = user_data; + + dbus->is_ready = false; + + l_util_debug(dbus->debug_handler, dbus->debug_data, "disconnect"); + + if (dbus->disconnect_handler) + dbus->disconnect_handler(dbus->disconnect_data); +} + +static void dbus_init(struct l_dbus *dbus, int fd) +{ + dbus->io = l_io_new(fd); + l_io_set_close_on_destroy(dbus->io, true); + l_io_set_disconnect_handler(dbus->io, disconnect_handler, dbus, NULL); + + dbus->is_ready = false; + dbus->next_id = 1; + dbus->next_serial = 1; + + dbus->message_queue = l_queue_new(); + dbus->message_list = l_hashmap_new(); + dbus->signal_list = l_hashmap_new(); + + dbus->tree = _dbus_object_tree_new(); +} + +static void classic_free(struct l_dbus *dbus) +{ + struct l_dbus_classic *classic = + l_container_of(dbus, struct l_dbus_classic, super); + unsigned int i; + + for (i = 0; i < classic->num_fds; i++) + close(classic->fd_buf[i]); + l_free(classic->fd_buf); + + l_free(classic->auth_command); + l_hashmap_destroy(classic->match_strings, l_free); + l_free(classic); +} + +static bool classic_send_message(struct l_dbus *dbus, + struct l_dbus_message *message) +{ + int fd = l_io_get_fd(dbus->io); + struct msghdr msg; + struct iovec iov[2], *iovpos; + ssize_t r; + int *fds = NULL; + uint32_t num_fds = 0; + struct cmsghdr *cmsg; + int iovlen; + + iov[0].iov_base = _dbus_message_get_header(message, &iov[0].iov_len); + iov[1].iov_base = _dbus_message_get_body(message, &iov[1].iov_len); + + if (dbus->support_unix_fd) + fds = _dbus_message_get_fds(message, &num_fds); + + iovpos = iov; + iovlen = 2; + + while (1) { + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = iovpos; + msg.msg_iovlen = iovlen; + + if (num_fds) { + msg.msg_control = + alloca(CMSG_SPACE(num_fds * sizeof(int))); + msg.msg_controllen = CMSG_LEN(num_fds * sizeof(int)); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = msg.msg_controllen; + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + memcpy(CMSG_DATA(cmsg), fds, num_fds * sizeof(int)); + } + + r = L_TFR(sendmsg(fd, &msg, 0)); + if (r < 0) + return false; + + while ((size_t) r >= iovpos->iov_len) { + r -= iovpos->iov_len; + iovpos++; + iovlen--; + + if (!iovlen) + break; + } + + if (!iovlen) + break; + + iovpos->iov_base += r; + iovpos->iov_len -= r; + + /* The FDs have been transmitted, don't retransmit */ + num_fds = 0; + } + + return true; +} + +static struct l_dbus_message *classic_recv_message(struct l_dbus *dbus) +{ + struct l_dbus_classic *classic = + l_container_of(dbus, struct l_dbus_classic, super); + int fd = l_io_get_fd(dbus->io); + struct dbus_header hdr; + struct msghdr msg; + struct iovec iov[2], *iovpos; + struct cmsghdr *cmsg; + ssize_t len, r; + void *header, *body; + size_t header_size, body_size; + union { + uint8_t bytes[CMSG_SPACE(16 * sizeof(int))]; + struct cmsghdr align; + } fd_buf; + int *fds = NULL; + uint32_t num_fds = 0; + int iovlen; + struct l_dbus_message *message; + unsigned int i; + + len = recv(fd, &hdr, DBUS_HEADER_SIZE, MSG_PEEK | MSG_DONTWAIT); + if (len != DBUS_HEADER_SIZE) + return NULL; + + header_size = align_len(DBUS_HEADER_SIZE + hdr.dbus1.field_length, 8); + header = l_malloc(header_size); + + body_size = hdr.dbus1.body_length; + body = l_malloc(body_size); + + iov[0].iov_base = header; + iov[0].iov_len = header_size; + iov[1].iov_base = body; + iov[1].iov_len = body_size; + + iovpos = iov; + iovlen = 2; + + while (1) { + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = iovpos; + msg.msg_iovlen = iovlen; + msg.msg_control = &fd_buf; + msg.msg_controllen = sizeof(fd_buf); + + r = L_TFR(recvmsg(fd, &msg, + MSG_CMSG_CLOEXEC | MSG_WAITALL)); + if (r < 0) + goto cmsg_fail; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level != SOL_SOCKET || + cmsg->cmsg_type != SCM_RIGHTS) + continue; + + num_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + fds = (void *) CMSG_DATA(cmsg); + + /* Set FD_CLOEXEC on all file descriptors */ + for (i = 0; i < num_fds; i++) { + long flags; + + flags = fcntl(fds[i], F_GETFD, NULL); + if (flags < 0) + continue; + + if (!(flags & FD_CLOEXEC)) + fcntl(fds[i], F_SETFD, + flags | FD_CLOEXEC); + } + + classic->fd_buf = l_realloc(classic->fd_buf, + (classic->num_fds + num_fds) * + sizeof(int)); + memcpy(classic->fd_buf + classic->num_fds, fds, + num_fds * sizeof(int)); + classic->num_fds += num_fds; + } + + while ((size_t) r >= iovpos->iov_len) { + r -= iovpos->iov_len; + iovpos++; + iovlen--; + + if (!iovlen) + break; + } + + if (!iovlen) + break; + + iovpos->iov_base += r; + iovpos->iov_len -= r; + } + + if (hdr.endian != DBUS_NATIVE_ENDIAN) { + l_util_debug(dbus->debug_handler, + dbus->debug_data, "Endianness incorrect"); + goto bad_msg; + } + + if (hdr.version != 1) { + l_util_debug(dbus->debug_handler, + dbus->debug_data, "Protocol version incorrect"); + goto bad_msg; + } + + num_fds = _dbus_message_unix_fds_from_header(header, header_size); + if (num_fds > classic->num_fds) + goto bad_msg; + + message = dbus_message_build(header, header_size, body, body_size, + classic->fd_buf, num_fds); + + if (message && num_fds) { + if (classic->num_fds > num_fds) { + memmove(classic->fd_buf, classic->fd_buf + num_fds, + (classic->num_fds - num_fds) * sizeof(int)); + classic->num_fds -= num_fds; + } else { + l_free(classic->fd_buf); + + classic->fd_buf = NULL; + classic->num_fds = 0; + } + } + + if (message) + return message; + +bad_msg: +cmsg_fail: + for (i = 0; i < classic->num_fds; i++) + close(classic->fd_buf[i]); + + l_free(classic->fd_buf); + + classic->fd_buf = NULL; + classic->num_fds = 0; + + l_free(header); + l_free(body); + + return NULL; +} + +static bool classic_add_match(struct l_dbus *dbus, unsigned int id, + const struct _dbus_filter_condition *rule, + int rule_len) +{ + struct l_dbus_classic *classic = + l_container_of(dbus, struct l_dbus_classic, super); + char *match_str; + struct l_dbus_message *message; + + match_str = _dbus_filter_rule_to_str(rule, rule_len); + + l_hashmap_insert(classic->match_strings, L_UINT_TO_PTR(id), match_str); + + message = l_dbus_message_new_method_call(dbus, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + L_DBUS_INTERFACE_DBUS, + "AddMatch"); + + l_dbus_message_set_arguments(message, "s", match_str); + + send_message(dbus, false, message, NULL, NULL, NULL); + + return true; +} + +static bool classic_remove_match(struct l_dbus *dbus, unsigned int id) +{ + struct l_dbus_classic *classic = + l_container_of(dbus, struct l_dbus_classic, super); + char *match_str = l_hashmap_remove(classic->match_strings, + L_UINT_TO_PTR(id)); + struct l_dbus_message *message; + + if (!match_str) + return false; + + message = l_dbus_message_new_method_call(dbus, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + L_DBUS_INTERFACE_DBUS, + "RemoveMatch"); + + l_dbus_message_set_arguments(message, "s", match_str); + + send_message(dbus, false, message, NULL, NULL, NULL); + + l_free(match_str); + + return true; +} + +static void name_owner_changed_cb(struct l_dbus_message *message, + void *user_data) +{ + struct l_dbus *dbus = user_data; + char *name, *old, *new; + + if (!l_dbus_message_get_arguments(message, "sss", &name, &old, &new)) + return; + + _dbus_name_cache_notify(dbus->name_cache, name, new); +} + +struct get_name_owner_request { + struct l_dbus_message *message; + struct l_dbus *dbus; +}; + +static void get_name_owner_reply_cb(struct l_dbus_message *reply, + void *user_data) +{ + struct get_name_owner_request *req = user_data; + const char *name, *owner; + + /* No name owner yet */ + if (l_dbus_message_is_error(reply)) + return; + + /* Shouldn't happen */ + if (!l_dbus_message_get_arguments(reply, "s", &owner)) + return; + + /* Shouldn't happen */ + if (!l_dbus_message_get_arguments(req->message, "s", &name)) + return; + + _dbus_name_cache_notify(req->dbus->name_cache, name, owner); +} + +static bool classic_get_name_owner(struct l_dbus *bus, const char *name) +{ + struct get_name_owner_request *req; + + /* Name resolution is not performed for DBUS_SERVICE_DBUS */ + if (!strcmp(name, DBUS_SERVICE_DBUS)) + return false; + + req = l_new(struct get_name_owner_request, 1); + req->dbus = bus; + req->message = l_dbus_message_new_method_call(bus, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + L_DBUS_INTERFACE_DBUS, + "GetNameOwner"); + + l_dbus_message_set_arguments(req->message, "s", name); + + send_message(bus, false, req->message, get_name_owner_reply_cb, + req, l_free); + + if (!bus->name_notify_enabled) { + static struct _dbus_filter_condition rule[] = { + { L_DBUS_MATCH_TYPE, "signal" }, + { L_DBUS_MATCH_SENDER, DBUS_SERVICE_DBUS }, + { L_DBUS_MATCH_PATH, DBUS_PATH_DBUS }, + { L_DBUS_MATCH_INTERFACE, L_DBUS_INTERFACE_DBUS }, + { L_DBUS_MATCH_MEMBER, "NameOwnerChanged" }, + }; + + if (!bus->filter) + bus->filter = _dbus_filter_new(bus, + &bus->driver->filter_ops, + bus->name_cache); + + _dbus_filter_add_rule(bus->filter, rule, L_ARRAY_SIZE(rule), + name_owner_changed_cb, bus); + + bus->name_notify_enabled = true; + } + + return true; +} + +struct name_request { + l_dbus_name_acquire_func_t callback; + void *user_data; + struct l_dbus *dbus; +}; + +enum dbus_name_flag { + DBUS_NAME_FLAG_ALLOW_REPLACEMENT = 0x1, + DBUS_NAME_FLAG_REPLACE_EXISTING = 0x2, + DBUS_NAME_FLAG_DO_NOT_QUEUE = 0x4, +}; + +enum dbus_name_reply { + DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER = 1, + DBUS_REQUEST_NAME_REPLY_IN_QUEUE = 2, + DBUS_REQUEST_NAME_REPLY_EXISTS = 3, + DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER = 4, +}; + +static void request_name_reply_cb(struct l_dbus_message *reply, void *user_data) +{ + struct name_request *req = user_data; + bool success = false, queued = false; + uint32_t retval; + + if (!req->callback) + return; + + /* No name owner yet */ + if (l_dbus_message_is_error(reply)) + goto call_back; + + /* Shouldn't happen */ + if (!l_dbus_message_get_arguments(reply, "u", &retval)) + goto call_back; + + success = (retval == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) || + (retval == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER) || + (retval == DBUS_REQUEST_NAME_REPLY_IN_QUEUE); + queued = (retval == DBUS_REQUEST_NAME_REPLY_IN_QUEUE); + +call_back: + req->callback(req->dbus, success, queued, req->user_data); +} + +static uint32_t classic_name_acquire(struct l_dbus *dbus, const char *name, + bool allow_replacement, + bool replace_existing, bool queue, + l_dbus_name_acquire_func_t callback, + void *user_data) +{ + struct name_request *req; + struct l_dbus_message *message; + uint32_t flags = 0; + + req = l_new(struct name_request, 1); + req->dbus = dbus; + req->user_data = user_data; + req->callback = callback; + + message = l_dbus_message_new_method_call(dbus, DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + L_DBUS_INTERFACE_DBUS, + "RequestName"); + + if (allow_replacement) + flags |= DBUS_NAME_FLAG_ALLOW_REPLACEMENT; + + if (replace_existing) + flags |= DBUS_NAME_FLAG_REPLACE_EXISTING; + + if (!queue) + flags |= DBUS_NAME_FLAG_DO_NOT_QUEUE; + + l_dbus_message_set_arguments(message, "su", name, flags); + + return send_message(dbus, false, message, request_name_reply_cb, + req, free); +} + +static const struct l_dbus_ops classic_ops = { + .version = 1, + .send_message = classic_send_message, + .recv_message = classic_recv_message, + .free = classic_free, + .name_ops = { + .get_name_owner = classic_get_name_owner, + }, + .filter_ops = { + .add_match = classic_add_match, + .remove_match = classic_remove_match, + }, + .name_acquire = classic_name_acquire, +}; + +static struct l_dbus *setup_dbus1(int fd, const char *guid, bool skip_hello) +{ + static const unsigned char creds = 0x00; + char uid[6], hexuid[12], *ptr = hexuid; + struct l_dbus *dbus; + struct l_dbus_classic *classic; + ssize_t written; + unsigned int i; + + if (snprintf(uid, sizeof(uid), "%d", geteuid()) < 1) { + close(fd); + return NULL; + } + + for (i = 0; i < strlen(uid); i++) + ptr += sprintf(ptr, "%02x", uid[i]); + + /* Send special credentials-passing nul byte */ + written = L_TFR(send(fd, &creds, 1, 0)); + if (written < 1) { + close(fd); + return NULL; + } + + classic = l_new(struct l_dbus_classic, 1); + dbus = &classic->super; + dbus->driver = &classic_ops; + + classic->match_strings = l_hashmap_new(); + + dbus_init(dbus, fd); + dbus->guid = l_strdup(guid); + + classic->auth_command = l_strdup_printf("AUTH EXTERNAL %s\r\n", hexuid); + classic->auth_state = WAITING_FOR_OK; + classic->skip_hello = skip_hello; + + dbus->negotiate_unix_fd = true; + dbus->support_unix_fd = false; + + l_io_set_read_handler(dbus->io, auth_read_handler, dbus, NULL); + l_io_set_write_handler(dbus->io, auth_write_handler, dbus, NULL); + + return dbus; +} + +static struct l_dbus *setup_unix(char *params) +{ + char *path = NULL, *guid = NULL; + bool abstract = false; + struct sockaddr_un addr; + size_t len; + int fd; + + while (params) { + char *key = strsep(¶ms, ","); + char *value; + + if (!key) + break; + + value = strchr(key, '='); + if (!value) + continue; + + *value++ = '\0'; + + if (!strcmp(key, "path")) { + path = value; + abstract = false; + } else if (!strcmp(key, "abstract")) { + path = value; + abstract = true; + } else if (!strcmp(key, "guid")) + guid = value; + } + + if (!path) + return NULL; + + fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) + return NULL; + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + + len = strlen(path); + + if (abstract) { + if (len > sizeof(addr.sun_path) - 1) { + close(fd); + return NULL; + } + + addr.sun_path[0] = '\0'; + strncpy(addr.sun_path + 1, path, sizeof(addr.sun_path) - 2); + len++; + } else { + if (len > sizeof(addr.sun_path)) { + close(fd); + return NULL; + } + + strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); + } + + if (connect(fd, (struct sockaddr *) &addr, + sizeof(addr.sun_family) + len) < 0) { + close(fd); + return NULL; + } + + return setup_dbus1(fd, guid, false); +} + +static bool setup_tcp_cb(struct l_io *io, void *user_data) +{ + static const unsigned char creds = 0x00; + struct l_dbus *dbus = user_data; + struct l_dbus_classic *classic; + ssize_t written; + int fd = l_io_get_fd(io); + + /* Send special credentials-passing nul byte */ + written = L_TFR(send(fd, &creds, 1, 0)); + if (written < 1) { + l_util_debug(dbus->debug_handler, dbus->debug_handler, + "error writing NUL byte"); + close(fd); + return false; + } + + dbus->driver = &classic_ops; + dbus->negotiate_unix_fd = false; + dbus->support_unix_fd = false; + + classic = l_container_of(dbus, struct l_dbus_classic, super); + classic->match_strings = l_hashmap_new(); + classic->auth_command = l_strdup("AUTH ANONYMOUS\r\n"); + classic->auth_state = WAITING_FOR_OK; + + l_io_set_read_handler(dbus->io, auth_read_handler, dbus, NULL); + l_io_set_write_handler(dbus->io, auth_write_handler, dbus, NULL); + + return auth_write_handler(dbus->io, dbus); +} + +static struct l_dbus *setup_tcp(char *params) +{ + char *host = NULL; + char *port = NULL; + char *family = NULL; + struct addrinfo hints = { 0 }; + struct addrinfo *res; + struct addrinfo *iter; + struct l_dbus *dbus = NULL; + + while (params) { + char *key = strsep(¶ms, ","); + char *value; + + value = strchr(key, '='); + if (!value) + continue; + + *value++ = '\0'; + + if (!strcmp(key, "host")) + host = value; + else if (!strcmp(key, "port")) + port = value; + else if (!strcmp(key, "family")) + family = value; + } + + if (!host || !port) + return NULL; + + if (!family) + hints.ai_family = AF_UNSPEC; + else if (!strcmp(family, "ipv4")) + hints.ai_family = AF_INET; + else if (!strcmp(family, "ipv6")) + hints.ai_family = AF_INET6; + else + return NULL; + + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; + hints.ai_protocol = IPPROTO_TCP; + + if (getaddrinfo(host, port, &hints, &res) != 0) + return NULL; + + for (iter = res; iter; iter = iter->ai_next) { + int fd; + struct l_dbus_classic *classic; + + fd = socket(iter->ai_family, iter->ai_socktype | SOCK_NONBLOCK, + iter->ai_protocol); + if (fd < 0) + continue; + + if (connect(fd, iter->ai_addr, iter->ai_addrlen) < 0) { + if (errno != EINPROGRESS) { + close(fd); + continue; + } + } + + classic = l_new(struct l_dbus_classic, 1); + dbus = &classic->super; + dbus_init(dbus, fd); + l_io_set_write_handler(dbus->io, setup_tcp_cb, dbus, NULL); + break; + } + + freeaddrinfo(res); + return dbus; +} + +static struct l_dbus *setup_address(const char *address) +{ + struct l_dbus *dbus = NULL; + char *address_copy; + + address_copy = strdupa(address); + + while (address_copy) { + char *transport = strsep(&address_copy, ";"); + char *params; + + if (!transport) + break; + + params = strchr(transport, ':'); + if (params) + *params++ = '\0'; + + if (!strcmp(transport, "unix")) { + /* Function will modify params string */ + dbus = setup_unix(params); + break; + } else if (!strcmp(transport, "tcp")) { + dbus = setup_tcp(params); + break; + } + } + + return dbus; +} + +LIB_EXPORT struct l_dbus *l_dbus_new(const char *address) +{ + if (unlikely(!address)) + return NULL; + + return setup_address(address); +} + +LIB_EXPORT struct l_dbus *l_dbus_new_default(enum l_dbus_bus bus) +{ + const char *address; + + switch (bus) { + case L_DBUS_SYSTEM_BUS: + address = getenv("DBUS_SYSTEM_BUS_ADDRESS"); + if (!address) + address = DEFAULT_SYSTEM_BUS_ADDRESS; + break; + case L_DBUS_SESSION_BUS: + address = getenv("DBUS_SESSION_BUS_ADDRESS"); + if (!address) + return NULL; + break; + default: + return NULL; + } + + return setup_address(address); +} + +LIB_EXPORT struct l_dbus *l_dbus_new_private(int fd) +{ + return setup_dbus1(fd, NULL, true); +} + +LIB_EXPORT void l_dbus_destroy(struct l_dbus *dbus) +{ + if (unlikely(!dbus)) + return; + + if (dbus->ready_destroy) + dbus->ready_destroy(dbus->ready_data); + + _dbus_filter_free(dbus->filter); + + _dbus_name_cache_free(dbus->name_cache); + + l_hashmap_destroy(dbus->signal_list, signal_list_destroy); + l_hashmap_destroy(dbus->message_list, message_list_destroy); + l_queue_destroy(dbus->message_queue, message_queue_destroy); + + l_io_destroy(dbus->io); + + if (dbus->disconnect_destroy) + dbus->disconnect_destroy(dbus->disconnect_data); + + if (dbus->debug_destroy) + dbus->debug_destroy(dbus->debug_data); + + l_free(dbus->guid); + l_free(dbus->unique_name); + + _dbus_object_tree_free(dbus->tree); + + dbus->driver->free(dbus); +} + +LIB_EXPORT bool l_dbus_set_ready_handler(struct l_dbus *dbus, + l_dbus_ready_func_t function, + void *user_data, l_dbus_destroy_func_t destroy) +{ + if (unlikely(!dbus)) + return false; + + if (dbus->ready_destroy) + dbus->ready_destroy(dbus->ready_data); + + dbus->ready_handler = function; + dbus->ready_destroy = destroy; + dbus->ready_data = user_data; + + return true; +} + +LIB_EXPORT bool l_dbus_set_disconnect_handler(struct l_dbus *dbus, + l_dbus_disconnect_func_t function, + void *user_data, l_dbus_destroy_func_t destroy) +{ + if (unlikely(!dbus)) + return false; + + if (dbus->disconnect_destroy) + dbus->disconnect_destroy(dbus->disconnect_data); + + dbus->disconnect_handler = function; + dbus->disconnect_destroy = destroy; + dbus->disconnect_data = user_data; + + return true; +} + +LIB_EXPORT bool l_dbus_set_debug(struct l_dbus *dbus, + l_dbus_debug_func_t function, + void *user_data, l_dbus_destroy_func_t destroy) +{ + if (unlikely(!dbus)) + return false; + + if (dbus->debug_destroy) + dbus->debug_destroy(dbus->debug_data); + + dbus->debug_handler = function; + dbus->debug_destroy = destroy; + dbus->debug_data = user_data; + + /* l_io_set_debug(dbus->io, function, user_data, NULL); */ + + return true; +} + +LIB_EXPORT uint32_t l_dbus_send_with_reply(struct l_dbus *dbus, + struct l_dbus_message *message, + l_dbus_message_func_t function, + void *user_data, + l_dbus_destroy_func_t destroy) +{ + if (unlikely(!dbus || !message)) + return 0; + + return send_message(dbus, false, message, function, user_data, destroy); +} + +LIB_EXPORT uint32_t l_dbus_send(struct l_dbus *dbus, + struct l_dbus_message *message) +{ + if (unlikely(!dbus || !message)) + return 0; + + return send_message(dbus, false, message, NULL, NULL, NULL); +} + +static bool remove_entry(void *data, void *user_data) +{ + struct message_callback *callback = data; + uint32_t serial = L_PTR_TO_UINT(user_data); + + if (callback->serial == serial) { + message_queue_destroy(callback); + return true; + } + + return false; +} + +LIB_EXPORT bool l_dbus_cancel(struct l_dbus *dbus, uint32_t serial) +{ + struct message_callback *callback; + unsigned int count; + + if (unlikely(!dbus || !serial)) + return false; + + callback = l_hashmap_remove(dbus->message_list, L_UINT_TO_PTR(serial)); + if (callback) { + message_queue_destroy(callback); + return true; + } + + count = l_queue_foreach_remove(dbus->message_queue, remove_entry, + L_UINT_TO_PTR(serial)); + if (!count) + return false; + + return true; +} + +LIB_EXPORT unsigned int l_dbus_register(struct l_dbus *dbus, + l_dbus_message_func_t function, + void *user_data, l_dbus_destroy_func_t destroy) +{ + struct signal_callback *callback; + + if (unlikely(!dbus)) + return 0; + + callback = l_new(struct signal_callback, 1); + + callback->id = dbus->next_id++; + callback->callback = function; + callback->destroy = destroy; + callback->user_data = user_data; + + l_hashmap_insert(dbus->signal_list, + L_UINT_TO_PTR(callback->id), callback); + + return callback->id; +} + +LIB_EXPORT bool l_dbus_unregister(struct l_dbus *dbus, unsigned int id) +{ + struct signal_callback *callback; + + if (unlikely(!dbus || !id)) + return false; + + callback = l_hashmap_remove(dbus->signal_list, L_UINT_TO_PTR(id)); + if (!callback) + return false; + + signal_list_destroy(callback); + + return true; +} + +LIB_EXPORT uint32_t l_dbus_method_call(struct l_dbus *dbus, + const char *destination, const char *path, + const char *interface, const char *method, + l_dbus_message_func_t setup, + l_dbus_message_func_t function, + void *user_data, l_dbus_destroy_func_t destroy) +{ + struct l_dbus_message *message; + + if (unlikely(!dbus)) + return 0; + + message = l_dbus_message_new_method_call(dbus, destination, path, + interface, method); + + if (setup) + setup(message, user_data); + else + l_dbus_message_set_arguments(message, ""); + + return send_message(dbus, false, message, function, user_data, destroy); +} + +uint8_t _dbus_get_version(struct l_dbus *dbus) +{ + return dbus->driver->version; +} + +int _dbus_get_fd(struct l_dbus *dbus) +{ + return l_io_get_fd(dbus->io); +} + +struct _dbus_object_tree *_dbus_get_tree(struct l_dbus *dbus) +{ + return dbus->tree; +} + +/** + * l_dbus_register_interface: + * @dbus: D-Bus connection as returned by @l_dbus_new* + * @interface: interface name string + * @setup_func: function that sets up the methods, signals and properties by + * using the #dbus-service.h API. + * @destroy: optional destructor to be called every time an instance of this + * interface is being removed from an object on this bus. + * @handle_old_style_properties: whether to automatically handle SetProperty and + * GetProperties for any properties registered by + * @setup_func. + * + * Registers an interface. If successful the interface can then be added + * to any number of objects with @l_dbus_object_add_interface. + * + * Returns: whether the interface was successfully registered + **/ +LIB_EXPORT bool l_dbus_register_interface(struct l_dbus *dbus, + const char *interface, + l_dbus_interface_setup_func_t setup_func, + l_dbus_destroy_func_t destroy, + bool handle_old_style_properties) +{ + if (unlikely(!dbus)) + return false; + + if (unlikely(!dbus->tree)) + return false; + + return _dbus_object_tree_register_interface(dbus->tree, interface, + setup_func, destroy, + handle_old_style_properties); +} + +LIB_EXPORT bool l_dbus_unregister_interface(struct l_dbus *dbus, + const char *interface) +{ + if (unlikely(!dbus)) + return false; + + if (unlikely(!dbus->tree)) + return false; + + return _dbus_object_tree_unregister_interface(dbus->tree, interface); +} + +/** + * l_dbus_register_object: + * @dbus: D-Bus connection + * @path: new object path + * @user_data: user pointer to be passed to @destroy if any + * @destroy: optional destructor to be called when object dropped from the tree + * @...: NULL-terminated list of 0 or more interfaces to be present on the + * object from the moment of creation. For every interface the interface + * name string is expected followed by the @user_data pointer same as + * would be passed as @l_dbus_object_add_interface's last two parameters. + * + * Create a new D-Bus object on the tree visible to D-Bus peers. For example: + * success = l_dbus_register_object(bus, "/org/example/ExampleManager", + * NULL, NULL, + * "org.example.Manager", + * manager_data, + * NULL); + * + * Returns: whether the object path was successfully registered + **/ +LIB_EXPORT bool l_dbus_register_object(struct l_dbus *dbus, const char *path, + void *user_data, + l_dbus_destroy_func_t destroy, ...) +{ + va_list args; + const char *interface; + void *if_user_data; + bool r = true; + + if (unlikely(!dbus)) + return false; + + if (unlikely(!dbus->tree)) + return false; + + if (!_dbus_object_tree_new_object(dbus->tree, path, user_data, destroy)) + return false; + + va_start(args, destroy); + while ((interface = va_arg(args, const char *))) { + if_user_data = va_arg(args, void *); + + if (!_dbus_object_tree_add_interface(dbus->tree, path, + interface, + if_user_data)) { + _dbus_object_tree_object_destroy(dbus->tree, path); + r = false; + + break; + } + } + va_end(args); + + return r; +} + +LIB_EXPORT bool l_dbus_unregister_object(struct l_dbus *dbus, + const char *object) +{ + if (unlikely(!dbus)) + return false; + + if (unlikely(!dbus->tree)) + return false; + + return _dbus_object_tree_object_destroy(dbus->tree, object); +} + +/** + * l_dbus_object_add_interface: + * @dbus: D-Bus connection + * @object: object path as passed to @l_dbus_register_object + * @interface: interface name as passed to @l_dbus_register_interface + * @user_data: user data pointer to be passed to any method and property + * callbacks provided by the @setup_func and to the @destroy + * callback as passed to @l_dbus_register_interface + * + * Creates an instance of given interface at the given path in the + * connection's object tree. If no object was registered at this path + * before @l_dbus_register_object gets called automatically. + * + * The addition of an interface to the object may trigger a query of + * all the properties on this interface and + * #org.freedesktop.DBus.ObjectManager.InterfacesAdded signals. + * + * Returns: whether the interface was successfully added. + **/ +LIB_EXPORT bool l_dbus_object_add_interface(struct l_dbus *dbus, + const char *object, + const char *interface, + void *user_data) +{ + if (unlikely(!dbus)) + return false; + + if (unlikely(!dbus->tree)) + return false; + + return _dbus_object_tree_add_interface(dbus->tree, object, interface, + user_data); +} + +LIB_EXPORT bool l_dbus_object_remove_interface(struct l_dbus *dbus, + const char *object, + const char *interface) +{ + if (unlikely(!dbus)) + return false; + + if (unlikely(!dbus->tree)) + return false; + + return _dbus_object_tree_remove_interface(dbus->tree, object, + interface); +} + +LIB_EXPORT void *l_dbus_object_get_data(struct l_dbus *dbus, const char *object, + const char *interface) +{ + if (unlikely(!dbus)) + return false; + + if (unlikely(!dbus->tree)) + return false; + + return _dbus_object_tree_get_interface_data(dbus->tree, object, + interface); +} + +LIB_EXPORT bool l_dbus_object_set_data(struct l_dbus *dbus, const char *object, + const char *interface, void *user_data) +{ + if (unlikely(!dbus)) + return false; + + if (unlikely(!dbus->tree)) + return false; + + return _dbus_object_tree_set_interface_data(dbus->tree, object, + interface, user_data); +} + +LIB_EXPORT bool l_dbus_object_manager_enable(struct l_dbus *dbus, + const char *root) +{ + if (unlikely(!dbus)) + return false; + + if (unlikely(!dbus->tree)) + return false; + + return _dbus_object_tree_add_interface(dbus->tree, root, + L_DBUS_INTERFACE_OBJECT_MANAGER, + dbus); +} + +LIB_EXPORT unsigned int l_dbus_add_disconnect_watch(struct l_dbus *dbus, + const char *name, + l_dbus_watch_func_t disconnect_func, + void *user_data, + l_dbus_destroy_func_t destroy) +{ + return l_dbus_add_service_watch(dbus, name, NULL, disconnect_func, + user_data, destroy); +} + +LIB_EXPORT unsigned int l_dbus_add_service_watch(struct l_dbus *dbus, + const char *name, + l_dbus_watch_func_t connect_func, + l_dbus_watch_func_t disconnect_func, + void *user_data, + l_dbus_destroy_func_t destroy) +{ + if (!name) + return 0; + + if (!dbus->name_cache) + dbus->name_cache = _dbus_name_cache_new(dbus, + &dbus->driver->name_ops); + + return _dbus_name_cache_add_watch(dbus->name_cache, name, connect_func, + disconnect_func, user_data, + destroy); +} + +LIB_EXPORT bool l_dbus_remove_watch(struct l_dbus *dbus, unsigned int id) +{ + if (!dbus->name_cache) + return false; + + return _dbus_name_cache_remove_watch(dbus->name_cache, id); +} + +/** + * l_dbus_add_signal_watch: + * @dbus: D-Bus connection + * @sender: bus name to match the signal sender against or NULL to + * match any sender + * @path: object path to match the signal path against or NULL to + * match any path + * @interface: interface name to match the signal interface against + * or NULL to match any interface + * @member: name to match the signal name against or NULL to match any + * signal + * @...: a list of further conditions to be met by the signal followed + * by three more mandatory parameters: + * enum l_dbus_match_type list_end_marker, + * l_dbus_message_func callback, + * void *user_data, + * The value L_DBUS_MATCH_NONE must be passed as the end of list + * marker, followed by the signal match callback and user_data. + * In the list, every condition is a pair of parameters: + * enum l_dbus_match_type match_type, const char *value. + * + * Subscribe to a group of signals based on a set of conditions that + * compare the signal's header fields and string arguments against given + * values. For example: + * signal_id = l_dbus_add_signal_watch(bus, "org.example", "/" + * "org.example.Manager", + * "PropertyChanged", + * L_DBUS_MATCH_ARGUMENT(0), + * "ExampleProperty", + * L_DBUS_MATCH_NONE + * manager_property_change_cb, + * NULL); + * + * Returns: a non-zero signal filter identifier that can be passed to + * l_dbus_remove_signal_watch to remove this filter rule, or + * zero on failure. + **/ +LIB_EXPORT unsigned int l_dbus_add_signal_watch(struct l_dbus *dbus, + const char *sender, + const char *path, + const char *interface, + const char *member, ...) +{ + struct _dbus_filter_condition *rule; + int rule_len; + va_list args; + const char *value; + l_dbus_message_func_t signal_func; + enum l_dbus_match_type type; + void *user_data; + unsigned int id; + + va_start(args, member); + + rule_len = 0; + while (va_arg(args, enum l_dbus_match_type) != L_DBUS_MATCH_NONE) + rule_len++; + + va_end(args); + + rule = l_new(struct _dbus_filter_condition, rule_len + 5); + + rule_len = 0; + + rule[rule_len].type = L_DBUS_MATCH_TYPE; + rule[rule_len++].value = "signal"; + + if (sender) { + rule[rule_len].type = L_DBUS_MATCH_SENDER; + rule[rule_len++].value = sender; + } + + if (path) { + rule[rule_len].type = L_DBUS_MATCH_PATH; + rule[rule_len++].value = path; + } + + if (interface) { + rule[rule_len].type = L_DBUS_MATCH_INTERFACE; + rule[rule_len++].value = interface; + } + + if (member) { + rule[rule_len].type = L_DBUS_MATCH_MEMBER; + rule[rule_len++].value = member; + } + + va_start(args, member); + + while (true) { + type = va_arg(args, enum l_dbus_match_type); + if (type == L_DBUS_MATCH_NONE) + break; + + value = va_arg(args, const char *); + + rule[rule_len].type = type; + rule[rule_len++].value = value; + } + + signal_func = va_arg(args, l_dbus_message_func_t); + user_data = va_arg(args, void *); + + va_end(args); + + if (!dbus->filter) { + if (!dbus->name_cache) + dbus->name_cache = _dbus_name_cache_new(dbus, + &dbus->driver->name_ops); + + dbus->filter = _dbus_filter_new(dbus, + &dbus->driver->filter_ops, + dbus->name_cache); + } + + id = _dbus_filter_add_rule(dbus->filter, rule, rule_len, + signal_func, user_data); + + l_free(rule); + + return id; +} + +LIB_EXPORT bool l_dbus_remove_signal_watch(struct l_dbus *dbus, unsigned int id) +{ + if (!dbus->filter) + return false; + + return _dbus_filter_remove_rule(dbus->filter, id); +} + +/** + * l_dbus_name_acquire: + * @dbus: D-Bus connection + * @name: Well-known bus name to be acquired + * @allow_replacement: Whether to allow another peer's name request to + * take the name ownership away from this connection + * @replace_existing: Whether to allow D-Bus to take the name's ownership + * away from another peer in case the name is already + * owned and allows replacement. Ignored if name is + * currently free. + * @queue: Whether to allow the name request to be queued by D-Bus in + * case it cannot be acquired now, rather than to return a failure. + * @callback: Callback to receive the request result when done. + * + * Acquire a well-known bus name (service name) on the bus. + * + * Returns: a non-zero request serial that can be passed to l_dbus_cancel + * while waiting for the callback or zero if the callback has + * has happened while l_dbus_name_acquire was running. + **/ +LIB_EXPORT uint32_t l_dbus_name_acquire(struct l_dbus *dbus, const char *name, + bool allow_replacement, bool replace_existing, + bool queue, l_dbus_name_acquire_func_t callback, + void *user_data) +{ + return dbus->driver->name_acquire(dbus, name, allow_replacement, + replace_existing, queue, + callback, user_data); +} diff --git a/ell/dbus.h b/ell/dbus.h new file mode 100644 index 0000000000000000000000000000000000000000..21777cbd025ad686dbfae73b0d95a5da5396b75e --- /dev/null +++ b/ell/dbus.h @@ -0,0 +1,266 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_DBUS_H +#define __ELL_DBUS_H + +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdarg.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define L_DBUS_INTERFACE_DBUS "org.freedesktop.DBus" +#define L_DBUS_INTERFACE_INTROSPECTABLE "org.freedesktop.DBus.Introspectable" +#define L_DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties" +#define L_DBUS_INTERFACE_OBJECT_MANAGER "org.freedesktop.DBus.ObjectManager" + +enum l_dbus_bus { + L_DBUS_SYSTEM_BUS, + L_DBUS_SESSION_BUS, +}; + +enum l_dbus_match_type { + L_DBUS_MATCH_NONE = 0, + L_DBUS_MATCH_TYPE, + L_DBUS_MATCH_SENDER, + L_DBUS_MATCH_PATH, + L_DBUS_MATCH_INTERFACE, + L_DBUS_MATCH_MEMBER, + L_DBUS_MATCH_ARG0, +}; + +#define L_DBUS_MATCH_ARGUMENT(i) (L_DBUS_MATCH_ARG0 + (i)) + +struct l_dbus; +struct l_dbus_interface; +struct l_dbus_message_builder; + +typedef void (*l_dbus_ready_func_t) (void *user_data); +typedef void (*l_dbus_disconnect_func_t) (void *user_data); + +typedef void (*l_dbus_debug_func_t) (const char *str, void *user_data); +typedef void (*l_dbus_destroy_func_t) (void *user_data); +typedef void (*l_dbus_interface_setup_func_t) (struct l_dbus_interface *); + +typedef void (*l_dbus_watch_func_t) (struct l_dbus *dbus, void *user_data); + +typedef void (*l_dbus_name_acquire_func_t) (struct l_dbus *dbus, bool success, + bool queued, void *user_data); + +struct l_dbus *l_dbus_new(const char *address); +struct l_dbus *l_dbus_new_default(enum l_dbus_bus bus); +struct l_dbus *l_dbus_new_private(int fd); +void l_dbus_destroy(struct l_dbus *dbus); + +bool l_dbus_set_ready_handler(struct l_dbus *dbus, l_dbus_ready_func_t function, + void *user_data, l_dbus_destroy_func_t destroy); +bool l_dbus_set_disconnect_handler(struct l_dbus *dbus, + l_dbus_disconnect_func_t function, + void *user_data, l_dbus_destroy_func_t destroy); + +bool l_dbus_set_debug(struct l_dbus *dbus, l_dbus_debug_func_t function, + void *user_data, l_dbus_destroy_func_t destroy); + +struct l_dbus_message; + +struct l_dbus_message_iter { + struct l_dbus_message *message; + const char *sig_start; + uint8_t sig_len; + uint8_t sig_pos; + const void *data; + size_t len; + size_t pos; + char container_type; + const void *offsets; +}; + +struct l_dbus_message *l_dbus_message_new_method_call(struct l_dbus *dbus, + const char *destination, + const char *path, + const char *interface, + const char *method); + +struct l_dbus_message *l_dbus_message_new_signal(struct l_dbus *dbus, + const char *path, + const char *interface, + const char *name); + +struct l_dbus_message *l_dbus_message_new_method_return( + struct l_dbus_message *method_call); + +struct l_dbus_message *l_dbus_message_new_error_valist( + struct l_dbus_message *method_call, + const char *name, + const char *format, va_list args) + __attribute__((format(printf, 3, 0))); +struct l_dbus_message *l_dbus_message_new_error( + struct l_dbus_message *method_call, + const char *name, + const char *format, ...) + __attribute__((format(printf, 3, 4))); + +struct l_dbus_message *l_dbus_message_ref(struct l_dbus_message *message); +void l_dbus_message_unref(struct l_dbus_message *message); + +const char *l_dbus_message_get_path(struct l_dbus_message *message); +const char *l_dbus_message_get_interface(struct l_dbus_message *message); +const char *l_dbus_message_get_member(struct l_dbus_message *message); +const char *l_dbus_message_get_destination(struct l_dbus_message *message); +const char *l_dbus_message_get_sender(struct l_dbus_message *message); +const char *l_dbus_message_get_signature(struct l_dbus_message *message); + +bool l_dbus_message_set_no_reply(struct l_dbus_message *message, bool on); +bool l_dbus_message_get_no_reply(struct l_dbus_message *message); + +bool l_dbus_message_set_no_autostart(struct l_dbus_message *message, bool on); +bool l_dbus_message_get_no_autostart(struct l_dbus_message *message); + +typedef void (*l_dbus_message_func_t) (struct l_dbus_message *message, + void *user_data); + +uint32_t l_dbus_send_with_reply(struct l_dbus *dbus, + struct l_dbus_message *message, + l_dbus_message_func_t function, + void *user_data, l_dbus_destroy_func_t destroy); +uint32_t l_dbus_send(struct l_dbus *dbus, + struct l_dbus_message *message); +bool l_dbus_cancel(struct l_dbus *dbus, uint32_t serial); + +unsigned int l_dbus_register(struct l_dbus *dbus, + l_dbus_message_func_t function, + void *user_data, l_dbus_destroy_func_t destroy); +bool l_dbus_unregister(struct l_dbus *dbus, unsigned int id); + +uint32_t l_dbus_method_call(struct l_dbus *dbus, + const char *destination, const char *path, + const char *interface, const char *method, + l_dbus_message_func_t setup, + l_dbus_message_func_t function, + void *user_data, l_dbus_destroy_func_t destroy); + +bool l_dbus_message_is_error(struct l_dbus_message *message); +bool l_dbus_message_get_error(struct l_dbus_message *message, + const char **name, const char **text); +bool l_dbus_message_get_arguments(struct l_dbus_message *message, + const char *signature, ...); +bool l_dbus_message_get_arguments_valist(struct l_dbus_message *message, + const char *signature, va_list args); + +bool l_dbus_message_iter_next_entry(struct l_dbus_message_iter *iter, ...); +bool l_dbus_message_iter_get_variant(struct l_dbus_message_iter *iter, + const char *signature, ...); +bool l_dbus_message_iter_get_fixed_array(struct l_dbus_message_iter *iter, + void *out, uint32_t *n_elem); + +bool l_dbus_message_set_arguments(struct l_dbus_message *message, + const char *signature, ...); +bool l_dbus_message_set_arguments_valist(struct l_dbus_message *message, + const char *signature, va_list args); + +struct l_dbus_message_builder *l_dbus_message_builder_new( + struct l_dbus_message *message); +void l_dbus_message_builder_destroy(struct l_dbus_message_builder *builder); + +bool l_dbus_message_builder_append_basic(struct l_dbus_message_builder *builder, + char type, const void *value); + +bool l_dbus_message_builder_enter_container( + struct l_dbus_message_builder *builder, + char container_type, + const char *signature); +bool l_dbus_message_builder_leave_container( + struct l_dbus_message_builder *builder, + char container_type); + +bool l_dbus_message_builder_enter_struct(struct l_dbus_message_builder *builder, + const char *signature); +bool l_dbus_message_builder_leave_struct( + struct l_dbus_message_builder *builder); + +bool l_dbus_message_builder_enter_dict(struct l_dbus_message_builder *builder, + const char *signature); +bool l_dbus_message_builder_leave_dict(struct l_dbus_message_builder *builder); + +bool l_dbus_message_builder_enter_array(struct l_dbus_message_builder *builder, + const char *signature); +bool l_dbus_message_builder_leave_array(struct l_dbus_message_builder *builder); + +bool l_dbus_message_builder_enter_variant( + struct l_dbus_message_builder *builder, + const char *signature); +bool l_dbus_message_builder_leave_variant( + struct l_dbus_message_builder *builder); + +bool l_dbus_message_builder_append_from_iter( + struct l_dbus_message_builder *builder, + struct l_dbus_message_iter *from); + +bool l_dbus_message_builder_append_from_valist( + struct l_dbus_message_builder *builder, + const char *signature, va_list args); + +struct l_dbus_message *l_dbus_message_builder_finalize( + struct l_dbus_message_builder *builder); + +bool l_dbus_register_interface(struct l_dbus *dbus, const char *interface, + l_dbus_interface_setup_func_t setup_func, + l_dbus_destroy_func_t destroy, + bool handle_old_style_properties); +bool l_dbus_unregister_interface(struct l_dbus *dbus, const char *interface); + +bool l_dbus_register_object(struct l_dbus *dbus, const char *path, + void *user_data, l_dbus_destroy_func_t destroy, + ...); +bool l_dbus_unregister_object(struct l_dbus *dbus, const char *object); + +bool l_dbus_object_add_interface(struct l_dbus *dbus, const char *object, + const char *interface, void *user_data); +bool l_dbus_object_remove_interface(struct l_dbus *dbus, const char *object, + const char *interface); +void *l_dbus_object_get_data(struct l_dbus *dbus, const char *object, + const char *interface); +bool l_dbus_object_set_data(struct l_dbus *dbus, const char *object, + const char *interface, void *user_data); + +bool l_dbus_object_manager_enable(struct l_dbus *dbus, const char *root); + +unsigned int l_dbus_add_service_watch(struct l_dbus *dbus, + const char *name, + l_dbus_watch_func_t connect_func, + l_dbus_watch_func_t disconnect_func, + void *user_data, + l_dbus_destroy_func_t destroy); + +unsigned int l_dbus_add_disconnect_watch(struct l_dbus *dbus, + const char *name, + l_dbus_watch_func_t disconnect_func, + void *user_data, + l_dbus_destroy_func_t destroy); +bool l_dbus_remove_watch(struct l_dbus *dbus, unsigned int id); + +unsigned int l_dbus_add_signal_watch(struct l_dbus *dbus, + const char *sender, + const char *path, + const char *interface, + const char *member, ...); +bool l_dbus_remove_signal_watch(struct l_dbus *dbus, unsigned int id); + +uint32_t l_dbus_name_acquire(struct l_dbus *dbus, const char *name, + bool allow_replacement, bool replace_existing, + bool queue, l_dbus_name_acquire_func_t callback, + void *user_data); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_DBUS_H */ diff --git a/ell/ecc-external.c b/ell/ecc-external.c new file mode 100644 index 0000000000000000000000000000000000000000..7a0882326811c5e5c82ce151cff24fcebdb0a179 --- /dev/null +++ b/ell/ecc-external.c @@ -0,0 +1,1023 @@ +/* + * Copyright (c) 2013, Kenneth MacKay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdint.h> +#include <stdbool.h> + +#include "private.h" +#include "ecc.h" +#include "ecc-private.h" +#include "random.h" + +typedef struct { + uint64_t m_low; + uint64_t m_high; +} uint128_t; + +static void vli_clear(uint64_t *vli, unsigned int ndigits) +{ + unsigned int i; + + for (i = 0; i < ndigits; i++) + vli[i] = 0; +} + +/* Returns true if vli == 0, false otherwise. */ +static bool vli_is_zero(const uint64_t *vli, unsigned int ndigits) +{ + unsigned int i; + + for (i = 0; i < ndigits; i++) { + if (vli[i]) + return false; + } + + return true; +} + +/* Returns nonzero if bit bit of vli is set. */ +static uint64_t vli_test_bit(const uint64_t *vli, unsigned int bit) +{ + return (vli[bit / 64] & ((uint64_t) 1 << (bit % 64))); +} + +/* Sets dest = src. */ +static void vli_set(uint64_t *dest, const uint64_t *src, unsigned int ndigits) +{ + unsigned int i; + + for (i = 0; i < ndigits; i++) + dest[i] = src[i]; +} + +/* Returns sign of left - right. */ +int _vli_cmp(const uint64_t *left, const uint64_t *right, unsigned int ndigits) +{ + int i; + + for (i = ndigits - 1; i >= 0; i--) { + if (left[i] > right[i]) + return 1; + if (left[i] < right[i]) + return -1; + } + + return 0; +} + +/* Computes result = in << c, returning carry. Can modify in place + * (if result == in). 0 < shift < 64. + */ +static uint64_t vli_lshift(uint64_t *result, const uint64_t *in, + unsigned int shift, + unsigned int ndigits) +{ + uint64_t carry = 0; + unsigned int i; + + for (i = 0; i < ndigits; i++) { + uint64_t temp = in[i]; + + result[i] = (temp << shift) | carry; + carry = temp >> (64 - shift); + } + + return carry; +} + +/* Computes vli = vli >> 1. */ +void _vli_rshift1(uint64_t *vli, unsigned int ndigits) +{ + uint64_t *end = vli; + uint64_t carry = 0; + + vli += ndigits; + + while (vli-- > end) { + uint64_t temp = *vli; + *vli = (temp >> 1) | carry; + carry = temp << 63; + } +} + +/* Computes result = left + right, returning carry. Can modify in place. */ +uint64_t _vli_add(uint64_t *result, const uint64_t *left, + const uint64_t *right, unsigned int ndigits) +{ + uint64_t carry = 0; + unsigned int i; + + for (i = 0; i < ndigits; i++) { + uint64_t sum; + + sum = left[i] + right[i] + carry; + if (sum != left[i]) + carry = (sum < left[i]); + + result[i] = sum; + } + + return carry; +} + +/* Computes result = left - right, returning borrow. Can modify in place. */ +uint64_t _vli_sub(uint64_t *result, const uint64_t *left, + const uint64_t *right, unsigned int ndigits) +{ + uint64_t borrow = 0; + unsigned int i; + + for (i = 0; i < ndigits; i++) { + uint64_t diff; + + diff = left[i] - right[i] - borrow; + if (diff != left[i]) + borrow = (diff > left[i]); + + result[i] = diff; + } + + return borrow; +} + +static uint128_t mul_64_64(uint64_t left, uint64_t right) +{ + uint64_t a0 = left & 0xffffffffull; + uint64_t a1 = left >> 32; + uint64_t b0 = right & 0xffffffffull; + uint64_t b1 = right >> 32; + uint64_t m0 = a0 * b0; + uint64_t m1 = a0 * b1; + uint64_t m2 = a1 * b0; + uint64_t m3 = a1 * b1; + uint128_t result; + + m2 += (m0 >> 32); + m2 += m1; + + /* Overflow */ + if (m2 < m1) + m3 += 0x100000000ull; + + result.m_low = (m0 & 0xffffffffull) | (m2 << 32); + result.m_high = m3 + (m2 >> 32); + + return result; +} + +static uint128_t add_128_128(uint128_t a, uint128_t b) +{ + uint128_t result; + + result.m_low = a.m_low + b.m_low; + result.m_high = a.m_high + b.m_high + (result.m_low < a.m_low); + + return result; +} + +static void vli_mult(uint64_t *result, const uint64_t *left, + const uint64_t *right, + unsigned int ndigits) +{ + uint128_t r01 = { 0, 0 }; + uint64_t r2 = 0; + unsigned int i, k; + + /* Compute each digit of result in sequence, maintaining the + * carries. + */ + for (k = 0; k < ndigits * 2 - 1; k++) { + unsigned int min; + + if (k < ndigits) + min = 0; + else + min = (k + 1) - ndigits; + + for (i = min; i <= k && i < ndigits; i++) { + uint128_t product; + + product = mul_64_64(left[i], right[k - i]); + + r01 = add_128_128(r01, product); + r2 += (r01.m_high < product.m_high); + } + + result[k] = r01.m_low; + r01.m_low = r01.m_high; + r01.m_high = r2; + r2 = 0; + } + + result[ndigits * 2 - 1] = r01.m_low; +} + +static void vli_square(uint64_t *result, const uint64_t *left, + unsigned int ndigits) +{ + uint128_t r01 = { 0, 0 }; + uint64_t r2 = 0; + unsigned int i, k; + + for (k = 0; k < ndigits * 2 - 1; k++) { + unsigned int min; + + if (k < ndigits) + min = 0; + else + min = (k + 1) - ndigits; + + for (i = min; i <= k && i <= k - i; i++) { + uint128_t product; + + product = mul_64_64(left[i], left[k - i]); + + if (i < k - i) { + r2 += product.m_high >> 63; + product.m_high = (product.m_high << 1) | + (product.m_low >> 63); + product.m_low <<= 1; + } + + r01 = add_128_128(r01, product); + r2 += (r01.m_high < product.m_high); + } + + result[k] = r01.m_low; + r01.m_low = r01.m_high; + r01.m_high = r2; + r2 = 0; + } + + result[ndigits * 2 - 1] = r01.m_low; +} + +/* Computes result = (left + right) % mod. + * Assumes that left < mod and right < mod, result != mod. + */ +void _vli_mod_add(uint64_t *result, const uint64_t *left, + const uint64_t *right, const uint64_t *mod, + unsigned int ndigits) +{ + uint64_t carry; + + carry = _vli_add(result, left, right, ndigits); + + /* result > mod (result = mod + remainder), so subtract mod to + * get remainder. + */ + if (carry || _vli_cmp(result, mod, ndigits) >= 0) + _vli_sub(result, result, mod, ndigits); +} + +/* Computes result = (left - right) % mod. + * Assumes that left < mod and right < mod, result != mod. + */ +void _vli_mod_sub(uint64_t *result, const uint64_t *left, + const uint64_t *right, const uint64_t *mod, + unsigned int ndigits) +{ + uint64_t borrow = _vli_sub(result, left, right, ndigits); + + /* In this case, p_result == -diff == (max int) - diff. + * Since -x % d == d - x, we can get the correct result from + * result + mod (with overflow). + */ + if (borrow) + _vli_add(result, result, mod, ndigits); +} + +/* Counts the number of 64-bit "digits" in vli. */ +static unsigned int _vli_num_digits(const uint64_t *vli, unsigned int ndigits) +{ + int i; + + /* Search from the end until we find a non-zero digit. + * We do it in reverse because we expect that most digits will + * be nonzero. + */ + for (i = ndigits - 1; i >= 0 && vli[i] == 0; i--); + + return (i + 1); +} + +/* Counts the number of bits required for vli. */ +static unsigned int _vli_num_bits(const uint64_t *vli, unsigned int ndigits) +{ + unsigned int i, num_digits; + uint64_t digit; + + num_digits = _vli_num_digits(vli, ndigits); + if (num_digits == 0) + return 0; + + digit = vli[num_digits - 1]; + for (i = 0; digit; i++) + digit >>= 1; + + return ((num_digits - 1) * 64 + i); +} + +/* Computes result = product % mod, where product is 2N words long. + * Currently only designed to work for curve_p or curve_n. + */ +void _vli_mmod_slow(uint64_t *result, const uint64_t *product, + const uint64_t *mod, unsigned int ndigits) +{ + uint64_t mod_m[2 * L_ECC_MAX_DIGITS]; + uint64_t tmp[2 * L_ECC_MAX_DIGITS]; + uint64_t *v[2] = { tmp, (uint64_t *) product }; + uint64_t carry = 0; + unsigned int i; + /* Shift mod so its highest set bit is at the maximum position. */ + int shift = (ndigits * 2 * 64) - _vli_num_bits(mod, ndigits); + int word_shift = shift / 64; + int bit_shift = shift % 64; + + vli_clear(mod_m, word_shift); + if (bit_shift > 0) { + for (i = 0; i < ndigits; ++i) { + mod_m[word_shift + i] = (mod[i] << bit_shift) | carry; + carry = mod[i] >> (64 - bit_shift); + } + } else + vli_set(mod_m + word_shift, mod, ndigits); + + for (i = 1; shift >= 0; --shift) { + uint64_t borrow = 0; + unsigned int j; + + for (j = 0; j < ndigits * 2; ++j) { + uint64_t diff = v[i][j] - mod_m[j] - borrow; + + if (diff != v[i][j]) + borrow = (diff > v[i][j]); + v[1 - i][j] = diff; + } + i = !(i ^ borrow); /* Swap the index if there was no borrow */ + _vli_rshift1(mod_m, ndigits); + mod_m[ndigits - 1] |= mod_m[ndigits] << (64 - 1); + _vli_rshift1(mod_m + ndigits, ndigits); + } + vli_set(result, v[i], ndigits); +} + +/* Computes p_result = p_product % curve_p. + * See algorithm 5 and 6 from + * http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf + */ +static void vli_mmod_fast_192(uint64_t *result, const uint64_t *product, + const uint64_t *curve_prime, uint64_t *tmp) +{ + const unsigned int ndigits = 3; + int carry; + + vli_set(result, product, ndigits); + + vli_set(tmp, &product[3], ndigits); + carry = _vli_add(result, result, tmp, ndigits); + + tmp[0] = 0; + tmp[1] = product[3]; + tmp[2] = product[4]; + carry += _vli_add(result, result, tmp, ndigits); + + tmp[0] = tmp[1] = product[5]; + tmp[2] = 0; + carry += _vli_add(result, result, tmp, ndigits); + + while (carry || _vli_cmp(curve_prime, result, ndigits) != 1) + carry -= _vli_sub(result, result, curve_prime, ndigits); +} + +/* Computes result = product % curve_prime + * from http://www.nsa.gov/ia/_files/nist-routines.pdf + */ +static void vli_mmod_fast_256(uint64_t *result, const uint64_t *product, + const uint64_t *curve_prime, uint64_t *tmp) +{ + int carry; + const unsigned int ndigits = 4; + + /* t */ + vli_set(result, product, ndigits); + + /* s1 */ + tmp[0] = 0; + tmp[1] = product[5] & 0xffffffff00000000ull; + tmp[2] = product[6]; + tmp[3] = product[7]; + carry = vli_lshift(tmp, tmp, 1, ndigits); + carry += _vli_add(result, result, tmp, ndigits); + + /* s2 */ + tmp[1] = product[6] << 32; + tmp[2] = (product[6] >> 32) | (product[7] << 32); + tmp[3] = product[7] >> 32; + carry += vli_lshift(tmp, tmp, 1, ndigits); + carry += _vli_add(result, result, tmp, ndigits); + + /* s3 */ + tmp[0] = product[4]; + tmp[1] = product[5] & 0xffffffff; + tmp[2] = 0; + tmp[3] = product[7]; + carry += _vli_add(result, result, tmp, ndigits); + + /* s4 */ + tmp[0] = (product[4] >> 32) | (product[5] << 32); + tmp[1] = (product[5] >> 32) | (product[6] & 0xffffffff00000000ull); + tmp[2] = product[7]; + tmp[3] = (product[6] >> 32) | (product[4] << 32); + carry += _vli_add(result, result, tmp, ndigits); + + /* d1 */ + tmp[0] = (product[5] >> 32) | (product[6] << 32); + tmp[1] = (product[6] >> 32); + tmp[2] = 0; + tmp[3] = (product[4] & 0xffffffff) | (product[5] << 32); + carry -= _vli_sub(result, result, tmp, ndigits); + + /* d2 */ + tmp[0] = product[6]; + tmp[1] = product[7]; + tmp[2] = 0; + tmp[3] = (product[4] >> 32) | (product[5] & 0xffffffff00000000ull); + carry -= _vli_sub(result, result, tmp, ndigits); + + /* d3 */ + tmp[0] = (product[6] >> 32) | (product[7] << 32); + tmp[1] = (product[7] >> 32) | (product[4] << 32); + tmp[2] = (product[4] >> 32) | (product[5] << 32); + tmp[3] = (product[6] << 32); + carry -= _vli_sub(result, result, tmp, ndigits); + + /* d4 */ + tmp[0] = product[7]; + tmp[1] = product[4] & 0xffffffff00000000ull; + tmp[2] = product[5]; + tmp[3] = product[6] & 0xffffffff00000000ull; + carry -= _vli_sub(result, result, tmp, ndigits); + + if (carry < 0) { + do { + carry += _vli_add(result, result, curve_prime, ndigits); + } while (carry < 0); + } else { + while (carry || _vli_cmp(curve_prime, result, ndigits) != 1) + carry -= _vli_sub(result, result, curve_prime, ndigits); + } +} + +/* + * The NIST algorithms define S values, which are comprised of 32 bit C values + * of the original product we are trying to reduce. Since we are working with + * 64 bit 'digits', we need to convert these C values into 64 bit chunks. This + * macro mainly makes code readability easier since we can directly pass the + * two C indexes (h and l). Some of these C values are zero, which is also a + * value C index. In this case -1 should be passed to indicate zero. + */ +#define ECC_SET_S(prod, h, l) ({ \ + uint64_t r = 0; \ + if (h == -1) { \ + /* zero, don't do anything */ \ + } else if (h & 1) \ + r |= (prod[h / 2] & 0xffffffff00000000ull); \ + else \ + r |= (prod[h / 2] << 32); \ + if (l == -1) { \ + /* zero, don't do anything */ \ + } else if (l & 1) \ + r |= (prod[l / 2] >> 32); \ + else \ + r |= (prod[l / 2] & 0xffffffff); \ + r; \ +}) + +static void vli_mmod_fast_384(uint64_t *result, const uint64_t *product, + const uint64_t *curve_prime, uint64_t *tmp) +{ + int carry; + const unsigned int ndigits = 6; + + /* t */ + vli_set(result, product, ndigits); + + /* s1 */ + tmp[0] = 0; + tmp[1] = 0; + tmp[2] = ECC_SET_S(product, 22, 21); + tmp[3] = ECC_SET_S(product, -1, 23); + tmp[4] = 0; + tmp[5] = 0; + carry = vli_lshift(tmp, tmp, 1, ndigits); + carry += _vli_add(result, result, tmp, ndigits); + + /* s2 */ + tmp[0] = product[6]; + tmp[1] = product[7]; + tmp[2] = product[8]; + tmp[3] = product[9]; + tmp[4] = product[10]; + tmp[5] = product[11]; + carry += _vli_add(result, result, tmp, ndigits); + + /* s3 */ + tmp[0] = ECC_SET_S(product, 22, 21); + tmp[1] = ECC_SET_S(product, 12, 23); + tmp[2] = ECC_SET_S(product, 14, 13); + tmp[3] = ECC_SET_S(product, 16, 15); + tmp[4] = ECC_SET_S(product, 18, 17); + tmp[5] = ECC_SET_S(product, 20, 19); + carry += _vli_add(result, result, tmp, ndigits); + + /* s4 */ + tmp[0] = ECC_SET_S(product, 23, -1); + tmp[1] = ECC_SET_S(product, 20, -1); + tmp[2] = ECC_SET_S(product, 13, 12); + tmp[3] = ECC_SET_S(product, 15, 14); + tmp[4] = ECC_SET_S(product, 17, 16); + tmp[5] = ECC_SET_S(product, 19, 18); + carry += _vli_add(result, result, tmp, ndigits); + + /* s5 */ + tmp[0] = 0; + tmp[1] = 0; + tmp[2] = ECC_SET_S(product, 21, 20); + tmp[3] = ECC_SET_S(product, 23, 22); + tmp[4] = 0; + tmp[5] = 0; + carry += _vli_add(result, result, tmp, ndigits); + + /* s6 */ + tmp[0] = ECC_SET_S(product, -1, 20); + tmp[1] = ECC_SET_S(product, 21, -1); + tmp[2] = ECC_SET_S(product, 23, 22); + tmp[3] = 0; + tmp[4] = 0; + tmp[5] = 0; + carry += _vli_add(result, result, tmp, ndigits); + + /* s7 */ + tmp[0] = ECC_SET_S(product, 12, 23); + tmp[1] = ECC_SET_S(product, 14, 13); + tmp[2] = ECC_SET_S(product, 16, 15); + tmp[3] = ECC_SET_S(product, 18, 17); + tmp[4] = ECC_SET_S(product, 20, 19); + tmp[5] = ECC_SET_S(product, 22, 21); + carry -= _vli_sub(result, result, tmp, ndigits); + + /* s8 */ + tmp[0] = ECC_SET_S(product, 20, -1); + tmp[1] = ECC_SET_S(product, 22, 21); + tmp[2] = ECC_SET_S(product, -1, 23); + tmp[3] = 0; + tmp[4] = 0; + tmp[5] = 0; + carry -= _vli_sub(result, result, tmp, ndigits); + + /* s9 */ + tmp[0] = 0; + tmp[1] = ECC_SET_S(product, 23, -1); + tmp[2] = ECC_SET_S(product, -1, 23); + tmp[3] = 0; + tmp[4] = 0; + tmp[5] = 0; + carry -= _vli_sub(result, result, tmp, ndigits); + + if (carry < 0) { + do { + carry += _vli_add(result, result, curve_prime, ndigits); + } while (carry < 0); + } else { + while (carry || _vli_cmp(curve_prime, result, ndigits) != 1) + carry -= _vli_sub(result, result, curve_prime, ndigits); + } +} + +/* Computes result = product % curve_prime + * from http://www.nsa.gov/ia/_files/nist-routines.pdf +*/ +bool _vli_mmod_fast(uint64_t *result, const uint64_t *product, + const uint64_t *curve_prime, unsigned int ndigits) +{ + uint64_t tmp[2 * L_ECC_MAX_DIGITS]; + + switch (ndigits) { + case 3: + vli_mmod_fast_192(result, product, curve_prime, tmp); + break; + case 4: + vli_mmod_fast_256(result, product, curve_prime, tmp); + break; + case 6: + vli_mmod_fast_384(result, product, curve_prime, tmp); + break; + default: + return false; + } + + return true; +} + +/* Computes result = (left * right) % curve_p. */ +void _vli_mod_mult_fast(uint64_t *result, const uint64_t *left, + const uint64_t *right, const uint64_t *curve_prime, + unsigned int ndigits) +{ + uint64_t product[2 * L_ECC_MAX_DIGITS]; + + vli_mult(product, left, right, ndigits); + _vli_mmod_fast(result, product, curve_prime, ndigits); +} + +/* Computes result = left^2 % curve_p. */ +void _vli_mod_square_fast(uint64_t *result, const uint64_t *left, + const uint64_t *curve_prime, + unsigned int ndigits) +{ + uint64_t product[2 * L_ECC_MAX_DIGITS]; + + vli_square(product, left, ndigits); + _vli_mmod_fast(result, product, curve_prime, ndigits); +} + +#define EVEN(vli) (!(vli[0] & 1)) +/* Computes result = (1 / p_input) % mod. All VLIs are the same size. + * See "From Euclid's GCD to Montgomery Multiplication to the Great Divide" + * https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf + */ +void _vli_mod_inv(uint64_t *result, const uint64_t *input, + const uint64_t *mod, + unsigned int ndigits) +{ + uint64_t a[L_ECC_MAX_DIGITS], b[L_ECC_MAX_DIGITS]; + uint64_t u[L_ECC_MAX_DIGITS], v[L_ECC_MAX_DIGITS]; + uint64_t carry; + int cmp_result; + + if (vli_is_zero(input, ndigits)) { + vli_clear(result, ndigits); + return; + } + + vli_set(a, input, ndigits); + vli_set(b, mod, ndigits); + vli_clear(u, ndigits); + u[0] = 1; + vli_clear(v, ndigits); + + while ((cmp_result = _vli_cmp(a, b, ndigits)) != 0) { + carry = 0; + + if (EVEN(a)) { + _vli_rshift1(a, ndigits); + + if (!EVEN(u)) + carry = _vli_add(u, u, mod, ndigits); + + _vli_rshift1(u, ndigits); + if (carry) + u[ndigits - 1] |= 0x8000000000000000ull; + } else if (EVEN(b)) { + _vli_rshift1(b, ndigits); + + if (!EVEN(v)) + carry = _vli_add(v, v, mod, ndigits); + + _vli_rshift1(v, ndigits); + if (carry) + v[ndigits - 1] |= 0x8000000000000000ull; + } else if (cmp_result > 0) { + _vli_sub(a, a, b, ndigits); + _vli_rshift1(a, ndigits); + + if (_vli_cmp(u, v, ndigits) < 0) + _vli_add(u, u, mod, ndigits); + + _vli_sub(u, u, v, ndigits); + if (!EVEN(u)) + carry = _vli_add(u, u, mod, ndigits); + + _vli_rshift1(u, ndigits); + if (carry) + u[ndigits - 1] |= 0x8000000000000000ull; + } else { + _vli_sub(b, b, a, ndigits); + _vli_rshift1(b, ndigits); + + if (_vli_cmp(v, u, ndigits) < 0) + _vli_add(v, v, mod, ndigits); + + _vli_sub(v, v, u, ndigits); + if (!EVEN(v)) + carry = _vli_add(v, v, mod, ndigits); + + _vli_rshift1(v, ndigits); + if (carry) + v[ndigits - 1] |= 0x8000000000000000ull; + } + } + + vli_set(result, u, ndigits); +} + +/* ------ Point operations ------ */ + +/* Point multiplication algorithm using Montgomery's ladder with co-Z + * coordinates. From http://eprint.iacr.org/2011/338.pdf + */ + +/* Double in place */ +static void ecc_point_double_jacobian(uint64_t *x1, uint64_t *y1, uint64_t *z1, + const uint64_t *curve_prime, + unsigned int ndigits) +{ + /* t1 = x, t2 = y, t3 = z */ + uint64_t t4[L_ECC_MAX_DIGITS]; + uint64_t t5[L_ECC_MAX_DIGITS]; + + if (vli_is_zero(z1, ndigits)) + return; + + /* t4 = y1^2 */ + _vli_mod_square_fast(t4, y1, curve_prime, ndigits); + /* t5 = x1*y1^2 = A */ + _vli_mod_mult_fast(t5, x1, t4, curve_prime, ndigits); + /* t4 = y1^4 */ + _vli_mod_square_fast(t4, t4, curve_prime, ndigits); + /* t2 = y1*z1 = z3 */ + _vli_mod_mult_fast(y1, y1, z1, curve_prime, ndigits); + /* t3 = z1^2 */ + _vli_mod_square_fast(z1, z1, curve_prime, ndigits); + + /* t1 = x1 + z1^2 */ + _vli_mod_add(x1, x1, z1, curve_prime, ndigits); + /* t3 = 2*z1^2 */ + _vli_mod_add(z1, z1, z1, curve_prime, ndigits); + /* t3 = x1 - z1^2 */ + _vli_mod_sub(z1, x1, z1, curve_prime, ndigits); + /* t1 = x1^2 - z1^4 */ + _vli_mod_mult_fast(x1, x1, z1, curve_prime, ndigits); + + /* t3 = 2*(x1^2 - z1^4) */ + _vli_mod_add(z1, x1, x1, curve_prime, ndigits); + /* t1 = 3*(x1^2 - z1^4) */ + _vli_mod_add(x1, x1, z1, curve_prime, ndigits); + if (vli_test_bit(x1, 0)) { + uint64_t carry = _vli_add(x1, x1, curve_prime, ndigits); + _vli_rshift1(x1, ndigits); + x1[ndigits - 1] |= carry << 63; + } else { + _vli_rshift1(x1, ndigits); + } + /* t1 = 3/2*(x1^2 - z1^4) = B */ + + /* t3 = B^2 */ + _vli_mod_square_fast(z1, x1, curve_prime, ndigits); + /* t3 = B^2 - A */ + _vli_mod_sub(z1, z1, t5, curve_prime, ndigits); + /* t3 = B^2 - 2A = x3 */ + _vli_mod_sub(z1, z1, t5, curve_prime, ndigits); + /* t5 = A - x3 */ + _vli_mod_sub(t5, t5, z1, curve_prime, ndigits); + /* t1 = B * (A - x3) */ + _vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits); + /* t4 = B * (A - x3) - y1^4 = y3 */ + _vli_mod_sub(t4, x1, t4, curve_prime, ndigits); + + vli_set(x1, z1, ndigits); + vli_set(z1, y1, ndigits); + vli_set(y1, t4, ndigits); +} + +/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */ +static void apply_z(uint64_t *x1, uint64_t *y1, uint64_t *z, + const uint64_t *curve_prime, unsigned int ndigits) +{ + uint64_t t1[L_ECC_MAX_DIGITS]; + + _vli_mod_square_fast(t1, z, curve_prime, ndigits); /* z^2 */ + _vli_mod_mult_fast(x1, x1, t1, curve_prime, ndigits); /* x1 * z^2 */ + _vli_mod_mult_fast(t1, t1, z, curve_prime, ndigits); /* z^3 */ + _vli_mod_mult_fast(y1, y1, t1, curve_prime, ndigits); /* y1 * z^3 */ +} + +/* P = (x1, y1) => 2P, (x2, y2) => P' */ +static void xycz_initial_double(uint64_t *x1, uint64_t *y1, uint64_t *x2, + uint64_t *y2, uint64_t *p_initial_z, + const uint64_t *curve_prime, + unsigned int ndigits) +{ + uint64_t z[L_ECC_MAX_DIGITS]; + + vli_set(x2, x1, ndigits); + vli_set(y2, y1, ndigits); + + vli_clear(z, ndigits); + z[0] = 1; + + if (p_initial_z) + vli_set(z, p_initial_z, ndigits); + + apply_z(x1, y1, z, curve_prime, ndigits); + + ecc_point_double_jacobian(x1, y1, z, curve_prime, ndigits); + + apply_z(x2, y2, z, curve_prime, ndigits); +} + +/* Input P = (x1, y1, Z), Q = (x2, y2, Z) + * Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3) + * or P => P', Q => P + Q + */ +static void xycz_add(uint64_t *x1, uint64_t *y1, uint64_t *x2, uint64_t *y2, + const uint64_t *curve_prime, unsigned int ndigits) +{ + /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ + uint64_t t5[L_ECC_MAX_DIGITS]; + + /* t5 = x2 - x1 */ + _vli_mod_sub(t5, x2, x1, curve_prime, ndigits); + /* t5 = (x2 - x1)^2 = A */ + _vli_mod_square_fast(t5, t5, curve_prime, ndigits); + /* t1 = x1*A = B */ + _vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits); + /* t3 = x2*A = C */ + _vli_mod_mult_fast(x2, x2, t5, curve_prime, ndigits); + /* t4 = y2 - y1 */ + _vli_mod_sub(y2, y2, y1, curve_prime, ndigits); + /* t5 = (y2 - y1)^2 = D */ + _vli_mod_square_fast(t5, y2, curve_prime, ndigits); + + /* t5 = D - B */ + _vli_mod_sub(t5, t5, x1, curve_prime, ndigits); + /* t5 = D - B - C = x3 */ + _vli_mod_sub(t5, t5, x2, curve_prime, ndigits); + /* t3 = C - B */ + _vli_mod_sub(x2, x2, x1, curve_prime, ndigits); + /* t2 = y1*(C - B) */ + _vli_mod_mult_fast(y1, y1, x2, curve_prime, ndigits); + /* t3 = B - x3 */ + _vli_mod_sub(x2, x1, t5, curve_prime, ndigits); + /* t4 = (y2 - y1)*(B - x3) */ + _vli_mod_mult_fast(y2, y2, x2, curve_prime, ndigits); + /* t4 = y3 */ + _vli_mod_sub(y2, y2, y1, curve_prime, ndigits); + + vli_set(x2, t5, ndigits); +} + +/* Input P = (x1, y1, Z), Q = (x2, y2, Z) + * Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3) + * or P => P - Q, Q => P + Q + */ +static void xycz_add_c(uint64_t *x1, uint64_t *y1, uint64_t *x2, uint64_t *y2, + const uint64_t *curve_prime, unsigned int ndigits) +{ + /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ + uint64_t t5[L_ECC_MAX_DIGITS]; + uint64_t t6[L_ECC_MAX_DIGITS]; + uint64_t t7[L_ECC_MAX_DIGITS]; + + /* t5 = x2 - x1 */ + _vli_mod_sub(t5, x2, x1, curve_prime, ndigits); + /* t5 = (x2 - x1)^2 = A */ + _vli_mod_square_fast(t5, t5, curve_prime, ndigits); + /* t1 = x1*A = B */ + _vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits); + /* t3 = x2*A = C */ + _vli_mod_mult_fast(x2, x2, t5, curve_prime, ndigits); + /* t4 = y2 + y1 */ + _vli_mod_add(t5, y2, y1, curve_prime, ndigits); + /* t4 = y2 - y1 */ + _vli_mod_sub(y2, y2, y1, curve_prime, ndigits); + + /* t6 = C - B */ + _vli_mod_sub(t6, x2, x1, curve_prime, ndigits); + /* t2 = y1 * (C - B) */ + _vli_mod_mult_fast(y1, y1, t6, curve_prime, ndigits); + /* t6 = B + C */ + _vli_mod_add(t6, x1, x2, curve_prime, ndigits); + /* t3 = (y2 - y1)^2 */ + _vli_mod_square_fast(x2, y2, curve_prime, ndigits); + /* t3 = x3 */ + _vli_mod_sub(x2, x2, t6, curve_prime, ndigits); + + /* t7 = B - x3 */ + _vli_mod_sub(t7, x1, x2, curve_prime, ndigits); + /* t4 = (y2 - y1)*(B - x3) */ + _vli_mod_mult_fast(y2, y2, t7, curve_prime, ndigits); + /* t4 = y3 */ + _vli_mod_sub(y2, y2, y1, curve_prime, ndigits); + + /* t7 = (y2 + y1)^2 = F */ + _vli_mod_square_fast(t7, t5, curve_prime, ndigits); + /* t7 = x3' */ + _vli_mod_sub(t7, t7, t6, curve_prime, ndigits); + /* t6 = x3' - B */ + _vli_mod_sub(t6, t7, x1, curve_prime, ndigits); + /* t6 = (y2 + y1)*(x3' - B) */ + _vli_mod_mult_fast(t6, t6, t5, curve_prime, ndigits); + /* t2 = y3' */ + _vli_mod_sub(y1, t6, y1, curve_prime, ndigits); + + vli_set(x1, t7, ndigits); +} + +void _ecc_point_mult(struct l_ecc_point *result, + const struct l_ecc_point *point, const uint64_t *scalar, + uint64_t *initial_z, const uint64_t *curve_prime) +{ + /* R0 and R1 */ + const struct l_ecc_curve *curve = point->curve; + uint64_t rx[2][L_ECC_MAX_DIGITS]; + uint64_t ry[2][L_ECC_MAX_DIGITS]; + uint64_t z[L_ECC_MAX_DIGITS]; + uint64_t sk[2][L_ECC_MAX_DIGITS]; + int i, nb; + unsigned int ndigits = curve->ndigits; + int num_bits; + int carry; + + carry = _vli_add(sk[0], scalar, curve->n, ndigits); + _vli_add(sk[1], sk[0], curve->n, ndigits); + scalar = sk[!carry]; + num_bits = sizeof(uint64_t) * ndigits * 8 + 1; + + vli_set(rx[1], point->x, ndigits); + vli_set(ry[1], point->y, ndigits); + + xycz_initial_double(rx[1], ry[1], rx[0], ry[0], initial_z, curve_prime, + ndigits); + + for (i = num_bits - 2; i > 0; i--) { + nb = !vli_test_bit(scalar, i); + xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve_prime, + ndigits); + xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve_prime, + ndigits); + } + + nb = !vli_test_bit(scalar, 0); + xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve_prime, + ndigits); + + /* Find final 1/Z value. */ + /* X1 - X0 */ + _vli_mod_sub(z, rx[1], rx[0], curve_prime, ndigits); + /* Yb * (X1 - X0) */ + _vli_mod_mult_fast(z, z, ry[1 - nb], curve_prime, ndigits); + /* xP * Yb * (X1 - X0) */ + _vli_mod_mult_fast(z, z, point->x, curve_prime, ndigits); + + /* 1 / (xP * Yb * (X1 - X0)) */ + _vli_mod_inv(z, z, curve_prime, ndigits); + + /* yP / (xP * Yb * (X1 - X0)) */ + _vli_mod_mult_fast(z, z, point->y, curve_prime, ndigits); + /* Xb * yP / (xP * Yb * (X1 - X0)) */ + _vli_mod_mult_fast(z, z, rx[1 - nb], curve_prime, ndigits); + /* End 1/Z calculation */ + + xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve_prime, ndigits); + + apply_z(rx[0], ry[0], z, curve_prime, ndigits); + + vli_set(result->x, rx[0], ndigits); + vli_set(result->y, ry[0], ndigits); +} + +/* Returns true if p_point is the point at infinity, false otherwise. */ +bool _ecc_point_is_zero(const struct l_ecc_point *point) +{ + return (vli_is_zero(point->x, point->curve->ndigits) && + vli_is_zero(point->y, point->curve->ndigits)); +} diff --git a/ell/ecc-private.h b/ell/ecc-private.h new file mode 100644 index 0000000000000000000000000000000000000000..de84bc64dc1bd99e9e965c12f848c5aa188131f0 --- /dev/null +++ b/ell/ecc-private.h @@ -0,0 +1,128 @@ +/* + * Embedded Linux library + * Copyright (C) 2018 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include <stdbool.h> +#include <stdint.h> + +#include "ecc.h" +#include "util.h" + +struct l_ecc_curve; + +struct l_ecc_point { + uint64_t x[L_ECC_MAX_DIGITS]; + uint64_t y[L_ECC_MAX_DIGITS]; + const struct l_ecc_curve *curve; +}; + +struct l_ecc_curve { + unsigned int ndigits; + unsigned int ike_group; + unsigned int tls_group; + const char *name; + struct l_ecc_point g; + uint64_t p[L_ECC_MAX_DIGITS]; + uint64_t n[L_ECC_MAX_DIGITS]; + uint64_t b[L_ECC_MAX_DIGITS]; + int z; +}; + +struct l_ecc_scalar { + uint64_t c[L_ECC_MAX_DIGITS]; + const struct l_ecc_curve *curve; +}; + +/* + * Performs a secure memory comparison of two uint64_t buffers of size bytes + * representing an integer. Blobs are ordered in little endian. It returns + * a negative, zero or positif value if a < b, a == b or a > b respectively. + */ +static inline int secure_memcmp_64(const uint64_t *a, const uint64_t *b, + size_t size) +{ + uint64_t aa_64, bb_64; + + int res = 0, mask; + + size_t i = 0; + + if (size) { + /* + * Arrays store blobs in LE, we will process each blob as a + * byte array of size 8 using l_secure_memcmp. We need to make + * sure to feed a BE byte array to avoid unexpected behavior + * on different architectures. + */ + do { + aa_64 = L_CPU_TO_BE64(a[i]); + bb_64 = L_CPU_TO_BE64(b[i]); + mask = l_secure_memcmp(&aa_64, &bb_64, 8); + res = (mask & res) | mask; + i++; + } while (i != size); + } + + return res; +} + +void _ecc_be2native(uint64_t *dest, const uint64_t *bytes, + unsigned int ndigits); + +void _ecc_native2be(uint64_t *dest, const uint64_t *native, + unsigned int ndigits); + +void _vli_mod_inv(uint64_t *result, const uint64_t *input, const uint64_t *mod, + unsigned int ndigits); + +void _vli_mod_sub(uint64_t *result, const uint64_t *left, const uint64_t *right, + const uint64_t *mod, unsigned int ndigits); + +void _vli_mod_add(uint64_t *result, const uint64_t *left, const uint64_t *right, + const uint64_t *mod, unsigned int ndigits); + +void _vli_rshift1(uint64_t *vli, unsigned int ndigits); + +void _vli_mmod_slow(uint64_t *result, const uint64_t *product, + const uint64_t *mod, unsigned int ndigits); + +bool _vli_mmod_fast(uint64_t *result, const uint64_t *product, + const uint64_t *curve_prime, unsigned int ndigits); + +void _vli_mod_mult_fast(uint64_t *result, const uint64_t *left, + const uint64_t *right, const uint64_t *curve_prime, + unsigned int ndigits); +void _vli_mod_square_fast(uint64_t *result, const uint64_t *left, + const uint64_t *curve_prime, + unsigned int ndigits); +void _vli_mod_exp(uint64_t *result, const uint64_t *base, const uint64_t *exp, + const uint64_t *mod, unsigned int ndigits); + +int _vli_cmp(const uint64_t *left, const uint64_t *right, unsigned int ndigits); +bool _vli_is_zero_or_one(const uint64_t *vli, unsigned int ndigits); + +uint64_t _vli_add(uint64_t *result, const uint64_t *left, + const uint64_t *right, unsigned int ndigits); +uint64_t _vli_sub(uint64_t *result, const uint64_t *left, + const uint64_t *right, unsigned int ndigits); + +int _vli_legendre(uint64_t *val, const uint64_t *p, unsigned int ndigits); + +bool _ecc_point_is_zero(const struct l_ecc_point *point); + +void _ecc_calculate_p2(const struct l_ecc_curve *curve, uint64_t *p2); + +bool _ecc_compute_y(const struct l_ecc_curve *curve, uint64_t *y, + const uint64_t *x); + +void _ecc_point_mult(struct l_ecc_point *result, + const struct l_ecc_point *point, const uint64_t *scalar, + uint64_t *initial_z, const uint64_t *curve_prime); +void _ecc_point_add(struct l_ecc_point *ret, const struct l_ecc_point *p, + const struct l_ecc_point *q, + const uint64_t *curve_prime); +struct l_ecc_scalar *_ecc_constant_new(const struct l_ecc_curve *curve, + const void *buf, size_t len); diff --git a/ell/ecc.c b/ell/ecc.c new file mode 100644 index 0000000000000000000000000000000000000000..d8d9c1ff0aa766c0f4e2820ce14aadf6181d42e7 --- /dev/null +++ b/ell/ecc.c @@ -0,0 +1,1073 @@ +/* + * Embedded Linux library + * Copyright (C) 2018 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> + +#include "ecc.h" +#include "ecc-private.h" +#include "random.h" +#include "useful.h" +#include "private.h" +#include "missing.h" + +/* + * RFC 5114 - Section 2.6 256-bit Random ECP Group + */ +#define P256_CURVE_P { 0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull, \ + 0x0000000000000000ull, 0xFFFFFFFF00000001ull } +#define P256_CURVE_GX { 0xF4A13945D898C296ull, 0x77037D812DEB33A0ull, \ + 0xF8BCE6E563A440F2ull, 0x6B17D1F2E12C4247ull } +#define P256_CURVE_GY { 0xCBB6406837BF51F5ull, 0x2BCE33576B315ECEull, \ + 0x8EE7EB4A7C0F9E16ull, 0x4FE342E2FE1A7F9Bull } +#define P256_CURVE_N { 0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull, \ + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull } +#define P256_CURVE_B { 0x3BCE3C3E27D2604Bull, 0x651D06B0CC53B0F6ull, \ + 0xB3EBBD55769886BCull, 0x5AC635D8AA3A93E7ull } + +static const struct l_ecc_curve p256 = { + .name = "secp256r1", + .ike_group = 19, + .tls_group = 23, + .ndigits = 4, + .g = { + .x = P256_CURVE_GX, + .y = P256_CURVE_GY, + .curve = &p256 + }, + .p = P256_CURVE_P, + .n = P256_CURVE_N, + .b = P256_CURVE_B, + .z = -10, +}; + +/* + * RFC 5114 - Section 2.7 384-bit Random ECP Group + */ +#define P384_CURVE_P { 0x00000000FFFFFFFFull, 0xFFFFFFFF00000000ull, \ + 0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFFFFFFFFFFull, \ + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull } +#define P384_CURVE_GX { 0x3A545E3872760AB7ull, 0x5502F25DBF55296Cull, \ + 0x59F741E082542A38ull, 0x6E1D3B628BA79B98ull, \ + 0x8EB1C71EF320AD74ull, 0xAA87CA22BE8B0537ull } +#define P384_CURVE_GY { 0x7A431D7C90EA0E5Full, 0x0A60B1CE1D7E819Dull, \ + 0xE9DA3113B5F0B8C0ull, 0xF8F41DBD289A147Cull, \ + 0x5D9E98BF9292DC29ull, 0x3617DE4A96262C6Full } +#define P384_CURVE_N { 0xECEC196ACCC52973ull, 0x581A0DB248B0A77Aull, \ + 0xC7634D81F4372DDFull, 0xFFFFFFFFFFFFFFFFull, \ + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull } +#define P384_CURVE_B { 0x2A85C8EDD3EC2AEFull, 0xC656398D8A2ED19Dull, \ + 0x0314088F5013875Aull, 0x181D9C6EFE814112ull, \ + 0x988E056BE3F82D19ull, 0xB3312FA7E23EE7E4ull } + +static const struct l_ecc_curve p384 = { + .name = "secp384r1", + .ike_group = 20, + .tls_group = 24, + .ndigits = 6, + .g = { + .x = P384_CURVE_GX, + .y = P384_CURVE_GY, + .curve = &p384 + }, + .p = P384_CURVE_P, + .n = P384_CURVE_N, + .b = P384_CURVE_B, + .z = -12, +}; + +static const struct l_ecc_curve *curves[] = { + &p384, + &p256, +}; + +/* Returns supported IKE groups, sorted by the highest effective key size */ +LIB_EXPORT const unsigned int *l_ecc_supported_ike_groups(void) +{ + static unsigned int supported_ike_groups[L_ARRAY_SIZE(curves) + 1]; + static bool ike_first = true; + + if (ike_first) { + unsigned int i; + + for (i = 0; i < L_ARRAY_SIZE(curves); i++) + supported_ike_groups[i] = curves[i]->ike_group; + + supported_ike_groups[i] = 0; + ike_first = false; + } + + return supported_ike_groups; +} + +/* Returns supported TLS groups, sorted by the highest effective key size */ +LIB_EXPORT const unsigned int *l_ecc_supported_tls_groups(void) +{ + static unsigned int supported_tls_groups[L_ARRAY_SIZE(curves) + 1]; + static bool tls_first = true; + + if (tls_first) { + unsigned int i; + + for (i = 0; i < L_ARRAY_SIZE(curves); i++) + supported_tls_groups[i] = curves[i]->tls_group; + + supported_tls_groups[i] = 0; + tls_first = false; + } + + return supported_tls_groups; +} + +LIB_EXPORT const struct l_ecc_curve *l_ecc_curve_from_name(const char *name) +{ + int i; + + if (unlikely(!name)) + return NULL; + + for (i = 0; curves[i]; i++) { + if (!strcmp(curves[i]->name, name)) + return curves[i]; + } + + return NULL; +} + +LIB_EXPORT const struct l_ecc_curve *l_ecc_curve_from_ike_group( + unsigned int group) +{ + unsigned int i; + + for (i = 0; i < L_ARRAY_SIZE(curves); i++) { + if (curves[i]->ike_group == group) + return curves[i]; + } + + return NULL; +} + +LIB_EXPORT const struct l_ecc_curve *l_ecc_curve_from_tls_group( + unsigned int group) +{ + unsigned int i; + + for (i = 0; i < L_ARRAY_SIZE(curves); i++) { + if (curves[i]->tls_group == group) + return curves[i]; + } + + return NULL; +} + +LIB_EXPORT const char *l_ecc_curve_get_name(const struct l_ecc_curve *curve) +{ + if (unlikely(!curve)) + return NULL; + + return curve->name; +} + +LIB_EXPORT unsigned int l_ecc_curve_get_ike_group( + const struct l_ecc_curve *curve) +{ + if (unlikely(!curve)) + return 0; + + return curve->ike_group; +} + +LIB_EXPORT unsigned int l_ecc_curve_get_tls_group( + const struct l_ecc_curve *curve) +{ + if (unlikely(!curve)) + return 0; + + return curve->tls_group; +} + +LIB_EXPORT struct l_ecc_scalar *l_ecc_curve_get_order( + const struct l_ecc_curve *curve) +{ + return _ecc_constant_new(curve, curve->n, curve->ndigits * 8); +} + +LIB_EXPORT struct l_ecc_scalar *l_ecc_curve_get_prime( + const struct l_ecc_curve *curve) +{ + if (unlikely(!curve)) + return NULL; + + return _ecc_constant_new(curve, curve->p, curve->ndigits * 8); +} + +LIB_EXPORT size_t l_ecc_curve_get_scalar_bytes(const struct l_ecc_curve *curve) +{ + if (unlikely(!curve)) + return 0; + + return curve->ndigits * 8; +} + +static bool ecc_valid_point(struct l_ecc_point *point) +{ + const struct l_ecc_curve *curve = point->curve; + uint64_t tmp1[L_ECC_MAX_DIGITS]; + uint64_t tmp2[L_ECC_MAX_DIGITS]; + uint64_t _3[L_ECC_MAX_DIGITS] = { 3 }; /* -a = 3 */ + unsigned int ndigits = curve->ndigits; + + /* The point at infinity is invalid. */ + if (_ecc_point_is_zero(point)) + return false; + + /* x and y must be smaller than p. */ + if (_vli_cmp(curve->p, point->x, ndigits) != 1 || + _vli_cmp(curve->p, point->y, ndigits) != 1) + return false; + + /* Computes result = y^2. */ + _vli_mod_square_fast(tmp1, point->y, curve->p, ndigits); + + /* Computes result = x^3 + ax + b. result must not overlap x. */ + /* r = x^2 */ + _vli_mod_square_fast(tmp2, point->x, curve->p, ndigits); + /* r = x^2 - 3 */ + _vli_mod_sub(tmp2, tmp2, _3, curve->p, ndigits); + /* r = x^3 - 3x */ + _vli_mod_mult_fast(tmp2, tmp2, point->x, curve->p, ndigits); + /* r = x^3 - 3x + b */ + _vli_mod_add(tmp2, tmp2, curve->b, curve->p, ndigits); + /* Make sure that y^2 == x^3 + ax + b */ + return (_vli_cmp(tmp1, tmp2, ndigits) == 0); +} + +void _ecc_be2native(uint64_t *dest, const uint64_t *bytes, + unsigned int ndigits) +{ + unsigned int i; + uint64_t tmp[2 * L_ECC_MAX_DIGITS]; + + for (i = 0; i < ndigits; i++) + tmp[ndigits - 1 - i] = l_get_be64(&bytes[i]); + + memcpy(dest, tmp, ndigits * 8); +} + +void _ecc_native2be(uint64_t *dest, const uint64_t *native, + unsigned int ndigits) +{ + unsigned int i; + uint64_t tmp[L_ECC_MAX_DIGITS]; + + for (i = 0; i < ndigits; i++) + l_put_be64(native[ndigits - 1 - i], &tmp[i]); + + memcpy(dest, tmp, ndigits * 8); +} + +static void ecc_compute_y_sqr(const struct l_ecc_curve *curve, + uint64_t *y_sqr, const uint64_t *x) +{ + uint64_t sum[L_ECC_MAX_DIGITS] = { 0 }; + uint64_t tmp[L_ECC_MAX_DIGITS] = { 0 }; + uint64_t _3[L_ECC_MAX_DIGITS] = { 3ull }; /* -a = 3 */ + + /* x^3 */ + _vli_mod_square_fast(sum, x, curve->p, curve->ndigits); + _vli_mod_mult_fast(sum, sum, x, curve->p, curve->ndigits); + /* x^3 - ax */ + _vli_mod_mult_fast(tmp, _3, x, curve->p, curve->ndigits); + _vli_mod_sub(sum, sum, tmp, curve->p, curve->ndigits); + /* x^3 - ax + b */ + _vli_mod_add(sum, sum, curve->b, curve->p, curve->ndigits); + + memcpy(y_sqr, sum, curve->ndigits * 8); +} + +/* + * Compute sqrt(y^2) + * Since our prime p satisfies p = 3 (mod 4), we can say: + * + * y = (y^2)^((p + 1) / 4) + * + * This avoids the need for a square root function. + */ +static void ecc_compute_sqrt(const struct l_ecc_curve *curve, + uint64_t *y, const uint64_t *y_sqr) +{ + uint64_t expo[L_ECC_MAX_DIGITS]; + uint64_t one[L_ECC_MAX_DIGITS] = { 1ull }; + + memcpy(expo, curve->p, curve->ndigits * 8); + + /* (p + 1) / 4 == (p >> 2) + 1 */ + _vli_rshift1(expo, curve->ndigits); + _vli_rshift1(expo, curve->ndigits); + _vli_mod_add(expo, expo, one, curve->p, curve->ndigits); + /* sum ^ ((p + 1) / 4) */ + _vli_mod_exp(y, y_sqr, expo, curve->p, curve->ndigits); +} + +bool _ecc_compute_y(const struct l_ecc_curve *curve, uint64_t *y, + const uint64_t *x) +{ + uint64_t sum[L_ECC_MAX_DIGITS] = { 0 }; + uint64_t check[L_ECC_MAX_DIGITS] = { 0 }; + + /* y = sqrt(x^3 + ax + b) (mod p) */ + ecc_compute_y_sqr(curve, sum, x); + ecc_compute_sqrt(curve, y, sum); + + /* square y to ensure we have a correct value */ + _vli_mod_mult_fast(check, y, y, curve->p, curve->ndigits); + + if (_vli_cmp(check, sum, curve->ndigits) != 0) + return false; + + return true; +} + +/* + * IETF - Compact representation of an elliptic curve point: + * https://tools.ietf.org/id/draft-jivsov-ecc-compact-00.xml + * + * "min(y,p-y) can be calculated with the help of the pre-calculated value + * p2=(p-1)/2. min(y,p-y) is y if y<p2 and p-y otherwise." + */ +void _ecc_calculate_p2(const struct l_ecc_curve *curve, uint64_t *p2) +{ + uint64_t one[L_ECC_MAX_DIGITS] = { 1 }; + + _vli_mod_sub(p2, curve->p, one, curve->p, curve->ndigits); + _vli_rshift1(p2, curve->ndigits); +} + +/* + * IETF draft-jivsov-ecc-compact-00 Section 4.1 + * Encoding and decoding of an elliptic curve point + * ... + * Decoding: + * Given the compact representation of Q, return canonical representation + * of Q=(x,y) as follows: + * 1. y' = sqrt( x^3 + a*x + b ), where y'>0 + * 2. y = min(y',p-y') + * 3. Q=(x,y) is the canonical representation of the point + */ +static bool decode_point(const struct l_ecc_curve *curve, uint64_t *x, + struct l_ecc_point *point) +{ + uint64_t y_min[L_ECC_MAX_DIGITS]; + uint64_t p2[L_ECC_MAX_DIGITS]; + + if (!_ecc_compute_y(curve, y_min, (uint64_t *)x)) + return false; + + _ecc_calculate_p2(curve, p2); + + if (_vli_cmp(y_min, p2, curve->ndigits) >= 0) + _vli_mod_sub(point->y, curve->p, y_min, + curve->p, curve->ndigits); + else + memcpy(point->y, y_min, curve->ndigits * 8); + + memcpy(point->x, x, curve->ndigits * 8); + + return true; +} + +/* (rx, ry) = (px, py) + (qx, qy) */ +void _ecc_point_add(struct l_ecc_point *ret, const struct l_ecc_point *p, + const struct l_ecc_point *q, + const uint64_t *curve_prime) +{ + /* + * s = (py - qy)/(px - qx) + * + * rx = s^2 - px - qx + * ry = s(px - rx) - py + */ + uint64_t s[L_ECC_MAX_DIGITS]; + uint64_t kp1[L_ECC_MAX_DIGITS]; + uint64_t kp2[L_ECC_MAX_DIGITS]; + uint64_t resx[L_ECC_MAX_DIGITS]; + uint64_t resy[L_ECC_MAX_DIGITS]; + unsigned int ndigits = p->curve->ndigits; + + memset(s, 0, ndigits * 8); + + /* kp1 = py - qy */ + _vli_mod_sub(kp1, q->y, p->y, curve_prime, ndigits); + /* kp2 = px - qx */ + _vli_mod_sub(kp2, q->x, p->x, curve_prime, ndigits); + /* s = kp1/kp2 */ + _vli_mod_inv(kp2, kp2, curve_prime, ndigits); + _vli_mod_mult_fast(s, kp1, kp2, curve_prime, ndigits); + /* rx = s^2 - px - qx */ + _vli_mod_mult_fast(kp1, s, s, curve_prime, ndigits); + _vli_mod_sub(kp1, kp1, p->x, curve_prime, ndigits); + _vli_mod_sub(resx, kp1, q->x, curve_prime, ndigits); + /* ry = s(px - rx) - py */ + _vli_mod_sub(kp1, p->x, resx, curve_prime, ndigits); + _vli_mod_mult_fast(kp1, s, kp1, curve_prime, ndigits); + _vli_mod_sub(resy, kp1, p->y, curve_prime, ndigits); + + memcpy(ret->x, resx, ndigits * 8); + memcpy(ret->y, resy, ndigits * 8); +} + +/* result = (base ^ exp) % p */ +void _vli_mod_exp(uint64_t *result, const uint64_t *base, const uint64_t *exp, + const uint64_t *mod, unsigned int ndigits) +{ + unsigned int i; + int bit; + uint64_t n[L_ECC_MAX_DIGITS]; + uint64_t r[L_ECC_MAX_DIGITS] = { 1 }; + + memcpy(n, base, ndigits * 8); + + for (i = 0; i < ndigits; i++) { + for (bit = 0; bit < 64; bit++) { + uint64_t tmp[L_ECC_MAX_DIGITS]; + + if (exp[i] & (1ull << bit)) { + _vli_mod_mult_fast(tmp, r, n, mod, ndigits); + memcpy(r, tmp, ndigits * 8); + } + + _vli_mod_mult_fast(tmp, n, n, mod, ndigits); + memcpy(n, tmp, ndigits * 8); + } + } + + memcpy(result, r, ndigits * 8); +} + +__attribute__((noinline)) static int vli_equal(const uint64_t *a, + const uint64_t *b, + unsigned int ndigits) +{ + uint64_t diff = 0; + unsigned int i; + + for (i = 0; i < ndigits; i++) { + diff |= a[i] ^ b[i]; + __asm__ ("" : "=r" (diff) : "0" (diff)); + } + + return (~diff & (diff - 1)) >> 63; +} + +int _vli_legendre(uint64_t *val, const uint64_t *p, unsigned int ndigits) +{ + uint64_t tmp[L_ECC_MAX_DIGITS]; + uint64_t exp[L_ECC_MAX_DIGITS]; + uint64_t _1[L_ECC_MAX_DIGITS] = { 1ull }; + uint64_t _0[L_ECC_MAX_DIGITS] = { 0 }; + + /* check that val ^ ((p - 1) / 2) == [1, 0 or -1] */ + + _vli_sub(exp, p, _1, ndigits); + _vli_rshift1(exp, ndigits); + _vli_mod_exp(tmp, val, exp, p, ndigits); + + if (_vli_cmp(tmp, _1, ndigits) == 0) + return 1; + if (_vli_cmp(tmp, _0, ndigits) == 0) + return 0; + return -1; +} + +bool _vli_is_zero_or_one(const uint64_t *vli, unsigned int ndigits) +{ + uint64_t _1[L_ECC_MAX_DIGITS] = { 1ull }; + int ret; + + ret = secure_select(vli_equal(vli, _1, ndigits), true, false); + ret = secure_select(l_secure_memeq(vli, ndigits * 8, 0), true, ret); + + return ret; +} + +LIB_EXPORT struct l_ecc_point *l_ecc_point_new(const struct l_ecc_curve *curve) +{ + struct l_ecc_point *p = l_new(struct l_ecc_point, 1); + + p->curve = curve; + + return p; +} + +LIB_EXPORT struct l_ecc_point *l_ecc_point_from_data( + const struct l_ecc_curve *curve, + enum l_ecc_point_type type, + const void *data, size_t len) +{ + struct l_ecc_point *p; + size_t bytes = curve->ndigits * 8; + uint64_t tmp[L_ECC_MAX_DIGITS]; + bool sub; + + if (!data) + return NULL; + + /* Verify the data length matches a full point or X coordinate */ + if (type == L_ECC_POINT_TYPE_FULL) { + if (len != bytes * 2) + return NULL; + } else if (len != bytes) + return NULL; + + p = l_ecc_point_new(curve); + + _ecc_be2native(p->x, (void *) data, curve->ndigits); + + switch (type) { + case L_ECC_POINT_TYPE_COMPLIANT: + if (!decode_point(curve, p->x, p)) + goto failed; + + break; + case L_ECC_POINT_TYPE_COMPRESSED_BIT0: + case L_ECC_POINT_TYPE_COMPRESSED_BIT1: + if (!_ecc_compute_y(curve, p->y, p->x)) + goto failed; + + /* + * This is determining whether or not to subtract the Y + * coordinate from P. According to ANSI X9.62 an even Y should + * be prefixed with 02 (BIT0) and an odd Y should be prefixed + * with 03 (BIT1). If this is not the case, subtract Y from P. + * + * ANSI X9.62 + * 4.3.6 Point-to-Octet-String Conversion + * + * 2. If the compressed form is used, then do the following: + * 2.1. Compute the bit ~Yp . (See Section 4.2.) + * 2.2. Assign the value 02 to the single octet PC if ~Yp + * is 0, or the value 03 if ~Yp is 1. + * 2.3. The result is the octet string PO = PC || X + */ + + sub = secure_select(type == L_ECC_POINT_TYPE_COMPRESSED_BIT0, + p->y[0] & 1, !(p->y[0] & 1)); + + _vli_mod_sub(tmp, curve->p, p->y, curve->p, curve->ndigits); + + l_secure_select(sub, tmp, p->y, p->y, curve->ndigits * 8); + + break; + case L_ECC_POINT_TYPE_FULL: + _ecc_be2native(p->y, (void *) data + bytes, curve->ndigits); + + if (!ecc_valid_point(p)) + goto failed; + + break; + } + + return p; + +failed: + l_free(p); + return NULL; +} + +LIB_EXPORT struct l_ecc_point *l_ecc_point_from_sswu( + const struct l_ecc_scalar *u) +{ + const struct l_ecc_curve *curve = u->curve; + unsigned int ndigits = curve->ndigits; + uint64_t z[L_ECC_MAX_DIGITS] = { abs(curve->z) }; + uint64_t _3[L_ECC_MAX_DIGITS] = { 3ull }; /* -a = 3 */ + uint64_t u2z[L_ECC_MAX_DIGITS]; + uint64_t t1[L_ECC_MAX_DIGITS]; + uint64_t t2[L_ECC_MAX_DIGITS]; + uint64_t m[L_ECC_MAX_DIGITS]; + uint64_t t[L_ECC_MAX_DIGITS]; + uint64_t x1l[L_ECC_MAX_DIGITS]; + uint64_t x1r[L_ECC_MAX_DIGITS]; + uint64_t x1[L_ECC_MAX_DIGITS]; + uint64_t gx1[L_ECC_MAX_DIGITS]; + uint64_t x2[L_ECC_MAX_DIGITS]; + uint64_t gx2[L_ECC_MAX_DIGITS]; + /* reuse m/t/x1l,x1r, they are unused by the time x/v/y/p-y is needed */ + uint64_t *x = m; + uint64_t *v = t; + uint64_t *yl = x1l; + uint64_t *yr = x1r; + bool l; + struct l_ecc_point *P; + + /* + * m = (z^2 * u^4 + z * u^2) modulo p + * u2z = u^2 * z + * t2 = u2z^2 + * m = t2 - u2z since for all our curves z is negative + */ + _vli_mod_square_fast(u2z, u->c, curve->p, ndigits); + _vli_mod_mult_fast(u2z, u2z, z, curve->p, ndigits); + _vli_mod_square_fast(t2, u2z, curve->p, ndigits); + _vli_mod_sub(m, t2, u2z, curve->p, ndigits); + + /* + * l = CEQ(m, 0) + * t = inv0(m) where inv0(x) is calculated as x^(p-2) modulo p + */ + l = l_secure_memeq(m, sizeof(m), 0); + + memset(t2, 0, sizeof(t2)); + t2[0] = 2ull; + _vli_mod_sub(t1, curve->p, t2, curve->p, ndigits); + _vli_mod_exp(t, m, t1, curve->p, ndigits); + + /* Calculate: b / z*a, both z and a are negative */ + _vli_mod_mult_fast(t1, z, _3, curve->p, ndigits); + _vli_mod_inv(t1, t1, curve->p, ndigits); + _vli_mod_mult_fast(x1l, curve->b, t1, curve->p, ndigits); + + /* t = 1 + t */ + memset(t2, 0, sizeof(t2)); + t2[0] = 1ull; + _vli_mod_add(t, t, t2, curve->p, ndigits); + + /* t1 = 1 / a */ + _vli_mod_inv(t1, _3, curve->p, ndigits); + + /* x1r = b * t1 * t */ + _vli_mod_mult_fast(x1r, curve->b, t1, curve->p, ndigits); + _vli_mod_mult_fast(x1r, x1r, t, curve->p, ndigits); + + /* x1 = CSEL(l, (b / (z*a) modulo p), ((-b/a) * (1 + t)) modulo p) */ + l_secure_select(l, x1l, x1r, x1, ndigits * 8); + + /* gx1 = (x1^3 + a*x1 + b) modulo p */ + ecc_compute_y_sqr(curve, gx1, x1); + + /* x2 = (z*u^2*x1) modulo p, z is negative, hence the second op */ + _vli_mod_mult_fast(x2, u2z, x1, curve->p, ndigits); + _vli_mod_sub(x2, curve->p, x2, curve->p, ndigits); + + /* gx2 = (x2^3 + a*x2 + b) modulo p */ + ecc_compute_y_sqr(curve, gx2, x2); + + /* + * l = gx1 is a quadratic residue modulo p + * x is a quadratic residue if x^((p-1)/2) modulo p is zero or one + */ + _vli_mod_sub(t1, curve->p, t2, curve->p, ndigits); + _vli_rshift1(t1, ndigits); + _vli_mod_exp(t2, gx1, t1, curve->p, ndigits); + l = _vli_is_zero_or_one(t2, ndigits); + + /* v = CSEL(l, gx1, gx2) */ + l_secure_select(l, gx1, gx2, v, ndigits * 8); + /* x = CSEL(l, x1, x2) */ + l_secure_select(l, x1, x2, x, ndigits * 8); + /* y = sqrt(v) */ + ecc_compute_sqrt(curve, yl, v); + /* l = CEQ(LSB(u), LSB(y)) */ + l = !((u->c[0] & 1ull) ^ (yl[0] & 1ull)); + + /* p - y */ + _vli_mod_sub(yr, curve->p, yl, curve->p, ndigits); + + /* P = CSEL(l, (x,y), (x, p-y)) */ + P = l_ecc_point_new(curve); + memcpy(P->x, x, ndigits * 8); + l_secure_select(l, yl, yr, P->y, ndigits * 8); + + return P; +} + +LIB_EXPORT struct l_ecc_point *l_ecc_point_clone(const struct l_ecc_point *p) +{ + if (!p) + return NULL; + + return l_memdup(p, sizeof(*p)); +} + +LIB_EXPORT const struct l_ecc_curve *l_ecc_point_get_curve( + const struct l_ecc_point *p) +{ + if (!p) + return NULL; + + return p->curve; +} + +LIB_EXPORT ssize_t l_ecc_point_get_x(const struct l_ecc_point *p, void *x, + size_t xlen) +{ + if (xlen < p->curve->ndigits * 8) + return -EMSGSIZE; + + _ecc_native2be(x, p->x, p->curve->ndigits); + + return p->curve->ndigits * 8; +} + +LIB_EXPORT ssize_t l_ecc_point_get_y(const struct l_ecc_point *p, void *y, + size_t ylen) +{ + if (ylen < p->curve->ndigits * 8) + return -EMSGSIZE; + + _ecc_native2be(y, p->y, p->curve->ndigits); + + return p->curve->ndigits * 8; +} + +LIB_EXPORT bool l_ecc_point_y_isodd(const struct l_ecc_point *p) +{ + return p->y[0] & 1; +} + +LIB_EXPORT ssize_t l_ecc_point_get_data(const struct l_ecc_point *p, void *buf, + size_t len) +{ + if (len < (p->curve->ndigits * 8) * 2) + return -EMSGSIZE; + + _ecc_native2be(buf, (uint64_t *) p->x, p->curve->ndigits); + _ecc_native2be(buf + (p->curve->ndigits * 8), (uint64_t *) p->y, + p->curve->ndigits); + + return (p->curve->ndigits * 8) * 2; +} + +LIB_EXPORT void l_ecc_point_free(struct l_ecc_point *p) +{ + if (unlikely(!p)) + return; + + explicit_bzero(p->x, p->curve->ndigits * 8); + explicit_bzero(p->y, p->curve->ndigits * 8); + l_free(p); +} + +struct l_ecc_scalar *_ecc_constant_new(const struct l_ecc_curve *curve, + const void *buf, size_t len) +{ + struct l_ecc_scalar *c; + + if (unlikely(!curve)) + return NULL; + + if (buf && len != curve->ndigits * 8) + return NULL; + + c = l_new(struct l_ecc_scalar, 1); + + c->curve = curve; + + if (buf) + memcpy(c->c, buf, len); + + return c; +} + +LIB_EXPORT struct l_ecc_scalar *l_ecc_scalar_new( + const struct l_ecc_curve *curve, + const void *buf, size_t len) +{ + struct l_ecc_scalar *c; + + c = _ecc_constant_new(curve, NULL, 0); + if (!c) + return NULL; + + if (!buf) + return c; + + _ecc_be2native(c->c, buf, curve->ndigits); + + if (!_vli_is_zero_or_one(c->c, curve->ndigits) && + secure_memcmp_64(curve->n, c->c, curve->ndigits) > 0) + return c; + + l_ecc_scalar_free(c); + + return NULL; +} + +LIB_EXPORT struct l_ecc_scalar *l_ecc_scalar_clone(const struct l_ecc_scalar *s) +{ + if (!s) + return NULL; + + return l_memdup(s, sizeof(*s)); +} + +/* + * Build a scalar = value modulo p where p is the prime number for a given + * curve. bytes can contain a number with up to 2x number of digits as the + * curve. This is used in Hash to Curve calculations. + */ +LIB_EXPORT struct l_ecc_scalar *l_ecc_scalar_new_modp( + const struct l_ecc_curve *curve, + const void *bytes, size_t len) +{ + struct l_ecc_scalar *c; + uint64_t tmp[2 * L_ECC_MAX_DIGITS]; + unsigned int ndigits = len / 8; + + if (!bytes) + return NULL; + + if (len % 8) + return NULL; + + if (ndigits > curve->ndigits * 2) + return NULL; + + c = _ecc_constant_new(curve, NULL, 0); + if (!c) + return NULL; + + memset(tmp, 0, sizeof(tmp)); + _ecc_be2native(tmp, bytes, ndigits); + + _vli_mmod_fast(c->c, tmp, curve->p, curve->ndigits); + + if (!_vli_is_zero_or_one(c->c, curve->ndigits) && + secure_memcmp_64(curve->n, c->c, curve->ndigits) > 0) + return c; + + l_ecc_scalar_free(c); + + return NULL; +} + +LIB_EXPORT struct l_ecc_scalar *l_ecc_scalar_new_modn( + const struct l_ecc_curve *curve, + const void *bytes, size_t len) +{ + struct l_ecc_scalar *c; + uint64_t tmp[2 * L_ECC_MAX_DIGITS]; + unsigned int ndigits = len / 8; + + if (!bytes) + return NULL; + + if (len % 8) + return NULL; + + if (ndigits > curve->ndigits * 2) + return NULL; + + c = _ecc_constant_new(curve, NULL, 0); + if (!c) + return NULL; + + memset(tmp, 0, sizeof(tmp)); + _ecc_be2native(tmp, bytes, ndigits); + + _vli_mmod_slow(c->c, tmp, curve->n, curve->ndigits); + + if (!_vli_is_zero_or_one(c->c, curve->ndigits) && + secure_memcmp_64(curve->n, c->c, curve->ndigits) > 0) + return c; + + l_ecc_scalar_free(c); + + return NULL; +} + +/* + * Takes a buffer of the same size as the curve and scales it to a range + * 1..n using value = (value mod (n - 1)) + 1. For the curves we support + * this can be done using a subtraction operation due to the size of n + */ +LIB_EXPORT struct l_ecc_scalar *l_ecc_scalar_new_reduced_1_to_n( + const struct l_ecc_curve *curve, + const void *buf, size_t len) +{ + uint64_t _1[L_ECC_MAX_DIGITS] = { 1ull }; + uint64_t tmp[L_ECC_MAX_DIGITS]; + struct l_ecc_scalar *c; + + if (!buf) + return NULL; + + if (len != curve->ndigits * 8) + return NULL; + + c = _ecc_constant_new(curve, NULL, 0); + if (!c) + return NULL; + + _vli_sub(tmp, curve->n, _1, curve->ndigits); + _ecc_be2native(c->c, buf, curve->ndigits); + + if (_vli_cmp(c->c, tmp, curve->ndigits) >= 0) + _vli_sub(c->c, c->c, tmp, curve->ndigits); + + _vli_add(c->c, c->c, _1, curve->ndigits); + + return c; +} + +LIB_EXPORT struct l_ecc_scalar *l_ecc_scalar_new_random( + const struct l_ecc_curve *curve) +{ + uint64_t r[L_ECC_MAX_DIGITS]; + + l_getrandom(r, curve->ndigits * 8); + + while (_vli_cmp(r, curve->p, curve->ndigits) > 0 || + _vli_cmp(r, curve->n, curve->ndigits) > 0 || + _vli_is_zero_or_one(r, curve->ndigits)) + l_getrandom(r, curve->ndigits * 8); + + return _ecc_constant_new(curve, r, curve->ndigits * 8); +} + +LIB_EXPORT ssize_t l_ecc_scalar_get_data(const struct l_ecc_scalar *c, + void *buf, size_t len) +{ + if (len < c->curve->ndigits * 8) + return -EMSGSIZE; + + _ecc_native2be(buf, (uint64_t *) c->c, c->curve->ndigits); + + return c->curve->ndigits * 8; +} + +LIB_EXPORT void l_ecc_scalar_free(struct l_ecc_scalar *c) +{ + if (unlikely(!c)) + return; + + explicit_bzero(c->c, c->curve->ndigits * 8); + l_free(c); +} + +LIB_EXPORT bool l_ecc_scalar_add(struct l_ecc_scalar *ret, + const struct l_ecc_scalar *a, + const struct l_ecc_scalar *b, + const struct l_ecc_scalar *mod) +{ + if (unlikely(!ret || !a || !b || !mod)) + return false; + + _vli_mod_add(ret->c, a->c, b->c, mod->c, a->curve->ndigits); + + return true; +} + +LIB_EXPORT bool l_ecc_point_multiply(struct l_ecc_point *ret, + const struct l_ecc_scalar *scalar, + const struct l_ecc_point *point) +{ + if (unlikely(!ret || !scalar || !point)) + return false; + + _ecc_point_mult(ret, point, scalar->c, NULL, scalar->curve->p); + + return true; +} + +LIB_EXPORT bool l_ecc_point_multiply_g(struct l_ecc_point *ret, + const struct l_ecc_scalar *scalar) +{ + if (unlikely(!ret || !scalar)) + return false; + + _ecc_point_mult(ret, &scalar->curve->g, scalar->c, NULL, + scalar->curve->p); + + return true; +} + +LIB_EXPORT bool l_ecc_point_add(struct l_ecc_point *ret, + const struct l_ecc_point *a, + const struct l_ecc_point *b) +{ + if (unlikely(!ret || !a || !b)) + return false; + + _ecc_point_add(ret, a, b, a->curve->p); + + return true; +} + +LIB_EXPORT bool l_ecc_point_inverse(struct l_ecc_point *p) +{ + if (unlikely(!p)) + return false; + + _vli_mod_sub(p->y, p->curve->p, p->y, p->curve->p, p->curve->ndigits); + + return true; +} + +LIB_EXPORT bool l_ecc_scalar_multiply(struct l_ecc_scalar *ret, + const struct l_ecc_scalar *a, + const struct l_ecc_scalar *b) +{ + if (unlikely(!ret || !a || !b)) + return false; + + _vli_mod_mult_fast(ret->c, a->c, b->c, a->curve->p, a->curve->ndigits); + + return true; +} + +LIB_EXPORT int l_ecc_scalar_legendre(struct l_ecc_scalar *value) +{ + if (unlikely(!value)) + return -1; + + return _vli_legendre(value->c, value->curve->p, value->curve->ndigits); +} + +LIB_EXPORT bool l_ecc_scalar_sum_x(struct l_ecc_scalar *ret, + const struct l_ecc_scalar *x) +{ + if (unlikely(!ret || !x)) + return false; + + ecc_compute_y_sqr(x->curve, ret->c, x->c); + + return true; +} + +LIB_EXPORT bool l_ecc_scalars_are_equal(const struct l_ecc_scalar *a, + const struct l_ecc_scalar *b) +{ + if (unlikely(!a || !b)) + return false; + + return (memcmp(a->c, b->c, a->curve->ndigits * 8) == 0); +} + +LIB_EXPORT bool l_ecc_points_are_equal(const struct l_ecc_point *a, + const struct l_ecc_point *b) +{ + if (unlikely(!a || !b)) + return false; + + return ((memcmp(a->x, b->x, a->curve->ndigits * 8) == 0) && + (memcmp(a->y, b->y, a->curve->ndigits * 8) == 0)); +} + +LIB_EXPORT bool l_ecc_point_is_infinity(const struct l_ecc_point *p) +{ + return _ecc_point_is_zero(p); +} diff --git a/ell/ecc.h b/ell/ecc.h new file mode 100644 index 0000000000000000000000000000000000000000..3502b98975099f2945cf3f60d08b680e1835c06e --- /dev/null +++ b/ell/ecc.h @@ -0,0 +1,113 @@ +/* + * Embedded Linux library + * Copyright (C) 2018 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_ECC_H +#define __ELL_ECC_H + +#include <sys/types.h> +#include <ell/cleanup.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define L_ECC_MAX_DIGITS 6 +#define L_ECC_SCALAR_MAX_BYTES L_ECC_MAX_DIGITS * 8 +#define L_ECC_POINT_MAX_BYTES L_ECC_SCALAR_MAX_BYTES * 2 + +struct l_ecc_curve; +struct l_ecc_point; +struct l_ecc_scalar; + +enum l_ecc_point_type { + L_ECC_POINT_TYPE_COMPLIANT = 0x01, + L_ECC_POINT_TYPE_COMPRESSED_BIT0 = 0x02, + L_ECC_POINT_TYPE_COMPRESSED_BIT1 = 0x03, + L_ECC_POINT_TYPE_FULL = 0x04, +}; + +const unsigned int *l_ecc_supported_ike_groups(void); +const unsigned int *l_ecc_supported_tls_groups(void); + +const struct l_ecc_curve *l_ecc_curve_from_name(const char *name); +const struct l_ecc_curve *l_ecc_curve_from_ike_group(unsigned int group); +const struct l_ecc_curve *l_ecc_curve_from_tls_group(unsigned int group); + +const char *l_ecc_curve_get_name(const struct l_ecc_curve *curve); +unsigned int l_ecc_curve_get_ike_group(const struct l_ecc_curve *curve); +unsigned int l_ecc_curve_get_tls_group(const struct l_ecc_curve *curve); +struct l_ecc_scalar *l_ecc_curve_get_order(const struct l_ecc_curve *curve); +struct l_ecc_scalar *l_ecc_curve_get_prime(const struct l_ecc_curve *curve); +size_t l_ecc_curve_get_scalar_bytes(const struct l_ecc_curve *curve); + +struct l_ecc_point *l_ecc_point_new(const struct l_ecc_curve *curve); +struct l_ecc_point *l_ecc_point_from_data(const struct l_ecc_curve *curve, + enum l_ecc_point_type type, + const void *data, size_t len); +struct l_ecc_point *l_ecc_point_from_sswu(const struct l_ecc_scalar *u); +struct l_ecc_point *l_ecc_point_clone(const struct l_ecc_point *p); + +const struct l_ecc_curve *l_ecc_point_get_curve(const struct l_ecc_point *p); +ssize_t l_ecc_point_get_x(const struct l_ecc_point *p, void *x, size_t xlen); +ssize_t l_ecc_point_get_y(const struct l_ecc_point *p, void *y, size_t ylen); +bool l_ecc_point_y_isodd(const struct l_ecc_point *p); + +ssize_t l_ecc_point_get_data(const struct l_ecc_point *p, void *buf, size_t len); +void l_ecc_point_free(struct l_ecc_point *p); +DEFINE_CLEANUP_FUNC(l_ecc_point_free); + +struct l_ecc_scalar *l_ecc_scalar_new(const struct l_ecc_curve *curve, + const void *buf, size_t len); +struct l_ecc_scalar *l_ecc_scalar_clone(const struct l_ecc_scalar *s); +struct l_ecc_scalar *l_ecc_scalar_new_random( + const struct l_ecc_curve *curve); +struct l_ecc_scalar *l_ecc_scalar_new_modp(const struct l_ecc_curve *curve, + const void *buf, size_t len); +struct l_ecc_scalar *l_ecc_scalar_new_modn(const struct l_ecc_curve *curve, + const void *buf, size_t len); +struct l_ecc_scalar *l_ecc_scalar_new_reduced_1_to_n( + const struct l_ecc_curve *curve, + const void *buf, size_t len); +ssize_t l_ecc_scalar_get_data(const struct l_ecc_scalar *c, void *buf, + size_t len); +void l_ecc_scalar_free(struct l_ecc_scalar *c); +DEFINE_CLEANUP_FUNC(l_ecc_scalar_free); + +/* Constant operations */ +bool l_ecc_scalar_add(struct l_ecc_scalar *ret, const struct l_ecc_scalar *a, + const struct l_ecc_scalar *b, + const struct l_ecc_scalar *mod); + +/* Point operations */ +bool l_ecc_point_multiply(struct l_ecc_point *ret, + const struct l_ecc_scalar *scalar, + const struct l_ecc_point *point); +bool l_ecc_point_multiply_g(struct l_ecc_point *ret, + const struct l_ecc_scalar *scalar); +bool l_ecc_point_add(struct l_ecc_point *ret, const struct l_ecc_point *a, + const struct l_ecc_point *b); +bool l_ecc_point_inverse(struct l_ecc_point *p); + +/* extra operations needed for SAE */ +bool l_ecc_scalar_multiply(struct l_ecc_scalar *ret, + const struct l_ecc_scalar *a, + const struct l_ecc_scalar *b); +int l_ecc_scalar_legendre(struct l_ecc_scalar *value); +bool l_ecc_scalar_sum_x(struct l_ecc_scalar *ret, const struct l_ecc_scalar *x); + +bool l_ecc_scalars_are_equal(const struct l_ecc_scalar *a, + const struct l_ecc_scalar *b); + +bool l_ecc_points_are_equal(const struct l_ecc_point *a, + const struct l_ecc_point *b); +bool l_ecc_point_is_infinity(const struct l_ecc_point *p); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_ECC_H */ diff --git a/ell/ecdh.c b/ell/ecdh.c new file mode 100644 index 0000000000000000000000000000000000000000..e10a7d431c4fe7197a4bf7d1943f445a8523be91 --- /dev/null +++ b/ell/ecdh.c @@ -0,0 +1,99 @@ +/* + * Embedded Linux library + * Copyright (C) 2018 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdint.h> + +#include "private.h" +#include "ecc-private.h" +#include "ecc.h" +#include "ecdh.h" +#include "random.h" +#include "useful.h" + +/* + * Some sane maximum for calculating the public key. + */ +#define ECDH_MAX_ITERATIONS 20 + +/* + * IETF draft-jivsov-ecc-compact-00 Section 4.2.1 + * + * The following algorithm calculates a key pair {k, Q=k*G=(x,y)}, where k is + * the private key and Q=(x,y) is the public key. + * + * Black box generation: + * 1. Generate a key pair {k, Q=k*G=(x,y)} with KG + * 2. if( y != min(y,p-y) ) goto step 1 + * 3. output {k, Q=(x,y)} as a key pair + */ +LIB_EXPORT bool l_ecdh_generate_key_pair(const struct l_ecc_curve *curve, + struct l_ecc_scalar **out_private, + struct l_ecc_point **out_public) +{ + bool compliant = false; + int iter = 0; + uint64_t p2[L_ECC_MAX_DIGITS]; + + if (unlikely(!curve || !out_private || !out_public)) + return false; + + _ecc_calculate_p2(curve, p2); + + *out_public = l_ecc_point_new(curve); + + while (!compliant && iter++ < ECDH_MAX_ITERATIONS) { + *out_private = l_ecc_scalar_new_random(curve); + + _ecc_point_mult(*out_public, &curve->g, (*out_private)->c, + NULL, curve->p); + + /* ensure public key is compliant */ + if (_vli_cmp((*out_public)->y, p2, curve->ndigits) >= 0) { + compliant = true; + break; + } + + l_ecc_scalar_free(*out_private); + } + + if (!compliant) { + l_ecc_point_free(*out_public); + return false; + } + + return true; +} + +LIB_EXPORT bool l_ecdh_generate_shared_secret( + const struct l_ecc_scalar *private_key, + const struct l_ecc_point *other_public, + struct l_ecc_scalar **secret) +{ + const struct l_ecc_curve *curve = private_key->curve; + struct l_ecc_scalar *z; + struct l_ecc_point *product; + + if (unlikely(!private_key || !other_public || !secret)) + return false; + + z = l_ecc_scalar_new_random(curve); + + product = l_ecc_point_new(curve); + + _ecc_point_mult(product, other_public, private_key->c, z->c, curve->p); + + *secret = _ecc_constant_new(curve, product->x, curve->ndigits * 8); + + l_ecc_point_free(product); + l_ecc_scalar_free(z); + + return true; +} diff --git a/ell/ecdh.h b/ell/ecdh.h new file mode 100644 index 0000000000000000000000000000000000000000..768a532b78d18bd9f56d3fa609c18864d3a3f950 --- /dev/null +++ b/ell/ecdh.h @@ -0,0 +1,38 @@ +/* + * Embedded Linux library + * Copyright (C) 2018 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_ECDH_H +#define __ELL_ECDH_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct l_ecc_curve; +struct l_ecc_point; +struct l_ecc_scalar; + +/* + * Generate a private/public key pair. private/public are out parameters and + * must be freed. + */ +bool l_ecdh_generate_key_pair(const struct l_ecc_curve *curve, + struct l_ecc_scalar **out_private, + struct l_ecc_point **out_public); +/* + * Generate a shared secret from a private/public key. secret is an out + * parameters and must be freed. + */ +bool l_ecdh_generate_shared_secret(const struct l_ecc_scalar *private_key, + const struct l_ecc_point *other_public, + struct l_ecc_scalar **secret); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_ECDH_H */ diff --git a/ell/ell.h b/ell/ell.h new file mode 100644 index 0000000000000000000000000000000000000000..527679925a64bc40c6eda1c7a6c4cde0e5c9bee8 --- /dev/null +++ b/ell/ell.h @@ -0,0 +1,38 @@ +#include <ell/util.h> +#include <ell/log.h> +#include <ell/queue.h> +#include <ell/hashmap.h> +#include <ell/random.h> +#include <ell/signal.h> +#include <ell/time.h> +#include <ell/time-private.h> +#include <ell/timeout.h> +#include <ell/cipher.h> +#include <ell/checksum.h> +#include <ell/io.h> +#include <ell/idle.h> +#include <ell/main.h> +#include <ell/settings.h> +#include <ell/strv.h> +#include <ell/string.h> +#include <ell/utf8.h> +#include <ell/dbus.h> +#include <ell/dbus-service.h> +#include <ell/dbus-client.h> +#include <ell/key.h> +#include <ell/cert.h> +#include <ell/pem.h> +#include <ell/base64.h> +#include <ell/asn1-private.h> +#include <ell/cert-private.h> +#include <ell/pem-private.h> +#include <ell/uuid.h> +#include <ell/useful.h> +#include <ell/main-private.h> +#include <ell/tester.h> +#include <ell/tls.h> +#include <ell/tls-private.h> +#include <ell/ecc.h> +#include <ell/ecc-private.h> +#include <ell/cleanup.h> +#include <ell/ecdh.h> diff --git a/ell/gvariant-private.h b/ell/gvariant-private.h new file mode 100644 index 0000000000000000000000000000000000000000..2aabd2eb041a95275d2530c2852e74bfa0ff3025 --- /dev/null +++ b/ell/gvariant-private.h @@ -0,0 +1,54 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +struct l_dbus_message_iter; +struct dbus_builder; + +bool _gvariant_iter_init(struct l_dbus_message_iter *iter, + struct l_dbus_message *message, + const char *sig_start, const char *sig_end, + const void *data, size_t len); +bool _gvariant_iter_next_entry_basic(struct l_dbus_message_iter *iter, + char type, void *out_p); +bool _gvariant_iter_enter_struct(struct l_dbus_message_iter *iter, + struct l_dbus_message_iter *structure); +bool _gvariant_iter_enter_variant(struct l_dbus_message_iter *iter, + struct l_dbus_message_iter *variant); +bool _gvariant_iter_enter_array(struct l_dbus_message_iter *iter, + struct l_dbus_message_iter *array); +bool _gvariant_iter_skip_entry(struct l_dbus_message_iter *iter); + +bool _gvariant_valid_signature(const char *sig); +int _gvariant_get_alignment(const char *signature); +bool _gvariant_is_fixed_size(const char *signature); +int _gvariant_get_fixed_size(const char *signature); +int _gvariant_num_children(const char *sig); + +struct dbus_builder *_gvariant_builder_new(void *body, size_t body_size); +void _gvariant_builder_free(struct dbus_builder *builder); +bool _gvariant_builder_append_basic(struct dbus_builder *builder, + char type, const void *value); +bool _gvariant_builder_mark(struct dbus_builder *builder); +bool _gvariant_builder_rewind(struct dbus_builder *builder); +char *_gvariant_builder_finish(struct dbus_builder *builder, + void **body, size_t *body_size); +bool _gvariant_builder_enter_struct(struct dbus_builder *builder, + const char *signature); +bool _gvariant_builder_leave_struct(struct dbus_builder *builder); +bool _gvariant_builder_enter_dict(struct dbus_builder *builder, + const char *signature); +bool _gvariant_builder_leave_dict(struct dbus_builder *builder); +bool _gvariant_builder_enter_variant(struct dbus_builder *builder, + const char *signature); +bool _gvariant_builder_leave_variant(struct dbus_builder *builder); +bool _gvariant_builder_enter_array(struct dbus_builder *builder, + const char *signature); +bool _gvariant_builder_leave_array(struct dbus_builder *builder); + +size_t _gvariant_message_finalize(size_t header_end, + void *body, size_t body_size, + const char *signature); diff --git a/ell/gvariant-util.c b/ell/gvariant-util.c new file mode 100644 index 0000000000000000000000000000000000000000..6482e24c8786dcd61bf9e0df2919d1c200653c73 --- /dev/null +++ b/ell/gvariant-util.c @@ -0,0 +1,1364 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <stdbool.h> +#include <unistd.h> +#include <string.h> +#include <endian.h> +#include <limits.h> + +#include "private.h" +#include "useful.h" +#include "util.h" +#include "queue.h" +#include "string.h" +#include "log.h" +#include "dbus.h" +#include "dbus-private.h" +#include "gvariant-private.h" + +static const char *simple_types = "sogybnqiuxtdh"; +static const char *variable_types = "sogav"; +static const char *fixed_types = "bynqhiuxtd"; + +/* + * The alignment of a container type is equal to the largest alignment of + * any potential child of that container. This means that, even if an array + * of 32-bit integers is empty, it still must be aligned to the nearest + * multiple of 4 bytes. It also means that the variant type (described below) + * has an alignment of 8 (since it could potentially contain a value of any + * other type and the maximum alignment is 8). + */ +static int get_basic_alignment(const char type) +{ + switch (type) { + case 'b': + return 1; + case 'y': + return 1; + case 'n': + case 'q': + return 2; + case 'i': + case 'u': + return 4; + case 'x': + case 't': + case 'd': + return 8; + case 's': + case 'g': + case 'o': + return 1; + case 'h': + return 4; + case 'v': + return 8; + default: + return 0; + } +} + +static int get_basic_fixed_size(const char type) +{ + switch (type) { + case 'b': + return 1; + case 'y': + return 1; + case 'n': + case 'q': + return 2; + case 'i': + case 'u': + return 4; + case 'x': + case 't': + case 'd': + return 8; + case 'h': + return 4; + default: + return 0; + } +} + +static const char *validate_next_type(const char *sig, int *out_alignment) +{ + char s = *sig; + int alignment; + + if (s == '\0') + return NULL; + + if (strchr(simple_types, s) || s == 'v') { + *out_alignment = get_basic_alignment(s); + return sig + 1; + } + + switch (s) { + case 'a': + return validate_next_type(++sig, out_alignment); + + case '{': + s = *++sig; + + /* Dictionary keys can only be simple types */ + if (!strchr(simple_types, s)) + return NULL; + + alignment = get_basic_alignment(s); + + sig = validate_next_type(sig + 1, out_alignment); + + if (!sig) + return NULL; + + if (*sig != '}') + return NULL; + + if (alignment > *out_alignment) + *out_alignment = alignment; + + return sig + 1; + + case '(': + { + int max_alignment = 1, alignment; + + sig++; + + while (sig && *sig != ')') { + sig = validate_next_type(sig, &alignment); + + if (alignment > max_alignment) + max_alignment = alignment; + } + + if (!sig) + return NULL; + + if (*sig != ')') + return NULL; + + *out_alignment = max_alignment; + + return sig + 1; + } + } + + return NULL; +} + +bool _gvariant_valid_signature(const char *sig) +{ + const char *s = sig; + int a; + + if (strlen(sig) > 255) + return false; + + do { + s = validate_next_type(s, &a); + + if (!s) + return false; + } while (*s); + + return true; +} + +int _gvariant_num_children(const char *sig) +{ + const char *s = sig; + int a; + int num_children = 0; + + if (strlen(sig) > 255) + return false; + + do { + s = validate_next_type(s, &a); + + if (!s) + return -1; + + num_children += 1; + } while (*s); + + return num_children; +} + +int _gvariant_get_alignment(const char *sig) +{ + int max_alignment = 1, alignment; + const char *s = sig; + + /* 8 is the largest alignment possible, so quit if we reach it */ + while (*s && max_alignment != 8) { + s = validate_next_type(s, &alignment); + if (!s) + return 0; + + if (alignment > max_alignment) + max_alignment = alignment; + } + + return max_alignment; +} + +bool _gvariant_is_fixed_size(const char *sig) +{ + while (*sig != 0) { + if (strchr(variable_types, sig[0])) + return false; + + sig += 1; + } + + return true; +} + +int _gvariant_get_fixed_size(const char *sig) +{ + const char *s = sig; + const char *p; + int size = 0; + int alignment; + int max_alignment = 1; + int r; + + while (*s) { + if (strchr(variable_types, *s)) + return 0; + + if (strchr(fixed_types, *s)) { + alignment = get_basic_alignment(*s); + + if (alignment > max_alignment) + max_alignment = alignment; + + size = align_len(size, alignment); + size += get_basic_fixed_size(*s); + s++; + continue; + } + + if (*s == '}' || *s == ')') + break; + + p = validate_next_type(s, &alignment); + + if (!p) + return 0; + + if (alignment > max_alignment) + max_alignment = alignment; + + size = align_len(size, alignment); + + /* Handle special case of unit type */ + if (s[0] == '(' && s[1] == ')') + r = 1; + else + r = _gvariant_get_fixed_size(s + 1); + + if (r == 0) + return 0; + + size += r; + s = p; + } + + size = align_len(size, max_alignment); + + return size; +} + +static inline size_t offset_length(size_t size, size_t n_offsets) +{ + if (size + n_offsets <= 0xff) + return 1; + if (size + n_offsets * 2 <= 0xffff) + return 2; + if (size + n_offsets * 4 <= 0xffffffff) + return 4; + return 8; +} + +static inline size_t read_word_le(const void *p, size_t sz) { + union { + uint16_t u16; + uint32_t u32; + uint64_t u64; + } x; + + if (sz == 1) + return *(uint8_t *) p; + + memcpy(&x, p, sz); + + if (sz == 2) + return le16toh(x.u16); + if (sz == 4) + return le32toh(x.u32); + return le64toh(x.u64); +} + +static inline void write_word_le(void *p, size_t value, size_t sz) { + union { + uint16_t u16; + uint32_t u32; + uint64_t u64; + } x; + + if (sz == 1) { + *(uint8_t *) p = value; + return; + } + + if (sz == 2) + x.u16 = htole16((uint16_t) value); + else if (sz == 4) + x.u32 = htole32((uint32_t) value); + else + x.u64 = htole64((uint64_t) value); + + memcpy(p, &x, sz); +} + +static bool gvariant_iter_init_internal(struct l_dbus_message_iter *iter, + struct l_dbus_message *message, + enum dbus_container_type type, + const char *sig_start, + const char *sig_end, const void *data, + size_t len) +{ + const char *p; + int i; + int v; + char subsig[256]; + unsigned int num_variable = 0; + unsigned int offset_len = offset_length(len, 0); + size_t last_offset; + struct gvariant_type_info { + uint8_t sig_start; + uint8_t sig_end; + bool fixed_size : 1; + unsigned int alignment : 4; + size_t end; /* Index past the end of the type */ + } *children; + int n_children; + + if (sig_end) { + size_t len = sig_end - sig_start; + memcpy(subsig, sig_start, len); + subsig[len] = '\0'; + } else + strcpy(subsig, sig_start); + + iter->message = message; + iter->sig_start = sig_start; + iter->sig_len = strlen(subsig); + iter->sig_pos = 0; + iter->data = data; + iter->len = len; + iter->pos = 0; + + if (subsig[0] != '\0') { + n_children = _gvariant_num_children(subsig); + if (n_children < 0) + return false; + + children = l_new(struct gvariant_type_info, n_children); + } else { + n_children = 0; + + children = NULL; + } + + for (p = sig_start, i = 0; i < n_children; i++) { + int alignment; + size_t size; + size_t len; + + children[i].sig_start = p - sig_start; + p = validate_next_type(p, &alignment); + children[i].sig_end = p - sig_start; + + len = children[i].sig_end - children[i].sig_start; + memcpy(subsig, sig_start + children[i].sig_start, len); + subsig[len] = '\0'; + + children[i].alignment = alignment; + children[i].fixed_size = _gvariant_is_fixed_size(subsig); + + if (children[i].fixed_size) { + size = _gvariant_get_fixed_size(subsig); + children[i].end = size; + } else if (i + 1 < n_children) + num_variable += 1; + } + + if (len < num_variable * offset_len) + goto fail; + + last_offset = len - num_variable * offset_len; + + if (num_variable > 0) + iter->offsets = iter->data + len - offset_len; + else + iter->offsets = NULL; + + for (i = 0, v = 0; i < n_children; i++) { + size_t o; + + if (children[i].fixed_size) { + if (i == 0) + continue; + + o = align_len(children[i-1].end, + children[i].alignment); + children[i].end += o; + + if (children[i].end > len) + goto fail; + + continue; + } + + if (num_variable == 0) { + children[i].end = last_offset; + continue; + } + + v += 1; + children[i].end = read_word_le(data + len - offset_len * v, + offset_len); + num_variable -= 1; + + if (children[i].end > len) + goto fail; + } + + iter->container_type = type; + + if (type == DBUS_CONTAINER_TYPE_ARRAY && + !children[0].fixed_size) { + size_t offset = read_word_le(iter->data + iter->len - + offset_len, offset_len); + iter->offsets = iter->data + offset; + } + + l_free(children); + + return true; + +fail: + l_free(children); + return false; +} + +bool _gvariant_iter_init(struct l_dbus_message_iter *iter, + struct l_dbus_message *message, + const char *sig_start, const char *sig_end, + const void *data, size_t len) +{ + return gvariant_iter_init_internal(iter, message, + DBUS_CONTAINER_TYPE_STRUCT, + sig_start, sig_end, data, len); +} + +static const void *next_item(struct l_dbus_message_iter *iter, + size_t *out_item_size) +{ + const void *start; + const char *p; + char sig[256]; + int alignment; + bool fixed_size; + bool last_member; + unsigned int sig_len; + unsigned int offset_len; + + memcpy(sig, iter->sig_start + iter->sig_pos, + iter->sig_len - iter->sig_pos); + sig[iter->sig_len - iter->sig_pos] = '\0'; + + /* + * Find the next type and make a note whether it is the last in the + * structure. Arrays will always have a single complete type, so + * last_member will always be true. + */ + p = validate_next_type(sig, &alignment); + if (!p) + return NULL; + + sig_len = p - sig; + + last_member = *p == '\0'; + sig[sig_len] = '\0'; + + fixed_size = _gvariant_is_fixed_size(sig); + + if (iter->container_type != DBUS_CONTAINER_TYPE_ARRAY) + iter->sig_pos += sig_len; + + iter->pos = align_len(iter->pos, alignment); + + if (fixed_size) { + *out_item_size = _gvariant_get_fixed_size(sig); + goto done; + } + + if (iter->container_type != DBUS_CONTAINER_TYPE_ARRAY && last_member) { + unsigned int len = iter->len; + + offset_len = offset_length(iter->len, 0); + + if (iter->offsets && iter->offsets + offset_len < + iter->data + len) + len = iter->offsets + offset_len - iter->data; + + *out_item_size = len - iter->pos; + goto done; + } + + if (iter->offsets >= iter->data + iter->len) + return NULL; + + offset_len = offset_length(iter->len, 0); + *out_item_size = read_word_le(iter->offsets, offset_len) - iter->pos; + + /* In structures the offsets are in reverse order */ + if (iter->container_type == DBUS_CONTAINER_TYPE_ARRAY) + iter->offsets += offset_len; + else + iter->offsets -= offset_len; + +done: + start = iter->data + iter->pos; + + if (start >= iter->data + iter->len) + return NULL; + + iter->pos += *out_item_size; + + return start; +} + +bool _gvariant_iter_next_entry_basic(struct l_dbus_message_iter *iter, + char type, void *out) +{ + size_t item_size = 0; + const void *start; + uint8_t uint8_val; + uint16_t uint16_val; + uint32_t uint32_val; + uint64_t uint64_val; + int16_t int16_val; + int32_t int32_val; + int64_t int64_val; + + if (iter->pos >= iter->len) + return false; + + if (iter->sig_start[iter->sig_pos] != type) + return false; + + start = next_item(iter, &item_size); + if (!start) + return false; + + switch (type) { + case 'o': + case 's': + case 'g': + { + const void *end = memchr(start, 0, item_size); + + if (!end) + return false; + + *(const char**) out = start; + break; + } + case 'b': + uint8_val = l_get_u8(start); + *(bool *) out = !!uint8_val; + break; + case 'y': + uint8_val = l_get_u8(start); + *(uint8_t *) out = uint8_val; + break; + case 'n': + int16_val = l_get_s16(start); + *(int16_t *) out = int16_val; + break; + case 'q': + uint16_val = l_get_u16(start); + *(uint16_t *) out = uint16_val; + break; + case 'i': + int32_val = l_get_s32(start); + *(int32_t *) out = int32_val; + break; + case 'h': + case 'u': + uint32_val = l_get_u32(start); + *(uint32_t *) out = uint32_val; + break; + case 'x': + int64_val = l_get_s64(start); + *(int64_t *) out = int64_val; + break; + case 't': + uint64_val = l_get_u64(start); + *(uint64_t *) out = uint64_val; + break; + case 'd': + uint64_val = l_get_u64(start); + *(uint64_t *) out = uint64_val; + break; + } + + return true; +} + +bool _gvariant_iter_enter_struct(struct l_dbus_message_iter *iter, + struct l_dbus_message_iter *structure) +{ + bool is_dict = iter->sig_start[iter->sig_pos] == '{'; + bool is_struct = iter->sig_start[iter->sig_pos] == '('; + const char *sig_start = iter->sig_start + iter->sig_pos + 1; + const char *sig_end; + const void *start; + size_t item_size; + enum dbus_container_type type; + + if (!is_dict && !is_struct) + return false; + + start = next_item(iter, &item_size); + if (!start) + return false; + + /* For ARRAY containers the sig_pos is never incremented */ + if (iter->container_type == DBUS_CONTAINER_TYPE_ARRAY) + sig_end = iter->sig_start + iter->sig_len - 1; + else + sig_end = iter->sig_start + iter->sig_pos - 1; + + type = is_dict ? DBUS_CONTAINER_TYPE_DICT_ENTRY : + DBUS_CONTAINER_TYPE_STRUCT; + + return gvariant_iter_init_internal(structure, iter->message, + type, sig_start, sig_end, + start, item_size); +} + +bool _gvariant_iter_enter_variant(struct l_dbus_message_iter *iter, + struct l_dbus_message_iter *variant) +{ + size_t item_size; + const void *start, *end, *nul; + char signature[256]; + + if (iter->sig_start[iter->sig_pos] != 'v') + return false; + + start = next_item(iter, &item_size); + if (!start) + return false; + + /* Find the signature */ + end = start + item_size; + nul = memrchr(start, 0, end - start); + + if (!nul) + return false; + + if (end - nul - 1 > 255) + return false; + + memcpy(signature, nul + 1, end - nul - 1); + signature[end - nul - 1] = '\0'; + + if (_gvariant_num_children(signature) != 1) + return false; + + return gvariant_iter_init_internal(variant, iter->message, + DBUS_CONTAINER_TYPE_VARIANT, + nul + 1, end, + start, nul - start); +} + +bool _gvariant_iter_enter_array(struct l_dbus_message_iter *iter, + struct l_dbus_message_iter *array) +{ + const char *sig_start; + const char *sig_end; + size_t item_size; + const void *start; + + if (iter->sig_start[iter->sig_pos] != 'a') + return false; + + sig_start = iter->sig_start + iter->sig_pos + 1; + + start = next_item(iter, &item_size); + if (!start) + return false; + + /* For ARRAY containers the sig_pos is never incremented */ + if (iter->container_type == DBUS_CONTAINER_TYPE_ARRAY) + sig_end = iter->sig_start + iter->sig_len; + else + sig_end = iter->sig_start + iter->sig_pos; + + return gvariant_iter_init_internal(array, iter->message, + DBUS_CONTAINER_TYPE_ARRAY, + sig_start, sig_end, + start, item_size); +} + +bool _gvariant_iter_skip_entry(struct l_dbus_message_iter *iter) +{ + size_t size; + + if (!next_item(iter, &size)) + return false; + + return true; +} + +struct dbus_builder { + struct l_string *signature; + void *body; + size_t body_size; + size_t body_pos; + struct l_queue *containers; + struct { + struct container *container; + int sig_end; + size_t body_pos; + size_t offset_index; + bool variable_is_last : 1; + } mark; +}; + +struct container { + size_t *offsets; + size_t offsets_size; + size_t offset_index; + size_t start; + bool variable_is_last : 1; + enum dbus_container_type type; + char signature[256]; + uint8_t sigindex; +}; + +static inline size_t grow_body(struct dbus_builder *builder, + size_t len, unsigned int alignment) +{ + size_t size = align_len(builder->body_pos, alignment); + + if (size + len > builder->body_size) { + builder->body = l_realloc(builder->body, size + len); + builder->body_size = size + len; + } + + if (size - builder->body_pos > 0) + memset(builder->body + builder->body_pos, 0, + size - builder->body_pos); + + builder->body_pos = size + len; + + return size; +} + +static inline bool grow_offsets(struct container *container) +{ + size_t needed; + + if (container->offset_index < container->offsets_size) + return true; + + needed = container->offsets_size * 2; + + if (needed > USHRT_MAX) + return false; + + if (needed == 0) + needed = 8; + + container->offsets = l_realloc(container->offsets, + needed * sizeof(size_t)); + container->offsets_size = needed; + + return true; +} + +static struct container *container_new(enum dbus_container_type type, + const char *signature, size_t start) +{ + struct container *ret; + + ret = l_new(struct container, 1); + + ret->type = type; + strcpy(ret->signature, signature); + ret->start = start; + + return ret; +} + +static void container_free(struct container *container) +{ + l_free(container->offsets); + l_free(container); +} + +static void container_append_struct_offsets(struct container *container, + struct dbus_builder *builder) +{ + size_t offset_size; + int i; + size_t start; + + if (container->variable_is_last) + container->offset_index -= 1; + + if (container->offset_index == 0) + return; + + offset_size = offset_length(builder->body_pos, + container->offset_index); + + start = grow_body(builder, offset_size * container->offset_index, 1); + + for (i = container->offset_index - 1; i >= 0; i--) { + write_word_le(builder->body + start, + container->offsets[i], offset_size); + start += offset_size; + } +} + +static void container_append_array_offsets(struct container *container, + struct dbus_builder *builder) +{ + size_t offset_size; + unsigned int i; + size_t start; + + if (container->offset_index == 0) + return; + + offset_size = offset_length(builder->body_pos, + container->offset_index); + start = grow_body(builder, offset_size * container->offset_index, 1); + + for (i = 0; i < container->offset_index; i++) { + write_word_le(builder->body + start, + container->offsets[i], offset_size); + start += offset_size; + } +} + +struct dbus_builder *_gvariant_builder_new(void *body, size_t body_size) +{ + struct dbus_builder *builder; + struct container *root; + + builder = l_new(struct dbus_builder, 1); + builder->signature = l_string_new(63); + + builder->containers = l_queue_new(); + root = container_new(DBUS_CONTAINER_TYPE_STRUCT, "", 0); + l_queue_push_head(builder->containers, root); + + builder->body = body; + builder->body_size = body_size; + builder->body_pos = body_size; + + builder->mark.container = root; + + return builder; +} + +void _gvariant_builder_free(struct dbus_builder *builder) +{ + if (unlikely(!builder)) + return; + + l_string_free(builder->signature); + l_queue_destroy(builder->containers, + (l_queue_destroy_func_t) container_free); + l_free(builder->body); + + l_free(builder); +} + +static bool enter_struct_dict_common(struct dbus_builder *builder, + const char *signature, + enum dbus_container_type type, + const char open, + const char close) +{ + size_t qlen = l_queue_length(builder->containers); + struct container *container = l_queue_peek_head(builder->containers); + int alignment; + size_t start; + + if (qlen == 1) { + if (l_string_length(builder->signature) + + strlen(signature) + 2 > 255) + return false; + } else { + /* Verify Signatures Match */ + char expect[256]; + const char *start; + const char *end; + + start = container->signature + container->sigindex; + end = validate_next_type(start, &alignment) - 1; + + if (*start != open || *end != close) + return false; + + memcpy(expect, start + 1, end - start - 1); + expect[end - start - 1] = '\0'; + + if (strcmp(expect, signature)) + return false; + } + + alignment = _gvariant_get_alignment(signature); + start = grow_body(builder, 0, alignment); + + container = container_new(type, signature, start); + l_queue_push_head(builder->containers, container); + + return true; +} + +bool _gvariant_builder_enter_struct(struct dbus_builder *builder, + const char *signature) +{ + if (signature[0] && !_gvariant_valid_signature(signature)) + return false; + + return enter_struct_dict_common(builder, signature, + DBUS_CONTAINER_TYPE_STRUCT, '(', ')'); +} + +bool _gvariant_builder_enter_dict(struct dbus_builder *builder, + const char *signature) +{ + if (_gvariant_num_children(signature) != 2) + return false; + + if (!strchr(simple_types, signature[0])) + return false; + + return enter_struct_dict_common(builder, signature, + DBUS_CONTAINER_TYPE_DICT_ENTRY, + '{', '}'); +} + +static bool leave_struct_dict_common(struct dbus_builder *builder, + enum dbus_container_type type, + const char open, + const char close) +{ + struct container *container = l_queue_peek_head(builder->containers); + size_t qlen = l_queue_length(builder->containers); + struct container *parent; + + if (unlikely(qlen <= 1)) + return false; + + if (unlikely(container->type != type)) + return false; + + l_queue_pop_head(builder->containers); + qlen -= 1; + parent = l_queue_peek_head(builder->containers); + + if (_gvariant_is_fixed_size(container->signature)) { + int alignment = _gvariant_get_alignment(container->signature); + grow_body(builder, 0, alignment); + + /* Empty struct or "unit type" is encoded as a zero byte */ + if (container->signature[0] == '\0') { + size_t start = grow_body(builder, 1, 1); + + memset(builder->body + start, 0, 1); + } + + parent->variable_is_last = false; + } else { + size_t offset; + + if (!grow_offsets(parent)) + return false; + + container_append_struct_offsets(container, builder); + offset = builder->body_pos - parent->start; + parent->offsets[parent->offset_index++] = offset; + parent->variable_is_last = true; + } + + if (qlen == 1) + l_string_append_printf(builder->signature, "%c%s%c", + open, + container->signature, + close); + else if (parent->type != DBUS_CONTAINER_TYPE_ARRAY) + parent->sigindex += strlen(container->signature) + 2; + + container_free(container); + + return true; +} + +bool _gvariant_builder_leave_struct(struct dbus_builder *builder) +{ + return leave_struct_dict_common(builder, DBUS_CONTAINER_TYPE_STRUCT, + '(', ')'); +} + +bool _gvariant_builder_leave_dict(struct dbus_builder *builder) +{ + return leave_struct_dict_common(builder, + DBUS_CONTAINER_TYPE_DICT_ENTRY, + '{', '}'); +} + +bool _gvariant_builder_enter_variant(struct dbus_builder *builder, + const char *signature) +{ + size_t qlen = l_queue_length(builder->containers); + struct container *container = l_queue_peek_head(builder->containers); + size_t start; + + if (_gvariant_num_children(signature) != 1) + return false; + + if (qlen == 1) { + if (l_string_length(builder->signature) + 1 > 255) + return false; + } else if (container->signature[container->sigindex] != 'v') + return false; + + start = grow_body(builder, 0, 8); + + container = container_new(DBUS_CONTAINER_TYPE_VARIANT, + signature, start); + l_queue_push_head(builder->containers, container); + + return true; +} + +bool _gvariant_builder_leave_variant(struct dbus_builder *builder) +{ + struct container *container = l_queue_peek_head(builder->containers); + size_t qlen = l_queue_length(builder->containers); + struct container *parent; + size_t start; + size_t siglen; + size_t offset; + + if (unlikely(qlen <= 1)) + return false; + + if (unlikely(container->type != DBUS_CONTAINER_TYPE_VARIANT)) + return false; + + l_queue_pop_head(builder->containers); + qlen -= 1; + parent = l_queue_peek_head(builder->containers); + + siglen = strlen(container->signature); + start = grow_body(builder, siglen + 1, 1); + memset(builder->body + start, 0, 1); + memcpy(builder->body + start + 1, container->signature, siglen); + + if (!grow_offsets(parent)) + return false; + + offset = builder->body_pos - parent->start; + parent->offsets[parent->offset_index++] = offset; + parent->variable_is_last = true; + + if (qlen == 1) + l_string_append_c(builder->signature, 'v'); + else if (parent->type != DBUS_CONTAINER_TYPE_ARRAY) + parent->sigindex += 1; + + container_free(container); + + return true; +} + +bool _gvariant_builder_enter_array(struct dbus_builder *builder, + const char *signature) +{ + size_t qlen = l_queue_length(builder->containers); + struct container *container = l_queue_peek_head(builder->containers); + size_t start; + int alignment; + + if (_gvariant_num_children(signature) != 1) + return false; + + if (qlen == 1) { + if (l_string_length(builder->signature) + + strlen(signature) + 1 > 255) + return false; + } else { + /* Verify Signatures Match */ + char expect[256]; + const char *start; + const char *end; + + start = container->signature + container->sigindex; + end = validate_next_type(start, &alignment); + + if (*start != 'a') + return false; + + memcpy(expect, start + 1, end - start - 1); + expect[end - start - 1] = '\0'; + + if (strcmp(expect, signature)) + return false; + } + + alignment = _gvariant_get_alignment(signature); + start = grow_body(builder, 0, alignment); + + container = container_new(DBUS_CONTAINER_TYPE_ARRAY, signature, start); + l_queue_push_head(builder->containers, container); + + return true; +} + +bool _gvariant_builder_leave_array(struct dbus_builder *builder) +{ + struct container *container = l_queue_peek_head(builder->containers); + size_t qlen = l_queue_length(builder->containers); + struct container *parent; + size_t offset; + + if (unlikely(qlen <= 1)) + return false; + + if (unlikely(container->type != DBUS_CONTAINER_TYPE_ARRAY)) + return false; + + l_queue_pop_head(builder->containers); + qlen -= 1; + parent = l_queue_peek_head(builder->containers); + + if (!_gvariant_is_fixed_size(container->signature)) + container_append_array_offsets(container, builder); + + if (!grow_offsets(parent)) + return false; + + offset = builder->body_pos - parent->start; + parent->offsets[parent->offset_index++] = offset; + parent->variable_is_last = true; + + if (qlen == 1) + l_string_append_printf(builder->signature, "a%s", + container->signature); + else if (parent->type != DBUS_CONTAINER_TYPE_ARRAY) + parent->sigindex += strlen(container->signature) + 1; + + container_free(container); + + return true; +} + +bool _gvariant_builder_append_basic(struct dbus_builder *builder, + char type, const void *value) +{ + struct container *container = l_queue_peek_head(builder->containers); + size_t start; + unsigned int alignment; + size_t len; + size_t offset; + + if (unlikely(!builder)) + return false; + + if (unlikely(!strchr(simple_types, type))) + return false; + + alignment = get_basic_alignment(type); + if (!alignment) + return false; + + if (l_queue_length(builder->containers) == 1) + l_string_append_c(builder->signature, type); + else if (container->signature[container->sigindex] != type) + return false; + + len = get_basic_fixed_size(type); + + if (len) { + start = grow_body(builder, len, alignment); + memcpy(builder->body + start, value, len); + container->variable_is_last = false; + + if (container->type != DBUS_CONTAINER_TYPE_ARRAY) + container->sigindex += 1; + + return true; + } + + if (!grow_offsets(container)) + return false; + + len = strlen(value) + 1; + start = grow_body(builder, len, alignment); + memcpy(builder->body + start, value, len); + + offset = builder->body_pos - container->start; + container->offsets[container->offset_index++] = offset; + container->variable_is_last = true; + + if (container->type != DBUS_CONTAINER_TYPE_ARRAY) + container->sigindex += 1; + + return true; +} + +bool _gvariant_builder_mark(struct dbus_builder *builder) +{ + struct container *container = l_queue_peek_head(builder->containers); + + builder->mark.container = container; + + if (l_queue_length(builder->containers) == 1) + builder->mark.sig_end = l_string_length(builder->signature); + else + builder->mark.sig_end = container->sigindex; + + builder->mark.body_pos = builder->body_pos; + builder->mark.offset_index = container->offset_index; + builder->mark.variable_is_last = container->variable_is_last; + + return true; +} + +bool _gvariant_builder_rewind(struct dbus_builder *builder) +{ + struct container *container; + + while ((container = l_queue_peek_head(builder->containers)) != + builder->mark.container) { + container_free(container); + l_queue_pop_head(builder->containers); + } + + builder->body_pos = builder->mark.body_pos; + container->offset_index = builder->mark.offset_index; + container->variable_is_last = builder->mark.variable_is_last; + + if (l_queue_length(builder->containers) == 1) + l_string_truncate(builder->signature, builder->mark.sig_end); + else + container->sigindex = builder->mark.sig_end; + + return true; +} + +char *_gvariant_builder_finish(struct dbus_builder *builder, + void **body, size_t *body_size) +{ + char *signature; + struct container *root; + uint8_t *variant_buf; + size_t size; + + if (unlikely(!builder)) + return NULL; + + if (unlikely(l_queue_length(builder->containers) != 1)) + return NULL; + + root = l_queue_peek_head(builder->containers); + + signature = l_string_unwrap(builder->signature); + builder->signature = NULL; + + if (_gvariant_is_fixed_size(signature)) { + int alignment = _gvariant_get_alignment(signature); + grow_body(builder, 0, alignment); + + /* Empty struct or "unit type" is encoded as a zero byte */ + if (signature[0] == '\0') { + size_t start = grow_body(builder, 1, 1); + + memset(builder->body + start, 0, 1); + } + } else + container_append_struct_offsets(root, builder); + + /* + * Make sure there's enough space after the body for the variant + * signature written here but not included in the body size and + * one framing offset value to be written in + * _gvariant_message_finalize. + */ + size = 3 + strlen(signature) + 8; + if (builder->body_pos + size > builder->body_size) + builder->body = l_realloc(builder->body, + builder->body_pos + size); + + variant_buf = builder->body + builder->body_pos; + *variant_buf++ = 0; + *variant_buf++ = '('; + variant_buf = mempcpy(variant_buf, signature, strlen(signature)); + *variant_buf++ = ')'; + + *body = builder->body; + *body_size = builder->body_pos; + builder->body = NULL; + builder->body_size = 0; + + return signature; +} + +/* + * Write the header's framing offset after the body variant which is the + * last piece of data in the message after the header, the padding and + * the builder has written the message body. + */ +size_t _gvariant_message_finalize(size_t header_end, + void *body, size_t body_size, + const char *signature) +{ + size_t offset_start; + size_t offset_size; + + offset_start = body_size + 3 + strlen(signature); + + offset_size = offset_length(align_len(header_end, 8) + offset_start, 1); + + write_word_le(body + offset_start, header_end, offset_size); + + return align_len(header_end, 8) + offset_start + offset_size; +} diff --git a/ell/hashmap.c b/ell/hashmap.c new file mode 100644 index 0000000000000000000000000000000000000000..6769bc1e317e6ac4aefd6229a3f53d32d776d8b8 --- /dev/null +++ b/ell/hashmap.c @@ -0,0 +1,718 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "hashmap.h" +#include "private.h" +#include "useful.h" + +/** + * SECTION:hashmap + * @short_description: Hash table support + * + * Hash table support + */ + +#define NBUCKETS 127 + +struct entry { + void *key; + void *value; + struct entry *next; + unsigned int hash; +}; + +/** + * l_hashmap: + * + * Opaque object representing the hash table. + */ +struct l_hashmap { + l_hashmap_hash_func_t hash_func; + l_hashmap_compare_func_t compare_func; + l_hashmap_key_new_func_t key_new_func; + l_hashmap_key_free_func_t key_free_func; + unsigned int entries; + struct entry buckets[NBUCKETS]; +}; + +static inline void *get_key_new(const struct l_hashmap *hashmap, + const void *key) +{ + if (hashmap->key_new_func) + return hashmap->key_new_func(key); + + return (void *)key; +} + +static inline void free_key(const struct l_hashmap *hashmap, void *key) +{ + if (hashmap->key_free_func) + hashmap->key_free_func(key); +} + +static inline unsigned int hash_superfast(const uint8_t *key, unsigned int len) +{ + /* + * Paul Hsieh (http://www.azillionmonkeys.com/qed/hash.html) + * used by WebCore (http://webkit.org/blog/8/hashtables-part-2/), + * EFL's eina, kmod and possible others. + */ + unsigned int tmp, hash = len, rem = len & 3; + + len /= 4; + + /* Main loop */ + for (; len > 0; len--) { + hash += l_get_u16(key); + tmp = (l_get_u16(key + 2) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + key += 4; + hash += hash >> 11; + } + + /* Handle end cases */ + switch (rem) { + case 3: + hash += l_get_u16(key); + hash ^= hash << 16; + hash ^= key[2] << 18; + hash += hash >> 11; + break; + + case 2: + hash += l_get_u16(key); + hash ^= hash << 11; + hash += hash >> 17; + break; + + case 1: + hash += *key; + hash ^= hash << 10; + hash += hash >> 1; + break; + } + + /* Force "avalanching" of final 127 bits */ + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + + return hash; +} + +static unsigned int direct_hash_func(const void *p) +{ + return L_PTR_TO_UINT(p); +} + +static int direct_compare_func(const void *a, const void *b) +{ + return a < b ? -1 : (a > b ? 1 : 0); +} + +/** + * l_hashmap_new: + * + * Create a new hash table. The keys are managed as pointers, that is, + * the pointer value is hashed and looked up. + * + * No error handling is needed since. In case of real memory allocation + * problems abort() will be called. + * + * See also l_hashmap_string_new(). + * + * Returns: a newly allocated #l_hashmap object + **/ +LIB_EXPORT struct l_hashmap *l_hashmap_new(void) +{ + struct l_hashmap *hashmap; + + hashmap = l_new(struct l_hashmap, 1); + + hashmap->hash_func = direct_hash_func; + hashmap->compare_func = direct_compare_func; + hashmap->entries = 0; + + return hashmap; +} + +LIB_EXPORT unsigned int l_str_hash(const void *p) +{ + const char *s = p; + size_t len = strlen(s); + + return hash_superfast((const uint8_t *)s, len); +} + +/** + * l_hashmap_string_new: + * + * Create a new hash table. The keys are considered strings and are + * copied. + * + * No error handling is needed since. In case of real memory allocation + * problems abort() will be called. + * + * See also l_hashmap_new(). + * + * Returns: a newly allocated #l_hashmap object + **/ +LIB_EXPORT struct l_hashmap *l_hashmap_string_new(void) +{ + struct l_hashmap *hashmap; + + hashmap = l_new(struct l_hashmap, 1); + + hashmap->hash_func = l_str_hash; + hashmap->compare_func = (l_hashmap_compare_func_t) strcmp; + hashmap->key_new_func = (l_hashmap_key_new_func_t) l_strdup; + hashmap->key_free_func = l_free; + hashmap->entries = 0; + + return hashmap; +} + +/** + * l_hashmap_set_hash_function: + * @hashmap: hash table object + * @func: Key hashing function + * + * Sets the hashing function to be used by this object. + * + * This function can only be called when the @hashmap is empty. + * + * Returns: #true when the hashing function could be updated successfully, + * and #false otherwise. + **/ +LIB_EXPORT bool l_hashmap_set_hash_function(struct l_hashmap *hashmap, + l_hashmap_hash_func_t func) +{ + if (unlikely(!hashmap)) + return false; + + if (hashmap->entries != 0) + return false; + + hashmap->hash_func = func; + + return true; +} + +/** + * l_hashmap_set_compare_function: + * @hashmap: hash table object + * @func: Key compare function + * + * Sets the key comparison function to be used by this object. + * + * This function can only be called when the @hashmap is empty. + * + * Returns: #true when the comparison function could be updated successfully, + * and #false otherwise. + **/ +LIB_EXPORT bool l_hashmap_set_compare_function(struct l_hashmap *hashmap, + l_hashmap_compare_func_t func) +{ + if (unlikely(!hashmap)) + return false; + + if (hashmap->entries != 0) + return false; + + hashmap->compare_func = func; + + return true; +} + +/** + * l_hashmap_set_key_copy_function: + * @hashmap: hash table object + * @func: Key duplication function + * + * Sets the key duplication function to be used by this object. If the + * function is NULL, then the keys are assigned directly. + * + * This function can only be called when the @hashmap is empty. + * + * Returns: #true when the key copy function could be updated successfully, + * and #false otherwise. + **/ +LIB_EXPORT bool l_hashmap_set_key_copy_function(struct l_hashmap *hashmap, + l_hashmap_key_new_func_t func) +{ + if (unlikely(!hashmap)) + return false; + + if (hashmap->entries != 0) + return false; + + hashmap->key_new_func = func; + + return true; +} + +/** + * l_hashmap_set_key_free_function: + * @hashmap: hash table object + * @func: Key destructor function + * + * Sets the key destructor function to be used by this object. This function + * should undo the result of the function specified in + * l_hashmap_set_key_copy_function(). This function can be NULL, in which + * case no destructor is called. + * + * This function can only be called when the @hashmap is empty. + * + * Returns: #true when the key free function could be updated successfully, + * and #false otherwise. + **/ +LIB_EXPORT bool l_hashmap_set_key_free_function(struct l_hashmap *hashmap, + l_hashmap_key_free_func_t func) +{ + if (unlikely(!hashmap)) + return false; + + if (hashmap->entries != 0) + return false; + + hashmap->key_free_func = func; + + return true; +} + +/** + * l_hashmap_destroy: + * @hashmap: hash table object + * @destroy: destroy function + * + * Free hash table and call @destroy on all remaining entries. + * + * NOTE: While the destroy is in progress, the hashmap is assumed to be + * invariant. The behavior of adding or removing entries while a destroy + * operation is in progress is undefined. + **/ +LIB_EXPORT void l_hashmap_destroy(struct l_hashmap *hashmap, + l_hashmap_destroy_func_t destroy) +{ + unsigned int i; + + if (unlikely(!hashmap)) + return; + + for (i = 0; i < NBUCKETS; i++) { + struct entry *entry, *next, *head = &hashmap->buckets[i]; + + if (!head->next) + continue; + + for (entry = head;; entry = next) { + if (destroy) + destroy(entry->value); + + free_key(hashmap, entry->key); + + next = entry->next; + + if (entry != head) + l_free(entry); + + if (next == head) + break; + } + } + + l_free(hashmap); +} + +/** + * l_hashmap_insert: + * @hashmap: hash table object + * @key: key pointer + * @value: value pointer + * + * Insert new @value entry with @key. Note that entries with a duplicate key + * are allowed. If a duplicate entry in inserted, it will be added in order + * of insertion. @l_hashmap_lookup and @l_hashmap_remove will remove the + * first matching entry. + * + * Returns: #true when value has been added and #false in case of failure + **/ +LIB_EXPORT bool l_hashmap_insert(struct l_hashmap *hashmap, + const void *key, void *value) +{ + struct entry *entry, *head; + unsigned int hash; + void *key_new; + + if (unlikely(!hashmap)) + return false; + + key_new = get_key_new(hashmap, key); + hash = hashmap->hash_func(key_new); + head = &hashmap->buckets[hash % NBUCKETS]; + + if (!head->next) { + head->key = key_new; + head->value = value; + head->hash = hash; + head->next = head; + goto done; + } + + entry = l_new(struct entry, 1); + entry->key = key_new; + entry->value = value; + entry->hash = hash; + entry->next = head; + + while (head->next != entry->next) + head = head->next; + + head->next = entry; + +done: + hashmap->entries++; + + return true; +} + +/** + * l_hashmap_replace: + * @hashmap: hash table object + * @key: key pointer + * @value: value pointer + * @old_value: old value that has been replaced. + * + * Replace the first entry with @key by @value or insert a new @value entry + * with @key. If the entry was replaced, then the old value is returned + * in @old_value, otherwise @old_value is assigned a #NULL. + * + * Returns: #true when value has been added and #false in case of failure + **/ +LIB_EXPORT bool l_hashmap_replace(struct l_hashmap *hashmap, + const void *key, void *value, + void **old_value) +{ + struct entry *entry; + struct entry *head; + unsigned int hash; + void *key_new; + + if (unlikely(!hashmap)) + return false; + + key_new = get_key_new(hashmap, key); + hash = hashmap->hash_func(key_new); + head = &hashmap->buckets[hash % NBUCKETS]; + + if (!head->next) { + head->key = key_new; + head->value = value; + head->hash = hash; + head->next = head; + goto done; + } + + for (entry = head;; entry = entry->next) { + if (entry->hash != hash) + goto next; + + if (hashmap->compare_func(key, entry->key)) + goto next; + + if (old_value) + *old_value = entry->value; + + entry->value = value; + free_key(hashmap, key_new); + + return true; + +next: + if (entry->next == head) + break; + } + + entry = l_new(struct entry, 1); + entry->key = key_new; + entry->value = value; + entry->hash = hash; + entry->next = head; + + while (head->next != entry->next) + head = head->next; + + head->next = entry; + +done: + if (old_value) + *old_value = NULL; + + hashmap->entries++; + + return true; +} + +/** + * l_hashmap_remove: + * @hashmap: hash table object + * @key: key pointer + * + * Remove entry for @key. + * + * Returns: value pointer of the removed entry or #NULL in case of failure + **/ +LIB_EXPORT void *l_hashmap_remove(struct l_hashmap *hashmap, const void *key) +{ + struct entry *entry, *head, *prev; + unsigned int hash; + + if (unlikely(!hashmap)) + return NULL; + + hash = hashmap->hash_func(key); + head = &hashmap->buckets[hash % NBUCKETS]; + + if (!head->next) + return NULL; + + for (entry = head, prev = NULL;; prev = entry, entry = entry->next) { + void *value; + + if (entry->hash != hash) + goto next; + + if (hashmap->compare_func(key, entry->key)) + goto next; + + value = entry->value; + + if (entry == head) { + if (entry->next == head) { + free_key(hashmap, entry->key); + head->key = NULL; + head->value = NULL; + head->hash = 0; + head->next = NULL; + } else { + entry = entry->next; + free_key(hashmap, head->key); + head->key = entry->key; + head->value = entry->value; + head->hash = entry->hash; + head->next = entry->next; + l_free(entry); + } + } else { + prev->next = entry->next; + free_key(hashmap, entry->key); + l_free(entry); + } + + hashmap->entries--; + + return value; + +next: + if (entry->next == head) + break; + } + + return NULL; +} + +/** + * l_hashmap_lookup: + * @hashmap: hash table object + * @key: key pointer + * + * Lookup entry for @key. + * + * Returns: value pointer for @key or #NULL in case of failure + **/ +LIB_EXPORT void *l_hashmap_lookup(struct l_hashmap *hashmap, const void *key) +{ + struct entry *entry, *head; + unsigned int hash; + + if (unlikely(!hashmap)) + return NULL; + + hash = hashmap->hash_func(key); + head = &hashmap->buckets[hash % NBUCKETS]; + + if (!head->next) + return NULL; + + for (entry = head;; entry = entry->next) { + if (entry->hash == hash && + !hashmap->compare_func(key, entry->key)) + return entry->value; + + if (entry->next == head) + break; + } + + return NULL; +} + +/** + * l_hashmap_foreach: + * @hashmap: hash table object + * @function: callback function + * @user_data: user data given to callback function + * + * Call @function for every entry in @hashmap. + * + * NOTE: While the foreach is in progress, the hashmap is assumed to be + * invariant. The behavior of adding or removing entries while a foreach + * operation is in progress is undefined. + **/ +LIB_EXPORT void l_hashmap_foreach(struct l_hashmap *hashmap, + l_hashmap_foreach_func_t function, void *user_data) +{ + unsigned int i; + + if (unlikely(!hashmap || !function)) + return; + + for (i = 0; i < NBUCKETS; i++) { + struct entry *entry, *head = &hashmap->buckets[i]; + + if (!head->next) + continue; + + for (entry = head;; entry = entry->next) { + function(entry->key, entry->value, user_data); + + if (entry->next == head) + break; + } + } +} + +/** + * l_hashmap_foreach_remove: + * @hashmap: hash table object + * @function: callback function + * @user_data: user data given to callback function + * + * Call @function for every entry in @hashmap. If the @function returns + * true, then the object will be removed from the hashmap. + * + * NOTE: While the foreach is in progress, the hashmap is assumed to be + * invariant. The behavior of adding or removing entries while a foreach + * operation is in progress is undefined. + * + * Returns: Number of entries removed. + **/ +LIB_EXPORT unsigned int l_hashmap_foreach_remove(struct l_hashmap *hashmap, + l_hashmap_remove_func_t function, + void *user_data) +{ + unsigned int i; + unsigned int nremoved = 0; + + if (unlikely(!hashmap || !function)) + return 0; + + for (i = 0; i < NBUCKETS; i++) { + struct entry *head = &hashmap->buckets[i]; + struct entry *entry; + struct entry *prev; + bool remove; + + if (head->next == NULL) + continue; + + entry = head; + prev = NULL; + + while (true) { + remove = function(entry->key, entry->value, user_data); + + if (!remove) + goto next; + + nremoved += 1; + hashmap->entries -= 1; + + if (entry == head) { + if (entry->next == head) { + free_key(hashmap, entry->key); + head->key = NULL; + head->value = NULL; + head->hash = 0; + head->next = NULL; + break; + } else { + entry = entry->next; + free_key(hashmap, head->key); + head->key = entry->key; + head->value = entry->value; + head->hash = entry->hash; + head->next = entry->next; + l_free(entry); + entry = head; + continue; + } + } else { + prev->next = entry->next; + free_key(hashmap, entry->key); + l_free(entry); + entry = prev->next; + if (entry == head) + break; + continue; + } + +next: + if (entry->next == head) + break; + + prev = entry; + entry = entry->next; + } + } + + return nremoved; +} + +/** + * l_hashmap_size: + * @hashmap: hash table object + * + * Returns: entries in the hash table + **/ +LIB_EXPORT unsigned int l_hashmap_size(struct l_hashmap *hashmap) +{ + if (unlikely(!hashmap)) + return 0; + + return hashmap->entries; +} + +/** + * l_hashmap_isempty: + * @hashmap: hash table object + * + * Returns: #true if hash table is empty and #false if not + **/ +LIB_EXPORT bool l_hashmap_isempty(struct l_hashmap *hashmap) +{ + if (unlikely(!hashmap)) + return true; + + return hashmap->entries == 0; +} diff --git a/ell/hashmap.h b/ell/hashmap.h new file mode 100644 index 0000000000000000000000000000000000000000..cf61825b3dd5cd19647885139963de9dc44460fc --- /dev/null +++ b/ell/hashmap.h @@ -0,0 +1,66 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_HASHMAP_H +#define __ELL_HASHMAP_H + +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*l_hashmap_foreach_func_t) (const void *key, void *value, + void *user_data); +typedef void (*l_hashmap_destroy_func_t) (void *value); +typedef unsigned int (*l_hashmap_hash_func_t) (const void *p); +typedef int (*l_hashmap_compare_func_t) (const void *a, const void *b); +typedef void *(*l_hashmap_key_new_func_t) (const void *p); +typedef void (*l_hashmap_key_free_func_t) (void *p); +typedef bool (*l_hashmap_remove_func_t)(const void *key, void *value, + void *user_data); + +struct l_hashmap; + +unsigned int l_str_hash(const void *p); + +struct l_hashmap *l_hashmap_new(void); +struct l_hashmap *l_hashmap_string_new(void); + +bool l_hashmap_set_hash_function(struct l_hashmap *hashmap, + l_hashmap_hash_func_t func); +bool l_hashmap_set_compare_function(struct l_hashmap *hashmap, + l_hashmap_compare_func_t func); +bool l_hashmap_set_key_copy_function(struct l_hashmap *hashmap, + l_hashmap_key_new_func_t func); +bool l_hashmap_set_key_free_function(struct l_hashmap *hashmap, + l_hashmap_key_free_func_t func); + +void l_hashmap_destroy(struct l_hashmap *hashmap, + l_hashmap_destroy_func_t destroy); + +bool l_hashmap_insert(struct l_hashmap *hashmap, + const void *key, void *value); +bool l_hashmap_replace(struct l_hashmap *hashmap, + const void *key, void *value, + void **old_value); +void *l_hashmap_remove(struct l_hashmap *hashmap, const void *key); +void *l_hashmap_lookup(struct l_hashmap *hashmap, const void *key); + +void l_hashmap_foreach(struct l_hashmap *hashmap, + l_hashmap_foreach_func_t function, void *user_data); +unsigned int l_hashmap_foreach_remove(struct l_hashmap *hashmap, + l_hashmap_remove_func_t function, void *user_data); + +unsigned int l_hashmap_size(struct l_hashmap *hashmap); +bool l_hashmap_isempty(struct l_hashmap *hashmap); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_HASHMAP_H */ diff --git a/ell/idle.c b/ell/idle.c new file mode 100644 index 0000000000000000000000000000000000000000..11daaf415ff4ed5aac8b4d6072b474db1fb14465 --- /dev/null +++ b/ell/idle.c @@ -0,0 +1,153 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <unistd.h> +#include <stdbool.h> +#include <stdint.h> + +#include "useful.h" +#include "idle.h" +#include "main-private.h" +#include "private.h" + +/** + * SECTION:idle + * @short_description: Idle processing support + * + * Idle processing support + */ + +/** + * l_idle: + * + * Opaque object representing the idle time event. + */ +struct l_idle { + union { + l_idle_notify_cb_t callback; + l_idle_oneshot_cb_t oneshot; + }; + + l_idle_destroy_cb_t destroy; + void *user_data; + int id; +}; + +static void idle_destroy(void *user_data) +{ + struct l_idle *idle = user_data; + + if (idle->destroy) + idle->destroy(idle->user_data); + + l_free(idle); +} + +static void idle_callback(void *user_data) +{ + struct l_idle *idle = user_data; + + if (idle->callback) + idle->callback(idle, idle->user_data); +} + +static void oneshot_callback(void *user_data) +{ + struct l_idle *idle = user_data; + + if (idle->oneshot) + idle->oneshot(idle->user_data); + + idle_remove(idle->id); +} + +/** + * l_idle_create: + * @callback: idle callback function + * @user_data: user data provided to idle callback function + * @destroy: destroy function for user data + * + * Create a new idle event processing object. + * + * The idle callback will be called until canceled using l_idle_remove(). + * + * Returns: a newly allocated #l_idle object + **/ +LIB_EXPORT struct l_idle *l_idle_create(l_idle_notify_cb_t callback, + void *user_data, l_idle_destroy_cb_t destroy) +{ + struct l_idle *idle; + + if (unlikely(!callback)) + return NULL; + + idle = l_new(struct l_idle, 1); + + idle->callback = callback; + idle->destroy = destroy; + idle->user_data = user_data; + + idle->id = idle_add(idle_callback, idle, 0, idle_destroy); + if (idle->id < 0) { + l_free(idle); + return NULL; + } + + return idle; +} + +/** + * l_idle_oneshot: + * @callback: idle callback function + * @user_data: user data provided to idle callback function + * @destroy: destroy function for user data + * + * Create a new idle event processing object. The callback will be called + * only once at which point the object will be destroyed. + * + * Returns: true if the oneshot idle object could be created successfully. + **/ +LIB_EXPORT bool l_idle_oneshot(l_idle_oneshot_cb_t callback, void *user_data, + l_idle_destroy_cb_t destroy) +{ + struct l_idle *idle; + + if (unlikely(!callback)) + return NULL; + + idle = l_new(struct l_idle, 1); + + idle->oneshot = callback; + idle->destroy = destroy; + idle->user_data = user_data; + + idle->id = idle_add(oneshot_callback, idle, + IDLE_FLAG_NO_WARN_DANGLING, idle_destroy); + if (idle->id < 0) { + l_free(idle); + return false; + } + + return true; +} +/** + * l_idle_remove: + * @idle: idle object + * + * Remove idle event processing object. + **/ +LIB_EXPORT void l_idle_remove(struct l_idle *idle) +{ + if (unlikely(!idle)) + return; + + idle_remove(idle->id); +} diff --git a/ell/idle.h b/ell/idle.h new file mode 100644 index 0000000000000000000000000000000000000000..8856a98cefadd0990e676df9064dcbbd1f080e99 --- /dev/null +++ b/ell/idle.h @@ -0,0 +1,34 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_IDLE_H +#define __ELL_IDLE_H + +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct l_idle; + +typedef void (*l_idle_notify_cb_t) (struct l_idle *idle, void *user_data); +typedef void (*l_idle_oneshot_cb_t) (void *user_data); +typedef void (*l_idle_destroy_cb_t) (void *user_data); + +struct l_idle *l_idle_create(l_idle_notify_cb_t callback, + void *user_data, l_idle_destroy_cb_t destroy); +void l_idle_remove(struct l_idle *idle); + +bool l_idle_oneshot(l_idle_oneshot_cb_t callback, void *user_data, + l_idle_destroy_cb_t destroy); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_IDLE_H */ diff --git a/ell/internal b/ell/internal new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/ell/io.c b/ell/io.c new file mode 100644 index 0000000000000000000000000000000000000000..64bbed1ac1a28167fcdc61595eff2a33a67cd664 --- /dev/null +++ b/ell/io.c @@ -0,0 +1,399 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <unistd.h> +#include <stdbool.h> +#include <sys/epoll.h> + +#include "useful.h" +#include "main-private.h" +#include "io.h" +#include "private.h" + +/** + * SECTION:io + * @short_description: IO support + * + * IO support + */ + +/** + * l_io: + * + * Opaque object representing the IO. + */ +struct l_io { + int fd; + uint32_t events; + bool close_on_destroy; + l_io_read_cb_t read_handler; + l_io_destroy_cb_t read_destroy; + void *read_data; + l_io_write_cb_t write_handler; + l_io_destroy_cb_t write_destroy; + void *write_data; + l_io_disconnect_cb_t disconnect_handler; + l_io_destroy_cb_t disconnect_destroy; + void *disconnect_data; + l_io_debug_cb_t debug_handler; + l_io_destroy_cb_t debug_destroy; + void *debug_data; +}; + +static void io_cleanup(void *user_data) +{ + struct l_io *io = user_data; + + l_util_debug(io->debug_handler, io->debug_data, "cleanup <%p>", io); + + if (io->write_destroy) + io->write_destroy(io->write_data); + + io->write_handler = NULL; + io->write_data = NULL; + + if (io->read_destroy) + io->read_destroy(io->read_data); + + io->read_handler = NULL; + io->read_data = NULL; + + if (io->close_on_destroy) + close(io->fd); + + io->fd = -1; +} + +static void io_closed(struct l_io *io) +{ + /* + * Save off copies of disconnect_handler, disconnect_destroy + * and disconnect_data in case the handler calls io_destroy + */ + l_io_disconnect_cb_t handler = io->disconnect_handler; + l_io_destroy_cb_t destroy = io->disconnect_destroy; + void *disconnect_data = io->disconnect_data; + + io->disconnect_handler = NULL; + io->disconnect_destroy = NULL; + io->disconnect_data = NULL; + + if (handler) + handler(io, disconnect_data); + + if (destroy) + destroy(disconnect_data); +} + +static void io_callback(int fd, uint32_t events, void *user_data) +{ + struct l_io *io = user_data; + + if ((events & EPOLLIN) && io->read_handler) { + l_util_debug(io->debug_handler, io->debug_data, + "read event <%p>", io); + + if (!io->read_handler(io, io->read_data)) { + if (io->read_destroy) + io->read_destroy(io->read_data); + + io->read_handler = NULL; + io->read_destroy = NULL; + io->read_data = NULL; + + io->events &= ~EPOLLIN; + + if (watch_modify(io->fd, io->events, false) == -EBADF) { + io->close_on_destroy = false; + watch_clear(io->fd); + io_closed(io); + return; + } + } + } + + if (unlikely(events & (EPOLLERR | EPOLLHUP))) { + bool close_on_destroy = io->close_on_destroy; + int fd = io->fd; + + l_util_debug(io->debug_handler, io->debug_data, + "disconnect event <%p>", io); + io_closed(io); + watch_remove(fd, !close_on_destroy); + return; + } + + if ((events & EPOLLOUT) && io->write_handler) { + l_util_debug(io->debug_handler, io->debug_data, + "write event <%p>", io); + + if (!io->write_handler(io, io->write_data)) { + if (io->write_destroy) + io->write_destroy(io->write_data); + + io->write_handler = NULL; + io->write_destroy = NULL; + io->write_data = NULL; + + io->events &= ~EPOLLOUT; + + if (watch_modify(io->fd, io->events, false) == -EBADF) { + io->close_on_destroy = false; + watch_clear(io->fd); + io_closed(io); + return; + } + } + } +} + +/** + * l_io_new: + * @fd: file descriptor + * + * Create new IO handling for a given file descriptor. + * + * Returns: a newly allocated #l_io object + **/ +LIB_EXPORT struct l_io *l_io_new(int fd) +{ + struct l_io *io; + int err; + + if (unlikely(fd < 0)) + return NULL; + + io = l_new(struct l_io, 1); + + io->fd = fd; + io->events = EPOLLHUP | EPOLLERR; + io->close_on_destroy = false; + + err = watch_add(io->fd, io->events, io_callback, io, io_cleanup); + if (err) { + l_free(io); + return NULL; + } + + return io; +} + +/** + * l_io_destroy: + * @io: IO object + * + * Free IO object and close file descriptor (if enabled). + **/ +LIB_EXPORT void l_io_destroy(struct l_io *io) +{ + if (unlikely(!io)) + return; + + if (io->fd != -1) + watch_remove(io->fd, !io->close_on_destroy); + + io_closed(io); + + if (io->debug_destroy) + io->debug_destroy(io->debug_data); + + l_free(io); +} + +/** + * l_io_get_fd: + * @io: IO object + * + * Returns: file descriptor associated with @io + **/ +LIB_EXPORT int l_io_get_fd(struct l_io *io) +{ + if (unlikely(!io)) + return -1; + + return io->fd; +} + +/** + * l_io_set_close_on_destroy: + * @io: IO object + * @do_close: setting for destroy handling + * + * Set the automatic closing of the file descriptor when destroying @io. + * + * Returns: #true on success and #false on failure + **/ +LIB_EXPORT bool l_io_set_close_on_destroy(struct l_io *io, bool do_close) +{ + if (unlikely(!io)) + return false; + + io->close_on_destroy = do_close; + + return true; +} + +/** + * l_io_set_read_handler: + * @io: IO object + * @callback: read handler callback function + * @user_data: user data provided to read handler callback function + * @destroy: destroy function for user data + * + * Set read function. + * + * Returns: #true on success and #false on failure + **/ +LIB_EXPORT bool l_io_set_read_handler(struct l_io *io, l_io_read_cb_t callback, + void *user_data, l_io_destroy_cb_t destroy) +{ + uint32_t events; + int err; + + if (unlikely(!io || io->fd < 0)) + return false; + + l_util_debug(io->debug_handler, io->debug_data, + "set read handler <%p>", io); + + if (io->read_destroy) + io->read_destroy(io->read_data); + + if (callback) + events = io->events | EPOLLIN; + else + events = io->events & ~EPOLLIN; + + io->read_handler = callback; + io->read_destroy = destroy; + io->read_data = user_data; + + if (events == io->events) + return true; + + err = watch_modify(io->fd, events, false); + if (err) + return false; + + io->events = events; + + return true; +} + +/** + * l_io_set_write_handler: + * @io: IO object + * @callback: write handler callback function + * @user_data: user data provided to write handler callback function + * @destroy: destroy function for user data + * + * Set write function. + * + * Returns: #true on success and #false on failure + **/ +LIB_EXPORT bool l_io_set_write_handler(struct l_io *io, l_io_write_cb_t callback, + void *user_data, l_io_destroy_cb_t destroy) +{ + uint32_t events; + int err; + + if (unlikely(!io || io->fd < 0)) + return false; + + l_util_debug(io->debug_handler, io->debug_data, + "set write handler <%p>", io); + + if (io->write_handler == callback && io->write_destroy == destroy && + io->write_data == user_data) + return true; + + if (io->write_destroy) + io->write_destroy(io->write_data); + + if (callback) + events = io->events | EPOLLOUT; + else + events = io->events & ~EPOLLOUT; + + io->write_handler = callback; + io->write_destroy = destroy; + io->write_data = user_data; + + if (events == io->events) + return true; + + err = watch_modify(io->fd, events, false); + if (err) + return false; + + io->events = events; + + return true; +} + +/** + * l_io_set_disconnect_handler: + * @io: IO object + * @callback: disconnect handler callback function + * @user_data: user data provided to disconnect handler callback function + * @destroy: destroy function for user data + * + * Set disconnect function. + * + * Returns: #true on success and #false on failure + **/ +LIB_EXPORT bool l_io_set_disconnect_handler(struct l_io *io, + l_io_disconnect_cb_t callback, + void *user_data, l_io_destroy_cb_t destroy) +{ + if (unlikely(!io || io->fd < 0)) + return false; + + l_util_debug(io->debug_handler, io->debug_data, + "set disconnect handler <%p>", io); + + if (io->disconnect_destroy) + io->disconnect_destroy(io->disconnect_data); + + io->disconnect_handler = callback; + io->disconnect_destroy = destroy; + io->disconnect_data = user_data; + + return true; +} + +/** + * l_io_set_debug: + * @io: IO object + * @callback: debug callback function + * @user_data: user data provided to debug callback function + * @destroy: destroy function for user data + * + * Set debug function. + * + * Returns: #true on success and #false on failure + **/ +LIB_EXPORT bool l_io_set_debug(struct l_io *io, l_io_debug_cb_t callback, + void *user_data, l_io_destroy_cb_t destroy) +{ + if (unlikely(!io)) + return false; + + if (io->debug_destroy) + io->debug_destroy(io->debug_data); + + io->debug_handler = callback; + io->debug_destroy = destroy; + io->debug_data = user_data; + + return true; +} diff --git a/ell/io.h b/ell/io.h new file mode 100644 index 0000000000000000000000000000000000000000..a2a1dadc002fe98ff5f570d6ddeaa06b88ecf13b --- /dev/null +++ b/ell/io.h @@ -0,0 +1,47 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_IO_H +#define __ELL_IO_H + +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct l_io; + +typedef void (*l_io_debug_cb_t) (const char *str, void *user_data); + +typedef bool (*l_io_read_cb_t) (struct l_io *io, void *user_data); +typedef bool (*l_io_write_cb_t) (struct l_io *io, void *user_data); +typedef void (*l_io_disconnect_cb_t) (struct l_io *io, void *user_data); +typedef void (*l_io_destroy_cb_t) (void *user_data); + +struct l_io *l_io_new(int fd); +void l_io_destroy(struct l_io *io); + +int l_io_get_fd(struct l_io *io); +bool l_io_set_close_on_destroy(struct l_io *io, bool do_close); + +bool l_io_set_read_handler(struct l_io *io, l_io_read_cb_t callback, + void *user_data, l_io_destroy_cb_t destroy); +bool l_io_set_write_handler(struct l_io *io, l_io_write_cb_t callback, + void *user_data, l_io_destroy_cb_t destroy); +bool l_io_set_disconnect_handler(struct l_io *io, + l_io_disconnect_cb_t callback, + void *user_data, l_io_destroy_cb_t destroy); + +bool l_io_set_debug(struct l_io *io, l_io_debug_cb_t callback, + void *user_data, l_io_destroy_cb_t destroy); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_IO_H */ diff --git a/ell/key.c b/ell/key.c new file mode 100644 index 0000000000000000000000000000000000000000..325fa09d10e597d69c33fc7fe73392a34d3b9f74 --- /dev/null +++ b/ell/key.c @@ -0,0 +1,799 @@ +/* + * Embedded Linux library + * Copyright (C) 2016 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <unistd.h> +#include <stdint.h> +#include <sys/syscall.h> +#include <linux/keyctl.h> +#include <errno.h> + +#include "private.h" +#include "useful.h" +#include "key.h" +#include "string.h" +#include "random.h" +#include "missing.h" + +#ifndef KEYCTL_DH_COMPUTE +#define KEYCTL_DH_COMPUTE 23 +#endif + +#ifndef KEYCTL_PKEY_QUERY +#define KEYCTL_PKEY_QUERY 24 +#define KEYCTL_PKEY_ENCRYPT 25 +#define KEYCTL_PKEY_DECRYPT 26 +#define KEYCTL_PKEY_SIGN 27 +#define KEYCTL_PKEY_VERIFY 28 + +#define KEYCTL_SUPPORTS_ENCRYPT 0x01 +#define KEYCTL_SUPPORTS_DECRYPT 0x02 +#define KEYCTL_SUPPORTS_SIGN 0x04 +#define KEYCTL_SUPPORTS_VERIFY 0x08 + +struct keyctl_pkey_query { + uint32_t supported_ops; + uint32_t key_size; + uint16_t max_data_size; + uint16_t max_sig_size; + uint16_t max_enc_size; + uint16_t max_dec_size; + + uint32_t __spare[10]; +}; + +struct keyctl_pkey_params { + int32_t key_id; + uint32_t in_len; + union { + uint32_t out_len; + uint32_t in2_len; + }; + uint32_t __spare[7]; +}; + +/* Work around the missing (pre-4.7) or broken (4.14.{70,71,72} and + * 4.18.{8,9,10}) kernel declaration of struct keyctl_dh_params + */ +struct dh_params { + int32_t private; + int32_t prime; + int32_t base; +}; +#else +/* When KEYCTL_PKEY_QUERY is defined by the kernel, the + * struct keyctl_dh_params declaration is valid. + */ +#define dh_params keyctl_dh_params +#endif + +#ifndef KEYCTL_RESTRICT_KEYRING +#define KEYCTL_RESTRICT_KEYRING 29 +#endif + +static int32_t internal_keyring; + +struct l_key { + int type; + int32_t serial; +}; + +struct l_keyring { + int32_t serial; +}; + +static const char * const key_type_names[] = { + [L_KEY_RAW] = "user", + [L_KEY_RSA] = "asymmetric", + [L_KEY_ECC] = "asymmetric", +}; + +static long kernel_add_key(const char *type, const char *description, + const void *payload, size_t len, int32_t keyring) +{ + long result; + + result = syscall(__NR_add_key, type, description, payload, len, + keyring); + + return result >= 0 ? result : -errno; +} + +static long kernel_read_key(int32_t serial, const void *payload, size_t len) +{ + long result; + + result = syscall(__NR_keyctl, KEYCTL_READ, serial, payload, len); + + return result >= 0 ? result : -errno; +} + +static long kernel_update_key(int32_t serial, const void *payload, size_t len) +{ + long result; + + result = syscall(__NR_keyctl, KEYCTL_UPDATE, serial, payload, len); + + return result >= 0 ? result : -errno; +} + +static long kernel_invalidate_key(int32_t serial) +{ + long result; + + result = syscall(__NR_keyctl, KEYCTL_INVALIDATE, serial); + + return result >= 0 ? result : -errno; +} + +static long kernel_link_key(int32_t key_serial, int32_t ring_serial) +{ + long result; + + result = syscall(__NR_keyctl, KEYCTL_LINK, key_serial, ring_serial); + + return result >= 0 ? result : -errno; +} + +static long kernel_unlink_key(int32_t key_serial, int32_t ring_serial) +{ + long result; + + result = syscall(__NR_keyctl, KEYCTL_UNLINK, key_serial, ring_serial); + + return result >= 0 ? result : -errno; +} + +static char *format_key_info(const char *encoding, const char *hash) +{ + struct l_string *info; + + if (!encoding && !hash) + return NULL; + + info = l_string_new(0); + + if (encoding) + l_string_append_printf(info, "enc=%s ", encoding); + + if (hash) + l_string_append_printf(info, "hash=%s", hash); + + return l_string_unwrap(info); +} + +static long kernel_query_key(int32_t key_serial, const char *encoding, + const char *hash, size_t *size, bool *public) +{ + long result; + struct keyctl_pkey_query query; + char *info = format_key_info(encoding, hash); + + memset(&query, 0, sizeof(query)); + + result = syscall(__NR_keyctl, KEYCTL_PKEY_QUERY, key_serial, 0, + info ?: "", &query); + if (result == 0) { + *size = query.key_size; + *public = ((query.supported_ops & KEYCTL_SUPPORTS_ENCRYPT) && + !(query.supported_ops & KEYCTL_SUPPORTS_DECRYPT)); + } + l_free(info); + + return result >= 0 ? result : -errno; +} + +static long kernel_dh_compute(int32_t private, int32_t prime, int32_t base, + void *payload, size_t len) +{ + long result; + + struct dh_params params = { .private = private, + .prime = prime, + .base = base }; + + result = syscall(__NR_keyctl, KEYCTL_DH_COMPUTE, ¶ms, payload, len, + NULL); + + return result >= 0 ? result : -errno; +} + +static long kernel_restrict_keyring(int32_t serial, const char *keytype, + const char *restriction) +{ + long result; + + result = syscall(__NR_keyctl, KEYCTL_RESTRICT_KEYRING, serial, keytype, + restriction); + + return result >= 0 ? result : -errno; +} + +static long kernel_key_eds(int op, int32_t serial, const char *encoding, + const char *hash, const void *in, void *out, + size_t len_in, size_t len_out) +{ + long result; + struct keyctl_pkey_params params = { .key_id = serial, + .in_len = len_in, + .out_len = len_out }; + char *info = format_key_info(encoding, hash); + + memset(out, 0, len_out); + + result = syscall(__NR_keyctl, op, ¶ms, info ?: "", in, out); + l_free(info); + + return result >= 0 ? result : -errno; +} + +static long kernel_key_verify(int32_t serial, + const char *encoding, const char *hash, + const void *data, size_t data_len, + const void *sig, size_t sig_len) +{ + struct keyctl_pkey_params params = { + .key_id = serial, + .in_len = data_len, + .in2_len = sig_len, + }; + char *info = format_key_info(encoding, hash); + long result; + + result = syscall(__NR_keyctl, KEYCTL_PKEY_VERIFY, ¶ms, + info ?: "", data, sig); + l_free(info); + + return result >= 0 ? result : -errno; +} + +static bool setup_internal_keyring(void) +{ + internal_keyring = kernel_add_key("keyring", "ell-internal", NULL, 0, + KEY_SPEC_THREAD_KEYRING); + + if (internal_keyring <= 0) { + internal_keyring = 0; + return false; + } + + return true; +} + +LIB_EXPORT struct l_key *l_key_new(enum l_key_type type, const void *payload, + size_t payload_length) +{ + struct l_key *key; + char *description; + static unsigned long key_idx; + + if (unlikely(!payload)) + return NULL; + + if (unlikely((size_t)type >= L_ARRAY_SIZE(key_type_names))) + return NULL; + + if (!internal_keyring && !setup_internal_keyring()) + return NULL; + + key = l_new(struct l_key, 1); + key->type = type; + description = l_strdup_printf("ell-key-%lu", key_idx++); + key->serial = kernel_add_key(key_type_names[type], description, payload, + payload_length, internal_keyring); + l_free(description); + + if (key->serial < 0) { + l_free(key); + key = NULL; + } + + /* + * TODO: Query asymmetric key algorithm from the kernel and + * ensure that it matches the expected l_key_type. This can + * currently be found by digging through /proc/keys, but a + * keyctl() op makes more sense. + */ + + return key; +} + +LIB_EXPORT void l_key_free(struct l_key *key) +{ + if (unlikely(!key)) + return; + + /* + * Use invalidate as, unlike revoke, this doesn't delay the + * key garbage collection and causes the quota used by the + * key to be released sooner and more predictably. + */ + kernel_invalidate_key(key->serial); + + l_free(key); +} + +LIB_EXPORT void l_key_free_norevoke(struct l_key *key) +{ + if (unlikely(!key)) + return; + + kernel_unlink_key(key->serial, internal_keyring); + + l_free(key); +} + +LIB_EXPORT bool l_key_update(struct l_key *key, const void *payload, size_t len) +{ + long error; + + if (unlikely(!key)) + return false; + + error = kernel_update_key(key->serial, payload, len); + + return error == 0; +} + +LIB_EXPORT bool l_key_extract(struct l_key *key, void *payload, size_t *len) +{ + long keylen; + + if (unlikely(!key)) + return false; + + keylen = kernel_read_key(key->serial, payload, *len); + + if (keylen < 0 || (size_t)keylen > *len) { + explicit_bzero(payload, *len); + return false; + } + + *len = keylen; + return true; +} + +LIB_EXPORT ssize_t l_key_get_payload_size(struct l_key *key) +{ + return kernel_read_key(key->serial, NULL, 0); +} + +static const char *lookup_cipher(enum l_key_cipher_type cipher) +{ + switch (cipher) { + case L_KEY_RSA_PKCS1_V1_5: + return "pkcs1"; + case L_KEY_RSA_RAW: + return "raw"; + case L_KEY_ECDSA_X962: + return "x962"; + } + + return NULL; +} + +static const char *lookup_checksum(enum l_checksum_type checksum) +{ + const char* ret = NULL; + + switch (checksum) { + case L_CHECKSUM_NONE: + break; + case L_CHECKSUM_MD4: + ret = "md4"; + break; + case L_CHECKSUM_MD5: + ret = "md5"; + break; + case L_CHECKSUM_SHA1: + ret = "sha1"; + break; + case L_CHECKSUM_SHA224: + ret = "sha224"; + break; + case L_CHECKSUM_SHA256: + ret = "sha256"; + break; + case L_CHECKSUM_SHA384: + ret = "sha384"; + break; + case L_CHECKSUM_SHA512: + ret = "sha512"; + break; + } + + return ret; +} + +LIB_EXPORT bool l_key_get_info(struct l_key *key, enum l_key_cipher_type cipher, + enum l_checksum_type checksum, size_t *bits, + bool *public) +{ + if (unlikely(!key)) + return false; + + return !kernel_query_key(key->serial, lookup_cipher(cipher), + lookup_checksum(checksum), bits, + public); +} + +LIB_EXPORT struct l_key *l_key_generate_dh_private(const void *prime_buf, + size_t prime_len) +{ + uint8_t *buf; + const uint8_t *prime = prime_buf; + size_t prime_bits; + unsigned int i; + size_t private_bytes; + size_t random_bytes; + struct l_key *private; + + /* Find the prime's bit length excluding leading 0s */ + + for (i = 0; i < prime_len && !prime[i]; i++); + + if (i == prime_len || (i == prime_len - 1 && prime[i] < 5)) + return NULL; + + prime_bits = (prime_len - i) * 8 - __builtin_clz(prime[i]); + + /* + * Generate a random DH private value conforming to 1 < x < p - 1. + * To do this covering all possible values in this range with the + * same probability of generating each value generally requires + * looping. Instead we generate a value in the range + * [2 ^ (prime_bits - 2), 2 ^ (prime_bits - 1) - 1] by forcing bit + * prime_bits - 2 to 1, i.e. the range in PKCS #3 Section 7.1 for + * l equal to prime_bits - 1. This means we're using between + * one half and one quarter of the full [2, p - 2] range, i.e. + * between 1 and 2 bits fewer. Note that since p is odd + * p - 1 has the same bit length as p and so our maximum value + * 2 ^ (prime_bits - 1) - 1 is still less than p - 1. + */ + private_bytes = ((prime_bits - 1) + 7) / 8; + random_bytes = ((prime_bits - 2) + 7) / 8; + buf = l_malloc(private_bytes); + l_getrandom(buf + private_bytes - random_bytes, random_bytes); + + buf[0] &= (1 << ((prime_bits - 2) % 8)) - 1; + buf[0] |= 1 << ((prime_bits - 2) % 8); + + private = l_key_new(L_KEY_RAW, buf, private_bytes); + explicit_bzero(buf, private_bytes); + l_free(buf); + return private; +} + +static bool compute_common(struct l_key *base, struct l_key *private, + struct l_key *prime, void *payload, size_t *len) +{ + long result_len; + bool usable_payload = *len != 0; + + result_len = kernel_dh_compute(private->serial, prime->serial, + base->serial, payload, *len); + + if (result_len > 0) { + *len = result_len; + return usable_payload; + } + return false; +} + +LIB_EXPORT bool l_key_compute_dh_public(struct l_key *generator, + struct l_key *private, + struct l_key *prime, + void *payload, size_t *len) +{ + return compute_common(generator, private, prime, payload, len); +} + +LIB_EXPORT bool l_key_compute_dh_secret(struct l_key *other_public, + struct l_key *private, + struct l_key *prime, + void *payload, size_t *len) +{ + return compute_common(other_public, private, prime, payload, len); +} + +static int be_bignum_compare(const uint8_t *a, size_t a_len, + const uint8_t *b, size_t b_len) +{ + unsigned int i; + + if (a_len >= b_len) { + for (i = 0; i < a_len - b_len; i++) + if (a[i]) + return 1; + + return memcmp(a + i, b, b_len); + } + + for (i = 0; i < b_len - a_len; i++) + if (b[i]) + return -1; + + return memcmp(a, b + i, a_len); +} + +/* + * Validate that @payload is within range for a private and public key for + * a DH computation in the finite field group defined by modulus @prime_buf, + * both numbers stored as big-endian integers. We require a key in the + * [2, prime - 2] (inclusive) interval. PKCS #3 does not exclude 1 as a + * private key but other specs do. + */ +LIB_EXPORT bool l_key_validate_dh_payload(const void *payload, size_t len, + const void *prime_buf, size_t prime_len) +{ + static const uint8_t one[] = { 1 }; + uint8_t prime_1[prime_len]; + + /* + * Produce prime - 1 for the payload < prime - 1 check. + * prime is odd so just zero the LSB. + */ + memcpy(prime_1, prime_buf, prime_len); + + if (prime_len < 1 || !(prime_1[prime_len - 1] & 1)) + return false; + + prime_1[prime_len - 1] &= ~1; + + if (be_bignum_compare(payload, len, one, 1) <= 0) + return false; + + if (be_bignum_compare(payload, len, prime_1, prime_len) >= 0) + return false; + + return true; +} + +/* Common code for encrypt/decrypt/sign */ +static ssize_t eds_common(struct l_key *key, + enum l_key_cipher_type cipher, + enum l_checksum_type checksum, const void *in, + void *out, size_t len_in, size_t len_out, + int op) +{ + if (unlikely(!key)) + return -EINVAL; + + return kernel_key_eds(op, key->serial, lookup_cipher(cipher), + lookup_checksum(checksum), in, out, len_in, + len_out); +} + +LIB_EXPORT ssize_t l_key_encrypt(struct l_key *key, + enum l_key_cipher_type cipher, + enum l_checksum_type checksum, + const void *in, void *out, + size_t len_in, size_t len_out) +{ + ssize_t ret_len; + + ret_len = eds_common(key, cipher, checksum, in, out, + len_in, len_out, + KEYCTL_PKEY_ENCRYPT); + + return ret_len; +} + +LIB_EXPORT ssize_t l_key_decrypt(struct l_key *key, + enum l_key_cipher_type cipher, + enum l_checksum_type checksum, + const void *in, void *out, + size_t len_in, size_t len_out) +{ + ssize_t ret_len; + + ret_len = eds_common(key, cipher, checksum, in, out, len_in, + len_out, KEYCTL_PKEY_DECRYPT); + + if (ret_len < 0) + goto done; + +done: + return ret_len; +} + +LIB_EXPORT ssize_t l_key_sign(struct l_key *key, + enum l_key_cipher_type cipher, + enum l_checksum_type checksum, const void *in, + void *out, size_t len_in, size_t len_out) +{ + ssize_t ret_len; + + ret_len = eds_common(key, cipher, checksum, in, out, + len_in, len_out, + KEYCTL_PKEY_SIGN); + + return ret_len; +} + +LIB_EXPORT bool l_key_verify(struct l_key *key, + enum l_key_cipher_type cipher, + enum l_checksum_type checksum, const void *data, + const void *sig, size_t len_data, + size_t len_sig) +{ + long result; + + if (unlikely(!key)) + return false; + + result = kernel_key_verify(key->serial, lookup_cipher(cipher), + lookup_checksum(checksum), + data, len_data, + sig, len_sig); + + return result >= 0; +} + +LIB_EXPORT struct l_keyring *l_keyring_new(void) +{ + struct l_keyring *keyring; + char *description; + static unsigned long keyring_idx; + + if (!internal_keyring && !setup_internal_keyring()) + return NULL; + + keyring = l_new(struct l_keyring, 1); + description = l_strdup_printf("ell-keyring-%lu", keyring_idx++); + keyring->serial = kernel_add_key("keyring", description, NULL, 0, + internal_keyring); + l_free(description); + + if (keyring->serial < 0) { + l_free(keyring); + return NULL; + } + + return keyring; +} + +LIB_EXPORT bool l_keyring_restrict(struct l_keyring *keyring, + enum l_keyring_restriction res, + const struct l_keyring *trusted) +{ + char *restriction = NULL; + long result; + + switch (res) { + case L_KEYRING_RESTRICT_ASYM: + case L_KEYRING_RESTRICT_ASYM_CHAIN: + { + char *option = ""; + + if (res == L_KEYRING_RESTRICT_ASYM_CHAIN) + option = ":chain"; + + restriction = l_strdup_printf("key_or_keyring:%d%s", + trusted ? trusted->serial : 0, + option); + + break; + } + default: + /* Unsupported type */ + return NULL; + } + + result = kernel_restrict_keyring(keyring->serial, "asymmetric", + restriction); + + l_free(restriction); + + return result == 0; +} + +LIB_EXPORT void l_keyring_free(struct l_keyring *keyring) +{ + if (unlikely(!keyring)) + return; + + kernel_invalidate_key(keyring->serial); + + l_free(keyring); +} + +LIB_EXPORT void l_keyring_free_norevoke(struct l_keyring *keyring) +{ + if (unlikely(!keyring)) + return; + + kernel_unlink_key(keyring->serial, internal_keyring); + + l_free(keyring); +} + +LIB_EXPORT bool l_keyring_link(struct l_keyring *keyring, + const struct l_key *key) +{ + long error; + + if (unlikely(!keyring) || unlikely(!key)) + return false; + + error = kernel_link_key(key->serial, keyring->serial); + + return error == 0; +} + +LIB_EXPORT bool l_keyring_unlink(struct l_keyring *keyring, + const struct l_key *key) +{ + long error; + + if (unlikely(!keyring) || unlikely(!key)) + return false; + + error = kernel_unlink_key(key->serial, keyring->serial); + + return error == 0; +} + +LIB_EXPORT bool l_keyring_link_nested(struct l_keyring *keyring, + const struct l_keyring *nested) +{ + long error; + + if (unlikely(!keyring) || unlikely(!nested)) + return false; + + error = kernel_link_key(nested->serial, keyring->serial); + + return error == 0; +} + +LIB_EXPORT bool l_keyring_unlink_nested(struct l_keyring *keyring, + const struct l_keyring *nested) +{ + long error; + + if (unlikely(!keyring) || unlikely(!nested)) + return false; + + error = kernel_unlink_key(nested->serial, keyring->serial); + + return error == 0; +} + +LIB_EXPORT bool l_key_is_supported(uint32_t features) +{ + long result; + + if (features & L_KEY_FEATURE_DH) { + result = syscall(__NR_keyctl, KEYCTL_DH_COMPUTE, NULL, "x", 1, + NULL); + + if (result == -1 && errno == EOPNOTSUPP) + return false; + } + + if (features & L_KEY_FEATURE_RESTRICT) { + result = syscall(__NR_keyctl, KEYCTL_RESTRICT_KEYRING, 0, + "asymmetric", ""); + + if (result == -1 && errno == EOPNOTSUPP) + return false; + } + + if (features & L_KEY_FEATURE_CRYPTO) { + result = syscall(__NR_keyctl, KEYCTL_PKEY_QUERY, 0, 0, "", 0); + + if (result == -1 && errno == EOPNOTSUPP) + return false; + } + + return true; +} diff --git a/ell/key.h b/ell/key.h new file mode 100644 index 0000000000000000000000000000000000000000..657b863ba3e06848637171d590966581dac17f15 --- /dev/null +++ b/ell/key.h @@ -0,0 +1,118 @@ +/* + * Embedded Linux library + * Copyright (C) 2016 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_KEY_H +#define __ELL_KEY_H + +#include <stddef.h> +#include <stdbool.h> + +#include <ell/cleanup.h> +#include <ell/checksum.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct l_key; +struct l_keyring; + +enum l_key_feature { + L_KEY_FEATURE_DH = 1 << 0, + L_KEY_FEATURE_RESTRICT = 1 << 1, + L_KEY_FEATURE_CRYPTO = 1 << 2, +}; + +enum l_key_type { + L_KEY_RAW = 0, + L_KEY_RSA, + L_KEY_ECC, +}; + +enum l_keyring_restriction { + L_KEYRING_RESTRICT_ASYM = 0, + L_KEYRING_RESTRICT_ASYM_CHAIN, +}; + +enum l_key_cipher_type { + L_KEY_RSA_PKCS1_V1_5, + L_KEY_RSA_RAW, + L_KEY_ECDSA_X962, +}; + +struct l_key *l_key_new(enum l_key_type type, const void *payload, + size_t payload_length); + +void l_key_free(struct l_key *key); +void l_key_free_norevoke(struct l_key *key); + +bool l_key_update(struct l_key *key, const void *payload, size_t len); + +bool l_key_extract(struct l_key *key, void *payload, size_t *len); + +ssize_t l_key_get_payload_size(struct l_key *key); + +bool l_key_get_info(struct l_key *key, enum l_key_cipher_type cipher, + enum l_checksum_type checksum, size_t *bits, + bool *out_public); + +struct l_key *l_key_generate_dh_private(const void *prime_buf, + size_t prime_len); + +bool l_key_compute_dh_public(struct l_key *generator, struct l_key *private_key, + struct l_key *prime, + void *payload, size_t *len); + +bool l_key_compute_dh_secret(struct l_key *other_public, struct l_key *private_key, + struct l_key *prime, + void *payload, size_t *len); + +bool l_key_validate_dh_payload(const void *payload, size_t len, + const void *prime_buf, size_t prime_len); + +ssize_t l_key_encrypt(struct l_key *key, enum l_key_cipher_type cipher, + enum l_checksum_type checksum, const void *in, + void *out, size_t len_in, size_t len_out); + +ssize_t l_key_decrypt(struct l_key *key, enum l_key_cipher_type cipher, + enum l_checksum_type checksum, const void *in, + void *out, size_t len_in, size_t len_out); + +ssize_t l_key_sign(struct l_key *key, enum l_key_cipher_type cipher, + enum l_checksum_type checksum, const void *in, + void *out, size_t len_in, size_t len_out); + +bool l_key_verify(struct l_key *key, enum l_key_cipher_type cipher, + enum l_checksum_type checksum, const void *data, + const void *sig, size_t len_data, size_t len_sig); + +struct l_keyring *l_keyring_new(void); + +bool l_keyring_restrict(struct l_keyring *keyring, enum l_keyring_restriction res, + const struct l_keyring *trust); + +void l_keyring_free(struct l_keyring *keyring); +DEFINE_CLEANUP_FUNC(l_keyring_free); +void l_keyring_free_norevoke(struct l_keyring *keyring); +DEFINE_CLEANUP_FUNC(l_keyring_free_norevoke); + +bool l_keyring_link(struct l_keyring *keyring, const struct l_key *key); + +bool l_keyring_unlink(struct l_keyring *keyring, const struct l_key *key); + +bool l_keyring_link_nested(struct l_keyring *keyring, + const struct l_keyring *nested); +bool l_keyring_unlink_nested(struct l_keyring *keyring, + const struct l_keyring *nested); + +bool l_key_is_supported(uint32_t features); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_KEY_H */ diff --git a/ell/log.c b/ell/log.c new file mode 100644 index 0000000000000000000000000000000000000000..a8c26176c9615948fcfa10dcf49abe35729133db --- /dev/null +++ b/ell/log.c @@ -0,0 +1,442 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <fnmatch.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include "queue.h" +#include "log.h" +#include "private.h" + +struct debug_section { + struct l_debug_desc *start; + struct l_debug_desc *end; +}; + +struct l_queue *debug_sections; + +/** + * SECTION:log + * @short_description: Logging framework + * + * Logging framework + */ + +/** + * l_debug_desc: + * + * Debug descriptor. + */ + +static void log_null(int priority, const char *file, const char *line, + const char *func, const char *format, va_list ap) +{ +} + +static l_log_func_t log_func = log_null; +static const char *log_ident = ""; +static int log_fd = -1; +static unsigned long log_pid; + +static inline void close_log(void) +{ + if (log_fd > 0) { + close(log_fd); + log_fd = -1; + } +} + +static int open_log(const char *path) +{ + struct sockaddr_un addr; + + log_fd = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (log_fd < 0) + return -1; + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); + + if (connect(log_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + close_log(); + return -1; + } + + return 0; +} + +/** + * l_log_set_ident: + * @ident: string identifier + * + * Sets the log identifier string. + **/ +LIB_EXPORT void l_log_set_ident(const char *ident) +{ + log_ident = ident; +} + +/** + * l_log_set_handler: + * @function: log handler function + * + * Sets the log handler function. + **/ +LIB_EXPORT void l_log_set_handler(l_log_func_t function) +{ + L_DEBUG_SYMBOL(__debug_intern, ""); + + close_log(); + + if (!function) { + log_func = log_null; + return; + } + + log_func = function; +} + +/** + * l_log_set_null: + * + * Disable logging. + **/ +LIB_EXPORT void l_log_set_null(void) +{ + close_log(); + + log_func = log_null; +} + +__attribute__((format(printf, 5, 0))) +static void log_stderr(int priority, const char *file, const char *line, + const char *func, const char *format, va_list ap) +{ + vfprintf(stderr, format, ap); +} + +/** + * l_log_set_stderr: + * + * Enable logging to stderr. + **/ +LIB_EXPORT void l_log_set_stderr(void) +{ + close_log(); + + log_func = log_stderr; +} + +__attribute__((format(printf, 5, 0))) +static void log_syslog(int priority, const char *file, const char *line, + const char *func, const char *format, va_list ap) +{ + struct msghdr msg; + struct iovec iov[2]; + char hdr[64], *str; + int hdr_len, str_len; + + str_len = vasprintf(&str, format, ap); + if (str_len < 0) + return; + + hdr_len = snprintf(hdr, sizeof(hdr), "<%i>%s[%lu]: ", priority, + log_ident, (unsigned long) log_pid); + + iov[0].iov_base = hdr; + iov[0].iov_len = hdr_len; + iov[1].iov_base = str; + iov[1].iov_len = str_len; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = iov; + msg.msg_iovlen = 2; + + sendmsg(log_fd, &msg, 0); + + free(str); +} + +/** + * l_log_set_syslog: + * + * Enable logging to syslog. + **/ +LIB_EXPORT void l_log_set_syslog(void) +{ + close_log(); + + if (open_log("/dev/log") < 0) { + log_func = log_null; + return; + } + + log_pid = getpid(); + + log_func = log_syslog; +} + +__attribute__((format(printf, 5, 0))) +static void log_journal(int priority, const char *file, const char *line, + const char *func, const char *format, va_list ap) +{ + struct msghdr msg; + struct iovec iov[12]; + char prio[16], *str; + int prio_len, str_len; + + str_len = vasprintf(&str, format, ap); + if (str_len < 0) + return; + + prio_len = snprintf(prio, sizeof(prio), "PRIORITY=%u\n", priority); + + iov[0].iov_base = "MESSAGE="; + iov[0].iov_len = 8; + iov[1].iov_base = str; + iov[1].iov_len = str_len; + iov[2].iov_base = prio; + iov[2].iov_len = prio_len; + iov[3].iov_base = "CODE_FILE="; + iov[3].iov_len = 10; + iov[4].iov_base = (char *) file; + iov[4].iov_len = strlen(file); + iov[5].iov_base = "\n"; + iov[5].iov_len = 1; + iov[6].iov_base = "CODE_LINE="; + iov[6].iov_len = 10; + iov[7].iov_base = (char *) line; + iov[7].iov_len = strlen(line); + iov[8].iov_base = "\n"; + iov[8].iov_len = 1; + iov[9].iov_base = "CODE_FUNC="; + iov[9].iov_len = 10; + iov[10].iov_base = (char *) func; + iov[10].iov_len = strlen(func); + iov[11].iov_base = "\n"; + iov[11].iov_len = 1; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = iov; + msg.msg_iovlen = 12; + + sendmsg(log_fd, &msg, 0); + + free(str); +} + +/** + * l_log_set_journal: + * + * Enable logging to journal. + **/ +LIB_EXPORT void l_log_set_journal(void) +{ + close_log(); + + if (open_log("/run/systemd/journal/socket") < 0) { + log_func = log_null; + return; + } + + log_pid = getpid(); + + log_func = log_journal; +} + +/** + * l_log_with_location: + * @priority: priority level + * @file: source file + * @line: source line + * @func: source function + * @format: format string + * @...: format arguments + * + * Log information. + **/ +LIB_EXPORT void l_log_with_location(int priority, + const char *file, const char *line, + const char *func, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + log_func(priority, file, line, func, format, ap); + va_end(ap); +} + +/** + * l_error: + * @format: format string + * @...: format arguments + * + **/ + +/** + * l_warn: + * @format: format string + * @...: format arguments + * + **/ + +/** + * l_info: + * @format: format string + * @...: format arguments + * + **/ + +/** + * l_debug: + * @format: format string + * @...: format arguments + **/ + +static const char *debug_pattern; + +static void debug_enable(struct l_debug_desc *start, struct l_debug_desc *stop) +{ + struct l_debug_desc *desc; + char *pattern_copy; + + if (!debug_pattern) + return; + + pattern_copy = strdupa(debug_pattern); + + while (pattern_copy) { + char *str = strsep(&pattern_copy, ":,"); + if (!str) + break; + + for (desc = start; desc < stop; desc++) { + if (!fnmatch(str, desc->file, 0)) + desc->flags |= L_DEBUG_FLAG_PRINT; + if (!fnmatch(str, desc->func, 0)) + desc->flags |= L_DEBUG_FLAG_PRINT; + } + } +} + +static void debug_disable(struct l_debug_desc *start, struct l_debug_desc *stop) +{ + struct l_debug_desc *desc; + + for (desc = start; desc < stop; desc++) + desc->flags &= ~L_DEBUG_FLAG_PRINT; +} + +/** + * l_debug_add_section: + * @start: start of the debug section + * @stop: stop of the debug section + * + * Add information about a debug section. This is used by shared libraries + * to tell ell about their debug section start & stopping points. This is used + * to make l_debug statements work across all shared libraries that might be + * linked into the executable + */ +LIB_EXPORT void l_debug_add_section(struct l_debug_desc *start, + struct l_debug_desc *end) +{ + const struct l_queue_entry *entry; + struct debug_section *new_section; + + if (!debug_sections) { + debug_sections = l_queue_new(); + goto add; + } + + for (entry = l_queue_get_entries(debug_sections); entry; + entry = entry->next) { + const struct debug_section *section = entry->data; + + if (section->start == start && section->end == end) + return; + } + +add: + new_section = l_new(struct debug_section, 1); + new_section->start = start; + new_section->end = end; + + l_queue_push_head(debug_sections, new_section); +} + +/** + * l_debug_enable_full: + * @pattern: debug pattern + * @start: start of the debug section + * @stop: end of the debug section + * + * Enable debug sections based on @pattern. + **/ +LIB_EXPORT void l_debug_enable_full(const char *pattern, + struct l_debug_desc *start, + struct l_debug_desc *end) +{ + const struct l_queue_entry *entry; + + if (!pattern) + return; + + debug_pattern = pattern; + + l_debug_add_section(start, end); + + for (entry = l_queue_get_entries(debug_sections); entry; + entry = entry->next) { + const struct debug_section *section = entry->data; + + debug_enable(section->start, section->end); + } +} + +/** + * l_debug_disable: + * + * Disable all debug sections. + **/ +LIB_EXPORT void l_debug_disable(void) +{ + const struct l_queue_entry *entry; + + for (entry = l_queue_get_entries(debug_sections); entry; + entry = entry->next) { + const struct debug_section *section = entry->data; + + debug_disable(section->start, section->end); + } + + debug_pattern = NULL; +} + +__attribute__((constructor)) static void register_debug_section() +{ + extern struct l_debug_desc __start___ell_debug[]; + extern struct l_debug_desc __stop___ell_debug[]; + + l_debug_add_section(__start___ell_debug, __stop___ell_debug); +} + +__attribute__((destructor(65535))) static void free_debug_sections() +{ + l_queue_destroy(debug_sections, l_free); +} diff --git a/ell/log.h b/ell/log.h new file mode 100644 index 0000000000000000000000000000000000000000..7ddf6630414f3136afb38205ccfd99832384c3b0 --- /dev/null +++ b/ell/log.h @@ -0,0 +1,96 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_LOG_H +#define __ELL_LOG_H + +#include <stdarg.h> +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define L_LOG_ERR 3 +#define L_LOG_WARNING 4 +#define L_LOG_NOTICE 5 +#define L_LOG_INFO 6 +#define L_LOG_DEBUG 7 + +typedef void (*l_log_func_t) (int priority, const char *file, const char *line, + const char *func, const char *format, va_list ap); + +void l_log_set_ident(const char *ident); +void l_log_set_handler(l_log_func_t function); +void l_log_set_null(void); +void l_log_set_stderr(void); +void l_log_set_syslog(void); +void l_log_set_journal(void); + +void l_log_with_location(int priority, const char *file, const char *line, + const char *func, const char *format, ...) + __attribute__((format(printf, 5, 6))); + +#define l_log(priority, format, ...) l_log_with_location(priority, \ + __FILE__, L_STRINGIFY(__LINE__), \ + __func__, format "\n", ##__VA_ARGS__) + +struct l_debug_desc { + const char *file; + const char *func; +#define L_DEBUG_FLAG_DEFAULT (0) +#define L_DEBUG_FLAG_PRINT (1 << 0) + unsigned int flags; +} __attribute__((aligned(8))); + +/* + * Set the retain attribute so that the section cannot be discarded by ld + * --gc-sections -z start-stop-gc. Older compilers would warn for the unknown + * attribute, so just disable -Wattributes. + */ +#define L_DEBUG_SYMBOL(symbol, format, ...) do { \ +_Pragma("GCC diagnostic push") \ +_Pragma("GCC diagnostic ignored \"-Wattributes\"") \ + static struct l_debug_desc symbol \ + __attribute__((used, retain, section("__ell_debug"), aligned(8))) = { \ + .file = __FILE__, .func = __func__, \ + .flags = L_DEBUG_FLAG_DEFAULT, \ + }; \ +_Pragma("GCC diagnostic pop") \ + if (symbol.flags & L_DEBUG_FLAG_PRINT) \ + l_log(L_LOG_DEBUG, "%s:%s() " format, __FILE__, \ + __func__ , ##__VA_ARGS__); \ +} while (0) + +void l_debug_enable_full(const char *pattern, + struct l_debug_desc *start, + struct l_debug_desc *end); +void l_debug_add_section(struct l_debug_desc *start, + struct l_debug_desc *end); + +#define l_debug_enable(pattern) do { \ +_Pragma("GCC diagnostic push") \ +_Pragma("GCC diagnostic ignored \"-Wredundant-decls\"") \ + extern struct l_debug_desc __start___ell_debug[]; \ + extern struct l_debug_desc __stop___ell_debug[]; \ + l_debug_enable_full(pattern, __start___ell_debug, __stop___ell_debug); \ +_Pragma("GCC diagnostic pop") \ +} while (0) + +void l_debug_disable(void); + +#define l_error(format, ...) l_log(L_LOG_ERR, format, ##__VA_ARGS__) +#define l_warn(format, ...) l_log(L_LOG_WARNING, format, ##__VA_ARGS__) +#define l_notice(format, ...) l_log(L_LOG_NOTICE, format, ##__VA_ARGS__) +#define l_info(format, ...) l_log(L_LOG_INFO, format, ##__VA_ARGS__) +#define l_debug(format, ...) L_DEBUG_SYMBOL(__debug_desc, format, ##__VA_ARGS__) + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_LOG_H */ diff --git a/ell/main-private.h b/ell/main-private.h new file mode 100644 index 0000000000000000000000000000000000000000..d8afcefd0db059d6d49bab53e8a6295c4b8018e6 --- /dev/null +++ b/ell/main-private.h @@ -0,0 +1,23 @@ +/* + * Embedded Linux library + * Copyright (C) 2021 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +typedef void (*watch_event_cb_t) (int fd, uint32_t events, void *user_data); +typedef void (*watch_destroy_cb_t) (void *user_data); + +typedef void (*idle_event_cb_t) (void *user_data); +typedef void (*idle_destroy_cb_t) (void *user_data); + +int watch_add(int fd, uint32_t events, watch_event_cb_t callback, + void *user_data, watch_destroy_cb_t destroy); +int watch_modify(int fd, uint32_t events, bool force); +int watch_remove(int fd, bool epoll_del); +int watch_clear(int fd); + +#define IDLE_FLAG_NO_WARN_DANGLING 0x10000000 +int idle_add(idle_event_cb_t callback, void *user_data, uint32_t flags, + idle_destroy_cb_t destroy); +void idle_remove(int id); diff --git a/ell/main.c b/ell/main.c new file mode 100644 index 0000000000000000000000000000000000000000..1d591810e836d9816f0523f7a9f270ad25943e3a --- /dev/null +++ b/ell/main.c @@ -0,0 +1,651 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <stddef.h> +#include <limits.h> +#include <signal.h> +#include <sys/epoll.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include "signal.h" +#include "queue.h" +#include "log.h" +#include "useful.h" +#include "main.h" +#include "main-private.h" +#include "private.h" +#include "timeout.h" + +/** + * SECTION:main + * @short_description: Main loop handling + * + * Main loop handling + */ + +#define MAX_EPOLL_EVENTS 10 + +#define IDLE_FLAG_DISPATCHING 1 +#define IDLE_FLAG_DESTROYED 2 + +#define WATCH_FLAG_DISPATCHING 1 +#define WATCH_FLAG_DESTROYED 2 + +#define WATCHDOG_TRIGGER_FREQ 2 + +static int epoll_fd = -1; +static bool epoll_running; +static bool epoll_terminate; +static int idle_id; + +static int notify_fd; + +static struct l_timeout *watchdog; + +static struct l_queue *idle_list; + +struct watch_data { + int fd; + uint32_t events; + uint32_t flags; + watch_event_cb_t callback; + watch_destroy_cb_t destroy; + void *user_data; +}; + +#define DEFAULT_WATCH_ENTRIES 128 + +static unsigned int watch_entries; +static struct watch_data **watch_list; + +struct idle_data { + idle_event_cb_t callback; + idle_destroy_cb_t destroy; + void *user_data; + uint32_t flags; + int id; +}; + +static inline bool __attribute__ ((always_inline)) create_epoll(void) +{ + unsigned int i; + + epoll_fd = epoll_create1(EPOLL_CLOEXEC); + if (epoll_fd < 0) + return false; + + watch_list = malloc(DEFAULT_WATCH_ENTRIES * sizeof(void *)); + if (!watch_list) + goto close_epoll; + + idle_list = l_queue_new(); + + idle_id = 0; + + watch_entries = DEFAULT_WATCH_ENTRIES; + + for (i = 0; i < watch_entries; i++) + watch_list[i] = NULL; + + return true; + +close_epoll: + close(epoll_fd); + epoll_fd = -1; + + return false; +} + +int watch_add(int fd, uint32_t events, watch_event_cb_t callback, + void *user_data, watch_destroy_cb_t destroy) +{ + struct watch_data *data; + struct epoll_event ev; + int err; + + if (unlikely(fd < 0 || !callback)) + return -EINVAL; + + if (epoll_fd < 0) + return -EIO; + + if (L_WARN_ON((unsigned int) fd > watch_entries - 1)) + return -ERANGE; + + data = l_new(struct watch_data, 1); + + data->fd = fd; + data->events = events; + data->flags = 0; + data->callback = callback; + data->destroy = destroy; + data->user_data = user_data; + + memset(&ev, 0, sizeof(ev)); + ev.events = events; + ev.data.ptr = data; + + err = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, data->fd, &ev); + if (err < 0) { + l_free(data); + return -errno; + } + + watch_list[fd] = data; + + return 0; +} + +int watch_modify(int fd, uint32_t events, bool force) +{ + struct watch_data *data; + struct epoll_event ev; + int err; + + if (unlikely(fd < 0)) + return -EINVAL; + + if ((unsigned int) fd > watch_entries - 1) + return -ERANGE; + + data = watch_list[fd]; + if (!data) + return -ENXIO; + + if (data->events == events && !force) + return 0; + + memset(&ev, 0, sizeof(ev)); + ev.events = events; + ev.data.ptr = data; + + err = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, data->fd, &ev); + if (err < 0) + return -errno; + + data->events = events; + + return 0; +} + +int watch_clear(int fd) +{ + struct watch_data *data; + + if (unlikely(fd < 0)) + return -EINVAL; + + if ((unsigned int) fd > watch_entries - 1) + return -ERANGE; + + data = watch_list[fd]; + if (!data) + return -ENXIO; + + watch_list[fd] = NULL; + + if (data->destroy) + data->destroy(data->user_data); + + if (data->flags & WATCH_FLAG_DISPATCHING) + data->flags |= WATCH_FLAG_DESTROYED; + else + l_free(data); + + return 0; +} + +int watch_remove(int fd, bool epoll_del) +{ + int err = watch_clear(fd); + + if (err < 0) + return err; + + if (!epoll_del) + goto done; + + err = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL); + if (err < 0) + return -errno; + +done: + return err; +} + +static bool idle_remove_by_id(void *data, void *user_data) +{ + struct idle_data *idle = data; + int id = L_PTR_TO_INT(user_data); + + if (idle->id != id) + return false; + + if (idle->destroy) + idle->destroy(idle->user_data); + + if (idle->flags & IDLE_FLAG_DISPATCHING) { + idle->flags |= IDLE_FLAG_DESTROYED; + return false; + } + + l_free(idle); + + return true; +} + +static bool idle_prune(void *data, void *user_data) +{ + struct idle_data *idle = data; + + if ((idle->flags & IDLE_FLAG_DESTROYED) == 0) + return false; + + l_free(idle); + + return true; +} + +int idle_add(idle_event_cb_t callback, void *user_data, uint32_t flags, + idle_destroy_cb_t destroy) +{ + struct idle_data *data; + + if (unlikely(!callback)) + return -EINVAL; + + if (epoll_fd < 0) + return -EIO; + + data = l_new(struct idle_data, 1); + + data->callback = callback; + data->destroy = destroy; + data->user_data = user_data; + data->flags = flags; + + if (!l_queue_push_tail(idle_list, data)) { + l_free(data); + return -ENOMEM; + } + + data->id = idle_id++; + + if (idle_id == INT_MAX) + idle_id = 0; + + return data->id; +} + +void idle_remove(int id) +{ + l_queue_foreach_remove(idle_list, idle_remove_by_id, + L_INT_TO_PTR(id)); +} + +static void idle_destroy(void *data) +{ + struct idle_data *idle = data; + + if (!(idle->flags & IDLE_FLAG_NO_WARN_DANGLING)) + l_error("Dangling idle descriptor %p, %d found", + data, idle->id); + + if (idle->destroy) + idle->destroy(idle->user_data); + + l_free(idle); +} + +static void idle_dispatch(void *data, void *user_data) +{ + struct idle_data *idle = data; + + if (!idle->callback) + return; + + idle->flags |= IDLE_FLAG_DISPATCHING; + idle->callback(idle->user_data); + idle->flags &= ~IDLE_FLAG_DISPATCHING; +} + +static int sd_notify(const char *state) +{ + int err; + + if (notify_fd <= 0) + return -ENOTCONN; + + err = send(notify_fd, state, strlen(state), MSG_NOSIGNAL); + if (err < 0) + return -errno; + + return 0; +} + +static void watchdog_callback(struct l_timeout *timeout, void *user_data) +{ + int msec = L_PTR_TO_INT(user_data); + + sd_notify("WATCHDOG=1"); + + l_timeout_modify_ms(timeout, msec); +} + +static void create_sd_notify_socket(void) +{ + const char *sock; + struct sockaddr_un addr; + const char *watchdog_usec; + int msec; + + /* check if NOTIFY_SOCKET has been set */ + sock = getenv("NOTIFY_SOCKET"); + if (!sock) + return; + + /* check for abstract socket or absolute path */ + if (sock[0] != '@' && sock[0] != '/') + return; + + notify_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (notify_fd < 0) { + notify_fd = 0; + return; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, sock, sizeof(addr.sun_path) - 1); + + if (addr.sun_path[0] == '@') + addr.sun_path[0] = '\0'; + + if (bind(notify_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + close(notify_fd); + notify_fd = 0; + return; + } + + watchdog_usec = getenv("WATCHDOG_USEC"); + if (!watchdog_usec) + return; + + msec = atoi(watchdog_usec) / 1000; + if (msec < WATCHDOG_TRIGGER_FREQ) + return; + + msec /= WATCHDOG_TRIGGER_FREQ; + + watchdog = l_timeout_create_ms(msec, watchdog_callback, + L_INT_TO_PTR(msec), NULL); +} + +/** + * l_main_init: + * + * Initialize the main loop. This must be called before l_main_run() + * and any other function that directly or indirectly sets up an idle + * or watch. A safe rule-of-thumb is to call it before any function + * prefixed with "l_". + * + * Returns: true if initialization was successful, false otherwise. + **/ +LIB_EXPORT bool l_main_init(void) +{ + if (unlikely(epoll_running)) + return false; + + if (!create_epoll()) + return false; + + create_sd_notify_socket(); + + epoll_terminate = false; + + return true; +} + +/** + * l_main_prepare: + * + * Prepare the iteration of the main loop + * + * Returns: The timeout to use. This will be 0 if idle-event processing is + * currently pending, or -1 otherwise. This value can be used to pass to + * l_main_iterate. + */ +LIB_EXPORT int l_main_prepare(void) +{ + return l_queue_isempty(idle_list) ? -1 : 0; +} + +/** + * l_main_iterate: + * + * Run one iteration of the main event loop + */ +LIB_EXPORT void l_main_iterate(int timeout) +{ + struct epoll_event events[MAX_EPOLL_EVENTS]; + struct watch_data *data; + int n, nfds; + + nfds = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, timeout); + + for (n = 0; n < nfds; n++) { + data = events[n].data.ptr; + + data->flags |= WATCH_FLAG_DISPATCHING; + } + + for (n = 0; n < nfds; n++) { + data = events[n].data.ptr; + + if (data->flags & WATCH_FLAG_DESTROYED) + continue; + + data->callback(data->fd, events[n].events, + data->user_data); + } + + for (n = 0; n < nfds; n++) { + data = events[n].data.ptr; + + if (data->flags & WATCH_FLAG_DESTROYED) + l_free(data); + else + data->flags = 0; + } + + l_queue_foreach(idle_list, idle_dispatch, NULL); + l_queue_foreach_remove(idle_list, idle_prune, NULL); +} + +/** + * l_main_run: + * + * Run the main loop + * + * The loop may be restarted by invoking this function after a + * previous invocation returns, provided that l_main_exit() has not + * been called first. + * + * Returns: #EXIT_SUCCESS after successful execution or #EXIT_FAILURE in + * case of failure + **/ +LIB_EXPORT int l_main_run(void) +{ + int timeout; + + /* Has l_main_init() been called? */ + if (unlikely(epoll_fd < 0)) + return EXIT_FAILURE; + + if (unlikely(epoll_running)) + return EXIT_FAILURE; + + epoll_running = true; + + for (;;) { + if (epoll_terminate) + break; + + timeout = l_main_prepare(); + l_main_iterate(timeout); + } + + epoll_running = false; + + if (notify_fd) { + close(notify_fd); + notify_fd = 0; + l_timeout_remove(watchdog); + watchdog = NULL; + } + + return EXIT_SUCCESS; +} + +/** + * l_main_exit: + * + * Clean up after main loop completes. + * + **/ +LIB_EXPORT bool l_main_exit(void) +{ + unsigned int i; + + if (epoll_running) { + l_error("Cleanup attempted on running main loop"); + return false; + } + + for (i = 0; i < watch_entries; i++) { + struct watch_data *data = watch_list[i]; + + if (!data) + continue; + + epoll_ctl(epoll_fd, EPOLL_CTL_DEL, data->fd, NULL); + + if (data->destroy) + data->destroy(data->user_data); + else + l_error("Dangling file descriptor %d found", data->fd); + + l_free(data); + } + + watch_entries = 0; + + free(watch_list); + watch_list = NULL; + + l_queue_destroy(idle_list, idle_destroy); + idle_list = NULL; + + close(epoll_fd); + epoll_fd = -1; + + return true; +} + +/** + * l_main_quit: + * + * Terminate the running main loop + * + * Returns: #true when terminating the main loop or #false in case of failure + **/ +LIB_EXPORT bool l_main_quit(void) +{ + if (unlikely(!epoll_running)) + return false; + + epoll_terminate = true; + + return true; +} + +struct signal_data { + l_main_signal_cb_t callback; + void *user_data; +}; + +static void sigint_handler(void *user_data) +{ + struct signal_data *data = user_data; + + if (data->callback) + data->callback(SIGINT, data->user_data); +} + +static void sigterm_handler(void *user_data) +{ + struct signal_data *data = user_data; + + if (data->callback) + data->callback(SIGTERM, data->user_data); +} + +/** + * l_main_run_with_signal: + * + * Run the main loop with signal handling for SIGINT and SIGTERM + * + * Returns: #EXIT_SUCCESS after successful execution or #EXIT_FAILURE in + * case of failure + **/ +LIB_EXPORT int l_main_run_with_signal(l_main_signal_cb_t callback, + void *user_data) +{ + struct signal_data *data; + struct l_signal *sigint; + struct l_signal *sigterm; + int result; + + data = l_new(struct signal_data, 1); + + data->callback = callback; + data->user_data = user_data; + + sigint = l_signal_create(SIGINT, sigint_handler, data, NULL); + sigterm = l_signal_create(SIGTERM, sigterm_handler, data, NULL); + + result = l_main_run(); + + l_signal_remove(sigint); + l_signal_remove(sigterm); + + l_free(data); + + return result; +} + +/** + * l_main_get_epoll_fd: + * + * Can be used to obtain the epoll file descriptor in order to integrate + * the ell main event loop with other event loops. + * + * Returns: epoll file descriptor + **/ +LIB_EXPORT int l_main_get_epoll_fd(void) +{ + return epoll_fd; +} diff --git a/ell/main.h b/ell/main.h new file mode 100644 index 0000000000000000000000000000000000000000..e4826e54fd2c95a6e1e3a70af8c1673964d0a226 --- /dev/null +++ b/ell/main.h @@ -0,0 +1,36 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_MAIN_H +#define __ELL_MAIN_H + +#include <stdbool.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +bool l_main_init(void); +int l_main_prepare(void); +void l_main_iterate(int timeout); +int l_main_run(void); +bool l_main_exit(void); + +bool l_main_quit(void); + +typedef void (*l_main_signal_cb_t) (uint32_t signo, void *user_data); + +int l_main_run_with_signal(l_main_signal_cb_t callback, void *user_data); + +int l_main_get_epoll_fd(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_MAIN_H */ diff --git a/ell/missing.h b/ell/missing.h new file mode 100644 index 0000000000000000000000000000000000000000..b1ee0f147538d577fc6fea40d6ad2dd555ba146d --- /dev/null +++ b/ell/missing.h @@ -0,0 +1,64 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include <sys/syscall.h> +#include <sys/socket.h> + +#ifndef __NR_getrandom +# if defined __x86_64__ +# define __NR_getrandom 318 +# elif defined(__i386__) +# define __NR_getrandom 355 +# elif defined(__arm__) +# define __NR_getrandom 384 +# elif defined(__aarch64__) +# define __NR_getrandom 278 +# elif defined(__ia64__) +# define __NR_getrandom 1339 +# elif defined(__m68k__) +# define __NR_getrandom 352 +# elif defined(__s390x__) +# define __NR_getrandom 349 +# elif defined(__powerpc__) +# define __NR_getrandom 359 +# elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_getrandom 4353 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_getrandom 6317 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_getrandom 5313 +# endif +# else +# warning "__NR_getrandom unknown for your architecture" +# define __NR_getrandom 0xffffffff +# endif +#endif + +#ifndef HAVE_EXPLICIT_BZERO +static inline void explicit_bzero(void *s, size_t n) +{ + memset(s, 0, n); + __asm__ __volatile__ ("" : : "r"(s) : "memory"); +} +#endif + +#ifndef SO_BINDTOIFINDEX +#define SO_BINDTOIFINDEX 62 +#endif + +#ifndef HAVE_RAWMEMCHR +static inline void *rawmemchr(const void *s, int c) +{ +_Pragma("GCC diagnostic push") +_Pragma("GCC diagnostic ignored \"-Wstringop-overflow=\"") + return memchr(s, c, PTRDIFF_MAX); +_Pragma("GCC diagnostic pop") +} +#endif diff --git a/ell/pem-private.h b/ell/pem-private.h new file mode 100644 index 0000000000000000000000000000000000000000..78f7c8ec38170bcf3681405c01bcd2c86add9a6d --- /dev/null +++ b/ell/pem-private.h @@ -0,0 +1,36 @@ +/* + * Embedded Linux library + * Copyright (C) 2019 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#define _GNU_SOURCE +#include <sys/types.h> +#include <sys/stat.h> + +struct l_certchain; + +struct pem_file_info { + int fd; + struct stat st; + uint8_t *data; +}; + +int pem_file_open(struct pem_file_info *info, const char *filename); +void pem_file_close(struct pem_file_info *info); + +const char *pem_next(const void *buf, size_t buf_len, char **type_label, + size_t *base64_len, + const char **endp, bool strict); + +uint8_t *pem_load_buffer(const void *buf, size_t buf_len, + char **out_type_label, size_t *out_len, + char **out_headers, const char **out_endp); + +struct l_key *pem_load_private_key(uint8_t *content, size_t len, char *label, + const char *passphrase, char *headers, + bool *encrypted); + +int pem_write_certificate_chain(const struct l_certchain *cert, + const char *filename); diff --git a/ell/pem.c b/ell/pem.c new file mode 100644 index 0000000000000000000000000000000000000000..24e837262fe124d76cf48c6ecf18d3e0e7055e8e --- /dev/null +++ b/ell/pem.c @@ -0,0 +1,819 @@ +/* + * Embedded Linux library + * Copyright (C) 2015 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <fcntl.h> +#include <unistd.h> +#include <sys/mman.h> +#include <strings.h> +#include <errno.h> + +#include "useful.h" +#include "private.h" +#include "key.h" +#include "cert.h" +#include "queue.h" +#include "pem.h" +#include "base64.h" +#include "utf8.h" +#include "asn1-private.h" +#include "cipher.h" +#include "cert-private.h" +#include "missing.h" +#include "pem-private.h" + +#define PEM_START_BOUNDARY "-----BEGIN " +#define PEM_END_BOUNDARY "-----END " + +static const char *is_start_boundary(const void *buf, size_t buf_len, + size_t *label_len) +{ + const char *start, *end, *ptr; + int prev_special, special; + const char *buf_ptr = buf; + + if (buf_len < strlen(PEM_START_BOUNDARY)) + return NULL; + + /* Check we have a "-----BEGIN " (RFC7468 section 2) */ + if (memcmp(buf, PEM_START_BOUNDARY, strlen(PEM_START_BOUNDARY))) + return NULL; + + /* + * Check we have a string of printable characters in which no + * two consecutive characters are "special" nor is the first or the + * final character "special". These special characters are space + * and hyphen. (RFC7468 section 3) + * The loop will end on the second hyphen of the final "-----" if + * no error found earlier. + */ + start = buf + strlen(PEM_START_BOUNDARY); + end = start; + prev_special = 1; + + while (end < buf_ptr + buf_len && l_ascii_isprint(*end)) { + special = *end == ' ' || *end == '-'; + + if (prev_special && special) + break; + + end++; + prev_special = special; + } + + /* Rewind to the first '-', but handle empty labels */ + if (end != start) + end--; + + /* Check we have a "-----" (RFC7468 section 2) */ + if (end + 5 > buf_ptr + buf_len || memcmp(end, "-----", 5)) + return NULL; + + /* Check all remaining characters are horizontal whitespace (WSP) */ + for (ptr = end + 5; ptr < buf_ptr + buf_len; ptr++) + if (*ptr != ' ' && *ptr != '\t') + return NULL; + + *label_len = end - start; + + return start; +} + +static bool is_end_boundary(const void *buf, size_t buf_len, + const char *label, size_t label_len) +{ + const char *buf_ptr = buf; + size_t len = strlen(PEM_END_BOUNDARY) + label_len + 5; + + if (buf_len < len) + return false; + + if (memcmp(buf_ptr, PEM_END_BOUNDARY, strlen(PEM_END_BOUNDARY)) || + memcmp(buf_ptr + strlen(PEM_END_BOUNDARY), + label, label_len) || + memcmp(buf_ptr + (len - 5), "-----", 5)) + return false; + + /* Check all remaining characters are horizontal whitespace (WSP) */ + for (; len < buf_len; len++) + if (buf_ptr[len] != ' ' && buf_ptr[len] != '\t') + return false; + + return true; +} + +const char *pem_next(const void *buf, size_t buf_len, char **type_label, + size_t *base64_len, + const char **endp, bool strict) +{ + const char *buf_ptr = buf; + const char *base64_data = NULL, *eol; + const char *label = NULL; + size_t label_len = 0; + const char *start = NULL; + + /* + * The base64 parser uses the RFC7468 laxbase64text grammar but we + * do full checks on the encapsulation boundary lines, i.e. no + * leading spaces allowed, making sure quoted text and similar + * are not confused for actual PEM "textual encoding". + */ + while (buf_len) { + for (eol = buf_ptr; eol < buf_ptr + buf_len; eol++) + if (*eol == '\r' || *eol == '\n') + break; + + if (!base64_data) { + label = is_start_boundary(buf_ptr, eol - buf_ptr, + &label_len); + if (label) { + start = label - strlen("-----BEGIN "); + base64_data = eol; + } else if (strict) + break; + } else if (start && is_end_boundary(buf_ptr, eol - buf_ptr, + label, label_len)) { + if (type_label) + *type_label = l_strndup(label, label_len); + + if (base64_len) + *base64_len = buf_ptr - base64_data; + + if (endp) { + if (eol == buf_ptr + buf_len) + *endp = eol; + else + *endp = eol + 1; + } + + return base64_data; + } + + if (eol == buf_ptr + buf_len) + break; + + buf_len -= eol + 1 - buf_ptr; + buf_ptr = eol + 1; + + if (buf_len && *eol == '\r' && *buf_ptr == '\n') { + buf_ptr++; + buf_len--; + } + } + + /* If we found no label signal EOF rather than parse error */ + if (!base64_data && endp) + *endp = NULL; + + return NULL; +} + +uint8_t *pem_load_buffer(const void *buf, size_t buf_len, + char **out_type_label, size_t *out_len, + char **out_headers, const char **out_endp) +{ + size_t base64_len; + const char *base64; + char *label; + const char *headers = NULL; + size_t headers_len; + uint8_t *ret; + + base64 = pem_next(buf, buf_len, &label, &base64_len, + out_endp, false); + if (!base64) + return NULL; + + if (memchr(base64, ':', base64_len)) { + const char *start; + const char *end; + + while (base64_len && l_ascii_isspace(*base64)) { + base64++; + base64_len--; + } + + start = base64; + + if (!(end = memmem(start, base64_len, "\n\n", 2)) && + !(end = memmem(start, base64_len, "\n\r\n", 3))) + goto err; + + /* Check that each header line has a key and a colon */ + while (start < end) { + const char *lf = rawmemchr(start, '\n'); + const char *colon = memchr(start, ':', lf - start); + + if (!colon) + goto err; + + for (; start < colon; start++) + if (l_ascii_isalnum(*start)) + break; + + if (start == colon) + goto err; + + start = lf + 1; + } + + headers = base64; + headers_len = end - base64; + + base64_len -= headers_len + 2; + base64 = end + 2; + } + + ret = l_base64_decode(base64, base64_len, out_len); + if (ret) { + *out_type_label = label; + + if (out_headers) { + if (headers) + *out_headers = l_strndup(headers, headers_len); + else + *out_headers = NULL; + } + + return ret; + } + +err: + l_free(label); + + return NULL; +} + +LIB_EXPORT uint8_t *l_pem_load_buffer(const void *buf, size_t buf_len, + char **type_label, size_t *out_len) +{ + return pem_load_buffer(buf, buf_len, type_label, out_len, NULL, NULL); +} + +int pem_file_open(struct pem_file_info *info, const char *filename) +{ + info->fd = open(filename, O_RDONLY); + if (info->fd < 0) + return -errno; + + if (fstat(info->fd, &info->st) < 0) { + int r = -errno; + + close(info->fd); + return r; + } + + info->data = mmap(NULL, info->st.st_size, + PROT_READ, MAP_SHARED, info->fd, 0); + if (info->data == MAP_FAILED) { + int r = -errno; + + close(info->fd); + return r; + } + + return 0; +} + +void pem_file_close(struct pem_file_info *info) +{ + munmap(info->data, info->st.st_size); + close(info->fd); +} + +static uint8_t *pem_load_file(const char *filename, char **out_type_label, + size_t *out_len, char **out_headers) +{ + struct pem_file_info file; + uint8_t *result; + + if (unlikely(!filename)) + return NULL; + + if (pem_file_open(&file, filename) < 0) + return NULL; + + result = pem_load_buffer(file.data, file.st.st_size, + out_type_label, out_len, out_headers, + NULL); + pem_file_close(&file); + return result; +} + +LIB_EXPORT uint8_t *l_pem_load_file(const char *filename, + char **out_type_label, size_t *out_len) +{ + return pem_load_file(filename, out_type_label, out_len, NULL); +} + +static struct l_certchain *pem_list_to_chain(struct l_queue *list) +{ + struct l_certchain *chain; + + if (!list) + return NULL; + + chain = certchain_new_from_leaf(l_queue_pop_head(list)); + + while (!l_queue_isempty(list)) + certchain_link_issuer(chain, l_queue_pop_head(list)); + + l_queue_destroy(list, NULL); + return chain; +} + +LIB_EXPORT struct l_certchain *l_pem_load_certificate_chain_from_data( + const void *buf, size_t len) +{ + struct l_queue *list = l_pem_load_certificate_list_from_data(buf, len); + + if (!list) + return NULL; + + return pem_list_to_chain(list); +} + +LIB_EXPORT struct l_certchain *l_pem_load_certificate_chain( + const char *filename) +{ + struct l_queue *list = l_pem_load_certificate_list(filename); + + if (!list) + return NULL; + + return pem_list_to_chain(list); +} + +static bool pem_write_one_cert(struct l_cert *cert, void *user_data) +{ + int *fd = user_data; + const uint8_t *der; + size_t der_len; + struct iovec iov[3]; + ssize_t r; + + der = l_cert_get_der_data(cert, &der_len); + + iov[0].iov_base = "-----BEGIN CERTIFICATE-----\n"; + iov[0].iov_len = strlen(iov[0].iov_base); + iov[1].iov_base = l_base64_encode(der, der_len, 64); + iov[1].iov_len = strlen(iov[1].iov_base); + iov[2].iov_base = "\n-----END CERTIFICATE-----\n"; + iov[2].iov_len = strlen(iov[2].iov_base); + r = L_TFR(writev(*fd, iov, 3)); + l_free(iov[1].iov_base); + + if (r == (ssize_t) (iov[0].iov_len + iov[1].iov_len + iov[2].iov_len)) + return false; + + if (r < 0) + *fd = -errno; + else + *fd = -EIO; + + return true; +} + +int pem_write_certificate_chain(const struct l_certchain *chain, + const char *filename) +{ + int fd = L_TFR(open(filename, O_CREAT | O_WRONLY | O_CLOEXEC, 0600)); + int err = fd; + + if (err < 0) + return -errno; + + l_certchain_walk_from_leaf((struct l_certchain *) chain, + pem_write_one_cert, &err); + close(fd); + + return err < 0 ? err : 0; +} + +LIB_EXPORT struct l_queue *l_pem_load_certificate_list_from_data( + const void *buf, size_t len) +{ + const char *ptr, *end; + struct l_queue *list = NULL; + + ptr = buf; + end = buf + len; + + while (ptr && ptr < end) { + uint8_t *der; + size_t der_len; + char *label = NULL; + struct l_cert *cert; + const char *base64; + size_t base64_len; + bool is_certificate; + + base64 = pem_next(ptr, end - ptr, &label, + &base64_len, &ptr, false); + if (!base64) { + if (!ptr) + break; + + /* if ptr was not reset to NULL; parse error */ + goto error; + } + + is_certificate = !strcmp(label, "CERTIFICATE"); + l_free(label); + + if (!is_certificate) + goto error; + + der = l_base64_decode(base64, base64_len, &der_len); + if (!der) + goto error; + + cert = l_cert_new_from_der(der, der_len); + l_free(der); + + if (!cert) + goto error; + + if (!list) + list = l_queue_new(); + + l_queue_push_tail(list, cert); + } + + return list; + +error: + l_queue_destroy(list, (l_queue_destroy_func_t) l_cert_free); + return NULL; +} + +LIB_EXPORT struct l_queue *l_pem_load_certificate_list(const char *filename) +{ + struct pem_file_info file; + struct l_queue *list = NULL; + + if (unlikely(!filename)) + return NULL; + + if (pem_file_open(&file, filename) < 0) + return NULL; + + list = l_pem_load_certificate_list_from_data(file.data, + file.st.st_size); + pem_file_close(&file); + + return list; +} + +#define SKIP_WHITESPACE(str) \ + while (l_ascii_isspace(*(str))) \ + (str)++; + +static const char *parse_rfc1421_dek_info(char *headers, + const char **out_params) +{ + const char *proc_type = NULL; + char *dek_info = NULL; + char *comma; + + while (headers) { + char *lf = strchrnul(headers, '\n'); + char *key; + + key = headers; + SKIP_WHITESPACE(key); + headers = (*lf == '\n') ? lf + 1 : NULL; + + if (!memcmp(key, "X-", 2)) + key += 2; + + if (!memcmp(key, "Proc-Type:", 10)) { + if (proc_type) + return NULL; + + proc_type = key + 10; + SKIP_WHITESPACE(proc_type); + } else if (!memcmp(key, "DEK-Info:", 9)) { + if (dek_info) + return NULL; + + dek_info = key + 9; + SKIP_WHITESPACE(dek_info); + } else + continue; + + while (l_ascii_isspace(lf[-1])) + lf--; + + *lf = '\0'; + } + + if (!proc_type || !dek_info) + return NULL; + + /* Skip the version field (should be 3 or 4) */ + proc_type = strchr(proc_type, ','); + if (!proc_type) + return NULL; + + proc_type++; + SKIP_WHITESPACE(proc_type); + + /* Section 4.6.1.1 */ + if (strcmp(proc_type, "ENCRYPTED")) + return NULL; + + comma = strchr(dek_info, ','); + if (comma) { + *out_params = comma + 1; + SKIP_WHITESPACE(*out_params); + + while (comma > dek_info && l_ascii_isspace(comma[-1])) + comma--; + + *comma = '\0'; + } else + *out_params = NULL; + + return dek_info; +} + +static struct l_cipher *cipher_from_dek_info(const char *algid, const char *params, + const char *passphrase, + size_t *block_len) +{ + enum l_cipher_type type; + struct l_cipher *cipher; + struct l_checksum *md5; + uint8_t key[32]; + size_t key_len; + bool ok; + L_AUTO_FREE_VAR(uint8_t *, iv) = NULL; + size_t iv_len; + + if (!strcmp(algid, "DES-CBC")) { + type = L_CIPHER_DES_CBC; + key_len = 8; + iv_len = 8; + } else if (!strcmp(algid, "DES-EDE3-CBC")) { + type = L_CIPHER_DES3_EDE_CBC; + key_len = 24; + iv_len = 8; + } else if (!strcmp(algid, "AES-128-CBC")) { + type = L_CIPHER_AES_CBC; + key_len = 16; + iv_len = 16; + } else if (!strcmp(algid, "AES-192-CBC")) { + type = L_CIPHER_AES_CBC; + key_len = 24; + iv_len = 16; + } else if (!strcmp(algid, "AES-256-CBC")) { + type = L_CIPHER_AES_CBC; + key_len = 32; + iv_len = 16; + } else + return NULL; + + if (!params || strlen(params) != 2 * iv_len) + return NULL; + + *block_len = iv_len; + + iv = l_util_from_hexstring(params, &iv_len); + if (!iv) + return NULL; + + /* + * The encryption key is the MD5(password | IV[:8]), this comes from + * opessl's crypto/evp/evp_key.c:EVP_BytesToKey() and doesn't seem to + * be backed by any standard: + * https://web.archive.org/web/20190528100132/https://latacora.singles/2018/08/03/the-default-openssh.html + */ + md5 = l_checksum_new(L_CHECKSUM_MD5); + if (!md5) + return NULL; + + ok = l_checksum_update(md5, passphrase, strlen(passphrase)) && + l_checksum_update(md5, iv, 8) && + l_checksum_get_digest(md5, key, 16) == 16; + + if (ok && key_len > 16) { + l_checksum_reset(md5); + ok = l_checksum_update(md5, key, 16) && + l_checksum_update(md5, passphrase, strlen(passphrase)) && + l_checksum_update(md5, iv, 8) && + l_checksum_get_digest(md5, key + 16, 16) == 16; + } + + l_checksum_free(md5); + + if (!ok) { + cipher = NULL; + goto cleanup; + } + + cipher = l_cipher_new(type, key, key_len); + if (!cipher) + goto cleanup; + + if (l_cipher_set_iv(cipher, iv, iv_len)) + goto cleanup; + + l_cipher_free(cipher); + cipher = NULL; + +cleanup: + explicit_bzero(key, sizeof(key)); + return cipher; +} + +struct l_key *pem_load_private_key(uint8_t *content, size_t len, char *label, + const char *passphrase, char *headers, + bool *encrypted) +{ + struct l_key *pkey; + + /* + * RFC7468 Section 10-compatible unencrypted private key label + * (also mentioned in PKCS#8/RFC5958 Section 5), encodes + * the PKCS#8/RFC5958 PrivateKeyInfo structure -- supported + * directly by the pkcs8-key-parser kernel module. + */ + if (!strcmp(label, "PRIVATE KEY")) { + /* RFC822 Headers explicitly disallowed in RFC7468 */ + if (headers) + goto err; + + pkey = cert_key_from_pkcs8_private_key_info(content, len); + goto done; + } + + /* + * RFC7468 Section 11-compatible encrypted private key label + * (also mentioned in PKCS#8/RFC5958 Section 5), encodes + * the PKCS#8/RFC5958 EncryptedPrivateKeyInfo structure. We + * decrypt it into a plain PrivateKeyInfo for the + * pkcs8-key-parser module. + */ + if (!strcmp(label, "ENCRYPTED PRIVATE KEY")) { + if (encrypted) + *encrypted = true; + + if (!passphrase) + goto err; + + /* RFC822 Headers explicitly disallowed in RFC7468 */ + if (headers) + goto err; + + pkey = cert_key_from_pkcs8_encrypted_private_key_info(content, + len, + passphrase); + goto done; + } + + /* + * Legacy RSA private key label aka. SSLeay format, understood by + * most software but not documented in an RFC. Encodes the + * PKCS#1/RFC8017 RSAPrivateKey structure. We wrap it in a PKCS#8 + * PrivateKeyInfo for the pkcs8-key-parser module. + */ + if (!strcmp(label, "RSA PRIVATE KEY")) { + const char *dekalgid; + const char *dekparameters; + + /* + * "openssl rsa ..." can produce encrypted PKCS#1-formatted + * keys. These are incompatible with RFC7468 parsing because + * of the RFC822 headers present but the format is the same + * as documented in RFC1421. The encryption algorithms are + * supposed to be the ones defined in RFC1423 but that would + * be only DES-CBC while openssl allows other algorithms. + * When decrypted we get the RSAPrivateKey struct and proceed + * like with the unencrypted format. + */ + dekalgid = parse_rfc1421_dek_info(headers, &dekparameters); + if (dekalgid) { + struct l_cipher *alg; + bool r; + size_t block_len; + uint8_t pad; + + if (encrypted) + *encrypted = true; + + if (!passphrase) + goto err; + + alg = cipher_from_dek_info(dekalgid, dekparameters, + passphrase, &block_len); + if (!alg) + goto err; + + if (len % block_len || !len) { + l_cipher_free(alg); + goto err; + } + + r = l_cipher_decrypt(alg, content, content, len); + l_cipher_free(alg); + + if (!r) + goto err; + + /* Remove padding like in RFC1423 Section 1.1 */ + pad = content[len - 1]; + if (pad > block_len || pad == 0) + goto err; + + if (!l_secure_memeq(content + len - pad, pad - 1U, pad)) + goto err; + + len -= pad; + } + + pkey = cert_key_from_pkcs1_rsa_private_key(content, len); + goto done; + } + + /* Label not known */ +err: + pkey = NULL; +done: + explicit_bzero(content, len); + l_free(content); + l_free(label); + l_free(headers); + return pkey; +} + +LIB_EXPORT struct l_key *l_pem_load_private_key_from_data(const void *buf, + size_t buf_len, + const char *passphrase, + bool *encrypted) +{ + uint8_t *content; + char *label; + size_t len; + char *headers; + + if (encrypted) + *encrypted = false; + + content = pem_load_buffer(buf, buf_len, &label, &len, &headers, NULL); + + if (!content) + return NULL; + + return pem_load_private_key(content, len, label, passphrase, headers, + encrypted); +} + +/** + * l_pem_load_private_key + * @filename: path string to the PEM file to load + * @passphrase: private key encryption passphrase or NULL for unencrypted + * @encrypted: receives indication whether the file was encrypted if non-NULL + * + * Load the PEM encoded RSA Private Key file at @filename. If it is an + * encrypted private key and @passphrase was non-NULL, the file is + * decrypted. If it's unencrypted @passphrase is ignored. @encrypted + * stores information of whether the file was encrypted, both in a + * success case and on error when NULL is returned. This can be used to + * check if a passphrase is required without prior information. + * + * The passphrase, if given, must have been validated as UTF-8 unless the + * caller knows that PKCS#12 encryption algorithms are not used. + * Use l_utf8_validate. + * + * Returns: An l_key object to be freed with an l_key_free* function, + * or NULL. + **/ +LIB_EXPORT struct l_key *l_pem_load_private_key(const char *filename, + const char *passphrase, + bool *encrypted) +{ + uint8_t *content; + char *label; + size_t len; + char *headers; + + if (encrypted) + *encrypted = false; + + content = pem_load_file(filename, &label, &len, &headers); + + if (!content) + return NULL; + + return pem_load_private_key(content, len, label, passphrase, headers, + encrypted); +} diff --git a/ell/pem.h b/ell/pem.h new file mode 100644 index 0000000000000000000000000000000000000000..26aac84c833fc78ca16b02d6a1cb79307cba5c69 --- /dev/null +++ b/ell/pem.h @@ -0,0 +1,42 @@ +/* + * Embedded Linux library + * Copyright (C) 2015 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_PEM_H +#define __ELL_PEM_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct l_queue; +struct l_key; +struct l_cert; +struct l_certchain; + +uint8_t *l_pem_load_buffer(const void *buf, size_t buf_len, char **type_label, + size_t *out_len); +uint8_t *l_pem_load_file(const char *filename, char **type_label, size_t *len); + +struct l_certchain *l_pem_load_certificate_chain(const char *filename); +struct l_certchain *l_pem_load_certificate_chain_from_data(const void *buf, + size_t len); +struct l_queue *l_pem_load_certificate_list(const char *filename); +struct l_queue *l_pem_load_certificate_list_from_data(const void *buf, + size_t len); + +struct l_key *l_pem_load_private_key(const char *filename, + const char *passphrase, + bool *encrypted); +struct l_key *l_pem_load_private_key_from_data(const void *buf, size_t len, + const char *passphrase, + bool *encrypted); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_PEM_H */ diff --git a/ell/private.h b/ell/private.h new file mode 100644 index 0000000000000000000000000000000000000000..e4cbce95f523ebe382eb893f2402f902b3d1eb75 --- /dev/null +++ b/ell/private.h @@ -0,0 +1,10 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include <ell/util.h> + +#define LIB_EXPORT __attribute__ ((visibility("default"))) diff --git a/ell/queue.c b/ell/queue.c new file mode 100644 index 0000000000000000000000000000000000000000..901840223196f2e27ea5d7e91014ea4fb003b7de --- /dev/null +++ b/ell/queue.c @@ -0,0 +1,573 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "queue.h" +#include "private.h" +#include "useful.h" + +/** + * SECTION:queue + * @short_description: Queue support + * + * Queue support + */ + +/** + * l_queue: + * + * Opaque object representing the queue. + */ +struct l_queue { + struct l_queue_entry *head; + struct l_queue_entry *tail; + unsigned int entries; +}; + +/** + * l_queue_new: + * + * Create a new queue. + * + * No error handling is needed since. In case of real memory allocation + * problems abort() will be called. + * + * Returns: a newly allocated #l_queue object + **/ +LIB_EXPORT struct l_queue *l_queue_new(void) +{ + struct l_queue *queue; + + queue = l_new(struct l_queue, 1); + + queue->head = NULL; + queue->tail = NULL; + queue->entries = 0; + + return queue; +} + +/** + * l_queue_destroy: + * @queue: queue object + * @destroy: destroy function + * + * Free queue and call @destroy on all remaining entries. + **/ +LIB_EXPORT void l_queue_destroy(struct l_queue *queue, + l_queue_destroy_func_t destroy) +{ + l_queue_clear(queue, destroy); + l_free(queue); +} + +/** + * l_queue_clear: + * @queue: queue object + * @destroy: destroy function + * + * Clear queue and call @destroy on all remaining entries. + **/ +LIB_EXPORT void l_queue_clear(struct l_queue *queue, + l_queue_destroy_func_t destroy) +{ + struct l_queue_entry *entry; + + if (unlikely(!queue)) + return; + + entry = queue->head; + + while (entry) { + struct l_queue_entry *tmp = entry; + + if (destroy) + destroy(entry->data); + + entry = entry->next; + + l_free(tmp); + } + + queue->head = NULL; + queue->tail = NULL; + queue->entries = 0; +} + +/** + * l_queue_push_tail: + * @queue: queue object + * @data: pointer to data + * + * Adds @data pointer at the end of the queue. + * + * Returns: #true when data has been added and #false in case an invalid + * @queue object has been provided + **/ +LIB_EXPORT bool l_queue_push_tail(struct l_queue *queue, void *data) +{ + struct l_queue_entry *entry; + + if (unlikely(!queue)) + return false; + + entry = l_new(struct l_queue_entry, 1); + + entry->data = data; + entry->next = NULL; + + if (queue->tail) + queue->tail->next = entry; + + queue->tail = entry; + + if (!queue->head) + queue->head = entry; + + queue->entries++; + + return true; +} + +/** + * l_queue_push_head: + * @queue: queue object + * @data: pointer to data + * + * Adds @data pointer at the start of the queue. + * + * Returns: #true when data has been added and #false in case an invalid + * @queue object has been provided + **/ +LIB_EXPORT bool l_queue_push_head(struct l_queue *queue, void *data) +{ + struct l_queue_entry *entry; + + if (unlikely(!queue)) + return false; + + entry = l_new(struct l_queue_entry, 1); + + entry->data = data; + entry->next = queue->head; + + queue->head = entry; + + if (!queue->tail) + queue->tail = entry; + + queue->entries++; + + return true; +} + +/** + * l_queue_pop_head: + * @queue: queue object + * + * Removes the first element of the queue an returns it. + * + * Returns: data pointer to first element or #NULL in case an empty queue + **/ +LIB_EXPORT void *l_queue_pop_head(struct l_queue *queue) +{ + struct l_queue_entry *entry; + void *data; + + if (unlikely(!queue)) + return NULL; + + if (!queue->head) + return NULL; + + entry = queue->head; + + if (!queue->head->next) { + queue->head = NULL; + queue->tail = NULL; + } else + queue->head = queue->head->next; + + data = entry->data; + + l_free(entry); + + queue->entries--; + + return data; +} + +/** + * l_queue_peek_head: + * @queue: queue object + * + * Peeks at the first element of the queue an returns it. + * + * Returns: data pointer to first element or #NULL in case an empty queue + **/ +LIB_EXPORT void *l_queue_peek_head(struct l_queue *queue) +{ + struct l_queue_entry *entry; + + if (unlikely(!queue)) + return NULL; + + if (!queue->head) + return NULL; + + entry = queue->head; + return entry->data; +} + +/** + * l_queue_peek_tail: + * @queue: queue object + * + * Peeks at the last element of the queue an returns it. + * + * Returns: data pointer to first element or #NULL in case an empty queue + **/ +LIB_EXPORT void *l_queue_peek_tail(struct l_queue *queue) +{ + struct l_queue_entry *entry; + + if (unlikely(!queue)) + return NULL; + + if (!queue->tail) + return NULL; + + entry = queue->tail; + return entry->data; +} + +/** + * l_queue_insert: + * @queue: queue object + * @data: pointer to data + * @function: compare function + * @user_data: user data given to compare function + * + * Inserts @data pointer at a position in the queue determined by the + * compare @function. @function should return >= 0 if the @data (first + * parameter) should be inserted after the current entry (second parameter) + * and should return < 0 if before it. + * + * Returns: #true when data has been added and #false in case of failure + **/ +LIB_EXPORT bool l_queue_insert(struct l_queue *queue, void *data, + l_queue_compare_func_t function, void *user_data) +{ + struct l_queue_entry *entry, *prev, *cur; + int cmp; + + if (unlikely(!queue || !function)) + return false; + + entry = l_new(struct l_queue_entry, 1); + + entry->data = data; + entry->next = NULL; + + if (!queue->head) { + queue->head = entry; + queue->tail = entry; + goto done; + } + + for (prev = NULL, cur = queue->head; cur; prev = cur, cur = cur->next) { + cmp = function(entry->data, cur->data, user_data); + + if (cmp >= 0) + continue; + + if (prev == NULL) { + entry->next = queue->head; + queue->head = entry; + goto done; + } + + entry->next = cur; + prev->next = entry; + + goto done; + } + + queue->tail->next = entry; + queue->tail = entry; + +done: + queue->entries++; + + return true; +} + +/** + * l_queue_find: + * @queue: queue object + * @function: match function + * @user_data: user data given to compare function + * + * Finds an entry in the queue by running the match @function + * + * Returns: Matching entry or NULL if no entry can be found + **/ +LIB_EXPORT void *l_queue_find(struct l_queue *queue, + l_queue_match_func_t function, + const void *user_data) +{ + struct l_queue_entry *entry; + + if (unlikely(!queue || !function)) + return NULL; + + for (entry = queue->head; entry; entry = entry->next) + if (function(entry->data, user_data)) + return entry->data; + + return NULL; +} + +/** + * l_queue_remove: + * @queue: queue object + * @data: pointer to data + * + * Remove given @data from the queue. + * + * Returns: #true when data has been removed and #false when data could not + * be found or an invalid @queue object has been provided + **/ +LIB_EXPORT bool l_queue_remove(struct l_queue *queue, void *data) +{ + struct l_queue_entry *entry, *prev; + + if (unlikely(!queue)) + return false; + + for (entry = queue->head, prev = NULL; entry; + prev = entry, entry = entry->next) { + if (entry->data != data) + continue; + + if (prev) + prev->next = entry->next; + else + queue->head = entry->next; + + if (!entry->next) + queue->tail = prev; + + l_free(entry); + + queue->entries--; + + return true; + } + + return false; +} + +/** + * l_queue_reverse: + * @queue: queue object + * + * Reverse entries in the queue. + * + * Returns: #true on success and #false on failure + **/ +LIB_EXPORT bool l_queue_reverse(struct l_queue *queue) +{ + struct l_queue_entry *entry, *prev = NULL; + + if (unlikely(!queue)) + return false; + + entry = queue->head; + + while (entry) { + struct l_queue_entry *next = entry->next; + + entry->next = prev; + + prev = entry; + entry = next; + } + + queue->tail = queue->head; + queue->head = prev; + + return true; +} + +/** + * l_queue_foreach: + * @queue: queue object + * @function: callback function + * @user_data: user data given to callback function + * + * Call @function for every given data in @queue. + **/ +LIB_EXPORT void l_queue_foreach(struct l_queue *queue, + l_queue_foreach_func_t function, void *user_data) +{ + struct l_queue_entry *entry; + + if (unlikely(!queue || !function)) + return; + + for (entry = queue->head; entry; entry = entry->next) + function(entry->data, user_data); +} + +/** + * l_queue_foreach_remove: + * @queue: queue object + * @function: callback function + * @user_data: user data given to callback function + * + * Remove all entries in the @queue where @function returns #true. + * + * Returns: number of removed entries + **/ +LIB_EXPORT unsigned int l_queue_foreach_remove(struct l_queue *queue, + l_queue_remove_func_t function, void *user_data) +{ + struct l_queue_entry *entry, *prev = NULL; + unsigned int count = 0; + + if (unlikely(!queue || !function)) + return 0; + + entry = queue->head; + + while (entry) { + if (function(entry->data, user_data)) { + struct l_queue_entry *tmp = entry; + + if (prev) + prev->next = entry->next; + else + queue->head = entry->next; + + if (!entry->next) + queue->tail = prev; + + entry = entry->next; + + l_free(tmp); + + count++; + } else { + prev = entry; + entry = entry->next; + } + } + + queue->entries -= count; + + return count; +} + +/** + * l_queue_remove_if + * @queue: queue object + * @function: callback function + * @user_data: user data given to callback function + * + * Remove the first entry in the @queue where the function returns #true. + * + * Returns: NULL if no entry was found, or the entry data if removal was + * successful. + **/ +LIB_EXPORT void *l_queue_remove_if(struct l_queue *queue, + l_queue_match_func_t function, + const void *user_data) +{ + struct l_queue_entry *entry, *prev = NULL; + + if (unlikely(!queue || !function)) + return NULL; + + entry = queue->head; + + while (entry) { + if (function(entry->data, user_data)) { + struct l_queue_entry *tmp = entry; + void *data; + + if (prev) + prev->next = entry->next; + else + queue->head = entry->next; + + if (!entry->next) + queue->tail = prev; + + data = tmp->data; + + l_free(tmp); + queue->entries--; + + return data; + } + + prev = entry; + entry = entry->next; + } + + return NULL; +} + +/** + * l_queue_length: + * @queue: queue object + * + * Returns: entries of the queue + **/ +LIB_EXPORT unsigned int l_queue_length(struct l_queue *queue) +{ + if (unlikely(!queue)) + return 0; + + return queue->entries; +} + +/** + * l_queue_isempty: + * @queue: queue object + * + * Returns: #true if @queue is empty and #false is not + **/ +LIB_EXPORT bool l_queue_isempty(struct l_queue *queue) +{ + if (unlikely(!queue)) + return true; + + return queue->entries == 0; +} + +/** + * l_queue_get_entries: + * @queue: queue object + * + * This function gives direct, read-only access to the internal list structure + * of the queue. This can be used to efficiently traverse the elements. + * + * Returns: A pointer to the head of the queue. + **/ +LIB_EXPORT const struct l_queue_entry *l_queue_get_entries( + const struct l_queue *queue) +{ + if (unlikely(!queue)) + return NULL; + + return queue->head; +} diff --git a/ell/queue.h b/ell/queue.h new file mode 100644 index 0000000000000000000000000000000000000000..517298c808d2743d30708eab0244cf003924f6c5 --- /dev/null +++ b/ell/queue.h @@ -0,0 +1,67 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_QUEUE_H +#define __ELL_QUEUE_H + +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*l_queue_foreach_func_t) (void *data, void *user_data); +typedef void (*l_queue_destroy_func_t) (void *data); +typedef int (*l_queue_compare_func_t) (const void *a, const void *b, + void *user_data); +typedef bool (*l_queue_match_func_t) (const void *data, const void *user_data); +typedef bool (*l_queue_remove_func_t) (void *data, void *user_data); + +struct l_queue; + +struct l_queue_entry { + void *data; + struct l_queue_entry *next; +}; + +struct l_queue *l_queue_new(void); +void l_queue_destroy(struct l_queue *queue, + l_queue_destroy_func_t destroy); +void l_queue_clear(struct l_queue *queue, + l_queue_destroy_func_t destroy); + +bool l_queue_push_tail(struct l_queue *queue, void *data); +bool l_queue_push_head(struct l_queue *queue, void *data); +void *l_queue_pop_head(struct l_queue *queue); +void *l_queue_peek_head(struct l_queue *queue); +void *l_queue_peek_tail(struct l_queue *queue); + +bool l_queue_insert(struct l_queue *queue, void *data, + l_queue_compare_func_t function, void *user_data); +void *l_queue_find(struct l_queue *queue, + l_queue_match_func_t function, const void *user_data); +bool l_queue_remove(struct l_queue *queue, void *data); +void *l_queue_remove_if(struct l_queue *queue, + l_queue_match_func_t function, const void *user_data); + +bool l_queue_reverse(struct l_queue *queue); + +void l_queue_foreach(struct l_queue *queue, + l_queue_foreach_func_t function, void *user_data); +unsigned int l_queue_foreach_remove(struct l_queue *queue, + l_queue_remove_func_t function, void *user_data); + +unsigned int l_queue_length(struct l_queue *queue); +bool l_queue_isempty(struct l_queue *queue); + +const struct l_queue_entry *l_queue_get_entries(const struct l_queue *queue); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_QUEUE_H */ diff --git a/ell/random.c b/ell/random.c new file mode 100644 index 0000000000000000000000000000000000000000..6e0adfe23a5bb38c6f58093cd767928833e8481f --- /dev/null +++ b/ell/random.c @@ -0,0 +1,90 @@ +/* + * Embedded Linux library + * Copyright (C) 2015 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/syscall.h> + +#include "random.h" +#include "private.h" +#include "missing.h" + +#ifndef GRND_NONBLOCK +#define GRND_NONBLOCK 0x0001 +#endif + +#ifndef GRND_RANDOM +#define GRND_RANDOM 0x0002 +#endif + +static inline int getrandom(void *buffer, size_t count, unsigned flags) { + return syscall(__NR_getrandom, buffer, count, flags); +} + +/** + * l_getrandom: + * @buf: buffer to fill with random data + * @len: length of random data requested + * + * Request a number of randomly generated bytes given by @len and put them + * into buffer @buf. + * + * Returns: true if the random data could be generated, false otherwise. + **/ +LIB_EXPORT bool l_getrandom(void *buf, size_t len) +{ + while (len) { + int ret; + + ret = L_TFR(getrandom(buf, len, 0)); + if (ret < 0) + return false; + + buf += ret; + len -= ret; + } + + return true; +} + +LIB_EXPORT bool l_getrandom_is_supported() +{ + static bool initialized = false; + static bool supported = true; + uint8_t buf[4]; + int ret; + + if (initialized) + return supported; + + ret = getrandom(buf, sizeof(buf), GRND_NONBLOCK); + + if (ret < 0 && errno == ENOSYS) + supported = false; + + initialized = true; + return supported; +} + +LIB_EXPORT uint32_t l_getrandom_uint32(void) +{ + int ret; + uint32_t u; + + ret = getrandom(&u, sizeof(u), GRND_NONBLOCK); + + if (ret == sizeof(u)) + return u; + + return random() * RAND_MAX + random(); +} diff --git a/ell/random.h b/ell/random.h new file mode 100644 index 0000000000000000000000000000000000000000..9c50192f75674175d84ff35fabe5b02db307ba11 --- /dev/null +++ b/ell/random.h @@ -0,0 +1,28 @@ +/* + * Embedded Linux library + * Copyright (C) 2015 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_RANDOM_H +#define __ELL_RANDOM_H + +#include <stddef.h> +#include <stdbool.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +bool l_getrandom(void *buf, size_t len); +bool l_getrandom_is_supported(void); + +uint32_t l_getrandom_uint32(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_RANDOM_H */ diff --git a/ell/settings.c b/ell/settings.c new file mode 100644 index 0000000000000000000000000000000000000000..a5f17d138281bf356eea9515c2486d45545772f9 --- /dev/null +++ b/ell/settings.c @@ -0,0 +1,1542 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#if __STDC_VERSION__ <= 199409L +#define _DEFAULT_SOURCE /* for strto{u}ll() */ +#endif + +#define _GNU_SOURCE +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <stdbool.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> + +#include "useful.h" +#include "strv.h" +#include "utf8.h" +#include "string.h" +#include "queue.h" +#include "settings.h" +#include "private.h" +#include "missing.h" +#include "pem-private.h" + +struct setting_data { + char *key; + char *value; +}; + +struct embedded_group_data { + char *name; + char type[32]; + size_t len; + char data[]; +}; + +struct group_data { + char *name; + struct l_queue *settings; +}; + +struct l_settings { + l_settings_debug_cb_t debug_handler; + l_settings_destroy_cb_t debug_destroy; + void *debug_data; + struct l_queue *groups; + struct l_queue *embedded_groups; +}; + +static void setting_destroy(void *data) +{ + struct setting_data *pair = data; + + l_free(pair->key); + explicit_bzero(pair->value, strlen(pair->value)); + l_free(pair->value); + l_free(pair); +} + +static void group_destroy(void *data) +{ + struct group_data *group = data; + + l_free(group->name); + l_queue_destroy(group->settings, setting_destroy); + + l_free(group); +} + +static void embedded_group_destroy(void *data) +{ + struct embedded_group_data *group = data; + + l_free(group->name); + l_free(group); +} + +LIB_EXPORT struct l_settings *l_settings_new(void) +{ + struct l_settings *settings; + + settings = l_new(struct l_settings, 1); + settings->groups = l_queue_new(); + settings->embedded_groups = l_queue_new(); + + return settings; +} + +static void copy_key_value_foreach(void *data, void *user_data) +{ + struct setting_data *s = data; + struct l_queue *settings = user_data; + struct setting_data *copy = l_new(struct setting_data, 1); + + copy->key = l_strdup(s->key); + copy->value = l_strdup(s->value); + + l_queue_push_head(settings, copy); +} + +static void copy_group_foreach(void *data, void *user_data) +{ + struct group_data *group = data; + struct l_queue *groups = user_data; + struct group_data *copy = l_new(struct group_data, 1); + + copy->name = l_strdup(group->name); + copy->settings = l_queue_new(); + + l_queue_push_head(groups, copy); + + l_queue_foreach(group->settings, copy_key_value_foreach, + copy->settings); +} + +static void copy_embedded_foreach(void *data, void *user_data) +{ + struct embedded_group_data *embedded = data; + struct l_queue *groups = user_data; + struct embedded_group_data *copy; + + copy = l_memdup(embedded, sizeof(struct embedded_group_data) + + embedded->len + 1); + copy->name = l_strdup(embedded->name); + + l_queue_push_tail(groups, copy); +} + +LIB_EXPORT struct l_settings *l_settings_clone( + const struct l_settings *settings) +{ + struct l_settings *copy; + + if (unlikely(!settings)) + return NULL; + + copy = l_settings_new(); + + l_queue_foreach(settings->groups, copy_group_foreach, copy->groups); + l_queue_foreach(settings->embedded_groups, copy_embedded_foreach, + copy->embedded_groups); + + return copy; +} + +LIB_EXPORT void l_settings_free(struct l_settings *settings) +{ + if (unlikely(!settings)) + return; + + if (settings->debug_destroy) + settings->debug_destroy(settings->debug_data); + + l_queue_destroy(settings->groups, group_destroy); + l_queue_destroy(settings->embedded_groups, embedded_group_destroy); + + l_free(settings); +} + +static char *unescape_value(const char *value) +{ + char *ret; + char *n; + const char *o; + + ret = l_new(char, strlen(value) + 1); + + for (n = ret, o = value; *o; o++, n++) { + if (*o != '\\') { + *n = *o; + continue; + } + + o += 1; + + switch (*o) { + case 's': + *n = ' '; + break; + case 'n': + *n = '\n'; + break; + case 't': + *n = '\t'; + break; + case 'r': + *n = '\r'; + break; + case '\\': + *n = '\\'; + break; + default: + explicit_bzero(ret, n - ret); + l_free(ret); + return NULL; + } + } + + return ret; +} + +static char *escape_value(const char *value) +{ + size_t i; + size_t j; + char *ret; + bool lead_whitespace; + + for (i = 0, j = 0, lead_whitespace = true; value[i]; i++) { + switch (value[i]) { + case ' ': + case '\t': + if (lead_whitespace) + j += 1; + + break; + case '\n': + case '\r': + case '\\': + j += 1; + /* fall through */ + default: + lead_whitespace = false; + } + } + + ret = l_malloc(i + j + 1); + + for (i = 0, j = 0, lead_whitespace = true; value[i]; i++) { + switch (value[i]) { + case ' ': + if (lead_whitespace) { + ret[j++] = '\\'; + ret[j++] = 's'; + } else + ret[j++] = value[i]; + + break; + case '\t': + if (lead_whitespace) { + ret[j++] = '\\'; + ret[j++] = 't'; + } else + ret[j++] = value[i]; + + break; + case '\n': + ret[j++] = '\\'; + ret[j++] = 'n'; + lead_whitespace = false; + break; + case '\r': + ret[j++] = '\\'; + ret[j++] = 'r'; + lead_whitespace = false; + break; + case '\\': + ret[j++] = '\\'; + ret[j++] = '\\'; + lead_whitespace = false; + break; + default: + ret[j++] = value[i]; + lead_whitespace = false; + } + } + + ret[j] = '\0'; + + return ret; +} + +static ssize_t parse_pem(const char *data, size_t len) +{ + const char *ptr; + const char *end; + size_t count = 0; + + ptr = data; + end = data + len; + + while (ptr && ptr < end) { + const char *pem_start = ptr; + + if (!pem_next(ptr, len, NULL, NULL, &ptr, true)) { + if (ptr) + return -EINVAL; + + break; + } + + len -= ptr - pem_start; + count += ptr - pem_start; + } + + return count; +} + +struct group_extension { + char *name; + ssize_t (*parse)(const char *data, size_t len); +}; + +static const struct group_extension pem_extension = { + .name = "pem", + .parse = parse_pem, +}; + +static const struct group_extension *extensions[] = { + &pem_extension, + NULL +}; + +static const struct group_extension *find_group_extension(const char *type, + size_t len) +{ + unsigned int i; + + for (i = 0; extensions[i]; i++) { + if (!strncmp(type, extensions[i]->name, len)) + return extensions[i]; + } + + return NULL; +} + +static ssize_t parse_embedded_group(struct l_settings *setting, + const char *data, + size_t line_len, size_t len, + size_t line) +{ + struct embedded_group_data *group; + const struct group_extension *ext; + const char *ptr; + const char *type; + size_t type_len; + const char *name; + size_t name_len; + ssize_t bytes; + + /* Must be at least [@a@b] */ + if (line_len < 6) + goto invalid_group; + + /* caller checked data[1] == '@', next char is type */ + type = data + 2; + + ptr = memchr(type, '@', line_len - 2); + + type_len = ptr - type; + + if (!ptr || type_len > 31 || type_len < 1) + goto invalid_group; + + if (ptr + 1 > data + line_len) + goto invalid_group; + + name = ptr + 1; + + /* subtract [@@ + type */ + ptr = memchr(name, ']', line_len - 3 - type_len); + + name_len = ptr - name; + + if (!ptr || name_len < 1) + goto invalid_group; + + ext = find_group_extension(type, type_len); + if (!ext) + goto invalid_group; + + if (ptr + 2 > data + len) { + l_util_debug(setting->debug_handler, setting->debug_data, + "Embedded group had no payload"); + return -EINVAL; + } + + bytes = ext->parse(ptr + 2, len - line_len); + if (bytes < 0) { + l_util_debug(setting->debug_handler, setting->debug_data, + "Failed to parse embedded group data"); + return -EINVAL; + } + + group = l_malloc(sizeof(struct embedded_group_data) + bytes + 1); + + group->name = l_strndup(name, name_len); + + memcpy(group->type, type, type_len); + group->type[type_len] = '\0'; + + group->len = bytes; + memcpy(group->data, ptr + 2, bytes); + group->data[bytes] = '\0'; + + l_queue_push_tail(setting->embedded_groups, group); + + return bytes; + +invalid_group: + l_util_debug(setting->debug_handler, setting->debug_data, + "Invalid embedded group at line %zd", line); + + return -EINVAL; +} + +static bool parse_group(struct l_settings *settings, const char *data, + size_t len, size_t line) +{ + size_t i = 1; + size_t end; + struct group_data *group; + + while (i < len && data[i] != ']') { + if (l_ascii_isprint(data[i]) == false || data[i] == '[') { + l_util_debug(settings->debug_handler, + settings->debug_data, + "Invalid group name at line %zd", line); + return false; + } + + i += 1; + } + + if (i >= len) { + l_util_debug(settings->debug_handler, settings->debug_data, + "Unterminated group name at line %zd", line); + return false; + } + + end = i; + i += 1; + + while (i < len && l_ascii_isblank(data[i])) + i += 1; + + if (i != len) { + l_util_debug(settings->debug_handler, settings->debug_data, + "Junk characters at the end of line %zd", line); + return false; + } + + group = l_new(struct group_data, 1); + group->name = l_strndup(data + 1, end - 1); + group->settings = l_queue_new(); + + l_queue_push_tail(settings->groups, group); + + return true; +} + +static bool validate_key_character(char c) +{ + if (l_ascii_isalnum(c)) + return true; + + if (c == '_' || c == '-' || c == '.') + return true; + + return false; +} + +static unsigned int parse_key(struct l_settings *settings, const char *data, + size_t len, size_t line) +{ + unsigned int i; + unsigned int end; + struct group_data *group; + struct setting_data *pair; + + for (i = 0; i < len; i++) { + if (validate_key_character(data[i])) + continue; + + if (l_ascii_isblank(data[i])) + break; + + l_util_debug(settings->debug_handler, settings->debug_data, + "Invalid character in Key on line %zd", line); + + return 0; + } + + end = i; + + /* Make sure the rest of the characters are blanks */ + while (i < len) { + if (l_ascii_isblank(data[i++])) + continue; + + l_util_debug(settings->debug_handler, settings->debug_data, + "Garbage after Key on line %zd", line); + + return 0; + } + + group = l_queue_peek_tail(settings->groups); + pair = l_new(struct setting_data, 1); + pair->key = l_strndup(data, end); + l_queue_push_head(group->settings, pair); + + return end; +} + +static bool parse_value(struct l_settings *settings, const char *data, + size_t len, size_t line) +{ + unsigned int end = len; + struct group_data *group; + struct setting_data *pair; + + group = l_queue_peek_tail(settings->groups); + pair = l_queue_pop_head(group->settings); + + if (!l_utf8_validate(data, len, NULL)) { + l_util_debug(settings->debug_handler, settings->debug_data, + "Invalid UTF8 in value on line: %zd", line); + + l_free(pair->key); + l_free(pair); + + return false; + } + + pair->value = l_strndup(data, end); + l_queue_push_tail(group->settings, pair); + + return true; +} + +static bool parse_keyvalue(struct l_settings *settings, const char *data, + size_t len, size_t line) +{ + const char *equal = memchr(data, '=', len); + + if (!equal) { + l_util_debug(settings->debug_handler, settings->debug_data, + "Delimiter '=' not found on line: %zd", line); + return false; + } + + if (equal == data) { + l_util_debug(settings->debug_handler, settings->debug_data, + "Empty key on line: %zd", line); + return false; + } + + if (!parse_key(settings, data, equal - data, line)) + return false; + + equal += 1; + while (equal < data + len && l_ascii_isblank(*equal)) + equal += 1; + + return parse_value(settings, equal, len - (equal - data), line); +} + +LIB_EXPORT bool l_settings_load_from_data(struct l_settings *settings, + const char *data, size_t len) +{ + size_t pos = 0; + bool r = true; + bool has_group = false; + const char *eol; + size_t line = 1; + size_t line_len; + + if (unlikely(!settings || !data || !len)) + return false; + + while (pos < len && r) { + if (l_ascii_isblank(data[pos])) { + pos += 1; + continue; + } + + if (data[pos] == '\n') { + line += 1; + pos += 1; + continue; + } + + eol = memchr(data + pos, '\n', len - pos); + if (!eol) + eol = data + len; + + line_len = eol - data - pos; + + if (line_len > 1 && data[pos] == '[' && data[pos + 1] == '@') { + ssize_t ret; + + ret = parse_embedded_group(settings, data + pos, + line_len, len - pos, + line); + if (ret < 0) + return false; + + /* + * This is the offset for the actual raw data, the + * group line will be offset below + */ + pos += ret; + } else if (data[pos] == '[') { + r = parse_group(settings, data + pos, line_len, line); + if (r) + has_group = true; + } else if (data[pos] != '#') { + if (!has_group) + return false; + + r = parse_keyvalue(settings, data + pos, line_len, + line); + } + + pos += line_len; + } + + return r; +} + +LIB_EXPORT char *l_settings_to_data(const struct l_settings *settings, + size_t *len) +{ + struct l_string *buf; + char *ret; + const struct l_queue_entry *group_entry; + + if (unlikely(!settings)) + return NULL; + + buf = l_string_new(255); + + group_entry = l_queue_get_entries(settings->groups); + while (group_entry) { + struct group_data *group = group_entry->data; + const struct l_queue_entry *setting_entry; + + l_string_append_printf(buf, "[%s]\n", group->name); + + setting_entry = l_queue_get_entries(group->settings); + + while (setting_entry) { + struct setting_data *setting = setting_entry->data; + + l_string_append_printf(buf, "%s=%s\n", + setting->key, setting->value); + setting_entry = setting_entry->next; + } + + if (group_entry->next) + l_string_append_c(buf, '\n'); + + group_entry = group_entry->next; + } + + group_entry = l_queue_get_entries(settings->embedded_groups); + + if (group_entry && l_queue_length(settings->groups) > 0) + l_string_append_c(buf, '\n'); + + while (group_entry) { + struct embedded_group_data *group = group_entry->data; + + l_string_append_printf(buf, "[@%s@%s]\n%s", + group->type, + group->name, + group->data); + if (group_entry->next) + l_string_append_c(buf, '\n'); + + group_entry = group_entry->next; + } + + ret = l_string_unwrap(buf); + + if (len) + *len = strlen(ret); + + return ret; +} + +LIB_EXPORT bool l_settings_load_from_file(struct l_settings *settings, + const char *filename) +{ + int fd; + struct stat st; + char *data; + bool r; + + if (unlikely(!settings || !filename)) + return false; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + l_util_debug(settings->debug_handler, settings->debug_data, + "Could not open %s (%s)", filename, + strerror(errno)); + return false; + } + + if (fstat(fd, &st) < 0) { + l_util_debug(settings->debug_handler, settings->debug_data, + "Could not stat %s (%s)", filename, + strerror(errno)); + close(fd); + + return false; + } + + /* Nothing to do, assume success */ + if (st.st_size == 0) { + close(fd); + return true; + } + + data = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) { + l_util_debug(settings->debug_handler, settings->debug_data, + "Could not mmap %s (%s)", filename, + strerror(errno)); + close(fd); + + return false; + } + + r = l_settings_load_from_data(settings, data, st.st_size); + + munmap(data, st.st_size); + close(fd); + + return r; +} + +LIB_EXPORT bool l_settings_set_debug(struct l_settings *settings, + l_settings_debug_cb_t callback, + void *user_data, + l_settings_destroy_cb_t destroy) +{ + if (unlikely(!settings)) + return false; + + if (settings->debug_destroy) + settings->debug_destroy(settings->debug_data); + + settings->debug_handler = callback; + settings->debug_destroy = destroy; + settings->debug_data = user_data; + + return true; +} + +static bool group_match(const void *a, const void *b) +{ + const struct group_data *group = a; + const char *name = b; + + return !strcmp(group->name, name); +} + +struct gather_data { + int cur; + char **v; +}; + +static void gather_groups(void *data, void *user_data) +{ + struct group_data *group_data = data; + struct gather_data *gather = user_data; + + gather->v[gather->cur++] = l_strdup(group_data->name); +} + +LIB_EXPORT char **l_settings_get_groups(const struct l_settings *settings) +{ + char **ret; + struct gather_data gather; + + if (unlikely(!settings)) + return NULL; + + ret = l_new(char *, l_queue_length(settings->groups) + 1); + gather.v = ret; + gather.cur = 0; + + l_queue_foreach(settings->groups, gather_groups, &gather); + + return ret; +} + +LIB_EXPORT bool l_settings_has_group(const struct l_settings *settings, + const char *group_name) +{ + struct group_data *group; + + if (unlikely(!settings)) + return false; + + group = l_queue_find(settings->groups, group_match, group_name); + + return !!group; +} + +static bool key_match(const void *a, const void *b) +{ + const struct setting_data *setting = a; + const char *key = b; + + return !strcmp(setting->key, key); +} + +static void gather_keys(void *data, void *user_data) +{ + struct setting_data *setting_data = data; + struct gather_data *gather = user_data; + + gather->v[gather->cur++] = l_strdup(setting_data->key); +} + +LIB_EXPORT char **l_settings_get_keys(const struct l_settings *settings, + const char *group_name) +{ + char **ret; + struct group_data *group_data; + struct gather_data gather; + + if (unlikely(!settings)) + return NULL; + + group_data = l_queue_find(settings->groups, group_match, group_name); + if (!group_data) + return NULL; + + ret = l_new(char *, l_queue_length(group_data->settings) + 1); + gather.v = ret; + gather.cur = 0; + + l_queue_foreach(group_data->settings, gather_keys, &gather); + + return ret; +} + +LIB_EXPORT bool l_settings_has_key(const struct l_settings *settings, + const char *group_name, const char *key) +{ + struct group_data *group; + struct setting_data *setting; + + if (unlikely(!settings)) + return false; + + group = l_queue_find(settings->groups, group_match, group_name); + if (!group) + return false; + + setting = l_queue_find(group->settings, key_match, key); + + return !!setting; +} + +LIB_EXPORT const char *l_settings_get_value(const struct l_settings *settings, + const char *group_name, + const char *key) +{ + struct group_data *group; + struct setting_data *setting; + + if (unlikely(!settings)) + return NULL; + + group = l_queue_find(settings->groups, group_match, group_name); + if (!group) + return NULL; + + setting = l_queue_find(group->settings, key_match, key); + if (!setting) + return NULL; + + return setting->value; +} + +static bool validate_group_name(const char *group_name) +{ + int i; + + for (i = 0; group_name[i]; i++) { + if (!l_ascii_isprint(group_name[i])) + return false; + + if (group_name[i] == ']' || group_name[i] == '[') + return false; + } + + return true; +} + +LIB_EXPORT bool l_settings_add_group(struct l_settings *settings, + const char *group_name) +{ + struct group_data *group; + + if (unlikely(!settings || !group_name)) + return false; + + if (!validate_group_name(group_name)) { + l_util_debug(settings->debug_handler, settings->debug_data, + "Invalid group name %s", group_name); + return false; + } + + group = l_queue_find(settings->groups, group_match, group_name); + if (group) { + l_util_debug(settings->debug_handler, settings->debug_data, + "Group %s exists", group_name); + return true; + } + + group = l_new(struct group_data, 1); + group->name = l_strdup(group_name); + group->settings = l_queue_new(); + l_queue_push_tail(settings->groups, group); + return true; +} + +static bool validate_key(const char *key) +{ + int i; + + for (i = 0; key[i]; i++) { + if (!validate_key_character(key[i])) + return false; + } + + return true; +} + +static bool set_value(struct l_settings *settings, const char *group_name, + const char *key, char *value) +{ + struct group_data *group; + struct setting_data *pair; + + if (!validate_group_name(group_name)) { + l_util_debug(settings->debug_handler, settings->debug_data, + "Invalid group name %s", group_name); + goto error; + } + + if (!validate_key(key)) { + l_util_debug(settings->debug_handler, settings->debug_data, + "Invalid key %s", key); + goto error; + } + + group = l_queue_find(settings->groups, group_match, group_name); + if (!group) { + group = l_new(struct group_data, 1); + group->name = l_strdup(group_name); + group->settings = l_queue_new(); + + l_queue_push_tail(settings->groups, group); + goto add_pair; + } + + pair = l_queue_find(group->settings, key_match, key); + if (!pair) { +add_pair: + pair = l_new(struct setting_data, 1); + pair->key = l_strdup(key); + pair->value = value; + l_queue_push_tail(group->settings, pair); + + return true; + } + + explicit_bzero(pair->value, strlen(pair->value)); + l_free(pair->value); + pair->value = value; + + return true; + +error: + explicit_bzero(value, strlen(value)); + l_free(value); + return false; +} + +LIB_EXPORT bool l_settings_set_value(struct l_settings *settings, + const char *group_name, const char *key, + const char *value) +{ + if (unlikely(!settings || !value)) + return false; + + return set_value(settings, group_name, key, l_strdup(value)); +} + +LIB_EXPORT bool l_settings_get_bool(const struct l_settings *settings, + const char *group_name, const char *key, + bool *out) +{ + const char *value; + + value = l_settings_get_value(settings, group_name, key); + if (!value) + return false; + + if (!strcasecmp(value, "true") || !strcmp(value, "1")) { + if (out) + *out = true; + + return true; + } + + if (!strcasecmp(value, "false") || !strcmp(value, "0")) { + if (out) + *out = false; + + return true; + } + + l_util_debug(settings->debug_handler, settings->debug_data, + "Could not interpret %s as a bool", value); + + return false; +} + +LIB_EXPORT bool l_settings_set_bool(struct l_settings *settings, + const char *group_name, const char *key, + bool in) +{ + static const char *true_str = "true"; + static const char *false_str = "false"; + const char *v; + + if (in == false) + v = false_str; + else + v = true_str; + + return l_settings_set_value(settings, group_name, key, v); +} + +LIB_EXPORT bool l_settings_get_int(const struct l_settings *settings, + const char *group_name, + const char *key, int *out) +{ + const char *value = l_settings_get_value(settings, group_name, key); + long int r; + int t; + char *endp; + + if (!value) + return false; + + if (*value == '\0') + goto error; + + errno = 0; + + t = r = strtol(value, &endp, 0); + if (*endp != '\0') + goto error; + + if (unlikely(errno == ERANGE || r != t)) + goto error; + + if (out) + *out = r; + + return true; + +error: + l_util_debug(settings->debug_handler, settings->debug_data, + "Could not interpret %s as an int", value); + + return false; +} + +LIB_EXPORT bool l_settings_set_int(struct l_settings *settings, + const char *group_name, const char *key, + int in) +{ + char buf[64]; + + snprintf(buf, sizeof(buf), "%d", in); + + return l_settings_set_value(settings, group_name, key, buf); +} + +LIB_EXPORT bool l_settings_get_uint(const struct l_settings *settings, + const char *group_name, + const char *key, + unsigned int *out) +{ + const char *value = l_settings_get_value(settings, group_name, key); + + if (!value) + return false; + + if (l_safe_atou32(value, out) < 0) + goto error; + + return true; + +error: + l_util_debug(settings->debug_handler, settings->debug_data, + "Could not interpret %s as a uint", value); + + return false; +} + +LIB_EXPORT bool l_settings_set_uint(struct l_settings *settings, + const char *group_name, const char *key, + unsigned int in) +{ + char buf[64]; + + snprintf(buf, sizeof(buf), "%u", in); + + return l_settings_set_value(settings, group_name, key, buf); +} + +LIB_EXPORT bool l_settings_get_int64(const struct l_settings *settings, + const char *group_name, const char *key, + int64_t *out) +{ + const char *value = l_settings_get_value(settings, group_name, key); + int64_t r; + char *endp; + + if (!value) + return false; + + if (*value == '\0') + goto error; + + errno = 0; + + r = strtoll(value, &endp, 0); + if (*endp != '\0') + goto error; + + if (unlikely(errno == ERANGE)) + goto error; + + if (out) + *out = r; + + return true; + +error: + l_util_debug(settings->debug_handler, settings->debug_data, + "Could not interpret %s as an int64", value); + + return false; +} + +LIB_EXPORT bool l_settings_set_int64(struct l_settings *settings, + const char *group_name, const char *key, + int64_t in) +{ + char buf[64]; + + snprintf(buf, sizeof(buf), "%" PRId64, in); + + return l_settings_set_value(settings, group_name, key, buf); +} + +LIB_EXPORT bool l_settings_get_uint64(const struct l_settings *settings, + const char *group_name, + const char *key, + uint64_t *out) +{ + const char *value = l_settings_get_value(settings, group_name, key); + uint64_t r; + char *endp; + + if (!value) + return false; + + /* Do not allow '+' or '-' or empty string */ + if (!l_ascii_isdigit(*value)) + goto error; + + errno = 0; + + r = strtoull(value, &endp, 0); + if (*endp != '\0') + goto error; + + if (unlikely(errno == ERANGE)) + goto error; + + if (out) + *out = r; + + return true; + +error: + l_util_debug(settings->debug_handler, settings->debug_data, + "Could not interpret %s as a uint64", value); + + return false; +} + +LIB_EXPORT bool l_settings_set_uint64(struct l_settings *settings, + const char *group_name, const char *key, + uint64_t in) +{ + char buf[64]; + + snprintf(buf, sizeof(buf), "%" PRIu64, in); + + return l_settings_set_value(settings, group_name, key, buf); +} + +LIB_EXPORT char *l_settings_get_string(const struct l_settings *settings, + const char *group_name, const char *key) +{ + const char *value = l_settings_get_value(settings, group_name, key); + + if (!value) + return NULL; + + return unescape_value(value); +} + +LIB_EXPORT bool l_settings_set_string(struct l_settings *settings, + const char *group_name, const char *key, + const char *value) +{ + char *buf; + + if (unlikely(!settings || !value)) + return false; + + buf = escape_value(value); + + return set_value(settings, group_name, key, buf); +} + +LIB_EXPORT char **l_settings_get_string_list(const struct l_settings *settings, + const char *group_name, + const char *key, + const char delimiter) +{ + const char *value = l_settings_get_value(settings, group_name, key); + char *str; + char **ret; + + if (!value) + return NULL; + + str = unescape_value(value); + if (str == NULL) + return NULL; + + ret = l_strsplit(str, delimiter); + l_free(str); + + return ret; +} + +LIB_EXPORT bool l_settings_set_string_list(struct l_settings *settings, + const char *group_name, const char *key, + char **value, char delimiter) +{ + char *buf; + char *tmp; + + if (unlikely(!settings || !value)) + return false; + + tmp = l_strjoinv(value, delimiter); + buf = escape_value(tmp); + l_free(tmp); + + return set_value(settings, group_name, key, buf); +} + +LIB_EXPORT bool l_settings_get_double(const struct l_settings *settings, + const char *group_name, const char *key, + double *out) +{ + const char *value = l_settings_get_value(settings, group_name, key); + char *endp; + double r; + + if (!value) + return NULL; + + if (*value == '\0') + goto error; + + errno = 0; + + r = strtod(value, &endp); + if (*endp != '\0') + goto error; + + if (unlikely(errno == ERANGE)) + goto error; + + if (out) + *out = r; + + return true; + +error: + l_util_debug(settings->debug_handler, settings->debug_data, + "Could not interpret %s as a double", value); + + return false; +} + +LIB_EXPORT bool l_settings_set_double(struct l_settings *settings, + const char *group_name, const char *key, + double in) +{ + L_AUTO_FREE_VAR(char *, buf); + + buf = l_strdup_printf("%f", in); + + return l_settings_set_value(settings, group_name, key, buf); +} + +LIB_EXPORT bool l_settings_get_float(const struct l_settings *settings, + const char *group_name, const char *key, + float *out) +{ + const char *value = l_settings_get_value(settings, group_name, key); + char *endp; + float r; + + if (!value) + return NULL; + + if (*value == '\0') + goto error; + + errno = 0; + + r = strtof(value, &endp); + if (*endp != '\0') + goto error; + + if (unlikely(errno == ERANGE)) + goto error; + + if (out) + *out = r; + + return true; + +error: + l_util_debug(settings->debug_handler, settings->debug_data, + "Could not interpret %s as a float", value); + + return false; +} + +LIB_EXPORT bool l_settings_set_float(struct l_settings *settings, + const char *group_name, const char *key, + float in) +{ + L_AUTO_FREE_VAR(char *, buf); + + buf = l_strdup_printf("%f", (double)in); + + return l_settings_set_value(settings, group_name, key, buf); +} + +LIB_EXPORT uint8_t *l_settings_get_bytes(const struct l_settings *settings, + const char *group_name, + const char *key, + size_t *out_len) +{ + const char *value = l_settings_get_value(settings, group_name, key); + + if (!value) + return NULL; + + if (value[0] == '\0') { + *out_len = 0; + + /* Return something that can be l_freed but is not a NULL */ + return l_memdup("", 1); + } + + return l_util_from_hexstring(value, out_len); +} + +LIB_EXPORT bool l_settings_set_bytes(struct l_settings *settings, + const char *group_name, const char *key, + const uint8_t *value, size_t value_len) +{ + char *buf; + + if (unlikely(!settings || !value)) + return false; + + if (value_len) + buf = l_util_hexstring(value, value_len); + else + buf = l_strdup(""); + + return set_value(settings, group_name, key, buf); +} + +LIB_EXPORT bool l_settings_remove_group(struct l_settings *settings, + const char *group_name) +{ + struct group_data *group; + + if (unlikely(!settings)) + return false; + + group = l_queue_remove_if(settings->groups, group_match, group_name); + if (!group) + return false; + + group_destroy(group); + + return true; +} + +LIB_EXPORT bool l_settings_remove_key(struct l_settings *settings, + const char *group_name, + const char *key) +{ + struct group_data *group; + struct setting_data *setting; + + if (unlikely(!settings)) + return false; + + group = l_queue_find(settings->groups, group_match, group_name); + if (!group) + return false; + + setting = l_queue_remove_if(group->settings, key_match, key); + if (!setting) + return false; + + setting_destroy(setting); + + return true; +} + +static void gather_embedded_groups(void *data, void *user_data) +{ + struct embedded_group_data *group_data = data; + struct gather_data *gather = user_data; + + gather->v[gather->cur++] = l_strdup(group_data->name); +} + +LIB_EXPORT char **l_settings_get_embedded_groups(struct l_settings *settings) +{ + char **ret; + struct gather_data gather; + + if (unlikely(!settings)) + return NULL; + + ret = l_new(char *, l_queue_length(settings->groups) + 1); + gather.v = ret; + gather.cur = 0; + + l_queue_foreach(settings->embedded_groups, gather_embedded_groups, + &gather); + + return ret; +} + +static bool embedded_group_match(const void *a, const void *b) +{ + const struct embedded_group_data *group = a; + const char *name = b; + + return !strcmp(group->name, name); +} + +LIB_EXPORT bool l_settings_has_embedded_group(struct l_settings *settings, + const char *group) +{ + struct embedded_group_data *group_data; + + if (unlikely(!settings)) + return false; + + group_data = l_queue_find(settings->embedded_groups, + embedded_group_match, group); + + return group_data != NULL; +} + +LIB_EXPORT const char *l_settings_get_embedded_value( + struct l_settings *settings, + const char *group_name, + const char **out_type) +{ + struct embedded_group_data *group; + + if (unlikely(!settings)) + return false; + + group = l_queue_find(settings->embedded_groups, + embedded_group_match, group_name); + if (!group) + return NULL; + + if (out_type) + *out_type = group->type; + + return group->data; +} + +LIB_EXPORT bool l_settings_remove_embedded_groups(struct l_settings *settings) +{ + if (unlikely(!settings)) + return false; + + l_queue_clear(settings->embedded_groups, embedded_group_destroy); + + return true; +} diff --git a/ell/settings.h b/ell/settings.h new file mode 100644 index 0000000000000000000000000000000000000000..b3e73d82bee569811d2d94bba13d0e2683483251 --- /dev/null +++ b/ell/settings.h @@ -0,0 +1,136 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_SETTINGS_H +#define __ELL_SETTINGS_H + +#include <stdbool.h> +#include <stddef.h> +#include <ell/cleanup.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct l_settings; + +typedef void (*l_settings_debug_cb_t) (const char *str, void *user_data); +typedef void (*l_settings_destroy_cb_t) (void *user_data); + +struct l_settings *l_settings_new(void); +struct l_settings *l_settings_clone(const struct l_settings *settings); + +void l_settings_free(struct l_settings *settings); +DEFINE_CLEANUP_FUNC(l_settings_free); + +bool l_settings_load_from_data(struct l_settings *settings, + const char *data, size_t len); +char *l_settings_to_data(const struct l_settings *settings, size_t *len); + +bool l_settings_load_from_file(struct l_settings *settings, + const char *filename); + +bool l_settings_set_debug(struct l_settings *settings, + l_settings_debug_cb_t callback, + void *user_data, + l_settings_destroy_cb_t destroy); + +char **l_settings_get_groups(const struct l_settings *settings); +char **l_settings_get_keys(const struct l_settings *settings, + const char *group_name); + +bool l_settings_add_group(struct l_settings *settings, const char *group_name); + +bool l_settings_has_group(const struct l_settings *settings, + const char *group_name); +bool l_settings_has_key(const struct l_settings *settings, + const char *group_name, const char *key); + +const char *l_settings_get_value(const struct l_settings *settings, + const char *group_name, + const char *key); +bool l_settings_set_value(struct l_settings *settings, const char *group_name, + const char *key, const char *value); + +bool l_settings_get_bool(const struct l_settings *settings, + const char *group_name, + const char *key, bool *out); +bool l_settings_set_bool(struct l_settings *settings, const char *group_name, + const char *key, bool in); + +bool l_settings_get_int(const struct l_settings *settings, + const char *group_name, const char *key, int *out); +bool l_settings_set_int(struct l_settings *settings, const char *group_name, + const char *key, int in); + +bool l_settings_get_uint(const struct l_settings *settings, + const char *group_name, + const char *key, unsigned int *out); +bool l_settings_set_uint(struct l_settings *settings, const char *group_name, + const char *key, unsigned int in); + +bool l_settings_get_int64(const struct l_settings *settings, + const char *group_name, + const char *key, int64_t *out); +bool l_settings_set_int64(struct l_settings *settings, const char *group_name, + const char *key, int64_t in); + +bool l_settings_get_uint64(const struct l_settings *settings, + const char *group_name, + const char *key, uint64_t *out); +bool l_settings_set_uint64(struct l_settings *settings, const char *group_name, + const char *key, uint64_t in); + +char *l_settings_get_string(const struct l_settings *settings, + const char *group_name, const char *key); +bool l_settings_set_string(struct l_settings *settings, const char *group_name, + const char *key, const char *value); + +char **l_settings_get_string_list(const struct l_settings *settings, + const char *group_name, + const char *key, char delimiter); +bool l_settings_set_string_list(struct l_settings *settings, + const char *group_name, + const char *key, char **list, + char delimiter); + +bool l_settings_get_double(const struct l_settings *settings, + const char *group_name, + const char *key, double *out); +bool l_settings_set_double(struct l_settings *settings, const char *group_name, + const char *key, double in); + +bool l_settings_get_float(const struct l_settings *settings, + const char *group_name, + const char *key, float *out); +bool l_settings_set_float(struct l_settings *settings, const char *group_name, + const char *key, float in); + +uint8_t *l_settings_get_bytes(const struct l_settings *settings, + const char *group_name, const char *key, + size_t *out_len); +bool l_settings_set_bytes(struct l_settings *settings, const char *group_name, + const char *key, + const uint8_t *value, size_t value_len); + +bool l_settings_remove_key(struct l_settings *settings, const char *group_name, + const char *key); +bool l_settings_remove_group(struct l_settings *settings, + const char *group_name); + +bool l_settings_remove_embedded_groups(struct l_settings *settings); +char **l_settings_get_embedded_groups(struct l_settings *settings); +bool l_settings_has_embedded_group(struct l_settings *settings, + const char *group); +const char *l_settings_get_embedded_value(struct l_settings *settings, + const char *group_name, + const char **out_type); +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_SETTINGS_H */ diff --git a/ell/signal.c b/ell/signal.c new file mode 100644 index 0000000000000000000000000000000000000000..c1c3512e71fa5ce8c3702e22ab6606d2a3966093 --- /dev/null +++ b/ell/signal.c @@ -0,0 +1,253 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <sys/epoll.h> +#include <sys/signalfd.h> + +#include "util.h" +#include "io.h" +#include "queue.h" +#include "signal.h" +#include "private.h" + +/** + * SECTION:signal + * @short_description: Unix signal support + * + * Unix signal support + */ + +/** + * l_signal: + * + * Opaque object representing the signal. + */ +struct l_signal { + struct signal_desc *desc; + l_signal_notify_cb_t callback; + void *user_data; + l_signal_destroy_cb_t destroy; +}; + +struct signal_desc { + uint32_t signo; + struct l_queue *callbacks; +}; + +static struct l_io *signalfd_io = NULL; +static struct l_queue *signal_list = NULL; +static sigset_t signal_mask; + +static void handle_callback(struct signal_desc *desc) +{ + const struct l_queue_entry *entry; + + for (entry = l_queue_get_entries(desc->callbacks); entry; + entry = entry->next) { + struct l_signal *signal = entry->data; + + if (signal->callback) + signal->callback(signal->user_data); + } +} + +static bool desc_match_signo(const void *a, const void *b) +{ + const struct signal_desc *desc = a; + uint32_t signo = L_PTR_TO_UINT(b); + + return (desc->signo == signo); +} + +static bool signalfd_read_cb(struct l_io *io, void *user_data) +{ + int fd = l_io_get_fd(io); + struct signal_desc *desc; + struct signalfd_siginfo si; + ssize_t result; + + result = read(fd, &si, sizeof(si)); + if (result != sizeof(si)) + return true; + + desc = l_queue_find(signal_list, desc_match_signo, + L_UINT_TO_PTR(si.ssi_signo)); + if (desc) + handle_callback(desc); + + return true; +} + +static bool signalfd_add(int signo) +{ + int fd; + + if (!signalfd_io) { + fd = -1; + sigemptyset(&signal_mask); + } else + fd = l_io_get_fd(signalfd_io); + + sigaddset(&signal_mask, signo); + + fd = signalfd(fd, &signal_mask, SFD_CLOEXEC); + if (fd < 0) + return false; + + if (signalfd_io) + return true; + + signalfd_io = l_io_new(fd); + if (!signalfd_io) { + close(fd); + return false; + } + + l_io_set_close_on_destroy(signalfd_io, true); + + if (!l_io_set_read_handler(signalfd_io, signalfd_read_cb, NULL, NULL)) { + l_io_destroy(signalfd_io); + return false; + } + + signal_list = l_queue_new(); + + return true; +} + +static void signalfd_remove(int signo) +{ + if (!signalfd_io) + return; + + sigdelset(&signal_mask, signo); + + if (!sigisemptyset(&signal_mask)) { + signalfd(l_io_get_fd(signalfd_io), &signal_mask, SFD_CLOEXEC); + return; + } + + l_io_destroy(signalfd_io); + signalfd_io = NULL; + + l_queue_destroy(signal_list, NULL); + signal_list = NULL; +} + +/** + * l_signal_create: + * @callback: signal callback function + * @user_data: user data provided to signal callback function + * @destroy: destroy function for user data + * + * Create new signal callback handling for a given set of signals. + * + * Returns: a newly allocated #l_signal object + **/ +LIB_EXPORT struct l_signal *l_signal_create(uint32_t signo, + l_signal_notify_cb_t callback, + void *user_data, l_signal_destroy_cb_t destroy) +{ + struct l_signal *signal; + struct signal_desc *desc; + sigset_t mask, oldmask; + + if (signo <= 1 || signo >= _NSIG) + return NULL; + + signal = l_new(struct l_signal, 1); + signal->callback = callback; + signal->destroy = destroy; + signal->user_data = user_data; + + desc = l_queue_find(signal_list, desc_match_signo, + L_UINT_TO_PTR(signo)); + if (desc) + goto done; + + sigemptyset(&mask); + sigaddset(&mask, signo); + + if (sigprocmask(SIG_BLOCK, &mask, &oldmask) < 0) { + l_free(signal); + return NULL; + } + + if (!signalfd_add(signo)) { + sigprocmask(SIG_SETMASK, &oldmask, NULL); + l_free(signal); + return NULL; + } + + desc = l_new(struct signal_desc, 1); + desc->signo = signo; + desc->callbacks = l_queue_new(); + + l_queue_push_tail(signal_list, desc); + +done: + l_queue_push_tail(desc->callbacks, signal); + signal->desc = desc; + return signal; +} + +/** + * l_signal_remove: + * @signal: signal object + * + * Remove signal handling. + **/ +LIB_EXPORT void l_signal_remove(struct l_signal *signal) +{ + struct signal_desc *desc; + sigset_t mask; + + if (!signal) + return; + + desc = signal->desc; + l_queue_remove(desc->callbacks, signal); + + /* + * As long as the signal descriptor has callbacks registered, it is + * still needed to be active. + */ + if (!l_queue_isempty(desc->callbacks)) + goto done; + + if (!l_queue_remove(signal_list, desc)) + goto done; + + sigemptyset(&mask); + sigaddset(&mask, desc->signo); + + /* + * When the number of signals goes to zero, then this will close + * the signalfd file descriptor, otherwise it will only adjust the + * signal mask to account for the removed signal. + * + */ + signalfd_remove(desc->signo); + sigprocmask(SIG_UNBLOCK, &mask, NULL); + l_queue_destroy(desc->callbacks, NULL); + l_free(desc); + +done: + if (signal->destroy) + signal->destroy(signal->user_data); + + l_free(signal); +} diff --git a/ell/signal.h b/ell/signal.h new file mode 100644 index 0000000000000000000000000000000000000000..f9a90f82b6577dc25ce42f41dc667ad52df4f957 --- /dev/null +++ b/ell/signal.h @@ -0,0 +1,30 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_SIGNAL_H +#define __ELL_SIGNAL_H + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct l_signal; + +typedef void (*l_signal_notify_cb_t) (void *user_data); +typedef void (*l_signal_destroy_cb_t) (void *user_data); + +struct l_signal *l_signal_create(uint32_t signo, l_signal_notify_cb_t callback, + void *user_data, l_signal_destroy_cb_t destroy); +void l_signal_remove(struct l_signal *signal); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_SIGNAL_H */ diff --git a/ell/siphash-private.h b/ell/siphash-private.h new file mode 100644 index 0000000000000000000000000000000000000000..97b2525b8b78b91d0f66036c0330f18bea651c01 --- /dev/null +++ b/ell/siphash-private.h @@ -0,0 +1,12 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include <string.h> +#include <stdint.h> + +void _siphash24(uint8_t out[8], const uint8_t *in, size_t inlen, + const uint8_t k[16]); diff --git a/ell/siphash.c b/ell/siphash.c new file mode 100644 index 0000000000000000000000000000000000000000..70daaadf447a0f5dbab43cb00a6d07609b3bf44e --- /dev/null +++ b/ell/siphash.c @@ -0,0 +1,123 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "siphash-private.h" + +/* + * Based on public domain SipHash reference C implementation + * + * Written in 2012 by + * Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com> + * Daniel J. Bernstein <djb@cr.yp.to> + * + */ + +#define ROTL(x,b) (uint64_t) (((x) << (b)) | ((x) >> (64 - (b)))) + +#define U32TO8_LE(p, v) \ + (p)[0] = (uint8_t) ((v)); \ + (p)[1] = (uint8_t) ((v) >> 8); \ + (p)[2] = (uint8_t) ((v) >> 16); \ + (p)[3] = (uint8_t) ((v) >> 24); + +#define U64TO8_LE(p, v) \ + U32TO8_LE((p), (uint32_t) ((v))); \ + U32TO8_LE((p) + 4, (uint32_t) ((v) >> 32)); + +#define U8TO64_LE(p) \ + (((uint64_t) ((p)[0])) | \ + ((uint64_t) ((p)[1]) << 8) | \ + ((uint64_t) ((p)[2]) << 16) | \ + ((uint64_t) ((p)[3]) << 24) | \ + ((uint64_t) ((p)[4]) << 32) | \ + ((uint64_t) ((p)[5]) << 40) | \ + ((uint64_t) ((p)[6]) << 48) | \ + ((uint64_t) ((p)[7]) << 56)) + +#define SIPROUND \ + do { \ + v0 += v1; v1=ROTL(v1, 13); \ + v1 ^= v0; v0=ROTL(v0, 32); \ + v2 += v3; v3=ROTL(v3, 16); \ + v3 ^= v2; \ + v0 += v3; v3=ROTL(v3, 21); \ + v3 ^= v0; \ + v2 += v1; v1=ROTL(v1, 17); \ + v1 ^= v2; v2=ROTL(v2, 32); \ + } while(0) + +void _siphash24(uint8_t out[8], const uint8_t *in, size_t inlen, + const uint8_t k[16]) +{ + /* "somepseudorandomlygeneratedbytes" */ + uint64_t v0 = 0x736f6d6570736575ULL; + uint64_t v1 = 0x646f72616e646f6dULL; + uint64_t v2 = 0x6c7967656e657261ULL; + uint64_t v3 = 0x7465646279746573ULL; + uint64_t b; + uint64_t k0 = U8TO64_LE(k); + uint64_t k1 = U8TO64_LE(k + 8); + uint64_t m; + const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t)); + const int left = inlen & 7; + + b = ((uint64_t) inlen) << 56; + v3 ^= k1; + v2 ^= k0; + v1 ^= k1; + v0 ^= k0; + + for (; in != end; in += 8) { + m = U8TO64_LE(in); + v3 ^= m; + SIPROUND; + SIPROUND; + v0 ^= m; + } + + switch (left) { + case 7: + b |= ((uint64_t) in[6]) << 48; + /* fall through */ + case 6: + b |= ((uint64_t) in[5]) << 40; + /* fall through */ + case 5: + b |= ((uint64_t) in[4]) << 32; + /* fall through */ + case 4: + b |= ((uint64_t) in[3]) << 24; + /* fall through */ + case 3: + b |= ((uint64_t) in[2]) << 16; + /* fall through */ + case 2: + b |= ((uint64_t) in[1]) << 8; + /* fall through */ + case 1: + b |= ((uint64_t) in[0]); + break; + case 0: + break; + } + + v3 ^= b; + SIPROUND; + SIPROUND; + v0 ^= b; + v2 ^= 0xff; + SIPROUND; + SIPROUND; + SIPROUND; + SIPROUND; + b = v0 ^ v1 ^ v2 ^ v3; + U64TO8_LE(out, b) +} diff --git a/ell/string.c b/ell/string.c new file mode 100644 index 0000000000000000000000000000000000000000..e8e45beacb92b60f4a41e65e24e0041b7f79fdd7 --- /dev/null +++ b/ell/string.c @@ -0,0 +1,496 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> + +#include "strv.h" +#include "string.h" +#include "private.h" +#include "useful.h" + +/** + * SECTION:string + * @short_description: Growable string buffer + * + * Growable string buffer support + */ + +/** + * l_string: + * + * Opaque object representing the string buffer. + */ +struct l_string { + size_t max; + size_t len; + char *str; +}; + +static void grow_string(struct l_string *str, size_t extra) +{ + if (str->len + extra < str->max) + return; + + str->max = str->len + extra + 1; + + if (str->max < l_util_pagesize()) + str->max = roundup_pow_of_two(str->max); + else + str->max = align_len(str->max, l_util_pagesize()); + + str->str = l_realloc(str->str, str->max); +} + +/** + * l_string_new: + * @initial_length: Initial length of the groable string + * + * Create new growable string. If the @initial_length is 0, then a safe + * default is chosen. + * + * Returns: a newly allocated #l_string object. + **/ +LIB_EXPORT struct l_string *l_string_new(size_t initial_length) +{ + static const size_t DEFAULT_INITIAL_LENGTH = 127; + struct l_string *ret; + + ret = l_new(struct l_string, 1); + + if (initial_length == 0) + initial_length = DEFAULT_INITIAL_LENGTH; + + grow_string(ret, initial_length); + ret->str[0] = '\0'; + + return ret; +} + +/** + * l_string_free: + * @string: growable string object + * + * Free the growable string object and all associated data + **/ +LIB_EXPORT void l_string_free(struct l_string *string) +{ + if (unlikely(!string)) + return; + + l_free(string->str); + l_free(string); +} + +/** + * l_string_unwrap: + * @string: growable string object + * + * Free the growable string object and return the internal string data. + * The caller is responsible for freeing the string data using l_free(), + * and the string object is no longer usable. + * + * Returns: @string's internal buffer + **/ +LIB_EXPORT char *l_string_unwrap(struct l_string *string) +{ + char *result; + + if (unlikely(!string)) + return NULL; + + result = string->str; + + l_free(string); + + return result; +} + +/** + * l_string_append: + * @dest: growable string object + * @src: C-style string to copy + * + * Appends the contents of @src to @dest. The internal buffer of @dest is + * grown if necessary. + * + * Returns: @dest + **/ +LIB_EXPORT struct l_string *l_string_append(struct l_string *dest, + const char *src) +{ + size_t size; + + if (unlikely(!dest || !src)) + return NULL; + + size = strlen(src); + + grow_string(dest, size); + + memcpy(dest->str + dest->len, src, size); + dest->len += size; + dest->str[dest->len] = '\0'; + + return dest; +} + +/** + * l_string_append_c: + * @dest: growable string object + * @c: Character + * + * Appends character given by @c to @dest. The internal buffer of @dest is + * grown if necessary. + * + * Returns: @dest + **/ +LIB_EXPORT struct l_string *l_string_append_c(struct l_string *dest, + const char c) +{ + if (unlikely(!dest)) + return NULL; + + grow_string(dest, 1); + dest->str[dest->len++] = c; + dest->str[dest->len] = '\0'; + + return dest; +} + +/** + * l_string_append_fixed: + * @dest: growable string object + * @src: Character array to copy from + * @max: Maximum number of characters to copy + * + * Appends the contents of a fixed size string array @src to @dest. + * The internal buffer of @dest is grown if necessary. Up to a maximum of + * @max characters are copied. If a null is encountered in the first @max + * characters, the string is copied only up to the NULL character. + * + * Returns: @dest + **/ +LIB_EXPORT struct l_string *l_string_append_fixed(struct l_string *dest, + const char *src, + size_t max) +{ + const char *nul; + + if (unlikely(!dest || !src || !max)) + return NULL; + + nul = memchr(src, 0, max); + if (nul) + max = nul - src; + + grow_string(dest, max); + + memcpy(dest->str + dest->len, src, max); + dest->len += max; + dest->str[dest->len] = '\0'; + + return dest; +} + +/** + * l_string_append_vprintf: + * @dest: growable string object + * @format: the string format. See the sprintf() documentation + * @args: the parameters to insert + * + * Appends a formatted string to the growable string buffer. This function + * is equivalent to l_string_append_printf except that the arguments are + * passed as a va_list. + **/ +LIB_EXPORT void l_string_append_vprintf(struct l_string *dest, + const char *format, va_list args) +{ + size_t len; + size_t have_space; + va_list args_copy; + + if (unlikely(!dest)) + return; + +#if __STDC_VERSION__ > 199409L + va_copy(args_copy, args); +#else + __va_copy(args_copy, args); +#endif + + have_space = dest->max - dest->len; + len = vsnprintf(dest->str + dest->len, have_space, format, args); + + if (len >= have_space) { + grow_string(dest, len); + len = vsprintf(dest->str + dest->len, format, args_copy); + } + + dest->len += len; + + va_end(args_copy); +} + +/** + * l_string_append_printf: + * @dest: growable string object + * @format: the string format. See the sprintf() documentation + * @...: the parameters to insert + * + * Appends a formatted string to the growable string buffer, growing it as + * necessary. + **/ +LIB_EXPORT void l_string_append_printf(struct l_string *dest, + const char *format, ...) +{ + va_list args; + + if (unlikely(!dest)) + return; + + va_start(args, format); + l_string_append_vprintf(dest, format, args); + va_end(args); +} + +/** + * l_string_length: + * @string: growable string object + * + * Returns: bytes used in the string. + **/ +LIB_EXPORT unsigned int l_string_length(struct l_string *string) +{ + if (unlikely(!string)) + return 0; + + return string->len; +} + +LIB_EXPORT struct l_string *l_string_truncate(struct l_string *string, + size_t new_size) +{ + if (unlikely(!string)) + return NULL; + + if (new_size >= string->len) + return string; + + string->len = new_size; + string->str[new_size] = '\0'; + + return string; +} + +struct arg { + size_t max_len; + size_t cur_len; + char *chars; +}; + +static inline void arg_init(struct arg *arg) +{ + arg->max_len = 0; + arg->cur_len = 0; + arg->chars = NULL; +} + +static void arg_putchar(struct arg *arg, char ch) +{ + if (arg->cur_len == arg->max_len) { + arg->max_len += 32; /* Grow by at least 32 bytes */ + arg->chars = l_realloc(arg->chars, 1 + arg->max_len); + } + + arg->chars[arg->cur_len++] = ch; + arg->chars[arg->cur_len] = '\0'; +} + +static void arg_putmem(struct arg *arg, const void *mem, size_t len) +{ + if (len == 0) + return; + + if (arg->cur_len + len > arg->max_len) { + size_t growby = len * 2; + + if (growby < 32) + growby = 32; + + arg->max_len += growby; + arg->chars = l_realloc(arg->chars, 1 + arg->max_len); + } + + memcpy(arg->chars + arg->cur_len, mem, len); + arg->cur_len += len; + arg->chars[arg->cur_len] = '\0'; +} + +static bool parse_backslash(struct arg *arg, const char *args, size_t *pos) +{ + /* We're at the backslash, not within double quotes */ + char c = args[*pos + 1]; + + switch (c) { + case 0: + return false; + case '\n': + break; + default: + arg_putchar(arg, c); + break; + } + + *pos += 1; + return true; +} + +static bool parse_quoted_backslash(struct arg *arg, + const char *args, size_t *pos) +{ + /* We're at the backslash, within double quotes */ + char c = args[*pos + 1]; + + switch (c) { + case 0: + return false; + case '\n': + break; + case '"': + case '\\': + arg_putchar(arg, c); + break; + default: + arg_putchar(arg, '\\'); + arg_putchar(arg, c); + break; + } + + *pos += 1; + return true; +} + +static bool parse_single_quote(struct arg *arg, const char *args, size_t *pos) +{ + /* We're just past the single quote */ + size_t start = *pos; + + for (; args[*pos]; *pos += 1) { + if (args[*pos] != '\'') + continue; + + arg_putmem(arg, args + start, *pos - start); + return true; + } + + /* Unterminated ' */ + return false; +} + +static bool parse_double_quote(struct arg *arg, const char *args, size_t *pos) +{ + /* We're just past the double quote */ + for (; args[*pos]; *pos += 1) { + char c = args[*pos]; + + switch (c) { + case '"': + return true; + case '\\': + if (!parse_quoted_backslash(arg, args, pos)) + return false; + + break; + default: + arg_putchar(arg, c); + break; + } + } + + /* Unterminated */ + return false; +} + +static void add_arg(char ***args, char *arg, int *n_args) +{ + *args = l_realloc(*args, sizeof(char *) * (2 + *n_args)); + (*args)[*n_args] = arg; + (*args)[*n_args + 1] = NULL; + + *n_args += 1; +} + +LIB_EXPORT char **l_parse_args(const char *args, int *out_n_args) +{ + size_t i; + struct arg arg; + char **ret = l_realloc(NULL, sizeof(char *)); + int n_args = 0; + + ret[0] = NULL; + arg_init(&arg); + + for (i = 0; args[i]; i++) { + switch (args[i]) { + case '\\': + if (!parse_backslash(&arg, args, &i)) + goto error; + break; + case '"': + i += 1; + if (!parse_double_quote(&arg, args, &i)) + goto error; + + /* Add an empty string */ + if (!arg.cur_len) + add_arg(&ret, l_strdup(""), &n_args); + + break; + case '\'': + i += 1; + if (!parse_single_quote(&arg, args, &i)) + goto error; + + /* Add an empty string */ + if (!arg.cur_len) + add_arg(&ret, l_strdup(""), &n_args); + + break; + default: + if (!strchr(" \t", args[i])) { + if (args[i] == '\n') + goto error; + + arg_putchar(&arg, args[i]); + continue; + } + + if (arg.cur_len) + add_arg(&ret, arg.chars, &n_args); + + arg_init(&arg); + break; + } + } + + if (arg.cur_len) + add_arg(&ret, arg.chars, &n_args); + + if (out_n_args) + *out_n_args = n_args; + + return ret; + +error: + l_free(arg.chars); + l_strfreev(ret); + return NULL; +} diff --git a/ell/string.h b/ell/string.h new file mode 100644 index 0000000000000000000000000000000000000000..471648f4d14f08fe22f614e79a2e02ae6d14377a --- /dev/null +++ b/ell/string.h @@ -0,0 +1,46 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_STRING_H +#define __ELL_STRING_H + +#include <stdarg.h> +#include <ell/cleanup.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct l_string; + +struct l_string *l_string_new(size_t initial_length); +void l_string_free(struct l_string *string); +DEFINE_CLEANUP_FUNC(l_string_free); +char *l_string_unwrap(struct l_string *string); + +struct l_string *l_string_append(struct l_string *dest, const char *src); +struct l_string *l_string_append_c(struct l_string *dest, const char c); +struct l_string *l_string_append_fixed(struct l_string *dest, const char *src, + size_t max); + +void l_string_append_vprintf(struct l_string *dest, + const char *format, va_list args) + __attribute__((format(printf, 2, 0))); +void l_string_append_printf(struct l_string *dest, const char *format, ...) + __attribute__((format(printf, 2, 3))); + +struct l_string *l_string_truncate(struct l_string *string, size_t new_size); + +unsigned int l_string_length(struct l_string *string); + +char **l_parse_args(const char *args, int *out_n_args); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_STRING_H */ diff --git a/ell/strv.c b/ell/strv.c new file mode 100644 index 0000000000000000000000000000000000000000..b7bf23c92292fea486c45b01724e5999d26b096f --- /dev/null +++ b/ell/strv.c @@ -0,0 +1,366 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <string.h> + +#include "strv.h" +#include "private.h" +#include "useful.h" + +/** + * SECTION:strv + * @short_description: String array functions + * + * String array functions + */ + +/** + * l_strfreev: + * @strlist: String list to free + * + * Frees a list of strings + **/ +LIB_EXPORT void l_strfreev(char **strlist) +{ + l_strv_free(strlist); +} + +/** + * l_strsplit: + * @str: String to split + * @sep: The delimiter character + * + * Splits a string into pieces which do not contain the delimiter character. + * As a special case, an empty string is returned as an empty array, e.g. + * an array with just the NULL element. + * + * Note that this function only works with ASCII delimiters. + * + * Returns: A newly allocated %NULL terminated string array. This array + * should be freed using l_strfreev(). + **/ +LIB_EXPORT char **l_strsplit(const char *str, const char sep) +{ + int len; + int i; + const char *p; + char **ret; + + if (unlikely(!str)) + return NULL; + + if (str[0] == '\0') + return l_new(char *, 1); + + for (p = str, len = 1; *p; p++) + if (*p == sep) + len += 1; + + ret = l_new(char *, len + 1); + + i = 0; + p = str; + len = 0; + + while (p[len]) { + if (p[len] != sep) { + len += 1; + continue; + } + + ret[i++] = l_strndup(p, len); + p += len + 1; + len = 0; + } + + ret[i++] = l_strndup(p, len); + + return ret; +} + +/** + * l_strsplit_set: + * @str: String to split + * @separators: A set of delimiters + * + * Splits a string into pieces which do not contain the delimiter characters + * that can be found in @separators. + * As a special case, an empty string is returned as an empty array, e.g. + * an array with just the NULL element. + * + * Note that this function only works with ASCII delimiters. + * + * Returns: A newly allocated %NULL terminated string array. This array + * should be freed using l_strfreev(). + **/ +LIB_EXPORT char **l_strsplit_set(const char *str, const char *separators) +{ + int len; + int i; + const char *p; + char **ret; + bool sep_table[256]; + + if (unlikely(!str)) + return NULL; + + if (str[0] == '\0') + return l_new(char *, 1); + + memset(sep_table, 0, sizeof(sep_table)); + + for (p = separators; *p; p++) + sep_table[(unsigned char) *p] = true; + + for (p = str, len = 1; *p; p++) + if (sep_table[(unsigned char) *p] == true) + len += 1; + + ret = l_new(char *, len + 1); + + i = 0; + p = str; + len = 0; + + while (p[len]) { + if (sep_table[(unsigned char) p[len]] != true) { + len += 1; + continue; + } + + ret[i++] = l_strndup(p, len); + p += len + 1; + len = 0; + } + + ret[i++] = l_strndup(p, len); + + return ret; +} + +/** + * l_strjoinv: + * @str_array: a %NULL terminated array of strings to join + * @delim: Delimiting character + * + * Joins strings contanied in the @str_array into one long string delimited + * by @delim. + * + * Returns: A newly allocated string that should be freed using l_free() + */ +LIB_EXPORT char *l_strjoinv(char **str_array, const char delim) +{ + size_t len = 0; + unsigned int i; + char *ret; + char *p; + + if (unlikely(!str_array)) + return NULL; + + if (!str_array[0]) + return l_strdup(""); + + for (i = 0; str_array[i]; i++) + len += strlen(str_array[i]); + + len += 1 + i - 1; + + ret = l_malloc(len); + + p = stpcpy(ret, str_array[0]); + + for (i = 1; str_array[i]; i++) { + *p++ = delim; + p = stpcpy(p, str_array[i]); + } + + return ret; +} + +/** + * l_strv_new: + * + * Returns: new empty string array + **/ +LIB_EXPORT char **l_strv_new(void) +{ + return l_new(char *, 1); +} + +/** + * l_strv_free: + * @str_array: a %NULL terminated array of strings + * + * Frees strings in @str_array and @str_array itself + **/ +LIB_EXPORT void l_strv_free(char **str_array) +{ + if (likely(str_array)) { + int i; + + for (i = 0; str_array[i]; i++) + l_free(str_array[i]); + + l_free(str_array); + } +} + +/** + * l_strv_length: + * @str_array: a %NULL terminated array of strings + * + * Returns: the number of strings in @str_array + */ +LIB_EXPORT unsigned int l_strv_length(char **str_array) +{ + unsigned int i = 0; + + if (unlikely(!str_array)) + return 0; + + while (str_array[i]) + i += 1; + + return i; +} + +/** + * l_strv_contains: + * @str_array: a %NULL terminated array of strings + * @item: An item to search for, must be not %NULL + * + * Returns: #true if @str_array contains item + */ +LIB_EXPORT bool l_strv_contains(char **str_array, const char *item) +{ + unsigned int i = 0; + + if (unlikely(!str_array || !item)) + return false; + + while (str_array[i]) { + if (!strcmp(str_array[i], item)) + return true; + + i += 1; + } + + return false; +} + +/** + * l_strv_append: + * @str_array: a %NULL terminated array of strings or %NULL + * @str: A string to be appened at the end of @str_array + * + * Returns: New %NULL terminated array of strings with @str added + */ +LIB_EXPORT char **l_strv_append(char **str_array, const char *str) +{ + char **ret; + unsigned int i, len; + + if (unlikely(!str)) + return str_array; + + len = l_strv_length(str_array); + ret = l_new(char *, len + 2); + + for (i = 0; i < len; i++) + ret[i] = str_array[i]; + + ret[i] = l_strdup(str); + + l_free(str_array); + + return ret; +} + +LIB_EXPORT char **l_strv_append_printf(char **str_array, + const char *format, ...) +{ + va_list args; + char **ret; + + va_start(args, format); + ret = l_strv_append_vprintf(str_array, format, args); + va_end(args); + + return ret; +} + +LIB_EXPORT char **l_strv_append_vprintf(char **str_array, + const char *format, va_list args) +{ + char **ret; + unsigned int i, len; + + if (unlikely(!format)) + return str_array; + + len = l_strv_length(str_array); + ret = l_new(char *, len + 2); + + for (i = 0; i < len; i++) + ret[i] = str_array[i]; + + ret[i] = l_strdup_vprintf(format, args); + + l_free(str_array); + + return ret; +} + +/** + * l_strv_copy: + * @str_array: a %NULL terminated array of strings or %NULL + * + * Returns: An independent copy of @str_array. + */ +LIB_EXPORT char **l_strv_copy(char **str_array) +{ + int i, len; + char **copy; + + if (unlikely(!str_array)) + return NULL; + + for (len = 0; str_array[len]; len++); + + copy = l_malloc(sizeof(char *) * (len + 1)); + + for (i = len; i >= 0; i--) + copy[i] = l_strdup(str_array[i]); + + return copy; +} + +/** + * l_strv_eq: + * @a: a %NULL terminated array of strings or %NULL + * @b: another %NULL terminated array of strings or %NULL + * + * Returns: Whether @a and @b's contents are identical, including the + * order, or @a and @b are both %NULL. + */ +LIB_EXPORT bool l_strv_eq(char **a, char **b) +{ + if (!a || !b) + return a == b; + + for (; *a; a++, b++) + if (!*b || strcmp(*a, *b)) + return false; + + return !*b; +} diff --git a/ell/strv.h b/ell/strv.h new file mode 100644 index 0000000000000000000000000000000000000000..f6f5c78dcf3f2d4d57a13bab1f73215e5db2256a --- /dev/null +++ b/ell/strv.h @@ -0,0 +1,42 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_STRV_H +#define __ELL_STRV_H + +#include <stdarg.h> +#include <stdbool.h> +#include <ell/cleanup.h> + +#ifdef __cplusplus +extern "C" { +#endif + +void l_strfreev(char **strlist); +char **l_strsplit(const char *str, const char sep); +char **l_strsplit_set(const char *str, const char *separators); +char *l_strjoinv(char **str_array, const char delim); + +char **l_strv_new(void); +void l_strv_free(char **str_array); +DEFINE_CLEANUP_FUNC(l_strv_free); +unsigned int l_strv_length(char **str_array); +bool l_strv_contains(char **str_array, const char *item); +char **l_strv_append(char **str_array, const char *str); +char **l_strv_append_printf(char **str_array, const char *format, ...) + __attribute__((format(printf, 2, 3))); +char **l_strv_append_vprintf(char **str_array, const char *format, + va_list args) + __attribute__((format(printf, 2, 0))); +char **l_strv_copy(char **str_array); +bool l_strv_eq(char **a, char **b); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_STRV_H */ diff --git a/ell/tester.c b/ell/tester.c new file mode 100644 index 0000000000000000000000000000000000000000..552ffb77879194c8a062c64d125a32bbba2baad2 --- /dev/null +++ b/ell/tester.c @@ -0,0 +1,765 @@ +/* + * Embedded Linux library + * Copyright (C) 2021 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> + +#include <sys/time.h> + +#include "idle.h" +#include "log.h" +#include "private.h" +#include "queue.h" +#include "time.h" +#include "timeout.h" +#include "useful.h" +#include "tester.h" + +/** + * SECTION:tester + * @short_description: Non-interactive test framework + * + * Non-interactive test framework + */ + +#define COLOR_OFF "\x1B[0m" +#define COLOR_BLACK "\x1B[0;30m" +#define COLOR_RED "\x1B[0;31m" +#define COLOR_GREEN "\x1B[0;32m" +#define COLOR_YELLOW "\x1B[0;33m" +#define COLOR_BLUE "\x1B[0;34m" +#define COLOR_MAGENTA "\x1B[0;35m" +#define COLOR_HIGHLIGHT "\x1B[1;39m" + +#define print_text(color, fmt, args...) \ + l_info(color fmt COLOR_OFF, ## args) + +#define print_summary(label, color, value, fmt, args...) \ + l_info("%-52s " color "%-10s" COLOR_OFF fmt, \ + label, value, ## args) + +#define print_progress(name, color, fmt, args...) \ + l_info(COLOR_HIGHLIGHT "%s" COLOR_OFF " - " \ + color fmt COLOR_OFF, name, ## args) + +enum test_result { + TEST_RESULT_NOT_RUN, + TEST_RESULT_PASSED, + TEST_RESULT_FAILED, + TEST_RESULT_TIMED_OUT, +}; + +struct l_tester { + uint64_t start_time; + struct l_queue *tests; + const struct l_queue_entry *test_entry; + bool list_cases; + const char *prefix; + const char *substring; + l_tester_finish_func_t finish_callback; +}; + +struct test_case { + uint64_t start_time; + uint64_t end_time; + char *name; + enum test_result result; + enum l_tester_stage stage; + const void *test_data; + l_tester_data_func_t pre_setup_func; + l_tester_data_func_t setup_func; + l_tester_data_func_t test_func; + l_tester_data_func_t teardown_func; + l_tester_data_func_t post_teardown_func; + unsigned int timeout; + struct l_timeout *run_timer; + l_tester_destroy_func_t destroy; + void *user_data; + bool teardown; +}; + +static void destroy_test(void *data) +{ + struct test_case *test = data; + + l_timeout_remove(test->run_timer); + + if (test->destroy) + test->destroy(test->user_data); + + l_free(test->name); + l_free(test); +} + +static uint64_t get_elapsed_time(uint64_t base) +{ + uint64_t now; + + now = l_time_now(); + + return l_time_diff(base, now); +} + +static void teardown_callback(void *user_data) +{ + struct l_tester *tester = user_data; + struct test_case *test; + + test = tester->test_entry->data; + test->stage = L_TESTER_STAGE_TEARDOWN; + test->teardown = false; + + print_progress(test->name, COLOR_MAGENTA, "teardown"); + + if (test->teardown_func) + test->teardown_func(test->test_data); + else + l_tester_teardown_complete(tester); +} + +static void test_timeout(struct l_timeout *timer, void *user_data) +{ + struct l_tester *tester = user_data; + struct test_case *test; + + test = tester->test_entry->data; + + l_timeout_remove(timer); + test->run_timer = NULL; + + test->result = TEST_RESULT_TIMED_OUT; + print_progress(test->name, COLOR_RED, "test timed out"); + + l_idle_oneshot(teardown_callback, tester, NULL); +} + +static void next_test_case(struct l_tester *tester) +{ + struct test_case *test; + + if (tester->test_entry) + tester->test_entry = tester->test_entry->next; + else + tester->test_entry = l_queue_get_entries(tester->tests); + + if (!tester->test_entry) { + if (tester->finish_callback) + tester->finish_callback(tester); + return; + } + + test = tester->test_entry->data; + + print_progress(test->name, COLOR_BLACK, "init"); + + test->start_time = get_elapsed_time(tester->start_time); + + if (test->timeout > 0) + test->run_timer = l_timeout_create(test->timeout, test_timeout, + tester, NULL); + + test->stage = L_TESTER_STAGE_PRE_SETUP; + + if (test->pre_setup_func) + test->pre_setup_func(test->test_data); + else + l_tester_pre_setup_complete(tester); +} + +static void setup_callback(void *user_data) +{ + struct l_tester *tester = user_data; + struct test_case *test = tester->test_entry->data; + + test->stage = L_TESTER_STAGE_SETUP; + + print_progress(test->name, COLOR_BLUE, "setup"); + + if (test->setup_func) + test->setup_func(test->test_data); + else + l_tester_setup_complete(tester); +} + +static void run_callback(void *user_data) +{ + struct l_tester *tester = user_data; + struct test_case *test = tester->test_entry->data; + + test->stage = L_TESTER_STAGE_RUN; + + print_progress(test->name, COLOR_BLACK, "run"); + test->test_func(test->test_data); +} + +static void done_callback(void *user_data) +{ + struct l_tester *tester = user_data; + struct test_case *test = tester->test_entry->data; + + test->end_time = get_elapsed_time(tester->start_time); + + print_progress(test->name, COLOR_BLACK, "done"); + next_test_case(tester); +} + +LIB_EXPORT void *l_tester_get_data(struct l_tester *tester) +{ + struct test_case *test; + + if (unlikely(!tester)) + return NULL; + + if (!tester->test_entry) + return NULL; + + test = tester->test_entry->data; + + return test->user_data; +} + +LIB_EXPORT void l_tester_pre_setup_complete(struct l_tester *tester) +{ + struct test_case *test; + + if (unlikely(!tester)) + return; + + if (!tester->test_entry) + return; + + test = tester->test_entry->data; + + if (test->stage != L_TESTER_STAGE_PRE_SETUP) + return; + + l_idle_oneshot(setup_callback, tester, NULL); +} + +LIB_EXPORT void l_tester_pre_setup_failed(struct l_tester *tester) +{ + struct test_case *test; + + if (unlikely(!tester)) + return; + + if (!tester->test_entry) + return; + + test = tester->test_entry->data; + + if (test->stage != L_TESTER_STAGE_PRE_SETUP) + return; + + print_progress(test->name, COLOR_RED, "pre setup failed"); + + l_timeout_remove(test->run_timer); + test->run_timer = NULL; + + l_idle_oneshot(done_callback, tester, NULL); +} + +LIB_EXPORT void l_tester_setup_complete(struct l_tester *tester) +{ + struct test_case *test; + + if (unlikely(!tester)) + return; + + if (!tester->test_entry) + return; + + test = tester->test_entry->data; + + if (test->stage != L_TESTER_STAGE_SETUP) + return; + + print_progress(test->name, COLOR_BLUE, "setup complete"); + + l_idle_oneshot(run_callback, tester, NULL); +} + +LIB_EXPORT void l_tester_setup_failed(struct l_tester *tester) +{ + struct test_case *test; + + if (unlikely(!tester)) + return; + + if (!tester->test_entry) + return; + + test = tester->test_entry->data; + + if (test->stage != L_TESTER_STAGE_SETUP) + return; + + test->stage = L_TESTER_STAGE_POST_TEARDOWN; + + l_timeout_remove(test->run_timer); + test->run_timer = NULL; + + print_progress(test->name, COLOR_RED, "setup failed"); + print_progress(test->name, COLOR_MAGENTA, "teardown"); + + test->post_teardown_func(test->test_data); +} + +static void test_result(struct l_tester *tester, enum test_result result) +{ + struct test_case *test; + + if (unlikely(!tester)) + return; + + if (!tester->test_entry) + return; + + test = tester->test_entry->data; + + if (test->stage != L_TESTER_STAGE_RUN) + return; + + l_timeout_remove(test->run_timer); + test->run_timer = NULL; + + test->result = result; + switch (result) { + case TEST_RESULT_PASSED: + print_progress(test->name, COLOR_GREEN, "test passed"); + break; + case TEST_RESULT_FAILED: + print_progress(test->name, COLOR_RED, "test failed"); + break; + case TEST_RESULT_NOT_RUN: + print_progress(test->name, COLOR_YELLOW, "test not run"); + break; + case TEST_RESULT_TIMED_OUT: + print_progress(test->name, COLOR_RED, "test timed out"); + break; + } + + if (test->teardown) + return; + + test->teardown = true; + + l_idle_oneshot(teardown_callback, tester, NULL); +} + +LIB_EXPORT void l_tester_test_passed(struct l_tester *tester) +{ + if (unlikely(!tester)) + return; + + test_result(tester, TEST_RESULT_PASSED); +} + +LIB_EXPORT void l_tester_test_failed(struct l_tester *tester) +{ + if (unlikely(!tester)) + return; + + test_result(tester, TEST_RESULT_FAILED); +} + +LIB_EXPORT void l_tester_test_abort(struct l_tester *tester) +{ + if (unlikely(!tester)) + return; + + test_result(tester, TEST_RESULT_NOT_RUN); +} + +LIB_EXPORT void l_tester_teardown_complete(struct l_tester *tester) +{ + struct test_case *test; + + if (unlikely(!tester)) + return; + + if (!tester->test_entry) + return; + + test = tester->test_entry->data; + + if (test->stage != L_TESTER_STAGE_TEARDOWN) + return; + + test->stage = L_TESTER_STAGE_POST_TEARDOWN; + + if (test->post_teardown_func) + test->post_teardown_func(test->test_data); + else + l_tester_post_teardown_complete(tester); +} + +LIB_EXPORT void l_tester_teardown_failed(struct l_tester *tester) +{ + struct test_case *test; + + if (unlikely(!tester)) + return; + + if (!tester->test_entry) + return; + + test = tester->test_entry->data; + + if (test->stage != L_TESTER_STAGE_TEARDOWN) + return; + + test->stage = L_TESTER_STAGE_POST_TEARDOWN; + + l_tester_post_teardown_failed(tester); +} + +LIB_EXPORT void l_tester_post_teardown_complete(struct l_tester *tester) +{ + struct test_case *test; + + if (unlikely(!tester)) + return; + + if (!tester->test_entry) + return; + + test = tester->test_entry->data; + + if (test->stage != L_TESTER_STAGE_POST_TEARDOWN) + return; + + print_progress(test->name, COLOR_MAGENTA, "teardown complete"); + + l_idle_oneshot(done_callback, tester, NULL); +} + +LIB_EXPORT void l_tester_post_teardown_failed(struct l_tester *tester) +{ + struct test_case *test; + + if (unlikely(!tester)) + return; + + if (!tester->test_entry) + return; + + test = tester->test_entry->data; + + if (test->stage != L_TESTER_STAGE_POST_TEARDOWN) + return; + + print_progress(test->name, COLOR_RED, "teardown failed"); + + l_idle_oneshot(done_callback, tester, NULL); +} + +struct wait_data { + unsigned int seconds; + struct test_case *test; + l_tester_wait_func_t func; + void *user_data; +}; + +static void wait_callback(struct l_timeout *timer, void *user_data) +{ + struct wait_data *wait = user_data; + struct test_case *test = wait->test; + + wait->seconds--; + + if (wait->seconds > 0) { + print_progress(test->name, COLOR_BLACK, "%u seconds left", + wait->seconds); + return; + } + + print_progress(test->name, COLOR_BLACK, "waiting done"); + + wait->func(wait->user_data); + + l_free(wait); + + l_timeout_remove(timer); +} + +LIB_EXPORT void l_tester_wait(struct l_tester *tester, unsigned int seconds, + l_tester_wait_func_t func, void *user_data) +{ + struct test_case *test; + struct wait_data *wait; + + if (unlikely(!tester)) + return; + + if (!func || seconds < 1) + return; + + if (!tester->test_entry) + return; + + test = tester->test_entry->data; + + wait = l_new(struct wait_data, 1); + wait->seconds = seconds; + wait->test = test; + wait->func = func; + wait->user_data = user_data; + + l_timeout_create(seconds, wait_callback, wait, NULL); + + print_progress(test->name, COLOR_BLACK, "waiting %u seconds", seconds); +} + +/** + * l_tester_add_full: + * @tester: tester instance + * @name: test case name + * @test_data: test data + * @pre_setup_func: test pre-setup function + * @setup_func: test setup function + * @test_func: test function + * @teardown_func: test teardown function + * @teardown_func: test post-teardown function + * @timeout: test teardown function + * @user_data: user data + * @destroy: user data destroy function + * + * Add a new test case. + **/ +LIB_EXPORT void l_tester_add_full(struct l_tester *tester, const char *name, + const void *test_data, + l_tester_data_func_t pre_setup_func, + l_tester_data_func_t setup_func, + l_tester_data_func_t test_func, + l_tester_data_func_t teardown_func, + l_tester_data_func_t post_teardown_func, + unsigned int timeout, + void *user_data, + l_tester_destroy_func_t destroy) +{ + struct test_case *test; + + if (unlikely(!tester || !test_func)) + return; + + if (tester->prefix && !l_str_has_prefix(name, tester->prefix)) { + if (destroy) + destroy(user_data); + return; + } + + if (tester->substring && !strstr(name, tester->substring)) { + if (destroy) + destroy(user_data); + return; + } + + if (tester->list_cases) { + l_info("%s", name); + + if (destroy) + destroy(user_data); + return; + } + + test = l_new(struct test_case, 1); + test->name = l_strdup(name); + test->result = TEST_RESULT_NOT_RUN; + test->stage = L_TESTER_STAGE_INVALID; + + test->test_data = test_data; + test->pre_setup_func = pre_setup_func; + test->setup_func = setup_func; + test->test_func = test_func; + test->teardown_func = teardown_func; + test->post_teardown_func = post_teardown_func; + test->timeout = timeout; + test->destroy = destroy; + test->user_data = user_data; + + l_queue_push_tail(tester->tests, test); +} + +/** + * l_tester_add: + * @tester: tester instance + * @name: test case name + * @test_data: test data + * @setup_func: test setup function + * @test_func: test function + * @teardown_func: test teardown function + * + * Add a new test with default settings for timeout and no pre-setup procedure. + **/ +LIB_EXPORT void l_tester_add(struct l_tester *tester, const char *name, + const void *test_data, + l_tester_data_func_t setup_func, + l_tester_data_func_t test_func, + l_tester_data_func_t teardown_func) +{ + l_tester_add_full(tester, name, test_data, NULL, setup_func, test_func, + teardown_func, NULL, 0, NULL, NULL); +} + +/** + * l_tester_new: + * + * Initialize tester framework. + * + * Returns: new tester instance + **/ +LIB_EXPORT struct l_tester *l_tester_new(const char *prefix, + const char *substring, bool list_cases) +{ + struct l_tester *tester = l_new(struct l_tester, 1); + + tester->prefix = prefix; + tester->substring = substring; + tester->list_cases = list_cases; + tester->tests = l_queue_new(); + return tester; +} + +/** + * l_tester_start: + * @tester: tester instance + * + * Kick off execution of the test queue + * + **/ +LIB_EXPORT void l_tester_start(struct l_tester *tester, + l_tester_finish_func_t finish_func) +{ + if (unlikely(!tester)) + return; + + if (!tester->tests) + return; + + tester->finish_callback = finish_func; + + tester->start_time = l_time_now(); + next_test_case(tester); +} + +/** + * l_tester_summarize: + * @tester: tester instance + * + * Print summary of all added test cases. + * + * Returns: true, if all the tests passed + * false, if any of the tests failed + **/ +LIB_EXPORT bool l_tester_summarize(struct l_tester *tester) +{ + unsigned int not_run = 0, passed = 0, failed = 0; + double execution_time; + const struct l_queue_entry *entry; + + if (unlikely(!tester)) + return false; + + l_info(COLOR_HIGHLIGHT "%s" COLOR_OFF, + "\n\nTest Summary\n------------"); + + entry = l_queue_get_entries(tester->tests); + + for (; entry; entry = entry->next) { + struct test_case *test = entry->data; + double exec_time; + + exec_time = (test->end_time - test->start_time) / + (double)L_USEC_PER_SEC; + + switch (test->result) { + case TEST_RESULT_NOT_RUN: + print_summary(test->name, COLOR_YELLOW, "Not Run", ""); + not_run++; + break; + case TEST_RESULT_PASSED: + print_summary(test->name, COLOR_GREEN, "Passed", + "%8.3f seconds", exec_time); + passed++; + break; + case TEST_RESULT_FAILED: + print_summary(test->name, COLOR_RED, "Failed", + "%8.3f seconds", exec_time); + failed++; + break; + case TEST_RESULT_TIMED_OUT: + print_summary(test->name, COLOR_RED, "Timed out", + "%8.3f seconds", exec_time); + failed++; + break; + } + } + + l_info("Total: %d, " + COLOR_GREEN "Passed: %d (%.1f%%)" COLOR_OFF ", " + COLOR_RED "Failed: %d" COLOR_OFF ", " + COLOR_YELLOW "Not Run: %d" COLOR_OFF, + not_run + passed + failed, passed, + (not_run + passed + failed) ? + (float) passed * 100 / (not_run + passed + failed) : 0, + failed, not_run); + + execution_time = get_elapsed_time(tester->start_time); + + l_info("Overall execution time: %8.3f seconds", + execution_time / (double)L_USEC_PER_SEC); + + return failed; +} + +/** + * l_tester_destroy: + * @tester: tester instance + * + * Free up the teter framework resources + * + **/ +LIB_EXPORT void l_tester_destroy(struct l_tester *tester) +{ + if (unlikely(!tester)) + return; + + l_queue_destroy(tester->tests, destroy_test); + l_free(tester); +} + +/** + * l_tester_get_stage: + * @tester: tester instance + * + * Get the current test stage + * + * Returns: the stage of the current test that is being processing. + * + **/ +LIB_EXPORT enum l_tester_stage l_tester_get_stage(struct l_tester *tester) +{ + struct test_case *test; + + if (unlikely(!tester)) + return L_TESTER_STAGE_INVALID; + + if (!tester->test_entry) + return L_TESTER_STAGE_INVALID; + + test = tester->test_entry->data; + + return test->stage; +} diff --git a/ell/tester.h b/ell/tester.h new file mode 100644 index 0000000000000000000000000000000000000000..370aecc61770c54565328338c02b30d8f1af2d48 --- /dev/null +++ b/ell/tester.h @@ -0,0 +1,82 @@ +/* + * Embedded Linux library + * Copyright (C) 2021 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_TESTER_H +#define __ELL_TESTER_H + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct l_tester; + +enum l_tester_stage { + L_TESTER_STAGE_INVALID, + L_TESTER_STAGE_PRE_SETUP, + L_TESTER_STAGE_SETUP, + L_TESTER_STAGE_RUN, + L_TESTER_STAGE_TEARDOWN, + L_TESTER_STAGE_POST_TEARDOWN, +}; + +typedef void (*l_tester_destroy_func_t)(void *user_data); +typedef void (*l_tester_data_func_t)(const void *test_data); +typedef void (*l_tester_finish_func_t)(struct l_tester *tester); +typedef void (*l_tester_wait_func_t)(void *user_data); + +struct l_tester *l_tester_new(const char *prefix, const char *substring, + bool list_cases); +void l_tester_destroy(struct l_tester *tester); +void l_tester_start(struct l_tester *tester, + l_tester_finish_func_t finish_func); + +bool l_tester_summarize(struct l_tester *tester); + +void l_tester_add_full(struct l_tester *tester, const char *name, + const void *test_data, + l_tester_data_func_t pre_setup_func, + l_tester_data_func_t setup_func, + l_tester_data_func_t test_func, + l_tester_data_func_t teardown_func, + l_tester_data_func_t post_teardown_func, + unsigned int timeout, + void *user_data, + l_tester_destroy_func_t destroy); + +void l_tester_add(struct l_tester *tester, const char *name, + const void *test_data, + l_tester_data_func_t setup_func, + l_tester_data_func_t test_func, + l_tester_data_func_t teardown_func); + +void l_tester_pre_setup_complete(struct l_tester *tester); +void l_tester_pre_setup_failed(struct l_tester *tester); +void l_tester_setup_complete(struct l_tester *tester); +void l_tester_setup_failed(struct l_tester *tester); +void l_tester_test_passed(struct l_tester *tester); +void l_tester_test_failed(struct l_tester *tester); +void l_tester_test_abort(struct l_tester *tester); +void l_tester_teardown_complete(struct l_tester *tester); +void l_tester_teardown_failed(struct l_tester *tester); +void l_tester_post_teardown_complete(struct l_tester *tester); +void l_tester_post_teardown_failed(struct l_tester *tester); + +enum l_tester_stage l_tester_get_stage(struct l_tester *tester); +void *l_tester_get_data(struct l_tester *tester); + +void l_tester_wait(struct l_tester *tester, unsigned int seconds, + l_tester_wait_func_t func, void *user_data); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_TESTER_H */ diff --git a/ell/time-private.h b/ell/time-private.h new file mode 100644 index 0000000000000000000000000000000000000000..28609433fd9892dc41043c33fa8062e7dacee2e8 --- /dev/null +++ b/ell/time-private.h @@ -0,0 +1,15 @@ +/* + * Embedded Linux library + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +struct timeval; + +uint64_t _time_pick_interval_secs(uint32_t min_secs, uint32_t max_secs); +uint64_t _time_fuzz_msecs(uint64_t ms); +uint64_t _time_fuzz_secs(uint32_t secs, uint32_t max_offset); +uint64_t _time_realtime_to_boottime(const struct timeval *ts); +uint64_t time_realtime_now(void); +uint64_t _time_from_timespec(const struct timespec *ts); diff --git a/ell/time.c b/ell/time.c new file mode 100644 index 0000000000000000000000000000000000000000..e124a91548d2263655eded6ebbda62de15cedfcc --- /dev/null +++ b/ell/time.c @@ -0,0 +1,141 @@ +/* + * Embedded Linux library + * Copyright (C) 2019 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <time.h> +#include <sys/time.h> + +#include "time.h" +#include "time-private.h" +#include "random.h" +#include "private.h" + +uint64_t _time_from_timespec(const struct timespec *ts) +{ + return ts->tv_sec * L_USEC_PER_SEC + ts->tv_nsec / L_NSEC_PER_USEC; +} + +static uint64_t _time_from_timeval(const struct timeval *tv) +{ + return tv->tv_sec * L_USEC_PER_SEC + tv->tv_usec; +} + +/** + * l_time_now: + * + * Get the running clocktime in microseconds + * + * Returns: Current clock time in microseconds + **/ +LIB_EXPORT uint64_t l_time_now(void) +{ + struct timespec now; + + clock_gettime(CLOCK_BOOTTIME, &now); + return _time_from_timespec(&now); +} + +uint64_t time_realtime_now(void) +{ + struct timespec now; + + clock_gettime(CLOCK_REALTIME, &now); + return _time_from_timespec(&now); +} + +/** + * l_time_after + * + * Returns: True if time a is after time b + **/ + +/** + * l_time_before + * + * Returns: True if time a is before time b + **/ + +/** + * l_time_offset + * + * @time: Start time to calculate offset + * @offset: Amount of time to add to 'time' + * + * Adds an offset to a time value. This checks for overflow, and if detected + * returns UINT64_MAX. + * + * Returns: A time value 'time' + 'offset'. Or UINT64_MAX if time + offset + * exceeds UINT64_MAX. + **/ + +/* Compute ms + RAND*ms where RAND is in range -0.1 .. 0.1 */ +uint64_t _time_fuzz_msecs(uint64_t ms) +{ + /* We do this by subtracting 0.1ms and adding 0.1ms * rand[0 .. 2] */ + return ms - ms / 10 + + (l_getrandom_uint32() % (2 * L_MSEC_PER_SEC)) * + ms / 10 / L_MSEC_PER_SEC; +} + +uint64_t _time_pick_interval_secs(uint32_t min_secs, uint32_t max_secs) +{ + uint64_t min_ms = min_secs * L_MSEC_PER_SEC; + uint64_t max_ms = max_secs * L_MSEC_PER_SEC; + + return l_getrandom_uint32() % (max_ms + 1 - min_ms) + min_ms; +} + +/* Compute a time in ms based on seconds + max_offset * [-1.0 .. 1.0] */ +uint64_t _time_fuzz_secs(uint32_t secs, uint32_t max_offset) +{ + uint64_t ms = secs * L_MSEC_PER_SEC; + uint64_t r = l_getrandom_uint32(); + + max_offset *= L_MSEC_PER_SEC; + + if (r & 0x80000000) + ms += (r & 0x7fffffff) % max_offset; + else + ms -= (r & 0x7fffffff) % max_offset; + + return ms; +} + +/* + * Convert a *recent* CLOCK_REALTIME-based timestamp to a + * CLOCK_BOOTTIME-based usec count consistent with l_time functions. + * The longer the time since the input timestamp the higher the + * probability of the two clocks having diverged and the higher the + * expected error magnitude. + */ +uint64_t _time_realtime_to_boottime(const struct timeval *ts) +{ + uint64_t now_realtime; + uint64_t now_boottime = l_time_now(); + struct timespec timespec; + uint64_t ts_realtime; + uint64_t offset; + + clock_gettime(CLOCK_REALTIME, ×pec); + now_realtime = _time_from_timespec(×pec); + ts_realtime = _time_from_timeval(ts); + offset = l_time_diff(ts_realtime, now_realtime); + + /* Most likely case, timestamp in the past */ + if (l_time_before(ts_realtime, now_realtime)) { + if (offset > now_boottime) + return 0; + + return now_boottime - offset; + } + + return l_time_offset(now_boottime, offset); +} diff --git a/ell/time.h b/ell/time.h new file mode 100644 index 0000000000000000000000000000000000000000..7be41a24b74adfd1a10291aba415fe2174ae33eb --- /dev/null +++ b/ell/time.h @@ -0,0 +1,66 @@ +/* + * Embedded Linux library + * Copyright (C) 2019 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_TIME_H +#define __ELL_TIME_H + +#include <stdint.h> +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define L_USEC_PER_SEC 1000000ULL +#define L_MSEC_PER_SEC 1000ULL +#define L_USEC_PER_MSEC 1000ULL +#define L_NSEC_PER_SEC 1000000000ULL +#define L_NSEC_PER_MSEC 1000000ULL +#define L_NSEC_PER_USEC 1000ULL +#define L_TIME_INVALID ((uint64_t) -1) + +uint64_t l_time_now(void); + +static inline bool l_time_after(uint64_t a, uint64_t b) +{ + return a > b; +} + +static inline bool l_time_before(uint64_t a, uint64_t b) +{ + return l_time_after(b, a); +} + +static inline uint64_t l_time_offset(uint64_t time, uint64_t offset) +{ + /* check overflow */ + if (offset > UINT64_MAX - time) + return UINT64_MAX; + + return time + offset; +} + +static inline uint64_t l_time_diff(uint64_t a, uint64_t b) +{ + return (a < b) ? b - a : a - b; +} + +static inline uint64_t l_time_to_secs(uint64_t time) +{ + return time / L_USEC_PER_SEC; +} + +static inline uint64_t l_time_to_msecs(uint64_t time) +{ + return time / L_USEC_PER_MSEC; +} + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_TIME_H */ diff --git a/ell/timeout.c b/ell/timeout.c new file mode 100644 index 0000000000000000000000000000000000000000..541692ecff93233ee0ceedf46b55953cca5c3cfb --- /dev/null +++ b/ell/timeout.c @@ -0,0 +1,329 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <errno.h> +#include <unistd.h> +#include <stdbool.h> +#include <string.h> +#include <sys/epoll.h> +#include <sys/timerfd.h> +#include <time.h> +#include <limits.h> + +#include "useful.h" +#include "timeout.h" +#include "main-private.h" +#include "private.h" +#include "time-private.h" + +/** + * SECTION:timeout + * @short_description: Timeout support + * + * Timeout support + */ + +/** + * l_timeout: + * + * Opaque object representing the timeout. + */ +struct l_timeout { + int fd; + l_timeout_notify_cb_t callback; + l_timeout_destroy_cb_t destroy; + void *user_data; +}; + +static void timeout_destroy(void *user_data) +{ + struct l_timeout *timeout = user_data; + + close(timeout->fd); + timeout->fd = -1; + + if (timeout->destroy) + timeout->destroy(timeout->user_data); +} + +static void timeout_callback(int fd, uint32_t events, void *user_data) +{ + struct l_timeout *timeout = user_data; + uint64_t expired; + ssize_t result; + + result = read(timeout->fd, &expired, sizeof(expired)); + if (result != sizeof(expired)) + return; + + if (timeout->callback) + timeout->callback(timeout, timeout->user_data); +} + +static inline int timeout_set(int fd, unsigned int seconds, long nanoseconds) +{ + struct itimerspec itimer; + + memset(&itimer, 0, sizeof(itimer)); + itimer.it_interval.tv_sec = 0; + itimer.it_interval.tv_nsec = 0; + itimer.it_value.tv_sec = seconds; + itimer.it_value.tv_nsec = nanoseconds; + + return timerfd_settime(fd, 0, &itimer, NULL); +} + +static bool convert_ms(uint64_t milliseconds, unsigned int *seconds, + long *nanoseconds) +{ + uint64_t big_seconds = milliseconds / 1000; + + if (big_seconds > UINT_MAX) + return false; + + *seconds = big_seconds; + *nanoseconds = (milliseconds % 1000) * 1000000L; + + return true; +} + +/** + * timeout_create_with_nanoseconds: + * @seconds: number of seconds + * @nanoseconds: number of nanoseconds + * @callback: timeout callback function + * @user_data: user data provided to timeout callback function + * @destroy: destroy function for user data + * + * Create new timeout callback handling. + * + * The timeout will only fire once. The timeout handling needs to be rearmed + * with one of the l_timeout_modify functions to trigger again. + * + * Returns: a newly allocated #l_timeout object. On failure, the function + * returns NULL. + **/ +static struct l_timeout *timeout_create_with_nanoseconds(unsigned int seconds, + long nanoseconds, l_timeout_notify_cb_t callback, + void *user_data, l_timeout_destroy_cb_t destroy) +{ + struct l_timeout *timeout; + int err; + + if (unlikely(!callback)) + return NULL; + + timeout = l_new(struct l_timeout, 1); + + timeout->callback = callback; + timeout->destroy = destroy; + timeout->user_data = user_data; + + timeout->fd = timerfd_create(CLOCK_MONOTONIC, + TFD_NONBLOCK | TFD_CLOEXEC); + if (timeout->fd < 0) { + l_free(timeout); + return NULL; + } + + if (seconds > 0 || nanoseconds > 0) { + if (timeout_set(timeout->fd, seconds, nanoseconds) < 0) { + close(timeout->fd); + l_free(timeout); + return NULL; + } + } + + err = watch_add(timeout->fd, EPOLLIN | EPOLLONESHOT, timeout_callback, + timeout, timeout_destroy); + + if (err < 0) { + l_free(timeout); + return NULL; + } + + return timeout; +} + +/** + * l_timeout_create: + * @seconds: timeout in seconds + * @callback: timeout callback function + * @user_data: user data provided to timeout callback function + * @destroy: destroy function for user data + * + * Create new timeout callback handling. + * + * The timeout will only fire once. The timeout handling needs to be rearmed + * with one of the l_timeout_modify functions to trigger again. + * + * Returns: a newly allocated #l_timeout object. On failure, the function + * returns NULL. + **/ +LIB_EXPORT struct l_timeout *l_timeout_create(unsigned int seconds, + l_timeout_notify_cb_t callback, + void *user_data, l_timeout_destroy_cb_t destroy) +{ + return timeout_create_with_nanoseconds(seconds, 0, callback, + user_data, destroy); +} + +/** + * l_timeout_create_ms: + * @milliseconds: timeout in milliseconds + * @callback: timeout callback function + * @user_data: user data provided to timeout callback function + * @destroy: destroy function for user data + * + * Create new timeout callback handling. + * + * The timeout will only fire once. The timeout handling needs to be rearmed + * with one of the l_timeout_modify functions to trigger again. + * + * Returns: a newly allocated #l_timeout object. On failure, the function + * returns NULL. + **/ +LIB_EXPORT struct l_timeout *l_timeout_create_ms(uint64_t milliseconds, + l_timeout_notify_cb_t callback, + void *user_data, l_timeout_destroy_cb_t destroy) +{ + unsigned int seconds; + long nanoseconds; + + if (!convert_ms(milliseconds, &seconds, &nanoseconds)) + return NULL; + + return timeout_create_with_nanoseconds(seconds, nanoseconds, callback, + user_data, destroy); +} + +/** + * l_timeout_modify: + * @timeout: timeout object + * @seconds: timeout in seconds + * + * Modify an existing @timeout and rearm it. + **/ +LIB_EXPORT void l_timeout_modify(struct l_timeout *timeout, + unsigned int seconds) +{ + if (unlikely(!timeout)) + return; + + if (unlikely(timeout->fd < 0)) + return; + + if (seconds > 0) { + if (timeout_set(timeout->fd, seconds, 0) < 0) + return; + } + + watch_modify(timeout->fd, EPOLLIN | EPOLLONESHOT, true); +} + +/** + * l_timeout_modify_ms: + * @timeout: timeout object + * @milliseconds: number of milliseconds + * + * Modify an existing @timeout and rearm it. + **/ +LIB_EXPORT void l_timeout_modify_ms(struct l_timeout *timeout, + uint64_t milliseconds) +{ + if (unlikely(!timeout)) + return; + + if (unlikely(timeout->fd < 0)) + return; + + if (milliseconds > 0) { + unsigned int sec; + long nanosec; + + if (!convert_ms(milliseconds, &sec, &nanosec) || + timeout_set(timeout->fd, sec, nanosec) < 0) + return; + } + + watch_modify(timeout->fd, EPOLLIN | EPOLLONESHOT, true); +} + +/** + * l_timeout_remove: + * @timeout: timeout object + * + * Remove timeout handling. + **/ +LIB_EXPORT void l_timeout_remove(struct l_timeout *timeout) +{ + if (unlikely(!timeout)) + return; + + watch_remove(timeout->fd, false); + + l_free(timeout); +} + +/** + * l_timeout_set_callback: + * @timeout: timeout object + * @callback: The new callback + * @user_data: The new user_data + * @destroy: The new destroy function + * + * Sets the new notify callback for @timeout. If the old user_data object had + * a destroy function set, then that function will be called. + */ +LIB_EXPORT void l_timeout_set_callback(struct l_timeout *timeout, + l_timeout_notify_cb_t callback, + void *user_data, + l_timeout_destroy_cb_t destroy) +{ + if (unlikely(!timeout)) + return; + + if (timeout->destroy) + timeout->destroy(timeout->user_data); + + timeout->callback = callback; + timeout->user_data = user_data; + timeout->destroy = destroy; +} + +/** + * l_timeout_get_remaining: + * + * Get the remaining time for a timeout in microseconds + * + * @timeout: timeout object + * @remaining: microseconds remaining on timer + * + * Returns: True if successfully got remaining time + * False if failure to get remaining time + **/ +LIB_EXPORT bool l_timeout_remaining(struct l_timeout *timeout, + uint64_t *remaining) +{ + struct itimerspec current; + + if (unlikely(!timeout)) + return false; + + if (timerfd_gettime(timeout->fd, ¤t) < 0) + return false; + + if (remaining) + *remaining = _time_from_timespec(¤t.it_value); + + return true; +} diff --git a/ell/timeout.h b/ell/timeout.h new file mode 100644 index 0000000000000000000000000000000000000000..c0d463c1d021b0c941a4f1d953e5b94994c56076 --- /dev/null +++ b/ell/timeout.h @@ -0,0 +1,43 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_TIMEOUT_H +#define __ELL_TIMEOUT_H + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct l_timeout; + +typedef void (*l_timeout_notify_cb_t) (struct l_timeout *timeout, + void *user_data); +typedef void (*l_timeout_destroy_cb_t) (void *user_data); + +struct l_timeout *l_timeout_create(unsigned int seconds, + l_timeout_notify_cb_t callback, + void *user_data, l_timeout_destroy_cb_t destroy); +struct l_timeout *l_timeout_create_ms(uint64_t milliseconds, + l_timeout_notify_cb_t callback, + void *user_data, l_timeout_destroy_cb_t destroy); +void l_timeout_modify(struct l_timeout *timeout, + unsigned int seconds); +void l_timeout_modify_ms(struct l_timeout *timeout, + uint64_t milliseconds); +void l_timeout_remove(struct l_timeout *timeout); +void l_timeout_set_callback(struct l_timeout *timeout, + l_timeout_notify_cb_t callback, void *user_data, + l_timeout_destroy_cb_t destroy); +bool l_timeout_remaining(struct l_timeout *timeout, + uint64_t *remaining); +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_TIMEOUT_H */ diff --git a/ell/tls-extensions.c b/ell/tls-extensions.c new file mode 100644 index 0000000000000000000000000000000000000000..eaa8912dc175145554ad794d78302b6247792e8b --- /dev/null +++ b/ell/tls-extensions.c @@ -0,0 +1,1037 @@ +/* + * Embedded Linux library + * Copyright (C) 2018 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> + +#include "util.h" +#include "tls.h" +#include "cipher.h" +#include "checksum.h" +#include "cert.h" +#include "tls-private.h" + +/* Most extensions are not used when resuming a cached session */ +#define SKIP_ON_RESUMPTION() \ + do { \ + if (tls->session_id_size && !tls->session_id_new) \ + return -ENOMSG; \ + } while (0); + +/* RFC 7919, Section A.1 */ +static const uint8_t tls_ffdhe2048_prime[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, + 0xa2, 0xbb, 0x4a, 0x9a, 0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, + 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, 0x36, 0x95, 0xa9, 0xe1, 0x36, 0x41, + 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, 0x9b, 0x3e, 0xf9, + 0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, + 0xae, 0xc4, 0x61, 0x7a, 0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, + 0x24, 0x33, 0xf5, 0x1f, 0x5f, 0x06, 0x6e, 0xd0, 0x85, 0x63, 0x65, 0x55, + 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35, + 0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, 0xa6, 0x89, 0xda, + 0xf3, 0xef, 0xe8, 0x72, 0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, + 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a, 0xbc, 0x0a, 0xb1, 0x82, + 0xb3, 0x24, 0xfb, 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb, + 0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, + 0xde, 0x39, 0x4d, 0xf4, 0xae, 0x56, 0xed, 0xe7, 0x63, 0x72, 0xbb, 0x19, + 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70, 0x9e, 0x02, 0xfc, 0xe1, + 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61, + 0x91, 0x72, 0xfe, 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, + 0xee, 0xf2, 0x81, 0x83, 0xc3, 0xfe, 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, + 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05, 0xc5, 0x8e, 0xf1, 0x83, + 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa, + 0x88, 0x6b, 0x42, 0x38, 0x61, 0x28, 0x5c, 0x97, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, +}; + +/* RFC 7919, Section A.2 */ +static const uint8_t tls_ffdhe3072_prime[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, + 0xa2, 0xbb, 0x4a, 0x9a, 0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, + 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, 0x36, 0x95, 0xa9, 0xe1, 0x36, 0x41, + 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, 0x9b, 0x3e, 0xf9, + 0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, + 0xae, 0xc4, 0x61, 0x7a, 0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, + 0x24, 0x33, 0xf5, 0x1f, 0x5f, 0x06, 0x6e, 0xd0, 0x85, 0x63, 0x65, 0x55, + 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35, + 0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, 0xa6, 0x89, 0xda, + 0xf3, 0xef, 0xe8, 0x72, 0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, + 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a, 0xbc, 0x0a, 0xb1, 0x82, + 0xb3, 0x24, 0xfb, 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb, + 0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, + 0xde, 0x39, 0x4d, 0xf4, 0xae, 0x56, 0xed, 0xe7, 0x63, 0x72, 0xbb, 0x19, + 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70, 0x9e, 0x02, 0xfc, 0xe1, + 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61, + 0x91, 0x72, 0xfe, 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, + 0xee, 0xf2, 0x81, 0x83, 0xc3, 0xfe, 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, + 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05, 0xc5, 0x8e, 0xf1, 0x83, + 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa, + 0x88, 0x6b, 0x42, 0x38, 0x61, 0x1f, 0xcf, 0xdc, 0xde, 0x35, 0x5b, 0x3b, + 0x65, 0x19, 0x03, 0x5b, 0xbc, 0x34, 0xf4, 0xde, 0xf9, 0x9c, 0x02, 0x38, + 0x61, 0xb4, 0x6f, 0xc9, 0xd6, 0xe6, 0xc9, 0x07, 0x7a, 0xd9, 0x1d, 0x26, + 0x91, 0xf7, 0xf7, 0xee, 0x59, 0x8c, 0xb0, 0xfa, 0xc1, 0x86, 0xd9, 0x1c, + 0xae, 0xfe, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, 0xb4, 0x13, 0x0c, 0x93, + 0xbc, 0x43, 0x79, 0x44, 0xf4, 0xfd, 0x44, 0x52, 0xe2, 0xd7, 0x4d, 0xd3, + 0x64, 0xf2, 0xe2, 0x1e, 0x71, 0xf5, 0x4b, 0xff, 0x5c, 0xae, 0x82, 0xab, + 0x9c, 0x9d, 0xf6, 0x9e, 0xe8, 0x6d, 0x2b, 0xc5, 0x22, 0x36, 0x3a, 0x0d, + 0xab, 0xc5, 0x21, 0x97, 0x9b, 0x0d, 0xea, 0xda, 0x1d, 0xbf, 0x9a, 0x42, + 0xd5, 0xc4, 0x48, 0x4e, 0x0a, 0xbc, 0xd0, 0x6b, 0xfa, 0x53, 0xdd, 0xef, + 0x3c, 0x1b, 0x20, 0xee, 0x3f, 0xd5, 0x9d, 0x7c, 0x25, 0xe4, 0x1d, 0x2b, + 0x66, 0xc6, 0x2e, 0x37, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +/* RFC 7919, Section A.3 */ +static const uint8_t tls_ffdhe4096_prime[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, + 0xa2, 0xbb, 0x4a, 0x9a, 0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, + 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, 0x36, 0x95, 0xa9, 0xe1, 0x36, 0x41, + 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, 0x9b, 0x3e, 0xf9, + 0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, + 0xae, 0xc4, 0x61, 0x7a, 0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, + 0x24, 0x33, 0xf5, 0x1f, 0x5f, 0x06, 0x6e, 0xd0, 0x85, 0x63, 0x65, 0x55, + 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35, + 0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, 0xa6, 0x89, 0xda, + 0xf3, 0xef, 0xe8, 0x72, 0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, + 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a, 0xbc, 0x0a, 0xb1, 0x82, + 0xb3, 0x24, 0xfb, 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb, + 0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, + 0xde, 0x39, 0x4d, 0xf4, 0xae, 0x56, 0xed, 0xe7, 0x63, 0x72, 0xbb, 0x19, + 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70, 0x9e, 0x02, 0xfc, 0xe1, + 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61, + 0x91, 0x72, 0xfe, 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, + 0xee, 0xf2, 0x81, 0x83, 0xc3, 0xfe, 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, + 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05, 0xc5, 0x8e, 0xf1, 0x83, + 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa, + 0x88, 0x6b, 0x42, 0x38, 0x61, 0x1f, 0xcf, 0xdc, 0xde, 0x35, 0x5b, 0x3b, + 0x65, 0x19, 0x03, 0x5b, 0xbc, 0x34, 0xf4, 0xde, 0xf9, 0x9c, 0x02, 0x38, + 0x61, 0xb4, 0x6f, 0xc9, 0xd6, 0xe6, 0xc9, 0x07, 0x7a, 0xd9, 0x1d, 0x26, + 0x91, 0xf7, 0xf7, 0xee, 0x59, 0x8c, 0xb0, 0xfa, 0xc1, 0x86, 0xd9, 0x1c, + 0xae, 0xfe, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, 0xb4, 0x13, 0x0c, 0x93, + 0xbc, 0x43, 0x79, 0x44, 0xf4, 0xfd, 0x44, 0x52, 0xe2, 0xd7, 0x4d, 0xd3, + 0x64, 0xf2, 0xe2, 0x1e, 0x71, 0xf5, 0x4b, 0xff, 0x5c, 0xae, 0x82, 0xab, + 0x9c, 0x9d, 0xf6, 0x9e, 0xe8, 0x6d, 0x2b, 0xc5, 0x22, 0x36, 0x3a, 0x0d, + 0xab, 0xc5, 0x21, 0x97, 0x9b, 0x0d, 0xea, 0xda, 0x1d, 0xbf, 0x9a, 0x42, + 0xd5, 0xc4, 0x48, 0x4e, 0x0a, 0xbc, 0xd0, 0x6b, 0xfa, 0x53, 0xdd, 0xef, + 0x3c, 0x1b, 0x20, 0xee, 0x3f, 0xd5, 0x9d, 0x7c, 0x25, 0xe4, 0x1d, 0x2b, + 0x66, 0x9e, 0x1e, 0xf1, 0x6e, 0x6f, 0x52, 0xc3, 0x16, 0x4d, 0xf4, 0xfb, + 0x79, 0x30, 0xe9, 0xe4, 0xe5, 0x88, 0x57, 0xb6, 0xac, 0x7d, 0x5f, 0x42, + 0xd6, 0x9f, 0x6d, 0x18, 0x77, 0x63, 0xcf, 0x1d, 0x55, 0x03, 0x40, 0x04, + 0x87, 0xf5, 0x5b, 0xa5, 0x7e, 0x31, 0xcc, 0x7a, 0x71, 0x35, 0xc8, 0x86, + 0xef, 0xb4, 0x31, 0x8a, 0xed, 0x6a, 0x1e, 0x01, 0x2d, 0x9e, 0x68, 0x32, + 0xa9, 0x07, 0x60, 0x0a, 0x91, 0x81, 0x30, 0xc4, 0x6d, 0xc7, 0x78, 0xf9, + 0x71, 0xad, 0x00, 0x38, 0x09, 0x29, 0x99, 0xa3, 0x33, 0xcb, 0x8b, 0x7a, + 0x1a, 0x1d, 0xb9, 0x3d, 0x71, 0x40, 0x00, 0x3c, 0x2a, 0x4e, 0xce, 0xa9, + 0xf9, 0x8d, 0x0a, 0xcc, 0x0a, 0x82, 0x91, 0xcd, 0xce, 0xc9, 0x7d, 0xcf, + 0x8e, 0xc9, 0xb5, 0x5a, 0x7f, 0x88, 0xa4, 0x6b, 0x4d, 0xb5, 0xa8, 0x51, + 0xf4, 0x41, 0x82, 0xe1, 0xc6, 0x8a, 0x00, 0x7e, 0x5e, 0x65, 0x5f, 0x6a, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +/* RFC 7919, Section A.4 */ +static const uint8_t tls_ffdhe6144_prime[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, + 0xa2, 0xbb, 0x4a, 0x9a, 0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, + 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, 0x36, 0x95, 0xa9, 0xe1, 0x36, 0x41, + 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, 0x9b, 0x3e, 0xf9, + 0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, + 0xae, 0xc4, 0x61, 0x7a, 0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, + 0x24, 0x33, 0xf5, 0x1f, 0x5f, 0x06, 0x6e, 0xd0, 0x85, 0x63, 0x65, 0x55, + 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35, + 0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, 0xa6, 0x89, 0xda, + 0xf3, 0xef, 0xe8, 0x72, 0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, + 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a, 0xbc, 0x0a, 0xb1, 0x82, + 0xb3, 0x24, 0xfb, 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb, + 0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, + 0xde, 0x39, 0x4d, 0xf4, 0xae, 0x56, 0xed, 0xe7, 0x63, 0x72, 0xbb, 0x19, + 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70, 0x9e, 0x02, 0xfc, 0xe1, + 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61, + 0x91, 0x72, 0xfe, 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, + 0xee, 0xf2, 0x81, 0x83, 0xc3, 0xfe, 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, + 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05, 0xc5, 0x8e, 0xf1, 0x83, + 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa, + 0x88, 0x6b, 0x42, 0x38, 0x61, 0x1f, 0xcf, 0xdc, 0xde, 0x35, 0x5b, 0x3b, + 0x65, 0x19, 0x03, 0x5b, 0xbc, 0x34, 0xf4, 0xde, 0xf9, 0x9c, 0x02, 0x38, + 0x61, 0xb4, 0x6f, 0xc9, 0xd6, 0xe6, 0xc9, 0x07, 0x7a, 0xd9, 0x1d, 0x26, + 0x91, 0xf7, 0xf7, 0xee, 0x59, 0x8c, 0xb0, 0xfa, 0xc1, 0x86, 0xd9, 0x1c, + 0xae, 0xfe, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, 0xb4, 0x13, 0x0c, 0x93, + 0xbc, 0x43, 0x79, 0x44, 0xf4, 0xfd, 0x44, 0x52, 0xe2, 0xd7, 0x4d, 0xd3, + 0x64, 0xf2, 0xe2, 0x1e, 0x71, 0xf5, 0x4b, 0xff, 0x5c, 0xae, 0x82, 0xab, + 0x9c, 0x9d, 0xf6, 0x9e, 0xe8, 0x6d, 0x2b, 0xc5, 0x22, 0x36, 0x3a, 0x0d, + 0xab, 0xc5, 0x21, 0x97, 0x9b, 0x0d, 0xea, 0xda, 0x1d, 0xbf, 0x9a, 0x42, + 0xd5, 0xc4, 0x48, 0x4e, 0x0a, 0xbc, 0xd0, 0x6b, 0xfa, 0x53, 0xdd, 0xef, + 0x3c, 0x1b, 0x20, 0xee, 0x3f, 0xd5, 0x9d, 0x7c, 0x25, 0xe4, 0x1d, 0x2b, + 0x66, 0x9e, 0x1e, 0xf1, 0x6e, 0x6f, 0x52, 0xc3, 0x16, 0x4d, 0xf4, 0xfb, + 0x79, 0x30, 0xe9, 0xe4, 0xe5, 0x88, 0x57, 0xb6, 0xac, 0x7d, 0x5f, 0x42, + 0xd6, 0x9f, 0x6d, 0x18, 0x77, 0x63, 0xcf, 0x1d, 0x55, 0x03, 0x40, 0x04, + 0x87, 0xf5, 0x5b, 0xa5, 0x7e, 0x31, 0xcc, 0x7a, 0x71, 0x35, 0xc8, 0x86, + 0xef, 0xb4, 0x31, 0x8a, 0xed, 0x6a, 0x1e, 0x01, 0x2d, 0x9e, 0x68, 0x32, + 0xa9, 0x07, 0x60, 0x0a, 0x91, 0x81, 0x30, 0xc4, 0x6d, 0xc7, 0x78, 0xf9, + 0x71, 0xad, 0x00, 0x38, 0x09, 0x29, 0x99, 0xa3, 0x33, 0xcb, 0x8b, 0x7a, + 0x1a, 0x1d, 0xb9, 0x3d, 0x71, 0x40, 0x00, 0x3c, 0x2a, 0x4e, 0xce, 0xa9, + 0xf9, 0x8d, 0x0a, 0xcc, 0x0a, 0x82, 0x91, 0xcd, 0xce, 0xc9, 0x7d, 0xcf, + 0x8e, 0xc9, 0xb5, 0x5a, 0x7f, 0x88, 0xa4, 0x6b, 0x4d, 0xb5, 0xa8, 0x51, + 0xf4, 0x41, 0x82, 0xe1, 0xc6, 0x8a, 0x00, 0x7e, 0x5e, 0x0d, 0xd9, 0x02, + 0x0b, 0xfd, 0x64, 0xb6, 0x45, 0x03, 0x6c, 0x7a, 0x4e, 0x67, 0x7d, 0x2c, + 0x38, 0x53, 0x2a, 0x3a, 0x23, 0xba, 0x44, 0x42, 0xca, 0xf5, 0x3e, 0xa6, + 0x3b, 0xb4, 0x54, 0x32, 0x9b, 0x76, 0x24, 0xc8, 0x91, 0x7b, 0xdd, 0x64, + 0xb1, 0xc0, 0xfd, 0x4c, 0xb3, 0x8e, 0x8c, 0x33, 0x4c, 0x70, 0x1c, 0x3a, + 0xcd, 0xad, 0x06, 0x57, 0xfc, 0xcf, 0xec, 0x71, 0x9b, 0x1f, 0x5c, 0x3e, + 0x4e, 0x46, 0x04, 0x1f, 0x38, 0x81, 0x47, 0xfb, 0x4c, 0xfd, 0xb4, 0x77, + 0xa5, 0x24, 0x71, 0xf7, 0xa9, 0xa9, 0x69, 0x10, 0xb8, 0x55, 0x32, 0x2e, + 0xdb, 0x63, 0x40, 0xd8, 0xa0, 0x0e, 0xf0, 0x92, 0x35, 0x05, 0x11, 0xe3, + 0x0a, 0xbe, 0xc1, 0xff, 0xf9, 0xe3, 0xa2, 0x6e, 0x7f, 0xb2, 0x9f, 0x8c, + 0x18, 0x30, 0x23, 0xc3, 0x58, 0x7e, 0x38, 0xda, 0x00, 0x77, 0xd9, 0xb4, + 0x76, 0x3e, 0x4e, 0x4b, 0x94, 0xb2, 0xbb, 0xc1, 0x94, 0xc6, 0x65, 0x1e, + 0x77, 0xca, 0xf9, 0x92, 0xee, 0xaa, 0xc0, 0x23, 0x2a, 0x28, 0x1b, 0xf6, + 0xb3, 0xa7, 0x39, 0xc1, 0x22, 0x61, 0x16, 0x82, 0x0a, 0xe8, 0xdb, 0x58, + 0x47, 0xa6, 0x7c, 0xbe, 0xf9, 0xc9, 0x09, 0x1b, 0x46, 0x2d, 0x53, 0x8c, + 0xd7, 0x2b, 0x03, 0x74, 0x6a, 0xe7, 0x7f, 0x5e, 0x62, 0x29, 0x2c, 0x31, + 0x15, 0x62, 0xa8, 0x46, 0x50, 0x5d, 0xc8, 0x2d, 0xb8, 0x54, 0x33, 0x8a, + 0xe4, 0x9f, 0x52, 0x35, 0xc9, 0x5b, 0x91, 0x17, 0x8c, 0xcf, 0x2d, 0xd5, + 0xca, 0xce, 0xf4, 0x03, 0xec, 0x9d, 0x18, 0x10, 0xc6, 0x27, 0x2b, 0x04, + 0x5b, 0x3b, 0x71, 0xf9, 0xdc, 0x6b, 0x80, 0xd6, 0x3f, 0xdd, 0x4a, 0x8e, + 0x9a, 0xdb, 0x1e, 0x69, 0x62, 0xa6, 0x95, 0x26, 0xd4, 0x31, 0x61, 0xc1, + 0xa4, 0x1d, 0x57, 0x0d, 0x79, 0x38, 0xda, 0xd4, 0xa4, 0x0e, 0x32, 0x9c, + 0xd0, 0xe4, 0x0e, 0x65, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +/* RFC 7919, Section A.5 */ +static const uint8_t tls_ffdhe8192_prime[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, + 0xa2, 0xbb, 0x4a, 0x9a, 0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, + 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, 0x36, 0x95, 0xa9, 0xe1, 0x36, 0x41, + 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, 0x9b, 0x3e, 0xf9, + 0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, + 0xae, 0xc4, 0x61, 0x7a, 0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, + 0x24, 0x33, 0xf5, 0x1f, 0x5f, 0x06, 0x6e, 0xd0, 0x85, 0x63, 0x65, 0x55, + 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35, + 0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, 0xa6, 0x89, 0xda, + 0xf3, 0xef, 0xe8, 0x72, 0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, + 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a, 0xbc, 0x0a, 0xb1, 0x82, + 0xb3, 0x24, 0xfb, 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb, + 0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, + 0xde, 0x39, 0x4d, 0xf4, 0xae, 0x56, 0xed, 0xe7, 0x63, 0x72, 0xbb, 0x19, + 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70, 0x9e, 0x02, 0xfc, 0xe1, + 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61, + 0x91, 0x72, 0xfe, 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, + 0xee, 0xf2, 0x81, 0x83, 0xc3, 0xfe, 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, + 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05, 0xc5, 0x8e, 0xf1, 0x83, + 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa, + 0x88, 0x6b, 0x42, 0x38, 0x61, 0x1f, 0xcf, 0xdc, 0xde, 0x35, 0x5b, 0x3b, + 0x65, 0x19, 0x03, 0x5b, 0xbc, 0x34, 0xf4, 0xde, 0xf9, 0x9c, 0x02, 0x38, + 0x61, 0xb4, 0x6f, 0xc9, 0xd6, 0xe6, 0xc9, 0x07, 0x7a, 0xd9, 0x1d, 0x26, + 0x91, 0xf7, 0xf7, 0xee, 0x59, 0x8c, 0xb0, 0xfa, 0xc1, 0x86, 0xd9, 0x1c, + 0xae, 0xfe, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, 0xb4, 0x13, 0x0c, 0x93, + 0xbc, 0x43, 0x79, 0x44, 0xf4, 0xfd, 0x44, 0x52, 0xe2, 0xd7, 0x4d, 0xd3, + 0x64, 0xf2, 0xe2, 0x1e, 0x71, 0xf5, 0x4b, 0xff, 0x5c, 0xae, 0x82, 0xab, + 0x9c, 0x9d, 0xf6, 0x9e, 0xe8, 0x6d, 0x2b, 0xc5, 0x22, 0x36, 0x3a, 0x0d, + 0xab, 0xc5, 0x21, 0x97, 0x9b, 0x0d, 0xea, 0xda, 0x1d, 0xbf, 0x9a, 0x42, + 0xd5, 0xc4, 0x48, 0x4e, 0x0a, 0xbc, 0xd0, 0x6b, 0xfa, 0x53, 0xdd, 0xef, + 0x3c, 0x1b, 0x20, 0xee, 0x3f, 0xd5, 0x9d, 0x7c, 0x25, 0xe4, 0x1d, 0x2b, + 0x66, 0x9e, 0x1e, 0xf1, 0x6e, 0x6f, 0x52, 0xc3, 0x16, 0x4d, 0xf4, 0xfb, + 0x79, 0x30, 0xe9, 0xe4, 0xe5, 0x88, 0x57, 0xb6, 0xac, 0x7d, 0x5f, 0x42, + 0xd6, 0x9f, 0x6d, 0x18, 0x77, 0x63, 0xcf, 0x1d, 0x55, 0x03, 0x40, 0x04, + 0x87, 0xf5, 0x5b, 0xa5, 0x7e, 0x31, 0xcc, 0x7a, 0x71, 0x35, 0xc8, 0x86, + 0xef, 0xb4, 0x31, 0x8a, 0xed, 0x6a, 0x1e, 0x01, 0x2d, 0x9e, 0x68, 0x32, + 0xa9, 0x07, 0x60, 0x0a, 0x91, 0x81, 0x30, 0xc4, 0x6d, 0xc7, 0x78, 0xf9, + 0x71, 0xad, 0x00, 0x38, 0x09, 0x29, 0x99, 0xa3, 0x33, 0xcb, 0x8b, 0x7a, + 0x1a, 0x1d, 0xb9, 0x3d, 0x71, 0x40, 0x00, 0x3c, 0x2a, 0x4e, 0xce, 0xa9, + 0xf9, 0x8d, 0x0a, 0xcc, 0x0a, 0x82, 0x91, 0xcd, 0xce, 0xc9, 0x7d, 0xcf, + 0x8e, 0xc9, 0xb5, 0x5a, 0x7f, 0x88, 0xa4, 0x6b, 0x4d, 0xb5, 0xa8, 0x51, + 0xf4, 0x41, 0x82, 0xe1, 0xc6, 0x8a, 0x00, 0x7e, 0x5e, 0x0d, 0xd9, 0x02, + 0x0b, 0xfd, 0x64, 0xb6, 0x45, 0x03, 0x6c, 0x7a, 0x4e, 0x67, 0x7d, 0x2c, + 0x38, 0x53, 0x2a, 0x3a, 0x23, 0xba, 0x44, 0x42, 0xca, 0xf5, 0x3e, 0xa6, + 0x3b, 0xb4, 0x54, 0x32, 0x9b, 0x76, 0x24, 0xc8, 0x91, 0x7b, 0xdd, 0x64, + 0xb1, 0xc0, 0xfd, 0x4c, 0xb3, 0x8e, 0x8c, 0x33, 0x4c, 0x70, 0x1c, 0x3a, + 0xcd, 0xad, 0x06, 0x57, 0xfc, 0xcf, 0xec, 0x71, 0x9b, 0x1f, 0x5c, 0x3e, + 0x4e, 0x46, 0x04, 0x1f, 0x38, 0x81, 0x47, 0xfb, 0x4c, 0xfd, 0xb4, 0x77, + 0xa5, 0x24, 0x71, 0xf7, 0xa9, 0xa9, 0x69, 0x10, 0xb8, 0x55, 0x32, 0x2e, + 0xdb, 0x63, 0x40, 0xd8, 0xa0, 0x0e, 0xf0, 0x92, 0x35, 0x05, 0x11, 0xe3, + 0x0a, 0xbe, 0xc1, 0xff, 0xf9, 0xe3, 0xa2, 0x6e, 0x7f, 0xb2, 0x9f, 0x8c, + 0x18, 0x30, 0x23, 0xc3, 0x58, 0x7e, 0x38, 0xda, 0x00, 0x77, 0xd9, 0xb4, + 0x76, 0x3e, 0x4e, 0x4b, 0x94, 0xb2, 0xbb, 0xc1, 0x94, 0xc6, 0x65, 0x1e, + 0x77, 0xca, 0xf9, 0x92, 0xee, 0xaa, 0xc0, 0x23, 0x2a, 0x28, 0x1b, 0xf6, + 0xb3, 0xa7, 0x39, 0xc1, 0x22, 0x61, 0x16, 0x82, 0x0a, 0xe8, 0xdb, 0x58, + 0x47, 0xa6, 0x7c, 0xbe, 0xf9, 0xc9, 0x09, 0x1b, 0x46, 0x2d, 0x53, 0x8c, + 0xd7, 0x2b, 0x03, 0x74, 0x6a, 0xe7, 0x7f, 0x5e, 0x62, 0x29, 0x2c, 0x31, + 0x15, 0x62, 0xa8, 0x46, 0x50, 0x5d, 0xc8, 0x2d, 0xb8, 0x54, 0x33, 0x8a, + 0xe4, 0x9f, 0x52, 0x35, 0xc9, 0x5b, 0x91, 0x17, 0x8c, 0xcf, 0x2d, 0xd5, + 0xca, 0xce, 0xf4, 0x03, 0xec, 0x9d, 0x18, 0x10, 0xc6, 0x27, 0x2b, 0x04, + 0x5b, 0x3b, 0x71, 0xf9, 0xdc, 0x6b, 0x80, 0xd6, 0x3f, 0xdd, 0x4a, 0x8e, + 0x9a, 0xdb, 0x1e, 0x69, 0x62, 0xa6, 0x95, 0x26, 0xd4, 0x31, 0x61, 0xc1, + 0xa4, 0x1d, 0x57, 0x0d, 0x79, 0x38, 0xda, 0xd4, 0xa4, 0x0e, 0x32, 0x9c, + 0xcf, 0xf4, 0x6a, 0xaa, 0x36, 0xad, 0x00, 0x4c, 0xf6, 0x00, 0xc8, 0x38, + 0x1e, 0x42, 0x5a, 0x31, 0xd9, 0x51, 0xae, 0x64, 0xfd, 0xb2, 0x3f, 0xce, + 0xc9, 0x50, 0x9d, 0x43, 0x68, 0x7f, 0xeb, 0x69, 0xed, 0xd1, 0xcc, 0x5e, + 0x0b, 0x8c, 0xc3, 0xbd, 0xf6, 0x4b, 0x10, 0xef, 0x86, 0xb6, 0x31, 0x42, + 0xa3, 0xab, 0x88, 0x29, 0x55, 0x5b, 0x2f, 0x74, 0x7c, 0x93, 0x26, 0x65, + 0xcb, 0x2c, 0x0f, 0x1c, 0xc0, 0x1b, 0xd7, 0x02, 0x29, 0x38, 0x88, 0x39, + 0xd2, 0xaf, 0x05, 0xe4, 0x54, 0x50, 0x4a, 0xc7, 0x8b, 0x75, 0x82, 0x82, + 0x28, 0x46, 0xc0, 0xba, 0x35, 0xc3, 0x5f, 0x5c, 0x59, 0x16, 0x0c, 0xc0, + 0x46, 0xfd, 0x82, 0x51, 0x54, 0x1f, 0xc6, 0x8c, 0x9c, 0x86, 0xb0, 0x22, + 0xbb, 0x70, 0x99, 0x87, 0x6a, 0x46, 0x0e, 0x74, 0x51, 0xa8, 0xa9, 0x31, + 0x09, 0x70, 0x3f, 0xee, 0x1c, 0x21, 0x7e, 0x6c, 0x38, 0x26, 0xe5, 0x2c, + 0x51, 0xaa, 0x69, 0x1e, 0x0e, 0x42, 0x3c, 0xfc, 0x99, 0xe9, 0xe3, 0x16, + 0x50, 0xc1, 0x21, 0x7b, 0x62, 0x48, 0x16, 0xcd, 0xad, 0x9a, 0x95, 0xf9, + 0xd5, 0xb8, 0x01, 0x94, 0x88, 0xd9, 0xc0, 0xa0, 0xa1, 0xfe, 0x30, 0x75, + 0xa5, 0x77, 0xe2, 0x31, 0x83, 0xf8, 0x1d, 0x4a, 0x3f, 0x2f, 0xa4, 0x57, + 0x1e, 0xfc, 0x8c, 0xe0, 0xba, 0x8a, 0x4f, 0xe8, 0xb6, 0x85, 0x5d, 0xfe, + 0x72, 0xb0, 0xa6, 0x6e, 0xde, 0xd2, 0xfb, 0xab, 0xfb, 0xe5, 0x8a, 0x30, + 0xfa, 0xfa, 0xbe, 0x1c, 0x5d, 0x71, 0xa8, 0x7e, 0x2f, 0x74, 0x1e, 0xf8, + 0xc1, 0xfe, 0x86, 0xfe, 0xa6, 0xbb, 0xfd, 0xe5, 0x30, 0x67, 0x7f, 0x0d, + 0x97, 0xd1, 0x1d, 0x49, 0xf7, 0xa8, 0x44, 0x3d, 0x08, 0x22, 0xe5, 0x06, + 0xa9, 0xf4, 0x61, 0x4e, 0x01, 0x1e, 0x2a, 0x94, 0x83, 0x8f, 0xf8, 0x8c, + 0xd6, 0x8c, 0x8b, 0xb7, 0xc5, 0xc6, 0x42, 0x4c, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, +}; + +/* RFC 3526, Section 3 */ +static const uint8_t tls_dh14_prime[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, + 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, + 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6, + 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd, + 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, + 0xf2, 0x5f, 0x14, 0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, + 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4, 0x4c, 0x42, 0xe9, + 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed, + 0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, + 0x7c, 0x4b, 0x1f, 0xe6, 0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d, + 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05, 0x98, 0xda, 0x48, 0x36, + 0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f, + 0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, 0x1c, 0x62, 0xf3, 0x56, + 0x20, 0x85, 0x52, 0xbb, 0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d, + 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04, 0xf1, 0x74, 0x6c, 0x08, + 0xca, 0x18, 0x21, 0x7c, 0x32, 0x90, 0x5e, 0x46, 0x2e, 0x36, 0xce, 0x3b, + 0xe3, 0x9e, 0x77, 0x2c, 0x18, 0x0e, 0x86, 0x03, 0x9b, 0x27, 0x83, 0xa2, + 0xec, 0x07, 0xa2, 0x8f, 0xb5, 0xc5, 0x5d, 0xf0, 0x6f, 0x4c, 0x52, 0xc9, + 0xde, 0x2b, 0xcb, 0xf6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7c, + 0xea, 0x95, 0x6a, 0xe5, 0x15, 0xd2, 0x26, 0x18, 0x98, 0xfa, 0x05, 0x10, + 0x15, 0x72, 0x8e, 0x5a, 0x8a, 0xac, 0xaa, 0x68, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, +}; + +static const struct tls_named_group tls_group_pref[] = { + { "secp256r1", 23, TLS_GROUP_TYPE_EC }, + { "secp384r1", 24, TLS_GROUP_TYPE_EC }, + { + "ffdhe2048", 256, TLS_GROUP_TYPE_FF, + .ff = { + .prime = tls_ffdhe2048_prime, + .prime_len = sizeof(tls_ffdhe2048_prime), + .generator = 2, + }, + }, + { + "ffdhe3072", 257, TLS_GROUP_TYPE_FF, + .ff = { + .prime = tls_ffdhe3072_prime, + .prime_len = sizeof(tls_ffdhe3072_prime), + .generator = 2, + }, + }, + { + "ffdhe4096", 258, TLS_GROUP_TYPE_FF, + .ff = { + .prime = tls_ffdhe4096_prime, + .prime_len = sizeof(tls_ffdhe4096_prime), + .generator = 2, + }, + }, + { + "ffdhe6144", 259, TLS_GROUP_TYPE_FF, + .ff = { + .prime = tls_ffdhe6144_prime, + .prime_len = sizeof(tls_ffdhe6144_prime), + .generator = 2, + }, + }, + { + "ffdhe8192", 260, TLS_GROUP_TYPE_FF, + .ff = { + .prime = tls_ffdhe8192_prime, + .prime_len = sizeof(tls_ffdhe8192_prime), + .generator = 2, + }, + }, +}; + +/* + * For now hardcode a default group for non-RFC7919 clients - same group + * as some other TLS servers use, which is actually a downside because the + * more common the group parameters are the less secure they are assumed + * to be, but it is also a test that the group is sufficiently good. + * + * Eventually we need to make this configurable so that a unique + * likely-prime number generated by either 'openssl dhparam' or + * 'ssh-keygen -G' can be set, or parse /etc/ssh/moduli to select + * a random pre-generated FFDH group each time. + */ +static const struct tls_named_group tls_default_ffdh_group = { + "RFC3526/Oakley Group 14", 0, TLS_GROUP_TYPE_FF, + .ff = { + .prime = tls_dh14_prime, + .prime_len = sizeof(tls_dh14_prime), + .generator = 2, + }, +}; + +/* RFC 8422, Section 5.1 + RFC 7919 */ +static ssize_t tls_elliptic_curves_client_write(struct l_tls *tls, + uint8_t *buf, size_t len) +{ + uint8_t *ptr = buf; + unsigned int i; + + if (len < 2 + L_ARRAY_SIZE(tls_group_pref) * 2) + return -ENOMEM; + + l_put_be16(L_ARRAY_SIZE(tls_group_pref) * 2, ptr); + ptr += 2; + + for (i = 0; i < L_ARRAY_SIZE(tls_group_pref); i++) { + l_put_be16(tls_group_pref[i].id, ptr); + ptr += 2; + } + + return ptr - buf; +} + +static bool tls_elliptic_curves_client_handle(struct l_tls *tls, + const uint8_t *buf, size_t len) +{ + bool ffdh_offered = false; + + if (len < 2) + return false; + + if (l_get_be16(buf) != len - 2 || (len & 1)) + return false; + + buf += 2; + len -= 2; + + /* + * We select one group for DH and one group for ECDH and we'll + * let the cipher suite selection logic decide which one is actually + * used. It will take into account the client's cipher suite + * preference but it could just as well look at the strengths of + * the groups chosen. This is not done for simplicity but RFC 7919 + * suggests the Supported Groups should actually overrule the + * cipher suite preference list in case of a conflict: + * "A server that encounters such a contradiction when selecting + * between an ECDHE or FFDHE key exchange mechanism while trying + * to respect client preferences SHOULD give priority to the + * Supported Groups extension (...) but MAY resolve the + * contradiction any way it sees fit." + * + * Not implemented: "If a non-anonymous FFDHE cipher suite is + * selected and the TLS client has used this extension to offer + * an FFDHE group of comparable or greater strength than the server's + * public key, the server SHOULD select an FFDHE group at least + * as strong as the server's public key." + */ + + while (len) { + unsigned int i; + uint16_t id; + const struct tls_named_group *group = NULL; + + id = l_get_be16(buf); + buf += 2; + len -= 2; + + if (id >> 8 == 1) /* RFC 7919 ids */ + ffdh_offered = true; + + for (i = 0; i < L_ARRAY_SIZE(tls_group_pref); i++) + if (tls_group_pref[i].id == id) { + group = &tls_group_pref[i]; + break; + } + + if (!group) + continue; + + switch (group->type) { + case TLS_GROUP_TYPE_EC: + if (!tls->negotiated_curve) + tls->negotiated_curve = group; + + break; + case TLS_GROUP_TYPE_FF: + if (!tls->negotiated_ff_group) + tls->negotiated_ff_group = group; + + break; + } + } + + /* + * Note we need to treat DH slightly differently from ECDH groups + * here because the extension is defined in RFC 8422 and if the + * client offers no elliptic curves we can't use ECDH at all: + * "If a server (...) is unable to complete the ECC handshake while + * restricting itself to the enumerated curves (...), it MUST NOT + * negotiate the use of an ECC cipher suite. Depending on what + * other cipher suites are proposed by the client and supported by + * the server, this may result in a fatal handshake failure alert + * due to the lack of common cipher suites." + * + * On the other hand if the client offers no FFDH groups we can + * only assume the client is okay with us picking a group. Note + * the "includes any FFDHE group" part in RFC 7919 Section 4: + * "If a compatible TLS server receives a Supported Groups + * extension from a client that includes any FFDHE group (i.e., + * any codepoint between 256 and 511, inclusive, even if unknown + * to the server), and if none of the client-proposed FFDHE groups + * are known and acceptable to the server, then the server MUST + * NOT select an FFDHE cipher suite." + */ + + if (tls->negotiated_curve) + TLS_DEBUG("Negotiated %s", tls->negotiated_curve->name); + else + TLS_DEBUG("non-fatal: No common supported elliptic curves " + "for ECDHE"); + + if (tls->negotiated_ff_group) + TLS_DEBUG("Negotiated %s", tls->negotiated_ff_group->name); + else if (ffdh_offered) + TLS_DEBUG("non-fatal: No common supported finite-field groups " + "for DHE"); + else + tls->negotiated_ff_group = &tls_default_ffdh_group; + + return true; +} + +static bool tls_elliptic_curves_client_absent(struct l_tls *tls) +{ + unsigned int i; + + for (i = 0; i < L_ARRAY_SIZE(tls_group_pref); i++) + if (tls_group_pref[i].type == TLS_GROUP_TYPE_EC) { + tls->negotiated_curve = &tls_group_pref[i]; + break; + } + + tls->negotiated_ff_group = &tls_default_ffdh_group; + + return true; +} + +static bool tls_ec_point_formats_client_handle(struct l_tls *tls, + const uint8_t *buf, size_t len) +{ + if (len < 2) + return false; + + if (buf[0] != len - 1) + return false; + + if (!memchr(buf + 1, 0, len - 1)) { + TLS_DEBUG("Uncompressed point format missing"); + return false; + } + + return true; +} + +/* + * For compatibility with clients respond to a valid Client Hello Supported + * Point Formats extension with the hardcoded confirmation that we do + * support the single valid point format. As a client we never send this + * extension so we never have to handle a server response to it either. + */ +static ssize_t tls_ec_point_formats_server_write(struct l_tls *tls, + uint8_t *buf, size_t len) +{ + SKIP_ON_RESUMPTION(); /* RFC 4492 Section 4 */ + + if (len < 2) + return -ENOMEM; + + buf[0] = 0x01; /* ec_point_format_list length */ + buf[1] = 0x00; /* uncompressed */ + return 2; +} + +/* + * This is used to append the list of signature algorithm and hash type + * combinations we support to the Signature Algorithms client hello + * extension (on the client) and the Certificate Request message (on the + * server). In both cases we need to list the algorithms we support for + * two use cases: certificate chain verification and signing/verifying + * Server Key Exchange params (server->client) or Certificate Verify + * data (client->server). + * + * For the server side RFC 5462, Section 7.4.1.4.1 says: + * "If the client [...] is willing to use them for verifying + * messages sent by the server, i.e., server certificates and + * server key exchange [...] it MUST send the + * signature_algorithms extension, listing the algorithms it + * is willing to accept." + * + * As for the certificate chains we mostly rely on the kernel to do + * this so when we receive the list we do not currently verify the + * that the whole chain uses only algorithms from the list on either + * side (TODO). But we know that the chain verification in the kernel + * can use a superset of the hash algorithms l_checksum supports. + * For the Server Key Exchange and Certificate Verify signatures we + * use l_checksum but we need to map the TLS-specific hash IDs to + * enum l_checksum_type using the tls_handshake_hash_data list in + * signature->sign() and signature->verify(), so we use + * tls_handshake_hash_data as the definitive list of allowed hash + * algorithms. + * + * Our supported signature algorithms can work with any hash type so we + * basically have to send all possible combinations of the signature + * algorithm IDs from the supported cipher suites (except anonymous) + * with the hash algorithms we can use for signature verification, + * i.e. those in the tls_handshake_hash_data table. + */ +ssize_t tls_write_signature_algorithms(struct l_tls *tls, + uint8_t *buf, size_t len) +{ + uint8_t *ptr = buf; + unsigned int i, j; + struct tls_cipher_suite **suite; + uint8_t sig_alg_ids[16]; + uint8_t hash_ids[16]; + unsigned int sig_alg_cnt = 0; + unsigned int hash_cnt = 0; + + for (suite = tls->cipher_suite_pref_list; *suite; suite++) { + uint8_t id; + + if (!(*suite)->signature) + continue; + + id = (*suite)->signature->id; + + if (memchr(sig_alg_ids, id, sig_alg_cnt)) + continue; + + if (!tls_cipher_suite_is_compatible(tls, *suite, NULL)) + continue; + + if (sig_alg_cnt >= sizeof(sig_alg_ids)) + return -ENOMEM; + + sig_alg_ids[sig_alg_cnt++] = id; + } + + for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++) { + const struct tls_hash_algorithm *hash = + &tls_handshake_hash_data[i]; + bool supported; + + /* + * The hash types in the Signature Algorithms extension are + * all supported hashes but the ones in the Certificate + * Request (server->client) must be in the set for which we + * maintain handshake message hashes because that is going + * to be used in Certificate Verify. + */ + if (tls->server) + supported = !!tls->handshake_hash[i]; + else + supported = l_checksum_is_supported(hash->l_id, false); + + if (supported) + hash_ids[hash_cnt++] = hash->tls_id; + } + + if (len < 2 + sig_alg_cnt * hash_cnt * 2) + return -ENOMEM; + + l_put_be16(sig_alg_cnt * hash_cnt * 2, ptr); + ptr += 2; + + for (i = 0; i < sig_alg_cnt; i++) + for (j = 0; j < hash_cnt; j++) { + *ptr++ = hash_ids[j]; + *ptr++ = sig_alg_ids[i]; + } + + return ptr - buf; +} + +ssize_t tls_parse_signature_algorithms(struct l_tls *tls, + const uint8_t *buf, size_t len) +{ + const uint8_t *ptr = buf; + enum handshake_hash_type first_supported, hash; + const struct tls_hash_algorithm *preferred; + struct tls_cipher_suite **suite; + uint8_t sig_alg_ids[16]; + unsigned int sig_alg_cnt = 0; + + /* + * This only makes sense as a variable-length field, assume + * there's a typo in RFC5246 7.4.4 here. + */ + if (len < 4) + return -EINVAL; + + if (l_get_be16(ptr) > len - 2) + return -EINVAL; + + len = l_get_be16(ptr); + ptr += 2; + + if (len & 1) + return -EINVAL; + + for (suite = tls->cipher_suite_pref_list; *suite; suite++) { + uint8_t id; + + if (!(*suite)->signature) + continue; + + id = (*suite)->signature->id; + + if (memchr(sig_alg_ids, id, sig_alg_cnt)) + continue; + + if (!tls_cipher_suite_is_compatible(tls, *suite, NULL)) + continue; + + if (sig_alg_cnt >= sizeof(sig_alg_ids)) + return -ENOMEM; + + sig_alg_ids[sig_alg_cnt++] = id; + } + + /* + * In 1.2 we force our preference for SHA256/SHA384 (depending on + * cipher suite's PRF hmac) if it is supported by the peer because + * that must be supported anyway for the PRF and the Finished hash + * meaning that we only need to keep one hash instead of two. + * If not available fall back to the first common hash algorithm. + */ + first_supported = -1; + + if (tls->prf_hmac) + preferred = tls->prf_hmac; + else + preferred = &tls_handshake_hash_data[HANDSHAKE_HASH_SHA256]; + + while (len) { + uint8_t hash_id = *ptr++; + uint8_t sig_alg_id = *ptr++; + bool supported; + + len -= 2; + + /* Ignore hash types for signatures other than ours */ + if (tls->pending.cipher_suite && + (!tls->pending.cipher_suite->signature || + tls->pending.cipher_suite->signature->id != + sig_alg_id)) + continue; + + if (!tls->pending.cipher_suite && + !memchr(sig_alg_ids, sig_alg_id, sig_alg_cnt)) + continue; + + if (hash_id == preferred->tls_id) { + for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) + if (&tls_handshake_hash_data[hash] == preferred) + break; + break; + } + + if ((int) first_supported != -1) + continue; + + for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) + if (hash_id == tls_handshake_hash_data[hash].tls_id) + break; + + if (hash == __HANDSHAKE_HASH_COUNT) + continue; + + if (tls->server) + supported = l_checksum_is_supported( + tls_handshake_hash_data[hash].l_id, + false); + else + supported = !!tls->handshake_hash[hash]; + + if (supported) + first_supported = hash; + } + + if (len) + tls->signature_hash = hash; + else if ((int) first_supported != -1) + tls->signature_hash = first_supported; + else + return -ENOTSUP; + + return ptr + len - buf; +} + +/* RFC 5246, Section 7.4.1.4.1 */ +static ssize_t tls_signature_algorithms_client_write(struct l_tls *tls, + uint8_t *buf, size_t len) +{ + /* + * "Note: this extension is not meaningful for TLS versions + * prior to 1.2. Clients MUST NOT offer it if they are offering + * prior versions." + */ + if (tls->max_version < L_TLS_V12) + return -ENOMSG; + + return tls_write_signature_algorithms(tls, buf, len); +} + +static bool tls_signature_algorithms_client_handle(struct l_tls *tls, + const uint8_t *buf, size_t len) +{ + ssize_t ret; + + /* + * "However, even if clients do offer it, the rules specified in + * [TLSEXT] require servers to ignore extensions they do not + * understand." + */ + if (tls->max_version < L_TLS_V12) + return true; + + ret = tls_parse_signature_algorithms(tls, buf, len); + + if (ret == -ENOTSUP) + TLS_DEBUG("No common signature algorithms"); + + /* + * TODO: also check our certificate chain against the parsed + * signature algorithms. + */ + + return ret == (ssize_t) len; +} + +static bool tls_signature_algorithms_client_absent(struct l_tls *tls) +{ + /* + * "If the client does not send the signature_algorithms extension, + * the server MUST do the following: + * - [...] behave as if client had sent the value {sha1,rsa}. + * - [...] behave as if client had sent the value {sha1,dsa}. + * - [...] behave as if client had sent the value {sha1,ecdsa}. + */ + if (tls->max_version >= L_TLS_V12) + tls->signature_hash = HANDSHAKE_HASH_SHA1; + + return true; +} + +/* RFC 5746, Section 3.2 */ +static ssize_t tls_renegotiation_info_client_write(struct l_tls *tls, + uint8_t *buf, size_t len) +{ + /* + * Section 4.2 implies we should send the client_verify_data on + * renegotiation even if .secure_renegotiation is false, if we want + * to go through with the renegotiation in the first place. + */ + if (tls->ready) { + size_t vdl = tls_verify_data_length(tls, 1); + + if (len < vdl + 1) + return -ENOMEM; + + buf[0] = vdl; + memcpy(buf + 1, tls->renegotiation_info.client_verify_data, + vdl); + return 1 + vdl; + } else { + if (len < 1) + return -ENOMEM; + + buf[0] = 0x00; /* Empty "renegotiated_connection" */ + return 1; + } +} + +static ssize_t tls_renegotiation_info_server_write(struct l_tls *tls, + uint8_t *buf, size_t len) +{ + if (tls->ready) { + size_t rx_vdl = tls_verify_data_length(tls, 0); + size_t tx_vdl = tls_verify_data_length(tls, 1); + + if (len < rx_vdl + tx_vdl + 1) + return -ENOMEM; + + buf[0] = rx_vdl + tx_vdl; + memcpy(buf + 1, + tls->renegotiation_info.client_verify_data, rx_vdl); + memcpy(buf + 1 + rx_vdl, + tls->renegotiation_info.server_verify_data, tx_vdl); + return 1 + rx_vdl + tx_vdl; + } else { + if (len < 1) + return -ENOMEM; + + buf[0] = 0x00; /* Empty "renegotiated_connection" */ + return 1; + } +} + +static bool tls_renegotiation_info_client_handle(struct l_tls *tls, + const uint8_t *buf, size_t len) +{ + if (tls->ready) { + size_t vdl = tls_verify_data_length(tls, 0); + + return len >= 1 + vdl && + tls->renegotiation_info.secure_renegotiation && + !memcmp(tls->renegotiation_info.client_verify_data, + buf + 1, vdl); + } + + /* + * RFC 5746 Section 3.6: "The server MUST then verify that the length + * of the "renegotiated_connection" field is zero, ..." + */ + if (len < 1 || buf[0] != 0x00) + return false; + + tls->renegotiation_info.secure_renegotiation = true; + return true; +} + +static bool tls_renegotiation_info_server_handle(struct l_tls *tls, + const uint8_t *buf, size_t len) +{ + if (tls->ready) { + size_t rx_vdl = tls_verify_data_length(tls, 0); + size_t tx_vdl = tls_verify_data_length(tls, 1); + + return len >= 1 + rx_vdl + tx_vdl && + tls->renegotiation_info.secure_renegotiation && + !memcmp(tls->renegotiation_info.client_verify_data, + buf + 1, tx_vdl) && + !memcmp(tls->renegotiation_info.server_verify_data, + buf + 1 + tx_vdl, rx_vdl); + } + + /* + * RFC 5746 Section 3.4: "The client MUST then verify that the length + * of the "renegotiated_connection" field is zero, ..." + */ + if (len < 1 || buf[0] != 0x00) + return false; + + tls->renegotiation_info.secure_renegotiation = true; + return true; +} + +static bool tls_renegotiation_info_absent(struct l_tls *tls) +{ + /* + * RFC 5746 Section 4.2: "It is possible that un-upgraded servers + * will request that the client renegotiate. It is RECOMMENDED + * that clients refuse this renegotiation request." and Section 4.4: + * "It is RECOMMENDED that servers not permit legacy renegotiation." + * + * This may need to be made configurable, for now follow the + * recommendation and don't renegotiate. + */ + if (tls->ready) + return false; + + /* + * The normal policy otherwise is that the extension must be + * present in renegotiation if the previous Client or Server Hello + * did include this extension, or the SCSV in the Client Hello case. + */ + return !tls->ready || !tls->renegotiation_info.secure_renegotiation; +} + +const struct tls_hello_extension tls_extensions[] = { + { + "Supported Groups", "elliptic_curves", 10, + tls_elliptic_curves_client_write, + tls_elliptic_curves_client_handle, + tls_elliptic_curves_client_absent, + NULL, NULL, NULL, + }, + { + "Supported Point Formats", "ec_point_formats", 11, + NULL, + tls_ec_point_formats_client_handle, + NULL, + tls_ec_point_formats_server_write, + NULL, NULL, + }, + { + "Signature Algorithms", "signature_algoritms", 13, + tls_signature_algorithms_client_write, + tls_signature_algorithms_client_handle, + tls_signature_algorithms_client_absent, + NULL, NULL, NULL, + }, + { + "Secure Renegotiation", "renegotiation_info", 0xff01, + tls_renegotiation_info_client_write, + tls_renegotiation_info_client_handle, + tls_renegotiation_info_absent, + tls_renegotiation_info_server_write, + tls_renegotiation_info_server_handle, + tls_renegotiation_info_absent, + }, + {} +}; + +const struct tls_named_group *tls_find_group(uint16_t id) +{ + unsigned int i; + + for (i = 0; i < L_ARRAY_SIZE(tls_group_pref); i++) + if (tls_group_pref[i].id == id) + return &tls_group_pref[i]; + + return NULL; +} + +const struct tls_named_group *tls_find_ff_group(const uint8_t *prime, + size_t prime_len, + const uint8_t *generator, + size_t generator_len) +{ + unsigned int i; + + if (generator_len != 1) + return NULL; + + for (i = 0; i < L_ARRAY_SIZE(tls_group_pref); i++) { + const struct tls_named_group *g = &tls_group_pref[i]; + + if (g->type != TLS_GROUP_TYPE_FF) + continue; + + if (g->ff.prime_len != prime_len || + memcmp(prime, g->ff.prime, prime_len)) + continue; + + if (g->ff.generator != *generator) + continue; + + return g; + } + + return NULL; +} diff --git a/ell/tls-private.h b/ell/tls-private.h new file mode 100644 index 0000000000000000000000000000000000000000..c493f7fe320bd6d40808ce2a9ad58f2ca5dfff6d --- /dev/null +++ b/ell/tls-private.h @@ -0,0 +1,373 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#define TLS_MAX_VERSION L_TLS_V12 +#define TLS_MIN_VERSION L_TLS_V10 + +enum tls_cipher_type { + TLS_CIPHER_STREAM, + TLS_CIPHER_BLOCK, + TLS_CIPHER_AEAD, +}; + +struct tls_bulk_encryption_algorithm { + enum tls_cipher_type cipher_type; + union { + enum l_cipher_type l_id; + enum l_aead_cipher_type l_aead_id; + }; + size_t key_length; + size_t iv_length; + size_t fixed_iv_length; + size_t block_length; + size_t auth_tag_length; +}; + +/* + * Support the minimum required set of handshake hash types for the + * Certificate Verify digital signature and the Finished PRF seed so we + * don't have to accumulate all of messages full contents until the + * Finished message. If we're sent a hash of a different type (in TLS 1.2+) + * and need to verify we'll give up. + * SHA1 and MD5 are explicitly required by versions < 1.2 and 1.2 requires + * that the Finished hash is the same as used for the PRF so we need to + * keep at least the hashes our supported cipher suites specify for the PRF. + */ +enum handshake_hash_type { + HANDSHAKE_HASH_SHA384, + HANDSHAKE_HASH_SHA256, + HANDSHAKE_HASH_MD5, + HANDSHAKE_HASH_SHA1, + __HANDSHAKE_HASH_COUNT, +}; +#define HANDSHAKE_HASH_MAX_SIZE 48 + +struct tls_hash_algorithm { + uint8_t tls_id; + enum handshake_hash_type type; + enum l_checksum_type l_id; + const char *name; +}; + +extern const struct tls_hash_algorithm tls_handshake_hash_data[]; + +typedef bool (*tls_get_hash_t)(struct l_tls *tls, + enum handshake_hash_type type, + const uint8_t *data, size_t data_len, + uint8_t *out, size_t *out_len); + +struct tls_signature_algorithm { + uint8_t id; + + bool (*validate_cert_key_type)(struct l_cert *cert); + + ssize_t (*sign)(struct l_tls *tls, uint8_t *out, size_t out_len, + tls_get_hash_t get_hash, + const uint8_t *data, size_t data_len); + bool (*verify)(struct l_tls *tls, const uint8_t *in, size_t in_len, + tls_get_hash_t get_hash, + const uint8_t *data, size_t data_len); +}; + +struct tls_key_exchange_algorithm { + bool need_ecc; + bool need_ffdh; + + bool (*send_server_key_exchange)(struct l_tls *tls); + void (*handle_server_key_exchange)(struct l_tls *tls, + const uint8_t *buf, size_t len); + + bool (*send_client_key_exchange)(struct l_tls *tls); + void (*handle_client_key_exchange)(struct l_tls *tls, + const uint8_t *buf, size_t len); + + void (*free_params)(struct l_tls *tls); +}; + +struct tls_mac_algorithm { + uint8_t id; + enum l_checksum_type hmac_type; + size_t mac_length; +}; + +struct tls_cipher_suite { + uint8_t id[2]; + const char *name; + size_t verify_data_length; + + struct tls_bulk_encryption_algorithm *encryption; + struct tls_signature_algorithm *signature; + struct tls_key_exchange_algorithm *key_xchg; + struct tls_mac_algorithm *mac; + enum l_checksum_type prf_hmac; +}; + +extern struct tls_cipher_suite *tls_cipher_suite_pref[]; + +struct tls_compression_method { + int id; + const char *name; +}; + +struct tls_hello_extension { + const char *name; + const char *short_name; + uint16_t id; + ssize_t (*client_write)(struct l_tls *tls, uint8_t *buf, size_t len); + /* Handle a Client Hello extension (on server), can't be NULL */ + bool (*client_handle)(struct l_tls *tls, + const uint8_t *buf, size_t len); + /* Handle a Client Hello extension's absence (on server) */ + bool (*client_handle_absent)(struct l_tls *tls); + ssize_t (*server_write)(struct l_tls *tls, uint8_t *buf, size_t len); + /* Handle a Server Hello extension (on client) */ + bool (*server_handle)(struct l_tls *tls, + const uint8_t *buf, size_t len); + /* Handle a Server Hello extension's absence (on client) */ + bool (*server_handle_absent)(struct l_tls *tls); +}; + +extern const struct tls_hello_extension tls_extensions[]; + +struct tls_named_group { + const char *name; + uint16_t id; + enum { + TLS_GROUP_TYPE_EC, + TLS_GROUP_TYPE_FF, + } type; + union { + struct { + const uint8_t *prime; + size_t prime_len; + unsigned int generator; + } ff; + }; +}; + +enum tls_handshake_state { + TLS_HANDSHAKE_WAIT_START, + TLS_HANDSHAKE_WAIT_HELLO, + TLS_HANDSHAKE_WAIT_CERTIFICATE, + TLS_HANDSHAKE_WAIT_KEY_EXCHANGE, + TLS_HANDSHAKE_WAIT_HELLO_DONE, + TLS_HANDSHAKE_WAIT_CERTIFICATE_VERIFY, + TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC, + TLS_HANDSHAKE_WAIT_FINISHED, + TLS_HANDSHAKE_DONE, +}; + +enum tls_content_type { + TLS_CT_CHANGE_CIPHER_SPEC = 20, + TLS_CT_ALERT = 21, + TLS_CT_HANDSHAKE = 22, + TLS_CT_APPLICATION_DATA = 23, +}; + +enum tls_handshake_type { + TLS_HELLO_REQUEST = 0, + TLS_CLIENT_HELLO = 1, + TLS_SERVER_HELLO = 2, + TLS_CERTIFICATE = 11, + TLS_SERVER_KEY_EXCHANGE = 12, + TLS_CERTIFICATE_REQUEST = 13, + TLS_SERVER_HELLO_DONE = 14, + TLS_CERTIFICATE_VERIFY = 15, + TLS_CLIENT_KEY_EXCHANGE = 16, + TLS_FINISHED = 20, +}; + +struct l_tls { + bool server; + + l_tls_write_cb_t tx, rx; + l_tls_ready_cb_t ready_handle; + l_tls_disconnect_cb_t disconnected; + void *user_data; + l_tls_debug_cb_t debug_handler; + l_tls_destroy_cb_t debug_destroy; + void *debug_data; + char *cert_dump_path; + enum l_tls_version min_version; + enum l_tls_version max_version; + + struct l_queue *ca_certs; + struct l_certchain *cert; + struct l_key *priv_key; + size_t priv_key_size; + char **subject_mask; + + struct tls_cipher_suite **cipher_suite_pref_list; + + struct l_settings *session_settings; + char *session_prefix; + uint64_t session_lifetime; + unsigned int session_count_max; + l_tls_session_update_cb_t session_update_cb; + void *session_update_user_data; + + bool in_callback; + bool pending_destroy; + + /* Record layer */ + + uint8_t *record_buf; + int record_buf_len; + int record_buf_max_len; + bool record_flush; + + uint8_t *message_buf; + int message_buf_len; + int message_buf_max_len; + enum tls_content_type message_content_type; + + /* Handshake protocol layer */ + + enum tls_handshake_state state; + struct l_checksum *handshake_hash[__HANDSHAKE_HASH_COUNT]; + uint8_t prev_digest[__HANDSHAKE_HASH_COUNT][HANDSHAKE_HASH_MAX_SIZE]; + + enum l_tls_version client_version; + enum l_tls_version negotiated_version; + bool cert_requested, cert_sent; + bool peer_authenticated; + struct l_cert *peer_cert; + struct l_key *peer_pubkey; + size_t peer_pubkey_size; + enum handshake_hash_type signature_hash; + const struct tls_hash_algorithm *prf_hmac; + const struct tls_named_group *negotiated_curve; + const struct tls_named_group *negotiated_ff_group; + + uint8_t session_id[32]; + size_t session_id_size; + uint8_t session_id_replaced[32]; + size_t session_id_size_replaced; + bool session_id_new; + uint8_t session_cipher_suite_id[2]; + uint8_t session_compression_method_id; + char *session_peer_identity; + bool session_resumed; + + struct { + bool secure_renegotiation; + /* Max .verify_data_length over supported cipher suites */ + uint8_t client_verify_data[12]; + uint8_t server_verify_data[12]; + } renegotiation_info; + + /* SecurityParameters current and pending */ + + struct { + struct tls_cipher_suite *cipher_suite; + struct tls_compression_method *compression_method; + uint8_t master_secret[48]; + uint8_t client_random[32]; + uint8_t server_random[32]; + /* + * Max key block size per 6.3 v1.1 is 136 bytes but if we + * allow AES_256_CBC_SHA256 with v1.0 we get 128 per section + * 6.3 v1.2 + two IVs of 32 bytes. + */ + uint8_t key_block[192]; + void *key_xchg_params; + } pending; + + enum tls_cipher_type cipher_type[2]; + struct tls_cipher_suite *cipher_suite[2]; + union { + struct l_cipher *cipher[2]; + struct l_aead_cipher *aead_cipher[2]; + }; + struct l_checksum *mac[2]; + size_t mac_length[2]; + size_t block_length[2]; + size_t record_iv_length[2]; + size_t fixed_iv_length[2]; + uint8_t fixed_iv[2][32]; + size_t auth_tag_length[2]; + uint64_t seq_num[2]; + /* + * Some of the key and IV parts of the "current" state are kept + * inside the cipher and mac states in the kernel so we don't + * duplicate them here. + */ + + bool ready; +}; + +bool tls10_prf(const void *secret, size_t secret_len, + const char *label, + const void *seed, size_t seed_len, + uint8_t *out, size_t out_len); + +bool tls12_prf(enum l_checksum_type type, + const void *secret, size_t secret_len, + const char *label, + const void *seed, size_t seed_len, + uint8_t *out, size_t out_len); + +void tls_disconnect(struct l_tls *tls, enum l_tls_alert_desc desc, + enum l_tls_alert_desc local_desc); + +void tls_tx_record(struct l_tls *tls, enum tls_content_type type, + const uint8_t *data, size_t len); +bool tls_handle_message(struct l_tls *tls, const uint8_t *message, + int len, enum tls_content_type type, uint16_t version); + +#define TLS_HANDSHAKE_HEADER_SIZE 4 + +void tls_tx_handshake(struct l_tls *tls, int type, uint8_t *buf, size_t length); + +bool tls_cipher_suite_is_compatible(struct l_tls *tls, + const struct tls_cipher_suite *suite, + const char **error); + +/* Optionally limit allowed cipher suites to a custom set */ +bool tls_set_cipher_suites(struct l_tls *tls, const char **suite_list); + +void tls_generate_master_secret(struct l_tls *tls, + const uint8_t *pre_master_secret, + int pre_master_secret_len); + +size_t tls_verify_data_length(struct l_tls *tls, unsigned int index); + +const struct tls_named_group *tls_find_group(uint16_t id); +const struct tls_named_group *tls_find_ff_group(const uint8_t *prime, + size_t prime_len, + const uint8_t *generator, + size_t generator_len); + +ssize_t tls_write_signature_algorithms(struct l_tls *tls, + uint8_t *buf, size_t len); +ssize_t tls_parse_signature_algorithms(struct l_tls *tls, + const uint8_t *buf, size_t len); + +int tls_parse_certificate_list(const void *data, size_t len, + struct l_certchain **out_certchain); + +#define TLS_DEBUG(fmt, args...) \ + l_util_debug(tls->debug_handler, tls->debug_data, "%s:%i " fmt, \ + __func__, __LINE__, ## args) +#define TLS_SET_STATE(new_state) \ + do { \ + TLS_DEBUG("New state %s", \ + tls_handshake_state_to_str(new_state)); \ + tls->state = new_state; \ + } while (0) +#define TLS_DISCONNECT(desc, local_desc, fmt, args...) \ + do { \ + TLS_DEBUG("Disconnect desc=%s local-desc=%s reason=" fmt,\ + l_tls_alert_to_str(desc), \ + l_tls_alert_to_str(local_desc), ## args);\ + tls_disconnect(tls, desc, local_desc); \ + } while (0) + +#define TLS_VER_FMT "1.%i" +#define TLS_VER_ARGS(version) (((version) & 0xff) - 1) + +const char *tls_handshake_state_to_str(enum tls_handshake_state state); diff --git a/ell/tls-record.c b/ell/tls-record.c new file mode 100644 index 0000000000000000000000000000000000000000..b0471f8712456c83cf41b6ea9f1831144b3d0a9e --- /dev/null +++ b/ell/tls-record.c @@ -0,0 +1,629 @@ +/* + * Embedded Linux library + * Copyright (C) 2015 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <alloca.h> + +#include "private.h" +#include "tls.h" +#include "checksum.h" +#include "cipher.h" +#include "cert.h" +#include "tls-private.h" +#include "random.h" + +/* Implementation-specific max Record Layer fragment size (must be < 16kB) */ +#define TX_RECORD_MAX_LEN 4096 + +/* TLSPlaintext + TLSCompressed + TLSCiphertext headers + seq_num sizes */ +#define TX_RECORD_MAX_HEADERS (5 + 5 + 8 + 5) +#define TX_RECORD_MAX_MAC 64 + +/* Head room and tail room for the buffer passed to the cipher */ +#define TX_RECORD_HEADROOM TX_RECORD_MAX_HEADERS +#define TX_RECORD_TAILROOM TX_RECORD_MAX_MAC + +static void tls_write_mac(struct l_tls *tls, uint8_t *compressed, + uint16_t compressed_len, uint8_t *out_buf, + bool txrx) +{ + uint8_t *in_buf; + + /* Prepend the sequence number to the TLSCompressed buffer */ + in_buf = compressed - 8; + l_put_be64(tls->seq_num[txrx]++, in_buf); + + if (tls->mac[txrx]) { + l_checksum_reset(tls->mac[txrx]); + l_checksum_update(tls->mac[txrx], in_buf, compressed_len + 8); + l_checksum_get_digest(tls->mac[txrx], out_buf, + tls->mac_length[txrx]); + } +} + +static void tls_tx_record_plaintext(struct l_tls *tls, + uint8_t *plaintext, + uint16_t plaintext_len) +{ + uint8_t *compressed; + uint16_t compressed_len; + uint8_t *cipher_input; + uint16_t cipher_input_len; + uint8_t *ciphertext; + uint16_t ciphertext_len; + uint8_t padding_length; + uint8_t buf[TX_RECORD_HEADROOM + TX_RECORD_MAX_LEN + + TX_RECORD_TAILROOM]; + uint8_t iv[32]; + uint8_t *assocdata; + int offset; + + /* + * TODO: if DEFLATE is selected in current state, use a new buffer + * on stack to write a TLSCompressed structure there, otherwise use + * the provided buffer. Since only null compression is supported + * today we always use the provided buffer. + */ + compressed_len = plaintext_len - 5; + compressed = plaintext; + + /* Build a TLSCompressed struct */ + compressed[0] = plaintext[0]; /* Copy type and version fields */ + compressed[1] = plaintext[1]; + compressed[2] = plaintext[2]; + compressed[3] = compressed_len >> 8; + compressed[4] = compressed_len >> 0; + + switch (tls->cipher_type[1]) { + case TLS_CIPHER_STREAM: + /* Append the MAC after TLSCompressed.fragment, if needed */ + tls_write_mac(tls, compressed, compressed_len + 5, + compressed + compressed_len + 5, true); + + cipher_input = compressed + 5; + cipher_input_len = compressed_len + tls->mac_length[1]; + + if (!tls->cipher[1]) { + ciphertext = cipher_input; + ciphertext_len = cipher_input_len; + } else { + ciphertext = buf + TX_RECORD_HEADROOM; + ciphertext_len = cipher_input_len; + l_cipher_encrypt(tls->cipher[1], cipher_input, + ciphertext, cipher_input_len); + } + + break; + + case TLS_CIPHER_BLOCK: + /* Append the MAC after TLSCompressed.fragment, if needed */ + cipher_input = compressed + 5; + tls_write_mac(tls, compressed, compressed_len + 5, + cipher_input + compressed_len, true); + cipher_input_len = compressed_len + tls->mac_length[1]; + + /* Add minimum padding */ + padding_length = (~cipher_input_len) & + (tls->block_length[1] - 1); + memset(cipher_input + cipher_input_len, padding_length, + padding_length + 1); + cipher_input_len += padding_length + 1; + + /* Generate an IV */ + ciphertext = buf + TX_RECORD_HEADROOM; + + offset = 0; + + if (tls->negotiated_version >= L_TLS_V12) { + l_getrandom(ciphertext, tls->record_iv_length[1]); + + l_cipher_set_iv(tls->cipher[1], ciphertext, + tls->record_iv_length[1]); + + offset = tls->record_iv_length[1]; + } else if (tls->negotiated_version >= L_TLS_V11) { + l_getrandom(iv, tls->record_iv_length[1]); + + l_cipher_encrypt(tls->cipher[1], iv, ciphertext, + tls->record_iv_length[1]); + + offset = tls->record_iv_length[1]; + } + + l_cipher_encrypt(tls->cipher[1], cipher_input, + ciphertext + offset, cipher_input_len); + ciphertext_len = offset + cipher_input_len; + + break; + + case TLS_CIPHER_AEAD: + /* Prepend seq_num to TLSCompressed.type + .version + .length */ + assocdata = compressed - 8; + l_put_be64(tls->seq_num[1]++, assocdata); + + cipher_input = compressed + 5; + cipher_input_len = compressed_len; + + /* + * Build the IV. The explicit part generation method is + * actually cipher suite-specific but our only AEAD cipher + * suites only require this part to be unique for each + * record. For future suites there may need to be a callback + * that generates the per-record IV or an enum for the suite + * to select one of a few IV types. + * + * Note kernel's rfc4106(gcm(...)) algorithm could potentially + * be used to build the IV. + */ + memcpy(iv, tls->fixed_iv[1], tls->fixed_iv_length[1]); + l_put_le64(tls->seq_num[1], iv + tls->fixed_iv_length[1]); + + if (tls->record_iv_length[1] > 8) + memset(iv + tls->fixed_iv_length[1] + 8, 42, + tls->record_iv_length[1] - 8); + + /* Build the GenericAEADCipher struct */ + ciphertext = buf + TX_RECORD_HEADROOM; + memcpy(ciphertext, iv + tls->fixed_iv_length[1], + tls->record_iv_length[1]); + l_aead_cipher_encrypt(tls->aead_cipher[1], + cipher_input, cipher_input_len, + assocdata, 13, + iv, tls->fixed_iv_length[1] + + tls->record_iv_length[1], + ciphertext + tls->record_iv_length[1], + cipher_input_len + + tls->auth_tag_length[1]); + + ciphertext_len = tls->record_iv_length[1] + + cipher_input_len + tls->auth_tag_length[1]; + + break; + + default: + return; + } + + /* Build a TLSCiphertext struct */ + ciphertext -= 5; + ciphertext[0] = plaintext[0]; /* Copy type and version fields */ + ciphertext[1] = plaintext[1]; + ciphertext[2] = plaintext[2]; + ciphertext[3] = ciphertext_len >> 8; + ciphertext[4] = ciphertext_len >> 0; + + tls->tx(ciphertext, ciphertext_len + 5, tls->user_data); +} + +void tls_tx_record(struct l_tls *tls, enum tls_content_type type, + const uint8_t *data, size_t len) +{ + uint8_t buf[TX_RECORD_HEADROOM + TX_RECORD_MAX_LEN + + TX_RECORD_TAILROOM]; + uint8_t *fragment, *plaintext; + uint16_t fragment_len; + uint16_t version = tls->negotiated_version ?: tls->min_version; + + if (type == TLS_CT_ALERT) + tls->record_flush = true; + + while (len) { + fragment = buf + TX_RECORD_HEADROOM; + fragment_len = len < TX_RECORD_MAX_LEN ? + len : TX_RECORD_MAX_LEN; + + /* Build a TLSPlaintext struct */ + plaintext = fragment - 5; + plaintext[0] = type; + plaintext[1] = (uint8_t) (version >> 8); + plaintext[2] = (uint8_t) (version >> 0); + plaintext[3] = fragment_len >> 8; + plaintext[4] = fragment_len >> 0; + memcpy(plaintext + 5, data, fragment_len); + + tls_tx_record_plaintext(tls, plaintext, fragment_len + 5); + + data += fragment_len; + len -= fragment_len; + } +} + +static bool tls_handle_plaintext(struct l_tls *tls, const uint8_t *plaintext, + int len, uint8_t type, uint16_t version) +{ + if (len > (1 << 14)) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "Plaintext message too long: %i", len); + return false; + } + + switch (type) { + case TLS_CT_CHANGE_CIPHER_SPEC: + case TLS_CT_APPLICATION_DATA: + return tls_handle_message(tls, plaintext, len, type, version); + + /* + * We need to perform input reassembly twice at different levels: + * once to make sure we're handling complete TLSCiphertext messages, + * in l_tls_handle_rx(), and again here so that the Alert and + * Handshake message type handlers deal with complete messages. + * This does not affect ChangeCipherSpec messages because they're + * just a single byte and there are never more than one such message + * in a row. Similarly it doesn't affect application data because + * the application is not guaranteed that message boundaries are + * preserved in any way and we don't know its message lengths anyway. + * It does affect Alert because these messages are 2 byte long and + * could potentially be split over two TLSPlaintext messages but + * there are never more than one Alert in a TLSPlaintext for the same + * reason as with ChangeCipherSpec. Handshake messages are the + * most affected although the need to do the reassembly twice still + * seems wasteful considering most of these messages are sent in + * plaintext and TLSCiphertext maps to TLSPlaintext records. + */ + case TLS_CT_ALERT: + case TLS_CT_HANDSHAKE: + break; + + default: + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "Unknown content type %i", type); + return false; + } + + if (tls->message_buf_len && type != tls->message_content_type) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "Message fragment type %i doesn't match " + "previous type %i", type, + tls->message_content_type); + return false; + } + + tls->message_content_type = type; + + while (1) { + int header_len, need_len; + int chunk_len; + + /* Do we have a full header in tls->message_buf? */ + header_len = (type == TLS_CT_ALERT) ? 2 : 4; + need_len = header_len; + + if (tls->message_buf_len >= header_len) { + if (type == TLS_CT_HANDSHAKE) { + uint32_t hs_len = (tls->message_buf[1] << 16) | + (tls->message_buf[2] << 8) | + (tls->message_buf[3] << 0); + if (hs_len > (1 << 14)) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, + 0, "Handshake message " + "too long: %i", + (int) hs_len); + return false; + } + + need_len += hs_len; + } + + /* Do we have a full structure? */ + if (tls->message_buf_len == need_len) { + if (!tls_handle_message(tls, tls->message_buf, + need_len, type, + version)) + return false; + + tls->message_buf_len = 0; + + if (tls->record_flush) + break; + + continue; + } + + if (!len) + break; + } + + /* Try to fill up tls->message_buf up to need_len */ + if (tls->message_buf_max_len < need_len) { + tls->message_buf_max_len = need_len; + tls->message_buf = + l_realloc(tls->message_buf, need_len); + } + + need_len -= tls->message_buf_len; + chunk_len = need_len; + if (len < chunk_len) + chunk_len = len; + + memcpy(tls->message_buf + tls->message_buf_len, plaintext, + chunk_len); + tls->message_buf_len += chunk_len; + plaintext += chunk_len; + len -= chunk_len; + + if (chunk_len < need_len) + break; + } + + return true; +} + +static bool tls_handle_ciphertext(struct l_tls *tls) +{ + uint8_t type; + uint16_t version; + uint16_t fragment_len; + uint8_t mac_buf[TX_RECORD_MAX_MAC], i, padding_len; + int cipher_output_len, error; + uint8_t *compressed; + int compressed_len; + uint8_t iv[32]; + uint8_t *assocdata; + + type = tls->record_buf[0]; + version = l_get_be16(tls->record_buf + 1); + fragment_len = l_get_be16(tls->record_buf + 3); + + if (fragment_len > (1 << 14) + 2048) { + TLS_DISCONNECT(TLS_ALERT_RECORD_OVERFLOW, 0, + "Record fragment too long: %u", fragment_len); + return false; + } + + if ((tls->negotiated_version && tls->negotiated_version != version) || + (!tls->negotiated_version && + tls->record_buf[1] != 0x03 /* Appending E.1 */)) { + TLS_DISCONNECT(TLS_ALERT_PROTOCOL_VERSION, 0, + "Record version mismatch: %02x", version); + return false; + } + + if (fragment_len < tls->mac_length[0]) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "Record fragment too short: %u", fragment_len); + return false; + } + + compressed = alloca(8 + 5 + fragment_len); + /* Copy the type and version fields */ + compressed[8] = type; + l_put_be16(version, compressed + 9); + + switch (tls->cipher_type[0]) { + case TLS_CIPHER_STREAM: + cipher_output_len = fragment_len; + compressed_len = cipher_output_len - tls->mac_length[0]; + l_put_be16(compressed_len, compressed + 11); + + if (!tls->cipher[0]) + memcpy(compressed + 13, tls->record_buf + 5, + cipher_output_len); + else if (!l_cipher_decrypt(tls->cipher[0], tls->record_buf + 5, + compressed + 13, + cipher_output_len)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Decrypting record fragment failed"); + return false; + } + + /* Calculate the MAC if needed */ + tls_write_mac(tls, compressed + 8, 5 + compressed_len, + mac_buf, false); + + if (memcmp(mac_buf, compressed + 13 + compressed_len, + tls->mac_length[0])) { + TLS_DISCONNECT(TLS_ALERT_BAD_RECORD_MAC, 0, + "Record fragment MAC mismatch"); + return false; + } + + compressed += 13; + + break; + + case TLS_CIPHER_BLOCK: + i = 0; + if (tls->negotiated_version >= L_TLS_V11) + i = tls->record_iv_length[0]; + + if (fragment_len <= tls->mac_length[0] + i) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "Record fragment too short: %u", + fragment_len); + return false; + } + + cipher_output_len = fragment_len - i; + + if (cipher_output_len % tls->block_length[0] != 0) { + /* + * In strict TLS 1.0 TLS_ALERT_DECRYPT_FAIL_RESERVED + * should be returned here but that was declared + * unsafe in the TLS 1.1 spec. + */ + TLS_DISCONNECT(TLS_ALERT_BAD_RECORD_MAC, 0, + "Fragment data len %i not a multiple " + "of block length %zi", + cipher_output_len, + tls->block_length[0]); + return false; + } + + if (tls->negotiated_version >= L_TLS_V12) { + if (!l_cipher_set_iv(tls->cipher[0], + tls->record_buf + 5, + tls->record_iv_length[0])) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Setting fragment IV failed"); + return false; + } + } else if (tls->negotiated_version >= L_TLS_V11) + if (!l_cipher_decrypt(tls->cipher[0], + tls->record_buf + 5, iv, + tls->record_iv_length[0])) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Setting fragment IV failed"); + return false; + } + + if (!l_cipher_decrypt(tls->cipher[0], tls->record_buf + 5 + i, + compressed + 13, cipher_output_len)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Fragment decryption failed"); + return false; + } + + /* + * RFC 5246, page 24: + * In order to defend against this attack, implementations + * MUST ensure that record processing time is essentially the + * same whether or not the padding is correct. In general, + * the best way to do this is to compute the MAC even if the + * padding is incorrect, and only then reject the packet. For + * instance, if the pad appears to be incorrect, the + * implementation might assume a zero-length pad and then + * compute the MAC. + */ + padding_len = compressed[13 + cipher_output_len - 1]; + error = 0; + if (padding_len + tls->mac_length[0] + 1 > + (size_t) cipher_output_len) { + /* + * In strict TLS 1.0 TLS_ALERT_DECRYPT_FAIL_RESERVED + * should be returned here but that was declared + * unsafe in the TLS 1.1 spec. + */ + padding_len = 0; + error = 1; + } + + compressed_len = cipher_output_len - 1 - padding_len - + tls->mac_length[0]; + l_put_be16(compressed_len, compressed + 11); + + error |= !l_secure_memeq(compressed + 13 + cipher_output_len - + 1 - padding_len, padding_len, + padding_len); + + /* Calculate the MAC if needed */ + tls_write_mac(tls, compressed + 8, 5 + compressed_len, + mac_buf, false); + + if ((tls->mac_length[0] && memcmp(mac_buf, compressed + 13 + + compressed_len, tls->mac_length[0])) || + error) { + TLS_DISCONNECT(TLS_ALERT_BAD_RECORD_MAC, 0, + "Record fragment MAC mismatch"); + return false; + } + + compressed += 13; + + break; + + case TLS_CIPHER_AEAD: + if (fragment_len <= tls->record_iv_length[0] + + tls->auth_tag_length[0]) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "Record fragment too short: %u", + fragment_len); + return false; + } + + compressed_len = fragment_len - tls->record_iv_length[0] - + tls->auth_tag_length[0]; + l_put_be16(compressed_len, compressed + 11); + + /* Prepend seq_num to TLSCompressed.type + .version + .length */ + assocdata = compressed; + l_put_be64(tls->seq_num[0]++, assocdata); + compressed += 13; + + /* Build the IV */ + memcpy(iv, tls->fixed_iv[0], tls->fixed_iv_length[0]); + memcpy(iv + tls->fixed_iv_length[0], tls->record_buf + 5, + tls->record_iv_length[0]); + + if (!l_aead_cipher_decrypt(tls->aead_cipher[0], + tls->record_buf + 5 + tls->record_iv_length[0], + fragment_len - tls->record_iv_length[0], + assocdata, 13, iv, tls->fixed_iv_length[0] + + tls->record_iv_length[0], + compressed, compressed_len)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Decrypting record fragment failed"); + return false; + } + + break; + + default: + return false; + } + + /* DEFLATE not supported so just pass on compressed / compressed_len */ + + return tls_handle_plaintext(tls, compressed, compressed_len, + type, version); +} + +LIB_EXPORT void l_tls_handle_rx(struct l_tls *tls, const uint8_t *data, + size_t len) +{ + int need_len; + int chunk_len; + + tls->record_flush = false; + + /* Reassemble TLSCiphertext structures from the received chunks */ + + while (1) { + /* Do we have a full header in tls->record_buf? */ + if (tls->record_buf_len >= 5) { + need_len = 5 + l_get_be16(tls->record_buf + 3); + + /* Do we have a full structure? */ + if (tls->record_buf_len == need_len) { + if (!tls_handle_ciphertext(tls)) + return; + + tls->record_buf_len = 0; + need_len = 5; + + if (tls->record_flush) + break; + } + + if (!len) + break; + } else + need_len = 5; + + /* Try to fill up tls->record_buf up to need_len */ + if (tls->record_buf_max_len < need_len) { + tls->record_buf_max_len = need_len; + tls->record_buf = l_realloc(tls->record_buf, need_len); + } + + need_len -= tls->record_buf_len; + chunk_len = need_len; + if (len < (size_t) chunk_len) + chunk_len = len; + + memcpy(tls->record_buf + tls->record_buf_len, data, chunk_len); + tls->record_buf_len += chunk_len; + data += chunk_len; + len -= chunk_len; + + if (chunk_len < need_len) + break; + } +} diff --git a/ell/tls-suites.c b/ell/tls-suites.c new file mode 100644 index 0000000000000000000000000000000000000000..eb023a6bf2c0e115a6813614cbdd8b7412b49959 --- /dev/null +++ b/ell/tls-suites.c @@ -0,0 +1,1458 @@ +/* + * Embedded Linux library + * Copyright (C) 2018 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <strings.h> + +#include "util.h" +#include "tls.h" +#include "cipher.h" +#include "checksum.h" +#include "cert.h" +#include "tls-private.h" +#include "key.h" +#include "random.h" +#include "ecc.h" +#include "ecdh.h" +#include "missing.h" + +enum signature_algorithm { + SIGNATURE_ALGORITHM_ANONYMOUS = 0, + SIGNATURE_ALGORITHM_RSA = 1, + SIGNATURE_ALGORITHM_DSA = 2, + SIGNATURE_ALGORITHM_ECDSA = 3, +}; + +static enum handshake_hash_type find_hash_by_id(uint8_t id) +{ + enum handshake_hash_type hash; + + for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) + if (tls_handshake_hash_data[hash].tls_id == id) + break; + + return hash; +} + +/* + * Sanitize DigitallySigned struct input, making sure the lengths + * are valid and correspond to what we expect. + * + * Returns: start of the opaque portion + */ +static const uint8_t *validate_digitally_signed(struct l_tls *tls, + const uint8_t *in, size_t in_len, + enum signature_algorithm expected_alg, + uint16_t *opaque_len) +{ + size_t offset = 2; + uint16_t len; + + if (tls->negotiated_version < L_TLS_V12) + offset = 0; + + if (in_len < offset + 2) + goto size_error; + + len = l_get_be16(in + offset); + if (len != in_len - offset - 2) + goto size_error; + + if (tls->negotiated_version >= L_TLS_V12) { + if (in[1] != expected_alg) { + TLS_DISCONNECT(TLS_ALERT_DECRYPT_ERROR, 0, + "Unknown signature algorithm %i", + in[1]); + + return NULL; + } + } + + *opaque_len = len; + return in + offset + 2; + +size_error: + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, "Signature msg too " + "short (%zi) or signature length doesn't match", + in_len); + return NULL; +} + +static bool tls_rsa_validate_cert_key(struct l_cert *cert) +{ + return l_cert_get_pubkey_type(cert) == L_CERT_KEY_RSA; +} + +static ssize_t tls_rsa_sign(struct l_tls *tls, uint8_t *out, size_t out_len, + tls_get_hash_t get_hash, + const uint8_t *data, size_t data_len) +{ + ssize_t result = -EMSGSIZE; + enum l_checksum_type sign_checksum_type; + uint8_t sign_input[HANDSHAKE_HASH_MAX_SIZE + 36]; + size_t sign_input_len; + uint8_t *ptr = out; + + if (!tls->priv_key || !tls->priv_key_size) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, TLS_ALERT_BAD_CERT, + "No private key loaded"); + + return -ENOKEY; + } + + if (tls->negotiated_version >= L_TLS_V12) { + const struct tls_hash_algorithm *hash_type = + &tls_handshake_hash_data[tls->signature_hash]; + + /* Build the DigitallySigned struct */ + if (out_len < 2) /* Is there space for the algorithm IDs */ + goto error; + + get_hash(tls, tls->signature_hash, data, data_len, + sign_input, &sign_input_len); + sign_checksum_type = hash_type->l_id; + + *ptr++ = hash_type->tls_id; + *ptr++ = 1; /* RSA_sign */ + out_len -= 2; + } else { + get_hash(tls, HANDSHAKE_HASH_MD5, data, data_len, + sign_input + 0, NULL); + get_hash(tls, HANDSHAKE_HASH_SHA1, data, data_len, + sign_input + 16, NULL); + sign_checksum_type = L_CHECKSUM_NONE; + sign_input_len = 36; + } + + if (out_len < tls->priv_key_size + 2) + goto error; + + l_put_be16(tls->priv_key_size, ptr); + result = l_key_sign(tls->priv_key, L_KEY_RSA_PKCS1_V1_5, + sign_checksum_type, sign_input, ptr + 2, + sign_input_len, tls->priv_key_size); + ptr += tls->priv_key_size + 2; + + if (result == (ssize_t) tls->priv_key_size) + return ptr - out; /* Success */ + +error: + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Signing the hash failed: %s", + strerror(-result)); + return result; +} + +static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t in_len, + tls_get_hash_t get_hash, + const uint8_t *data, size_t data_len) +{ + enum l_checksum_type sign_checksum_type; + uint8_t expected[HANDSHAKE_HASH_MAX_SIZE + 36]; + size_t expected_len; + const uint8_t *opaque; + uint16_t opaque_len; + bool success; + + opaque = validate_digitally_signed(tls, in, in_len, + SIGNATURE_ALGORITHM_RSA, &opaque_len); + if (!opaque) + return false; + + /* Only the default hash type supported */ + if (opaque_len != tls->peer_pubkey_size) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "Signature length %hu not equal %zi", + opaque_len, tls->peer_pubkey_size); + + return false; + } + + if (tls->negotiated_version >= L_TLS_V12) { + enum handshake_hash_type hash = find_hash_by_id(in[0]); + + if (hash == __HANDSHAKE_HASH_COUNT) { + TLS_DISCONNECT(TLS_ALERT_DECRYPT_ERROR, 0, + "Unknown hash type %i", in[0]); + return false; + } + + get_hash(tls, hash, data, data_len, expected, &expected_len); + sign_checksum_type = tls_handshake_hash_data[hash].l_id; + + /* + * Note: Next we let the l_key_verify's underlying kernel + * operation prepend the OID to the hash to build the + * DigestInfo struct. However according to 4.7 we need to + * support at least two forms of the signed content in the + * verification: + * - DigestInfo with NULL AlgorithmIdentifier.parameters, + * - DigestInfo with empty AlgorithmIdentifier.parameters, + * + * while the kernel only understands the former encoding. + * Note PKCS#1 versions 2.0 and later section A.2.4 do + * mandate NULL AlgorithmIdentifier.parameters. + * + * Additionally PKCS#1 v1.5 said BER is used in place of DER + * for DigestInfo encoding which adds more ambiguity in the + * encoding. + */ + } else { + get_hash(tls, HANDSHAKE_HASH_MD5, data, data_len, + expected + 0, NULL); + get_hash(tls, HANDSHAKE_HASH_SHA1, data, data_len, + expected + 16, NULL); + expected_len = 36; + sign_checksum_type = L_CHECKSUM_NONE; + + /* + * Note: Within the RSA padding for signatures PKCS#1 1.5 + * allows the block format to be either 0 or 1, while PKCS#1 + * v2.0+ mandates block type 1 making the signatures + * unambiguous. TLS 1.0 doesn't additionally specify which + * block type is to be used (TLS 1.2 does) meaning that both + * PKCS#1 v1.5 types are allowed. The l_key_verify's + * underlying kernel implementation only accepts block type + * 1. If this ever becomes an issue we'd need to go back to + * using L_KEY_RSA_RAW and our own PKCS#1 v1.5 verify logic. + */ + } + + success = l_key_verify(tls->peer_pubkey, L_KEY_RSA_PKCS1_V1_5, + sign_checksum_type, expected, opaque, + expected_len, tls->peer_pubkey_size); + + if (!success) + TLS_DISCONNECT(TLS_ALERT_DECRYPT_ERROR, 0, + "Peer signature verification failed"); + else + TLS_DEBUG("Peer signature verified"); + + return success; +} + +static struct tls_signature_algorithm tls_rsa_signature = { + .id = 1, /* SignatureAlgorithm.rsa */ + .validate_cert_key_type = tls_rsa_validate_cert_key, + .sign = tls_rsa_sign, + .verify = tls_rsa_verify, +}; + +static bool tls_ecdsa_validate_cert_key(struct l_cert *cert) +{ + return l_cert_get_pubkey_type(cert) == L_CERT_KEY_ECC; +} + +static bool tls_ecdsa_verify(struct l_tls *tls, + const uint8_t *in, size_t in_len, + tls_get_hash_t get_hash, + const uint8_t *data, size_t data_len) +{ + /* RFC 8422, Section 5.10: "SHA-1 is used in TLS 1.1 and earlier" */ + enum handshake_hash_type hash = HANDSHAKE_HASH_SHA1; + enum l_checksum_type sign_checksum_type; + const uint8_t *opaque; + uint16_t opaque_len; + uint8_t expected[HANDSHAKE_HASH_MAX_SIZE]; + size_t expected_len; + bool success; + + opaque = validate_digitally_signed(tls, in, in_len, + SIGNATURE_ALGORITHM_ECDSA, &opaque_len); + if (!opaque) + return false; + + if (tls->negotiated_version >= L_TLS_V12) { + hash = find_hash_by_id(in[0]); + if (hash == __HANDSHAKE_HASH_COUNT) { + TLS_DISCONNECT(TLS_ALERT_DECRYPT_ERROR, 0, + "Unknown hash type %i", in[0]); + return false; + } + + /* Hash should match the curve, refer to RFC 5480, Section 4 */ + switch (tls->peer_pubkey_size) { + case 32: + if (hash != HANDSHAKE_HASH_SHA256 && + hash != HANDSHAKE_HASH_SHA384) + goto bad_hash; + + break; + case 48: + if (hash != HANDSHAKE_HASH_SHA384) + goto bad_hash; + + break; + bad_hash: + default: + TLS_DISCONNECT(TLS_ALERT_DECRYPT_ERROR, 0, + "Invalid hash %i", + in[0]); + } + } + + get_hash(tls, hash, data, data_len, expected, &expected_len); + sign_checksum_type = tls_handshake_hash_data[hash].l_id; + + success = l_key_verify(tls->peer_pubkey, L_KEY_ECDSA_X962, + sign_checksum_type, expected, opaque, + expected_len, opaque_len); + + if (!success) + TLS_DISCONNECT(TLS_ALERT_DECRYPT_ERROR, 0, + "Peer signature verification failed"); + else + TLS_DEBUG("Peer signature verified"); + + return success; +} + +static struct tls_signature_algorithm tls_ecdsa_signature = { + .id = 3, /* SignatureAlgorithm.ecdsa */ + .validate_cert_key_type = tls_ecdsa_validate_cert_key, + .verify = tls_ecdsa_verify, +}; + +static bool tls_send_rsa_client_key_xchg(struct l_tls *tls) +{ + uint8_t buf[1024 + 32]; + uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; + uint8_t pre_master_secret[48]; + ssize_t bytes_encrypted; + + if (!tls->peer_pubkey) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Peer public key not received"); + + return false; + } + + /* Must match the version in tls_send_client_hello */ + pre_master_secret[0] = (uint8_t) (tls->client_version >> 8); + pre_master_secret[1] = (uint8_t) (tls->client_version >> 0); + + l_getrandom(pre_master_secret + 2, 46); + + if (tls->peer_pubkey_size + 32 > (int) sizeof(buf)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Peer public key too big: %zi", + tls->peer_pubkey_size); + + return false; + } + + l_put_be16(tls->peer_pubkey_size, ptr); + bytes_encrypted = l_key_encrypt(tls->peer_pubkey, + L_KEY_RSA_PKCS1_V1_5, L_CHECKSUM_NONE, + pre_master_secret, ptr + 2, 48, + tls->peer_pubkey_size); + ptr += tls->peer_pubkey_size + 2; + + if (bytes_encrypted != (ssize_t) tls->peer_pubkey_size) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Encrypting PreMasterSecret failed: %s", + strerror(-bytes_encrypted)); + + return false; + } + + tls_tx_handshake(tls, TLS_CLIENT_KEY_EXCHANGE, buf, ptr - buf); + + tls_generate_master_secret(tls, pre_master_secret, 48); + explicit_bzero(pre_master_secret, 48); + + return true; +} + +static void tls_handle_rsa_client_key_xchg(struct l_tls *tls, + const uint8_t *buf, size_t len) +{ + uint8_t pre_master_secret[48], random_secret[46]; + ssize_t bytes_decrypted; + + if (!tls->priv_key || !tls->priv_key_size) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, TLS_ALERT_BAD_CERT, + "No private key"); + + return; + } + + if (len != tls->priv_key_size + 2) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "ClientKeyExchange len %zi not %zi", len, + tls->priv_key_size + 2); + + return; + } + + len = l_get_be16(buf); + + if (len != tls->priv_key_size) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "EncryptedPreMasterSecret len %zi not %zi", + len, tls->priv_key_size); + + return; + } + + bytes_decrypted = l_key_decrypt(tls->priv_key, L_KEY_RSA_PKCS1_V1_5, + L_CHECKSUM_NONE, buf + 2, + pre_master_secret, tls->priv_key_size, + 48); + + /* + * Assume correct premaster secret client version which according + * to the TLS1.2 spec is unlikely in client implementations SSLv3 + * and prior. Spec suggests either not supporting them or adding + * a configurable override for <= SSLv3 clients. For now we have + * no need to support them. + * + * On any decode error randomise the Pre Master Secret as per the + * countermeasures in 7.4.7.1 and don't generate any alerts. + */ + l_getrandom(random_secret, 46); + + pre_master_secret[0] = tls->client_version >> 8; + pre_master_secret[1] = tls->client_version >> 0; + + if (bytes_decrypted != 48) { + memcpy(pre_master_secret + 2, random_secret, 46); + + TLS_DEBUG("Error decrypting PreMasterSecret: %s", + strerror(-bytes_decrypted)); + } + + tls_generate_master_secret(tls, pre_master_secret, 48); + explicit_bzero(pre_master_secret, 48); + explicit_bzero(random_secret, 46); +} + +static struct tls_key_exchange_algorithm tls_rsa_key_xchg = { + .send_client_key_exchange = tls_send_rsa_client_key_xchg, + .handle_client_key_exchange = tls_handle_rsa_client_key_xchg, +}; + +/* Used by both DHE and ECDHE */ +static bool tls_get_dh_params_hash(struct l_tls *tls, + enum handshake_hash_type type, + const uint8_t *data, size_t data_len, + uint8_t *out, size_t *out_len) +{ + struct l_checksum *checksum; + ssize_t ret; + + /* + * The ServerKeyExchange signature hash input format for RSA_sign is + * not really specified in either RFC 8422 or RFC 5246 explicitly + * but we use this format by analogy to DHE_RSA which uses RSA_sign + * as well. Also matches ecdsa, ed25519 and ed448 formats. + */ + struct iovec iov[] = { + { .iov_base = tls->pending.client_random, .iov_len = 32 }, + { .iov_base = tls->pending.server_random, .iov_len = 32 }, + { .iov_base = (void *) data, .iov_len = data_len }, + }; + + checksum = l_checksum_new(tls_handshake_hash_data[type].l_id); + if (!checksum) + return false; + + l_checksum_updatev(checksum, iov, L_ARRAY_SIZE(iov)); + ret = l_checksum_get_digest(checksum, out, HANDSHAKE_HASH_MAX_SIZE); + l_checksum_free(checksum); + + if (ret < 0) + return false; + + if (out_len) + *out_len = ret; + + return true; +} + +struct tls_ecdhe_params { + const struct l_ecc_curve *curve; + struct l_ecc_scalar *private; + struct l_ecc_point *public; +}; + +static void tls_free_ecdhe_params(struct l_tls *tls) +{ + struct tls_ecdhe_params *params = tls->pending.key_xchg_params; + + if (!params) + return; + + tls->pending.key_xchg_params = NULL; + + l_ecc_scalar_free(params->private); + l_ecc_point_free(params->public); + l_free(params); +} + +static size_t tls_write_ecpoint(uint8_t *buf, size_t len, + const struct tls_named_group *curve, + const struct l_ecc_point *point) +{ + size_t point_bytes; + + /* RFC 8422, Section 5.4.1 */ + point_bytes = l_ecc_point_get_data(point, buf + 2, len - 2); + buf[0] = 1 + point_bytes; /* length */ + buf[1] = 4; /* form: uncompressed */ + return 2 + point_bytes; +} + +static size_t tls_write_server_ecdh_params(struct l_tls *tls, uint8_t *buf, size_t len) +{ + struct tls_ecdhe_params *params = tls->pending.key_xchg_params; + + /* RFC 8422, Section 5.4 */ + buf[0] = 3; /* curve_type: named_curve */ + l_put_be16(tls->negotiated_curve->id, buf + 1); + return 3 + tls_write_ecpoint(buf + 3, len - 3, tls->negotiated_curve, + params->public); +} + +static bool tls_send_ecdhe_server_key_xchg(struct l_tls *tls) +{ + uint8_t buf[1024]; + uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; + struct tls_ecdhe_params *params; + ssize_t sign_len; + const uint8_t *server_ecdh_params_ptr; + + /* + * RFC 8422, Section 5.4 + * + * If we're getting here we can assume that tls->pending.key_xchg_params + * is NULL, tls->priv_key is our signing key and tls->negotiated_curve + * is non-NULL. + */ + + params = l_new(struct tls_ecdhe_params, 1); + params->curve = l_ecc_curve_from_tls_group(tls->negotiated_curve->id); + tls->pending.key_xchg_params = params; + + if (!l_ecdh_generate_key_pair(params->curve, + ¶ms->private, ¶ms->public)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Generating ECDH key pair failed"); + return false; + } + + server_ecdh_params_ptr = ptr; + ptr += tls_write_server_ecdh_params(tls, ptr, buf + sizeof(buf) - ptr); + + if (tls->pending.cipher_suite->signature) { + sign_len = tls->pending.cipher_suite->signature->sign(tls, ptr, + buf + sizeof(buf) - ptr, + tls_get_dh_params_hash, + server_ecdh_params_ptr, + ptr - server_ecdh_params_ptr); + if (sign_len < 0) + return false; + + ptr += sign_len; + } + + tls_tx_handshake(tls, TLS_SERVER_KEY_EXCHANGE, buf, ptr - buf); + + return true; +} + +static void tls_handle_ecdhe_server_key_xchg(struct l_tls *tls, + const uint8_t *buf, size_t len) +{ + struct tls_ecdhe_params *params; + uint16_t namedcurve; + const uint8_t *server_ecdh_params_ptr = buf; + size_t point_bytes; + + /* RFC 8422, Section 5.4 */ + + if (len < 5) + goto decode_error; + + if (*buf != 3) { + TLS_DISCONNECT(TLS_ALERT_ILLEGAL_PARAM, 0, + "Unsupported (deprecated?) ECCurveType %u", + *buf); + return; + } + + namedcurve = l_get_be16(buf + 1); + buf += 3; + len -= 3; + + tls->negotiated_curve = tls_find_group(namedcurve); + + if (!tls->negotiated_curve || + tls->negotiated_curve->type != TLS_GROUP_TYPE_EC) { + TLS_DISCONNECT(TLS_ALERT_ILLEGAL_PARAM, 0, + "Unsupported NamedCurve %u", namedcurve); + return; + } + + TLS_DEBUG("Negotiated %s", tls->negotiated_curve->name); + + if (*buf < 1) + goto decode_error; + + point_bytes = *buf++ - 1; + + if (*buf != 4) { /* uncompressed */ + TLS_DISCONNECT(TLS_ALERT_ILLEGAL_PARAM, 0, + "Unsupported (deprecated?) PointConversionForm " + "%u", *buf); + return; + } + + buf++; + len -= 2; + + if (len < point_bytes) + goto decode_error; + + /* + * RFC 8422, Section 5.11: "A receiving party MUST check that the + * x and y parameters from the peer's public value satisfy the + * curve equation, y^2 = x^3 + ax + b mod p." + * This happens in l_ecc_point_from_data when the L_ECC_POINT_TYPE_FULL + * format is used. + */ + params = l_new(struct tls_ecdhe_params, 1); + params->curve = l_ecc_curve_from_tls_group(tls->negotiated_curve->id); + params->public = l_ecc_point_from_data(params->curve, + L_ECC_POINT_TYPE_FULL, + buf, point_bytes); + tls->pending.key_xchg_params = params; + buf += point_bytes; + len -= point_bytes; + + if (!params->public || point_bytes != + 2 * l_ecc_curve_get_scalar_bytes(params->curve)) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "ServerKeyExchange.params.public decode error"); + return; + } + + if (tls->pending.cipher_suite->signature) { + if (!tls->pending.cipher_suite->signature->verify(tls, buf, len, + tls_get_dh_params_hash, + server_ecdh_params_ptr, + buf - server_ecdh_params_ptr)) + return; + } else { + if (len) + goto decode_error; + } + + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO_DONE); + + return; + +decode_error: + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "ServerKeyExchange decode error"); +} + +static bool tls_send_ecdhe_client_key_xchg(struct l_tls *tls) +{ + uint8_t buf[1024]; + uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; + uint8_t pre_master_secret[128]; + ssize_t pre_master_secret_len; + struct tls_ecdhe_params *params = tls->pending.key_xchg_params; + struct l_ecc_point *our_public; + struct l_ecc_scalar *secret; + + /* RFC 8422, Section 5.7 */ + + if (!l_ecdh_generate_key_pair(params->curve, + ¶ms->private, &our_public)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Generating ECDH key pair failed"); + return false; + } + + ptr += tls_write_ecpoint(ptr, buf + sizeof(buf) - ptr, + tls->negotiated_curve, our_public); + l_ecc_point_free(our_public); + + /* + * Neither 5.4 or 5.7 "Actions" paragraphs say when the ECDH shared + * secret is calculated but we can either do this in + * tls_handle_ecdhe_server_key_xchg or here. In both cases we only + * need to store the public key in the client's key_xchg_params and + * can free all of the params after sending the ClientKeyExchange. + * By doing this calculation here we're aligned with RSA and also + * with the server mode where the shared secret can only be + * calculated after the ClientKeyExchange is received. + */ + if (!l_ecdh_generate_shared_secret(params->private, params->public, + &secret)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Generating ECDH shared-secret failed"); + return false; + } + + tls_free_ecdhe_params(tls); + pre_master_secret_len = l_ecc_scalar_get_data(secret, + pre_master_secret, + sizeof(pre_master_secret)); + l_ecc_scalar_free(secret); + + if (pre_master_secret_len < 0) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "l_ecc_scalar_get_data(secret) failed"); + return false; + } + + tls_tx_handshake(tls, TLS_CLIENT_KEY_EXCHANGE, buf, ptr - buf); + + tls_generate_master_secret(tls, pre_master_secret, + pre_master_secret_len); + explicit_bzero(pre_master_secret, pre_master_secret_len); + + return true; +} + +static void tls_handle_ecdhe_client_key_xchg(struct l_tls *tls, + const uint8_t *buf, size_t len) +{ + struct tls_ecdhe_params *params = tls->pending.key_xchg_params; + uint8_t pre_master_secret[128]; + ssize_t pre_master_secret_len; + struct l_ecc_point *other_public; + struct l_ecc_scalar *secret; + size_t point_bytes = 2 * l_ecc_curve_get_scalar_bytes(params->curve); + + /* RFC 8422, Section 5.7 */ + + if (len < 2) + goto decode_error; + + if (*buf++ != 1 + point_bytes) + goto decode_error; + + if (*buf != 4) { /* uncompressed */ + TLS_DISCONNECT(TLS_ALERT_ILLEGAL_PARAM, 0, + "Unsupported (deprecated?) PointConversionForm " + "%u", *buf); + return; + } + + buf++; + len -= 2; + + if (len != point_bytes) + goto decode_error; + + /* + * RFC 8422, Section 5.11: "A receiving party MUST check that the + * x and y parameters from the peer's public value satisfy the + * curve equation, y^2 = x^3 + ax + b mod p." + * This happens in l_ecc_point_from_data when the L_ECC_POINT_TYPE_FULL + * format is used. + */ + other_public = l_ecc_point_from_data(params->curve, + L_ECC_POINT_TYPE_FULL, + buf, len); + if (!other_public) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "ClientKeyExchange.exchange_keys.ecdh_Yc " + "decode error"); + return; + } + + if (!l_ecdh_generate_shared_secret(params->private, other_public, + &secret)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Generating ECDH shared-secret failed"); + return; + } + + tls_free_ecdhe_params(tls); + l_ecc_point_free(other_public); + pre_master_secret_len = l_ecc_scalar_get_data(secret, + pre_master_secret, + sizeof(pre_master_secret)); + l_ecc_scalar_free(secret); + + if (pre_master_secret_len < 0) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "l_ecc_scalar_get_data(secret) failed"); + return; + } + + tls_generate_master_secret(tls, pre_master_secret, + pre_master_secret_len); + explicit_bzero(pre_master_secret, pre_master_secret_len); + + return; + +decode_error: + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "ClientKeyExchange decode error"); +} + +static struct tls_key_exchange_algorithm tls_ecdhe = { + .need_ecc = true, + .send_server_key_exchange = tls_send_ecdhe_server_key_xchg, + .handle_server_key_exchange = tls_handle_ecdhe_server_key_xchg, + .send_client_key_exchange = tls_send_ecdhe_client_key_xchg, + .handle_client_key_exchange = tls_handle_ecdhe_client_key_xchg, + .free_params = tls_free_ecdhe_params, +}; + +/* Maximum FF DH prime modulus size in bytes */ +#define TLS_DHE_MAX_SIZE 1024 + +struct tls_dhe_params { + size_t prime_len; + struct l_key *prime; + struct l_key *generator; + struct l_key *private; + struct l_key *public; +}; + +static void tls_free_dhe_params(struct l_tls *tls) +{ + struct tls_dhe_params *params = tls->pending.key_xchg_params; + + if (!params) + return; + + tls->pending.key_xchg_params = NULL; + + l_key_free(params->prime); + l_key_free(params->generator); + l_key_free(params->private); + l_key_free(params->public); + l_free(params); +} + +static bool tls_send_dhe_server_key_xchg(struct l_tls *tls) +{ + uint8_t buf[1024 + TLS_DHE_MAX_SIZE * 3]; + uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; + struct tls_dhe_params *params; + const uint8_t *prime_buf; + uint8_t generator_buf = tls->negotiated_ff_group->ff.generator; + uint8_t public_buf[TLS_DHE_MAX_SIZE]; + size_t public_len; + unsigned int zeros = 0; + ssize_t sign_len; + const uint8_t *server_dh_params_ptr; + + params = l_new(struct tls_dhe_params, 1); + prime_buf = tls->negotiated_ff_group->ff.prime; + params->prime_len = tls->negotiated_ff_group->ff.prime_len; + + params->prime = l_key_new(L_KEY_RAW, prime_buf, params->prime_len); + params->generator = l_key_new(L_KEY_RAW, &generator_buf, 1); + + if (!params->prime || !params->generator) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, "l_key_new failed"); + goto free_params; + } + + params->private = l_key_generate_dh_private(prime_buf, params->prime_len); + if (!params->private) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "l_key_generate_dh_private failed"); + goto free_params; + } + + memset(public_buf, 0, sizeof(public_buf)); + public_len = params->prime_len; + + if (!l_key_compute_dh_public(params->generator, params->private, + params->prime, public_buf, + &public_len)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "l_key_compute_dh_public failed"); + goto free_params; + } + + while (zeros < public_len && public_buf[zeros] == 0x00) + zeros++; + + server_dh_params_ptr = ptr; + + /* RFC 5246, Section 7.4.3 */ + + l_put_be16(params->prime_len, ptr); + memcpy(ptr + 2, prime_buf, params->prime_len); + ptr += 2 + params->prime_len; + + l_put_be16(1, ptr); + memcpy(ptr + 2, &generator_buf, 1); + ptr += 2 + 1; + + l_put_be16(public_len - zeros, ptr); + memcpy(ptr + 2, public_buf + zeros, public_len - zeros); + ptr += 2 + public_len - zeros; + + if (tls->pending.cipher_suite->signature) { + sign_len = tls->pending.cipher_suite->signature->sign(tls, ptr, + buf + sizeof(buf) - ptr, + tls_get_dh_params_hash, + server_dh_params_ptr, + ptr - server_dh_params_ptr); + if (sign_len < 0) + goto free_params; + + ptr += sign_len; + } + + tls->pending.key_xchg_params = params; + + tls_tx_handshake(tls, TLS_SERVER_KEY_EXCHANGE, buf, ptr - buf); + return true; + +free_params: + l_key_free(params->prime); + l_key_free(params->generator); + l_key_free(params->private); + l_free(params); + return false; +} + +static void tls_handle_dhe_server_key_xchg(struct l_tls *tls, + const uint8_t *buf, size_t len) +{ + struct tls_dhe_params *params = NULL; + const uint8_t *prime_buf; + const uint8_t *generator_buf; + size_t generator_len; + const uint8_t *public_buf; + size_t public_len; + const uint8_t *server_dh_params_ptr = buf; + + if (len < 2) + goto decode_error; + + params = l_new(struct tls_dhe_params, 1); + params->prime_len = l_get_be16(buf); + if (len < 2 + params->prime_len + 2) + goto decode_error; + + prime_buf = buf + 2; + buf += 2 + params->prime_len; + len -= 2 + params->prime_len; + + /* Strip leading zeros for the length checks later */ + while (params->prime_len && prime_buf[0] == 0x00) { + prime_buf++; + params->prime_len--; + } + + generator_len = l_get_be16(buf); + if (len < 2 + generator_len + 2) + goto decode_error; + + generator_buf = buf + 2; + buf += 2 + generator_len; + len -= 2 + generator_len; + + public_len = l_get_be16(buf); + if (len < 2 + public_len) + goto decode_error; + + public_buf = buf + 2; + buf += 2 + public_len; + len -= 2 + public_len; + + /* + * Validate the values received. Without requiring RFC 7919 from + * the server, and there are many servers that don't implement it + * yet, we basically have to blindly accept the provided prime value. + * We have no way to confirm that it's actually prime or that it's a + * "safe prime" or that it forms a group without small sub-groups. + * There's also no way to whitelist all valid values. But we do a + * basic sanity check and require it to be 1536-bit or longer, the + * minimum length required by the Linux kernel for keyctl_dh_compute(). + * The generator must also be at least within the min & max interval + * for the private/public values. + */ + + if (params->prime_len > TLS_DHE_MAX_SIZE || params->prime_len < 192 || + !(prime_buf[params->prime_len - 1] & 1)) { + TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, + "Server DH prime modulus invalid"); + goto free_params; + } + + if (!l_key_validate_dh_payload(generator_buf, generator_len, + prime_buf, params->prime_len)) { + TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, + "Server DH generator value invalid"); + goto free_params; + } + + /* + * Just output a warning if the server sent group parameters not + * offered in our RFC 7919 Supported Groups extension. + */ + if (!tls_find_ff_group(prime_buf, params->prime_len, + generator_buf, generator_len)) + TLS_DEBUG("Warning: using server's custom %i-bit FF DH group", + (int) (params->prime_len * 8)); + + /* + * RFC 7919 Section 3.0: + * "the client MUST verify that dh_Ys is in the range + * 1 < dh_Ys < dh_p - 1. If dh_Ys is not in this range, the client + * MUST terminate the connection with a fatal handshake_failure(40) + * alert." + */ + if (!l_key_validate_dh_payload(public_buf, public_len, + prime_buf, params->prime_len)) { + TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, + "Server DH public value invalid"); + goto free_params; + } + + params->prime = l_key_new(L_KEY_RAW, prime_buf, params->prime_len); + params->generator = l_key_new(L_KEY_RAW, generator_buf, generator_len); + params->public = l_key_new(L_KEY_RAW, public_buf, public_len); + + if (!params->prime || !params->generator || !params->public) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, "l_key_new failed"); + goto free_params; + } + + /* Do this now so we don't need prime_buf in send_client_key_xchg */ + params->private = l_key_generate_dh_private(prime_buf, params->prime_len); + if (!params->private) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "l_key_generate_dh_private failed"); + goto free_params; + } + + tls->pending.key_xchg_params = params; + + if (tls->pending.cipher_suite->signature) { + if (!tls->pending.cipher_suite->signature->verify(tls, buf, len, + tls_get_dh_params_hash, + server_dh_params_ptr, + buf - server_dh_params_ptr)) + return; + } else { + if (len) + goto decode_error; + } + + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO_DONE); + return; + +decode_error: + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "ServerKeyExchange decode error"); + +free_params: + if (params) { + l_key_free(params->prime); + l_key_free(params->generator); + l_key_free(params->public); + l_free(params); + } +} + +static bool tls_send_dhe_client_key_xchg(struct l_tls *tls) +{ + struct tls_dhe_params *params = tls->pending.key_xchg_params; + uint8_t buf[128 + params->prime_len]; + uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; + uint8_t public_buf[params->prime_len]; + size_t public_len; + unsigned int zeros = 0; + uint8_t pre_master_secret[params->prime_len]; + size_t pre_master_secret_len; + + public_len = params->prime_len; + memset(public_buf, 0, sizeof(public_buf)); + + if (!l_key_compute_dh_public(params->generator, params->private, + params->prime, public_buf, + &public_len)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "l_key_compute_dh_public failed"); + return false; + } + + while (zeros < public_len && public_buf[zeros] == 0x00) + zeros++; + + l_put_be16(public_len - zeros, ptr); + memcpy(ptr + 2, public_buf + zeros, public_len - zeros); + ptr += 2 + public_len - zeros; + + pre_master_secret_len = params->prime_len; + zeros = 0; + + if (!l_key_compute_dh_secret(params->public, params->private, + params->prime, pre_master_secret, + &pre_master_secret_len)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Generating DH shared-secret failed"); + return false; + } + + while (zeros < pre_master_secret_len && + pre_master_secret[zeros] == 0x00) + zeros++; + + tls_tx_handshake(tls, TLS_CLIENT_KEY_EXCHANGE, buf, ptr - buf); + + tls_free_dhe_params(tls); + tls_generate_master_secret(tls, pre_master_secret + zeros, + pre_master_secret_len - zeros); + explicit_bzero(pre_master_secret, pre_master_secret_len); + return true; +} + +static void tls_handle_dhe_client_key_xchg(struct l_tls *tls, + const uint8_t *buf, size_t len) +{ + struct tls_dhe_params *params = tls->pending.key_xchg_params; + uint8_t pre_master_secret[params->prime_len]; + size_t pre_master_secret_len; + size_t public_len; + unsigned int zeros = 0; + + if (len < 2) + goto decode_error; + + public_len = l_get_be16(buf); + buf += 2; + len -= 2; + + if (public_len != len) + goto decode_error; + + /* + * RFC 7919 Section 4: + * "the server MUST verify that 1 < dh_Yc < dh_p - 1. If dh_Yc is + * out of range, the server MUST terminate the connection with + * a fatal handshake_failure(40) alert." + */ + if (!l_key_validate_dh_payload(buf, public_len, + tls->negotiated_ff_group->ff.prime, + params->prime_len)) { + TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, + "Client DH public value invalid"); + return; + } + + params->public = l_key_new(L_KEY_RAW, buf, public_len); + if (!params->public) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, "l_key_new failed"); + return; + } + + pre_master_secret_len = params->prime_len; + + if (!l_key_compute_dh_secret(params->public, params->private, + params->prime, pre_master_secret, + &pre_master_secret_len)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Generating DH shared-secret failed"); + return; + } + + while (zeros < pre_master_secret_len && + pre_master_secret[zeros] == 0x00) + zeros++; + + tls_free_dhe_params(tls); + tls_generate_master_secret(tls, pre_master_secret + zeros, + pre_master_secret_len - zeros); + explicit_bzero(pre_master_secret, pre_master_secret_len); + return; + +decode_error: + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "ClientKeyExchange decode error"); +} + +static struct tls_key_exchange_algorithm tls_dhe = { + .need_ecc = true, + .send_server_key_exchange = tls_send_dhe_server_key_xchg, + .handle_server_key_exchange = tls_handle_dhe_server_key_xchg, + .send_client_key_exchange = tls_send_dhe_client_key_xchg, + .handle_client_key_exchange = tls_handle_dhe_client_key_xchg, + .free_params = tls_free_dhe_params, +}; + +static struct tls_bulk_encryption_algorithm tls_aes128 = { + .cipher_type = TLS_CIPHER_BLOCK, + .l_id = L_CIPHER_AES_CBC, + .key_length = 16, + .iv_length = 16, + .block_length = 16, +}, tls_aes256 = { + .cipher_type = TLS_CIPHER_BLOCK, + .l_id = L_CIPHER_AES_CBC, + .key_length = 32, + .iv_length = 16, + .block_length = 16, +}, tls_3des_ede = { + .cipher_type = TLS_CIPHER_BLOCK, + .l_id = L_CIPHER_DES3_EDE_CBC, + .key_length = 24, + .iv_length = 8, + .block_length = 8, +}, tls_aes128_gcm = { + .cipher_type = TLS_CIPHER_AEAD, + .l_aead_id = L_AEAD_CIPHER_AES_GCM, + .key_length = 16, + .iv_length = 12, + .fixed_iv_length = 4, + .auth_tag_length = 16, +}, tls_aes256_gcm = { + .cipher_type = TLS_CIPHER_AEAD, + .l_aead_id = L_AEAD_CIPHER_AES_GCM, + .key_length = 32, + .iv_length = 12, + .fixed_iv_length = 4, + .auth_tag_length = 16, +}; + +static struct tls_mac_algorithm tls_sha = { + .id = 2, + .hmac_type = L_CHECKSUM_SHA1, + .mac_length = 20, +}, tls_sha256 = { + .id = 4, + .hmac_type = L_CHECKSUM_SHA256, + .mac_length = 32, +}, tls_sha384 = { + .id = 5, + .hmac_type = L_CHECKSUM_SHA384, + .mac_length = 48, +}; + +static struct tls_cipher_suite tls_rsa_with_3des_ede_cbc_sha = { + .id = { 0x00, 0x0a }, + .name = "TLS_RSA_WITH_3DES_EDE_CBC_SHA", + .encryption = &tls_3des_ede, + .mac = &tls_sha, + .signature = &tls_rsa_signature, + .key_xchg = &tls_rsa_key_xchg, +}, tls_dhe_rsa_with_3des_ede_cbc_sha = { + .id = { 0x00, 0x16 }, + .name = "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", + .encryption = &tls_3des_ede, + .mac = &tls_sha, + .signature = &tls_rsa_signature, + .key_xchg = &tls_dhe, +}, tls_rsa_with_aes_128_cbc_sha = { + .id = { 0x00, 0x2f }, + .name = "TLS_RSA_WITH_AES_128_CBC_SHA", + .encryption = &tls_aes128, + .mac = &tls_sha, + .signature = &tls_rsa_signature, + .key_xchg = &tls_rsa_key_xchg, +}, tls_dhe_rsa_with_aes_128_cbc_sha = { + .id = { 0x00, 0x33 }, + .name = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", + .encryption = &tls_aes128, + .mac = &tls_sha, + .signature = &tls_rsa_signature, + .key_xchg = &tls_dhe, +}, tls_rsa_with_aes_256_cbc_sha = { + .id = { 0x00, 0x35 }, + .name = "TLS_RSA_WITH_AES_256_CBC_SHA", + .encryption = &tls_aes256, + .mac = &tls_sha, + .signature = &tls_rsa_signature, + .key_xchg = &tls_rsa_key_xchg, +}, tls_dhe_rsa_with_aes_256_cbc_sha = { + .id = { 0x00, 0x39 }, + .name = "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", + .encryption = &tls_aes256, + .mac = &tls_sha, + .signature = &tls_rsa_signature, + .key_xchg = &tls_dhe, +}, tls_rsa_with_aes_128_cbc_sha256 = { + .id = { 0x00, 0x3c }, + .name = "TLS_RSA_WITH_AES_128_CBC_SHA256", + .encryption = &tls_aes128, + .mac = &tls_sha256, + .signature = &tls_rsa_signature, + .key_xchg = &tls_rsa_key_xchg, +}, tls_rsa_with_aes_256_cbc_sha256 = { + .id = { 0x00, 0x3d }, + .name = "TLS_RSA_WITH_AES_256_CBC_SHA256", + .encryption = &tls_aes256, + .mac = &tls_sha256, + .signature = &tls_rsa_signature, + .key_xchg = &tls_rsa_key_xchg, +}, tls_dhe_rsa_with_aes_128_cbc_sha256 = { + .id = { 0x00, 0x67 }, + .name = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", + .encryption = &tls_aes128, + .mac = &tls_sha256, + .signature = &tls_rsa_signature, + .key_xchg = &tls_dhe, +}, tls_dhe_rsa_with_aes_256_cbc_sha256 = { + .id = { 0x00, 0x6b }, + .name = "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", + .encryption = &tls_aes256, + .mac = &tls_sha256, + .signature = &tls_rsa_signature, + .key_xchg = &tls_dhe, +}, tls_rsa_with_aes_128_gcm_sha256 = { + .id = { 0x00, 0x9c }, + .name = "TLS_RSA_WITH_AES_128_GCM_SHA256", + .encryption = &tls_aes128_gcm, + .signature = &tls_rsa_signature, + .key_xchg = &tls_rsa_key_xchg, +}, tls_rsa_with_aes_256_gcm_sha384 = { + .id = { 0x00, 0x9d }, + .name = "TLS_RSA_WITH_AES_256_GCM_SHA384", + .encryption = &tls_aes256_gcm, + .prf_hmac = L_CHECKSUM_SHA384, + .signature = &tls_rsa_signature, + .key_xchg = &tls_rsa_key_xchg, +}, tls_dhe_rsa_with_aes_128_gcm_sha256 = { + .id = { 0x00, 0x9e }, + .name = "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", + .encryption = &tls_aes128_gcm, + .signature = &tls_rsa_signature, + .key_xchg = &tls_dhe, +}, tls_dhe_rsa_with_aes_256_gcm_sha384 = { + .id = { 0x00, 0x9f }, + .name = "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", + .encryption = &tls_aes256_gcm, + .prf_hmac = L_CHECKSUM_SHA384, + .signature = &tls_rsa_signature, + .key_xchg = &tls_dhe, +}, tls_ecdhe_rsa_with_3des_ede_cbc_sha = { + .id = { 0xc0, 0x12 }, + .name = "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", + .encryption = &tls_3des_ede, + .mac = &tls_sha, + .signature = &tls_rsa_signature, + .key_xchg = &tls_ecdhe, +}, tls_ecdhe_rsa_with_aes_128_cbc_sha = { + .id = { 0xc0, 0x13 }, + .name = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + .encryption = &tls_aes128, + .mac = &tls_sha, + .signature = &tls_rsa_signature, + .key_xchg = &tls_ecdhe, +}, tls_ecdhe_rsa_with_aes_256_cbc_sha = { + .id = { 0xc0, 0x14 }, + .name = "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + .encryption = &tls_aes256, + .mac = &tls_sha, + .signature = &tls_rsa_signature, + .key_xchg = &tls_ecdhe, +}, tls_ecdhe_rsa_with_aes_128_cbc_sha256 = { + .id = { 0xc0, 0x27 }, + .name = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", + .encryption = &tls_aes128, + .mac = &tls_sha256, + .signature = &tls_rsa_signature, + .key_xchg = &tls_ecdhe, +}, tls_ecdhe_rsa_with_aes_256_cbc_sha384 = { + .id = { 0xc0, 0x28 }, + .name = "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", + .encryption = &tls_aes256, + .mac = &tls_sha384, + .prf_hmac = L_CHECKSUM_SHA384, + .signature = &tls_rsa_signature, + .key_xchg = &tls_ecdhe, +}, tls_ecdhe_rsa_with_aes_128_gcm_sha256 = { + .id = { 0xc0, 0x2f }, + .name = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + .encryption = &tls_aes128_gcm, + .signature = &tls_rsa_signature, + .key_xchg = &tls_ecdhe, +}, tls_ecdhe_rsa_with_aes_256_gcm_sha384 = { + .id = { 0xc0, 0x30 }, + .name = "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + .encryption = &tls_aes256_gcm, + .prf_hmac = L_CHECKSUM_SHA384, + .signature = &tls_rsa_signature, + .key_xchg = &tls_ecdhe, +}, tls_ecdhe_ecdsa_with_3des_ede_cbc_sha = { + .id = { 0xc0, 0x08 }, + .name = "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", + .encryption = &tls_3des_ede, + .mac = &tls_sha, + .signature = &tls_ecdsa_signature, + .key_xchg = &tls_ecdhe, +}, tls_ecdhe_ecdsa_with_aes_128_cbc_sha = { + .id = { 0xc0, 0x09 }, + .name = "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + .encryption = &tls_aes128, + .mac = &tls_sha, + .signature = &tls_ecdsa_signature, + .key_xchg = &tls_ecdhe, +}, tls_ecdhe_ecdsa_with_aes_256_cbc_sha = { + .id = { 0xc0, 0x0a }, + .name = "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + .encryption = &tls_aes256, + .mac = &tls_sha, + .signature = &tls_ecdsa_signature, + .key_xchg = &tls_ecdhe, +}, tls_ecdhe_ecdsa_with_aes_128_gcm_sha256 = { + .id = { 0xc0, 0x2b }, + .name = "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + .encryption = &tls_aes128_gcm, + .signature = &tls_ecdsa_signature, + .key_xchg = &tls_ecdhe, +}, tls_ecdhe_ecdsa_with_aes_256_gcm_sha384 = { + .id = { 0xc0, 0x2c }, + .name = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + .encryption = &tls_aes256_gcm, + .prf_hmac = L_CHECKSUM_SHA384, + .signature = &tls_ecdsa_signature, + .key_xchg = &tls_ecdhe, +}; + +struct tls_cipher_suite *tls_cipher_suite_pref[] = { + &tls_ecdhe_rsa_with_aes_256_cbc_sha, + &tls_ecdhe_ecdsa_with_aes_256_cbc_sha, + &tls_ecdhe_rsa_with_aes_128_cbc_sha, + &tls_ecdhe_ecdsa_with_aes_128_cbc_sha, + &tls_dhe_rsa_with_aes_256_cbc_sha, + &tls_dhe_rsa_with_aes_128_cbc_sha, + &tls_rsa_with_aes_256_cbc_sha, + &tls_rsa_with_aes_128_cbc_sha, + &tls_ecdhe_rsa_with_aes_256_cbc_sha384, + &tls_ecdhe_rsa_with_aes_128_cbc_sha256, + &tls_dhe_rsa_with_aes_256_cbc_sha256, + &tls_dhe_rsa_with_aes_128_cbc_sha256, + &tls_rsa_with_aes_256_cbc_sha256, + &tls_rsa_with_aes_128_cbc_sha256, + &tls_ecdhe_rsa_with_aes_256_gcm_sha384, + &tls_ecdhe_rsa_with_aes_128_gcm_sha256, + &tls_ecdhe_ecdsa_with_aes_256_gcm_sha384, + &tls_ecdhe_ecdsa_with_aes_128_gcm_sha256, + &tls_dhe_rsa_with_aes_256_gcm_sha384, + &tls_dhe_rsa_with_aes_128_gcm_sha256, + &tls_rsa_with_aes_256_gcm_sha384, + &tls_rsa_with_aes_128_gcm_sha256, + &tls_ecdhe_rsa_with_3des_ede_cbc_sha, + &tls_ecdhe_ecdsa_with_3des_ede_cbc_sha, + &tls_dhe_rsa_with_3des_ede_cbc_sha, + &tls_rsa_with_3des_ede_cbc_sha, + NULL, +}; diff --git a/ell/tls.c b/ell/tls.c new file mode 100644 index 0000000000000000000000000000000000000000..5246650e23e104f0b42e7be52116dc4a44a941ae --- /dev/null +++ b/ell/tls.c @@ -0,0 +1,3987 @@ +/* + * Embedded Linux library + * Copyright (C) 2015 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <time.h> +#include <stdlib.h> +#include <errno.h> +#include <stdio.h> +#include <strings.h> + +#include "useful.h" +#include "private.h" +#include "tls.h" +#include "checksum.h" +#include "cipher.h" +#include "random.h" +#include "queue.h" +#include "pem.h" +#include "pem-private.h" +#include "asn1-private.h" +#include "cert.h" +#include "cert-private.h" +#include "tls-private.h" +#include "key.h" +#include "strv.h" +#include "missing.h" +#include "string.h" +#include "settings.h" +#include "time.h" +#include "time-private.h" + +bool tls10_prf(const void *secret, size_t secret_len, + const char *label, + const void *seed, size_t seed_len, + uint8_t *out, size_t out_len) +{ + uint8_t p_hash2[out_len]; + uint8_t l_s1 = (secret_len + 1) / 2; + unsigned int i; + + /* + * RFC2246 section 5: + * S1 and S2 are the two halves of the secret, and each is the same + * length. S1 is taken from the first half of the secret, S2 from the + * second half. Their length is created by rounding up the length of + * the overall secret, divided by two; thus, if the original secret is + * an odd number of bytes long, the last byte of S1 will be the same as + * the first byte of S2. + */ + + if (!tls12_prf(L_CHECKSUM_MD5, secret, l_s1, + label, seed, seed_len, + out, out_len)) + return false; + + if (secret_len > 0) + secret += secret_len - l_s1; + + if (!tls12_prf(L_CHECKSUM_SHA1, secret, l_s1, + label, seed, seed_len, + p_hash2, out_len)) + return false; + + for (i = 0; i < out_len; i++) + out[i] ^= p_hash2[i]; + + return true; +} + +bool tls12_prf(enum l_checksum_type type, + const void *secret, size_t secret_len, + const char *label, + const void *seed, size_t seed_len, + uint8_t *out, size_t out_len) +{ + struct l_checksum *hmac = l_checksum_new_hmac(type, secret, secret_len); + size_t a_len, chunk_len, prfseed_len = strlen(label) + seed_len; + uint8_t a[64 + prfseed_len], prfseed[prfseed_len]; + + if (!hmac) + return false; + + /* Generate the hash seed or A(0) as label + seed */ + memcpy(prfseed, label, strlen(label)); + memcpy(prfseed + strlen(label), seed, seed_len); + + memcpy(a, prfseed, prfseed_len); + a_len = prfseed_len; + + while (out_len) { + /* Generate A(i) */ + l_checksum_reset(hmac); + l_checksum_update(hmac, a, a_len); + a_len = l_checksum_get_digest(hmac, a, sizeof(a)); + + /* Append seed & generate output */ + memcpy(a + a_len, prfseed, prfseed_len); + l_checksum_reset(hmac); + l_checksum_update(hmac, a, a_len + prfseed_len); + + chunk_len = l_checksum_get_digest(hmac, out, out_len); + out += chunk_len; + out_len -= chunk_len; + } + + l_checksum_free(hmac); + return true; +} + +static bool tls_prf_get_bytes(struct l_tls *tls, + const void *secret, size_t secret_len, + const char *label, + const void *seed, size_t seed_len, + uint8_t *buf, size_t len) +{ + if (tls->negotiated_version >= L_TLS_V12) + return tls12_prf(tls->prf_hmac->l_id, + secret, secret_len, label, + seed, seed_len, buf, len); + return tls10_prf(secret, secret_len, label, seed, seed_len, + buf, len); +} + +LIB_EXPORT bool l_tls_prf_get_bytes(struct l_tls *tls, bool use_master_secret, + const char *label, uint8_t *buf, size_t len) +{ + uint8_t seed[64]; + bool r; + + if (unlikely(!tls || !tls->prf_hmac)) + return false; + + memcpy(seed + 0, tls->pending.client_random, 32); + memcpy(seed + 32, tls->pending.server_random, 32); + + if (use_master_secret) + r = tls_prf_get_bytes(tls, tls->pending.master_secret, 48, + label, seed, 64, buf, len); + else + r = tls_prf_get_bytes(tls, "", 0, label, seed, 64, buf, len); + + explicit_bzero(seed, 64); + + return r; +} + +static void tls_write_random(uint8_t *buf) +{ + l_put_be32(time(NULL), buf); + + l_getrandom(buf + 4, 28); +} + +static void tls_drop_handshake_hash(struct l_tls *tls, + enum handshake_hash_type hash) +{ + if (tls->handshake_hash[hash]) { + l_checksum_free(tls->handshake_hash[hash]); + + tls->handshake_hash[hash] = NULL; + } +} + +static void tls_reset_handshake(struct l_tls *tls) +{ + enum handshake_hash_type hash; + + explicit_bzero(tls->pending.key_block, sizeof(tls->pending.key_block)); + + if (tls->pending.cipher_suite && + tls->pending.cipher_suite->key_xchg->free_params) + tls->pending.cipher_suite->key_xchg->free_params(tls); + + l_cert_free(tls->peer_cert); + l_key_free(tls->peer_pubkey); + + tls->peer_cert = NULL; + tls->peer_pubkey = NULL; + tls->peer_pubkey_size = 0; + tls->peer_authenticated = false; + tls->negotiated_curve = NULL; + tls->negotiated_ff_group = NULL; + + for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) + tls_drop_handshake_hash(tls, hash); + + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_START); + tls->cert_requested = 0; + tls->cert_sent = 0; + + tls->session_id_size = 0; + tls->session_id_size_replaced = 0; + tls->session_id_new = false; + l_free(l_steal_ptr(tls->session_peer_identity)); + tls->session_resumed = false; +} + +static void tls_cleanup_handshake(struct l_tls *tls) +{ + explicit_bzero(tls->pending.client_random, 32); + explicit_bzero(tls->pending.server_random, 32); + explicit_bzero(tls->pending.master_secret, 48); +} + +static bool tls_change_cipher_spec(struct l_tls *tls, bool txrx, + const char **error) +{ + struct tls_bulk_encryption_algorithm *enc; + struct tls_mac_algorithm *mac; + int key_offset; + static char error_buf[200]; + + if (tls->cipher_type[txrx] == TLS_CIPHER_AEAD) { + if (tls->aead_cipher[txrx]) { + l_aead_cipher_free(tls->aead_cipher[txrx]); + tls->aead_cipher[txrx] = NULL; + } + } else { + if (tls->cipher[txrx]) { + l_cipher_free(tls->cipher[txrx]); + tls->cipher[txrx] = NULL; + } + } + + tls->cipher_type[txrx] = TLS_CIPHER_STREAM; + + if (tls->mac[txrx]) { + l_checksum_free(tls->mac[txrx]); + tls->mac[txrx] = NULL; + } + + tls->mac_length[txrx] = 0; + tls->block_length[txrx] = 0; + tls->record_iv_length[txrx] = 0; + + if (tls->fixed_iv_length[txrx]) { + explicit_bzero(tls->fixed_iv[txrx], tls->fixed_iv_length[txrx]); + tls->fixed_iv_length[txrx] = 0; + } + + tls->auth_tag_length[txrx] = 0; + tls->seq_num[txrx] = 0; + + tls->cipher_suite[txrx] = tls->pending.cipher_suite; + if (!tls->cipher_suite[txrx]) + return true; + + key_offset = 0; + + if (tls->cipher_suite[txrx]->mac) { + mac = tls->cipher_suite[txrx]->mac; + + /* Server write / client read is 2nd in the key block */ + if ((tls->server && txrx) || (!tls->server && !txrx)) + key_offset += mac->mac_length; + + tls->mac[txrx] = l_checksum_new_hmac(mac->hmac_type, + tls->pending.key_block + + key_offset, mac->mac_length); + + /* Wipe out the now unneeded part of the key block */ + explicit_bzero(tls->pending.key_block + key_offset, + mac->mac_length); + + if (!tls->mac[txrx]) { + if (error) { + *error = error_buf; + snprintf(error_buf, sizeof(error_buf), + "Can't create %s's %s HMAC", + tls->cipher_suite[txrx]->name, + txrx ? "Tx" : "Rx"); + } + + return false; + } + + tls->mac_length[txrx] = mac->mac_length; + + key_offset = 2 * mac->mac_length; + } + + if (tls->cipher_suite[txrx]->encryption) { + void *cipher; + + enc = tls->cipher_suite[txrx]->encryption; + + /* Server write / client read is 4th in the key block */ + if ((tls->server && txrx) || (!tls->server && !txrx)) + key_offset += enc->key_length; + + if (enc->cipher_type == TLS_CIPHER_AEAD) { + cipher = l_aead_cipher_new(enc->l_aead_id, + tls->pending.key_block + + key_offset, enc->key_length, + enc->auth_tag_length); + tls->aead_cipher[txrx] = cipher; + } else { + cipher = l_cipher_new(enc->l_id, + tls->pending.key_block + + key_offset, enc->key_length); + tls->cipher[txrx] = cipher; + } + + /* Wipe out the now unneeded part of the key block */ + explicit_bzero(tls->pending.key_block + key_offset, + enc->key_length); + + if (!cipher) { + if (error) { + *error = error_buf; + snprintf(error_buf, sizeof(error_buf), + "Can't create %s's %s cipher", + tls->cipher_suite[txrx]->name, + txrx ? "Tx" : "Rx"); + } + + return false; + } + + tls->cipher_type[txrx] = enc->cipher_type; + tls->record_iv_length[txrx] = enc->iv_length - + enc->fixed_iv_length; + tls->block_length[txrx] = enc->block_length; + tls->auth_tag_length[txrx] = enc->auth_tag_length; + + if ((tls->server && txrx) || (!tls->server && !txrx)) + key_offset += enc->key_length; + else + key_offset += 2 * enc->key_length; + } + + if (tls->negotiated_version <= L_TLS_V10 && + tls->cipher_suite[txrx]->encryption && + tls->cipher_suite[txrx]->encryption->cipher_type == + TLS_CIPHER_BLOCK) { + enc = tls->cipher_suite[txrx]->encryption; + + /* Server write / client read is 6th in the key block */ + if ((tls->server && txrx) || (!tls->server && !txrx)) + key_offset += enc->iv_length; + + l_cipher_set_iv(tls->cipher[txrx], tls->pending.key_block + + key_offset, enc->iv_length); + + /* Wipe out the now unneeded part of the key block */ + explicit_bzero(tls->pending.key_block + key_offset, + enc->iv_length); + } else if (tls->cipher_suite[txrx]->encryption && + tls->cipher_suite[txrx]->encryption->fixed_iv_length) { + enc = tls->cipher_suite[txrx]->encryption; + + /* Server write / client read is 6th in the key block */ + if ((tls->server && txrx) || (!tls->server && !txrx)) + key_offset += enc->fixed_iv_length; + + tls->fixed_iv_length[txrx] = enc->fixed_iv_length; + memcpy(tls->fixed_iv[txrx], tls->pending.key_block + key_offset, + enc->fixed_iv_length); + + /* Wipe out the now unneeded part of the key block */ + explicit_bzero(tls->pending.key_block + key_offset, + enc->fixed_iv_length); + } + + return true; +} + +static void tls_reset_cipher_spec(struct l_tls *tls, bool txrx) +{ + /* Reset everything to the TLS_NULL_WITH_NULL_NULL state */ + + tls->pending.cipher_suite = NULL; + + tls_change_cipher_spec(tls, txrx, NULL); +} + +static bool tls_cipher_suite_is_compatible_no_key_xchg(struct l_tls *tls, + const struct tls_cipher_suite *suite, + const char **error) +{ + static char error_buf[200]; + struct l_cert *leaf; + enum l_tls_version min_version = + tls->negotiated_version ?: tls->min_version; + enum l_tls_version max_version = + tls->negotiated_version ?: tls->max_version; + + if (suite->encryption && + suite->encryption->cipher_type == TLS_CIPHER_AEAD) { + if (max_version < L_TLS_V12) { + if (error) { + *error = error_buf; + snprintf(error_buf, sizeof(error_buf), + "Cipher suite %s uses an AEAD " + "cipher (TLS 1.2+) but " + TLS_VER_FMT + " was negotiated or is the max " + "version allowed", suite->name, + TLS_VER_ARGS(tls->max_version)); + } + + return false; + } + + if (!l_aead_cipher_is_supported(suite->encryption->l_aead_id)) { + if (error) { + *error = error_buf; + snprintf(error_buf, sizeof(error_buf), + "Cipher suite %s's AEAD cipher " + "algorithm not supported by " + "the kernel", suite->name); + } + + return false; + } + } else if (suite->encryption) { /* Block or stream cipher */ + if (!l_cipher_is_supported(suite->encryption->l_id)) { + if (error) { + *error = error_buf; + snprintf(error_buf, sizeof(error_buf), + "Cipher suite %s's block/stream" + " cipher algorithm not " + "supported by the kernel", + suite->name); + } + + return false; + } + } + + if (suite->mac && + !l_checksum_is_supported(suite->mac->hmac_type, true)) { + if (error) { + *error = error_buf; + snprintf(error_buf, sizeof(error_buf), + "Cipher suite %s's HMAC algorithm not " + "supported by the kernel", suite->name); + } + + return false; + } + + if ( + (max_version < L_TLS_V12 && + (!l_checksum_is_supported(L_CHECKSUM_MD5, true) || + !l_checksum_is_supported(L_CHECKSUM_SHA1, true))) || + (min_version >= L_TLS_V12 && + !l_checksum_is_supported( + suite->prf_hmac != L_CHECKSUM_NONE ? + suite->prf_hmac : L_CHECKSUM_SHA256, + true))) { + if (error) { + *error = error_buf; + snprintf(error_buf, sizeof(error_buf), + "Cipher suite %s's PRF algorithm not " + "supported by the kernel", suite->name); + } + + return false; + } + + /* + * If the certificate is compatible with the signature algorithm it + * also must be compatible with the key exchange mechanism because + * the cipher suites are defined so that the same certificates can + * be used by both. + */ + leaf = l_certchain_get_leaf(tls->cert); + if (leaf && suite->signature && + !suite->signature->validate_cert_key_type(leaf)) { + if (error) { + *error = error_buf; + snprintf(error_buf, sizeof(error_buf), + "Local certificate has key type " + "incompatible with cipher suite %s's " + "signature algorithm", suite->name); + } + + return false; + } + + return true; +} + +/* + * Assumes that Client Hello extensions have been processed and that we + * will want to start a new session using this cipher suite, including the + * key exchange. This is unlike tls_cipher_suite_is_compatible_no_key_xchg() + * which runs fewer checks and must succeed even for a cipher suite loaded + * during session resumption. + */ +bool tls_cipher_suite_is_compatible(struct l_tls *tls, + const struct tls_cipher_suite *suite, + const char **error) +{ + static char error_buf[200]; + + if (!tls_cipher_suite_is_compatible_no_key_xchg(tls, suite, error)) + return false; + + if (suite->key_xchg->need_ffdh && + !l_key_is_supported(L_KEY_FEATURE_DH)) { + if (error) { + *error = error_buf; + snprintf(error_buf, sizeof(error_buf), + "Cipher suite %s's key exchange " + "mechanism needs kernel DH support", + suite->name); + } + + return false; + } + + /* + * On the server we know what elliptic curve we'll be using as soon + * as we've processed the ClientHello so for EC-based key exchange + * methods require that a curve has been selected. + */ + if (suite->key_xchg->need_ecc && tls->server && + !tls->negotiated_curve) { + if (error) { + *error = error_buf; + snprintf(error_buf, sizeof(error_buf), + "No common supported elliptic curves " + "with the client, can't use %s", + suite->name); + } + + return false; + } + + /* Similarly for FF DH groups */ + if (suite->key_xchg->need_ffdh && tls->server && + !tls->negotiated_ff_group) { + if (error) { + *error = error_buf; + snprintf(error_buf, sizeof(error_buf), + "No common supported finite-field " + "groups with the client, can't use %s", + suite->name); + } + + return false; + } + + return true; +} + +static struct tls_cipher_suite *tls_find_cipher_suite(const uint8_t *id) +{ + struct tls_cipher_suite **suite; + + for (suite = tls_cipher_suite_pref; *suite; suite++) + if ((*suite)->id[0] == id[0] && (*suite)->id[1] == id[1]) + return *suite; + + return NULL; +} + +static struct tls_compression_method tls_compression_pref[] = { + { + 0, + "CompressionMethod.null", + }, +}; + +static struct tls_compression_method *tls_find_compression_method( + const uint8_t id) +{ + int i; + + for (i = 0; i < (int) L_ARRAY_SIZE(tls_compression_pref); i++) + if (tls_compression_pref[i].id == id) + return &tls_compression_pref[i]; + + return NULL; +} + +const struct tls_hash_algorithm tls_handshake_hash_data[] = { + [HANDSHAKE_HASH_SHA384] = { 5, HANDSHAKE_HASH_SHA384, + L_CHECKSUM_SHA384, "SHA384" }, + [HANDSHAKE_HASH_SHA256] = { 4, HANDSHAKE_HASH_SHA256, + L_CHECKSUM_SHA256, "SHA256" }, + [HANDSHAKE_HASH_MD5] = { 1, HANDSHAKE_HASH_MD5, + L_CHECKSUM_MD5, "MD5" }, + [HANDSHAKE_HASH_SHA1] = { 2, HANDSHAKE_HASH_SHA1, + L_CHECKSUM_SHA1, "SHA1" }, +}; + +static bool tls_init_handshake_hash(struct l_tls *tls) +{ + enum handshake_hash_type hash; + bool tls10 = tls->max_version < L_TLS_V12; + + for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) { + /* Skip hash types we already know we won't need */ + if (tls10 && hash != HANDSHAKE_HASH_SHA1 && + hash != HANDSHAKE_HASH_MD5) + continue; + + if (tls->handshake_hash[hash]) { + TLS_DEBUG("Handshake hash %s already exists", + tls_handshake_hash_data[hash].name); + goto err; + } + + tls->handshake_hash[hash] = l_checksum_new( + tls_handshake_hash_data[hash].l_id); + + if (!tls->handshake_hash[hash]) { + TLS_DEBUG("Can't create %s hash", + tls_handshake_hash_data[hash].name); + goto err; + } + } + + return true; +err: + for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) + tls_drop_handshake_hash(tls, hash); + + return false; +} + +static const struct tls_hash_algorithm *tls_set_prf_hmac(struct l_tls *tls) +{ + enum handshake_hash_type hash; + + if (tls->pending.cipher_suite->prf_hmac == L_CHECKSUM_NONE) { + tls->prf_hmac = &tls_handshake_hash_data[HANDSHAKE_HASH_SHA256]; + return tls->prf_hmac; + } + + for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) + if (tls_handshake_hash_data[hash].l_id == + tls->pending.cipher_suite->prf_hmac) { + tls->prf_hmac = &tls_handshake_hash_data[hash]; + return tls->prf_hmac; + } + + return NULL; +} + +static bool tls_domain_match_mask(const char *name, size_t name_len, + const char *mask, size_t mask_len) +{ + bool at_start = true; + + while (1) { + const char *name_seg_end = memchr(name, '.', name_len); + const char *mask_seg_end = memchr(mask, '.', mask_len); + size_t name_seg_len = name_seg_end ? + (size_t) (name_seg_end - name) : name_len; + size_t mask_seg_len = mask_seg_end ? + (size_t) (mask_seg_end - mask) : mask_len; + + if (mask_seg_len == 1 && mask[0] == '*') { + /* + * A * at the beginning of the mask matches any + * number of labels. + */ + if (at_start && name_seg_end && + tls_domain_match_mask(name_seg_end + 1, + name_len - name_seg_len - 1, + mask, mask_len)) + return true; + + goto ok_next; + } + + if (name_seg_len != mask_seg_len || + memcmp(name, mask, name_seg_len)) + return false; + +ok_next: + /* If either string ends here both must end here */ + if (!name_seg_end || !mask_seg_end) + return !name_seg_end && !mask_seg_end; + + at_start = false; + name = name_seg_end + 1; + name_len -= name_seg_len + 1; + mask = mask_seg_end + 1; + mask_len -= mask_seg_len + 1; + } +} + +static const struct asn1_oid subject_alt_name_oid = + { 3, { 0x55, 0x1d, 0x11 } }; +static const struct asn1_oid dn_common_name_oid = + { 3, { 0x55, 0x04, 0x03 } }; + +#define SAN_DNS_NAME_ID ASN1_CONTEXT_IMPLICIT(2) + +static bool tls_cert_domains_match_mask(struct l_cert *cert, char **mask, + char **error_msg) +{ + const uint8_t *san, *dn, *end; + size_t san_len, dn_len; + uint8_t san_tag; + const char *cn = NULL; + size_t cn_len; + char **i; + struct l_string *dns_names = NULL; + int dns_name_count = 0; + + /* + * Locate SubjectAltName (RFC5280 Section 4.2.1.6) and descend into + * the sole SEQUENCE element, check if any DNSName matches. + */ + san = cert_get_extension(cert, &subject_alt_name_oid, NULL, &san_len); + if (san) { + san = asn1_der_find_elem(san, san_len, 0, &san_tag, &san_len); + if (unlikely(!san || san_tag != ASN1_ID_SEQUENCE)) + goto parse_error; + + end = san + san_len; + while (san < end) { + const uint8_t *value; + uint8_t tag; + size_t len; + + value = asn1_der_find_elem(san, end - san, + SAN_DNS_NAME_ID, + &tag, &len); + if (!value) + break; + + /* Type is implicitly IA5STRING */ + + for (i = mask; *i; i++) + if (tls_domain_match_mask((const char *) value, + len, *i, strlen(*i))) { + l_string_free(dns_names); + return true; + } + + if (!dns_names) { + dns_names = l_string_new(128); + l_string_append(dns_names, "tried DNSName(s) "); + l_string_append_fixed(dns_names, + (char *) value, len); + } else if (dns_name_count < 20) { + l_string_append(dns_names, ", "); + l_string_append_fixed(dns_names, + (char *) value, len); + } + + san = value + len; + dns_name_count++; + } + } + + /* + * Retrieve the Common Name from the Subject DN and check if it + * matches. + * + * We look at the Common Name only if no DNSNames were present in + * the certificate, following Wi-Fi Alliance's Hotspot 2.0 + * Specification v3.1 section 7.3.3.2 step 2: + * "Verify in the AAA server certificate that the domain name from + * the FQDN [...] is a suffix match of the domain name in at least + * one of the DNSName SubjectAltName extensions. If a SubjectAltName + * of type DNSName is not present, then the domain name from the + * FQDN shall be a suffix match to the CommonName portion of the + * SubjectName. If neither of these conditions holds, then + * verification fails." + */ + if (dns_name_count) { + if (dns_name_count > 20) + l_string_append_printf(dns_names, " and %i other", + dns_name_count - 20); + + *error_msg = l_string_unwrap(dns_names); + return false; + } + + dn = l_cert_get_dn(cert, &dn_len); + if (unlikely(!dn)) + goto parse_error; + + end = dn + dn_len; + while (dn < end) { + const uint8_t *set, *seq, *oid, *name; + uint8_t tag; + size_t len, oid_len, name_len; + + set = asn1_der_find_elem(dn, end - dn, 0, &tag, &len); + if (unlikely(!set || tag != ASN1_ID_SET)) + goto parse_error; + + dn = set + len; + + seq = asn1_der_find_elem(set, len, 0, &tag, &len); + if (unlikely(!seq || tag != ASN1_ID_SEQUENCE)) + goto parse_error; + + oid = asn1_der_find_elem(seq, len, 0, &tag, &oid_len); + if (unlikely(!oid || tag != ASN1_ID_OID)) + goto parse_error; + + name = asn1_der_find_elem(seq, len, 1, &tag, &name_len); + if (unlikely(!name || (tag != ASN1_ID_PRINTABLESTRING && + tag != ASN1_ID_UTF8STRING && + tag != ASN1_ID_IA5STRING))) + continue; + + if (asn1_oid_eq(&dn_common_name_oid, oid_len, oid)) { + cn = (const char *) name; + cn_len = name_len; + break; + } + } + + if (unlikely(!cn)) + goto parse_error; + + for (i = mask; *i; i++) + if (tls_domain_match_mask(cn, cn_len, *i, strlen(*i))) + return true; + + *error_msg = l_strdup_printf("tried CommonName %.*s", (int) cn_len, cn); + return false; + +parse_error: + *error_msg = l_strdup("couldn't locate DNSName or CommonName"); + + return false; +} + +static const char *tls_get_cache_group_name(struct l_tls *tls, + const uint8_t *session_id, + size_t session_id_size) +{ + _auto_(l_free) char *session_id_str = NULL; + static char group_name[256]; + + if (!tls->server) + return tls->session_prefix; + + session_id_str = l_util_hexstring(session_id, session_id_size); + snprintf(group_name, sizeof(group_name), "%s-%s", + tls->session_prefix, session_id_str); + return group_name; +} + +static void tls_forget_cached_session(struct l_tls *tls, const char *group_name, + const uint8_t *session_id, + size_t session_id_size, bool call_back) +{ + if (!group_name) + group_name = tls_get_cache_group_name(tls, session_id, + session_id_size); + + l_settings_remove_group(tls->session_settings, group_name); + + if (call_back && tls->session_update_cb) { + tls->in_callback = true; + tls->session_update_cb(tls->session_update_user_data); + tls->in_callback = false; + } +} + +static bool tls_load_cached_session(struct l_tls *tls, const char *group_name, + const uint8_t *session_id, + size_t session_id_size, + const char *session_id_str) +{ + _auto_(l_free) uint8_t *master_secret = NULL; + int version; + _auto_(l_free) uint8_t *cipher_suite_id = NULL; + struct tls_cipher_suite *cipher_suite; + unsigned int compression_method_id; + _auto_(l_free) char *peer_identity = NULL; + size_t size; + const char *error; + + if (l_settings_has_key(tls->session_settings, group_name, + "SessionExpiryTime")) { + uint64_t expiry_time; + + if (unlikely(!l_settings_get_uint64(tls->session_settings, + group_name, + "SessionExpiryTime", + &expiry_time))) + goto warn_corrupt; + + if (time_realtime_now() > expiry_time) { + TLS_DEBUG("Cached session %s is expired, removing it, " + "will start a new session", + session_id_str); + goto forget; + } + } + + if (unlikely(!l_settings_get_int(tls->session_settings, + group_name, + "SessionVersion", + &version) || + version < TLS_MIN_VERSION || version > TLS_MAX_VERSION)) + goto warn_corrupt; + + master_secret = l_settings_get_bytes(tls->session_settings, + group_name, + "SessionMasterSecret", + &size); + if (unlikely(!master_secret || size != 48)) + goto warn_corrupt; + + cipher_suite_id = l_settings_get_bytes(tls->session_settings, + group_name, + "SessionCipherSuite", + &size); + if (unlikely(!cipher_suite_id || size != 2 || + !(cipher_suite = + tls_find_cipher_suite(cipher_suite_id)))) + goto warn_corrupt; + + /* + * While we could attempt to resume a session even though we're now + * configured with, say, a different certificate type than what we + * had when we cached that session, that is too questionable of a + * scenario to support it. We don't specifically check that all of + * the authentication data is the same, e.g. we don't save the + * certificate serial number or path, but ensure the cached cipher + * suite is compatible with current authentication data. + * + * We filter the cipher suites in our Client Hello to only offer the + * ones compatible with current configuration so if we also include + * a Session ID from a session who's cipher suite is not one of those + * listed in that same Client Hello, the server is likely to notice + * and either start a new session or send a fatal Alert. + * + * It is up to the user to keep multiple cache instances if it needs + * to save multiple sessions. + */ + if (unlikely(!tls_cipher_suite_is_compatible_no_key_xchg(tls, + cipher_suite, + &error))) { + TLS_DEBUG("Cached session %s cipher suite not compatible: %s", + session_id_str, error); + goto forget; + } + + if (unlikely(!l_settings_get_uint(tls->session_settings, group_name, + "SessionCompressionMethod", + &compression_method_id) || + !tls_find_compression_method(compression_method_id))) + goto warn_corrupt; + + if (l_settings_has_key(tls->session_settings, group_name, + "SessionPeerIdentity")) { + peer_identity = l_settings_get_string(tls->session_settings, + group_name, + "SessionPeerIdentity"); + if (unlikely(!peer_identity || !cipher_suite->signature)) + goto warn_corrupt; + } + + tls->session_id_size = session_id_size; + memcpy(tls->session_id, session_id, session_id_size); + tls->session_id_new = false; + tls->client_version = version; + memcpy(tls->pending.master_secret, master_secret, 48); + memcpy(tls->session_cipher_suite_id, cipher_suite_id, 2); + tls->session_compression_method_id = compression_method_id; + l_free(tls->session_peer_identity); + tls->session_peer_identity = l_steal_ptr(peer_identity); + return true; + +warn_corrupt: + TLS_DEBUG("Cached session %s data is corrupt or has unsupported " + "parameters, removing it, will start a new session", + session_id_str); + +forget: + tls_forget_cached_session(tls, group_name, session_id, session_id_size, + true); + return false; +} + +static bool tls_load_cached_client_session(struct l_tls *tls) +{ + /* + * The following settings are required: + * SessionID, + * SessionMasterSecret, + * SessionVersion, + * SessionCipherSuite, + * SessionCompressionMethod, + * and these two are optional: + * SessionExpiryTime, + * SessionPeerIdentity. + */ + _auto_(l_free) uint8_t *session_id = NULL; + size_t session_id_size; + _auto_(l_free) char *session_id_str = NULL; + const char *group_name = tls_get_cache_group_name(tls, NULL, 0); + + tls->session_id_size = 0; + tls->session_id_new = false; + + if (!tls->session_settings || + !l_settings_has_key(tls->session_settings, group_name, + "SessionID")) + /* No session cached, no error */ + return false; + + session_id = l_settings_get_bytes(tls->session_settings, group_name, + "SessionID", &session_id_size); + if (unlikely(!session_id || + session_id_size < 1 || session_id_size > 32)) { + TLS_DEBUG("Bad cached session ID format"); + tls_forget_cached_session(tls, group_name, NULL, 0, true); + return false; + } + + session_id_str = l_util_hexstring(session_id, session_id_size); + + return tls_load_cached_session(tls, group_name, session_id, + session_id_size, session_id_str); +} + +static bool tls_load_cached_server_session(struct l_tls *tls, + const uint8_t *session_id, + size_t session_id_size) +{ + _auto_(l_free) char *session_id_str = + l_util_hexstring(session_id, session_id_size); + const char *target_group_name = + tls_get_cache_group_name(tls, session_id, session_id_size); + _auto_(l_strv_free) char **groups = + l_settings_get_groups(tls->session_settings); + char **group; + unsigned int cnt = 0; + size_t prefix_len = strlen(tls->session_prefix); + uint64_t now = time_realtime_now(); + char *oldest_session_group = NULL; + uint64_t oldest_session_expiry = UINT64_MAX; + bool found = false; + bool changed = false; + bool loaded = false; + + tls->session_id_size = 0; + tls->session_id_new = false; + + /* Clean up expired entries and enforce session count limit */ + for (group = groups; *group; group++) { + uint64_t expiry_time; + + if (memcmp(*group, tls->session_prefix, prefix_len) || + (*group)[prefix_len] != '-') + continue; + + /* Group seems to be a session cache entry */ + + if (unlikely(!l_settings_get_uint64(tls->session_settings, + *group, + "SessionExpiryTime", + &expiry_time)) || + expiry_time <= now) { + TLS_DEBUG("Cached session %s is expired or invalid, " + "purging entry", + *group + prefix_len + 1); + l_settings_remove_group(tls->session_settings, *group); + changed = true; + continue; + } + + cnt++; + + if (!strcmp(*group + prefix_len + 1, + target_group_name + prefix_len + 1)) { + found = true; + continue; /* Don't purge this entry */ + } + + if (expiry_time < oldest_session_expiry) { + oldest_session_group = *group; + oldest_session_expiry = expiry_time; + } + } + + /* + * Enforce tls->session_count_max by dropping the entry for the + * oldest session (more specifically the one closest to its expiry + * time) in the cache, that is not the session we're trying to + * load. If the target session was not found, do this as soon as + * tls->session_count_max is reached rather than when it's exceeded + * so as to make room for a new entry. If we end up not saving + * a new session due to an error before the handshake finish, we'll + * be left with tls->session_count_max - 1 entries and will have + * purged that entry unnecessarily but the cache will have room for + * a future session. Same when we did find the target session but + * later had to forget it because of a fatal alert during or after + * the handshake. + * + * If we did find the target session but we later find that we + * can't resume it, we will forget it so the new session can take + * the old session's place and the limit is not exceeded, see + * discussion in tls_server_resume_error. + */ + if (tls->session_count_max && oldest_session_group && + cnt >= tls->session_count_max + (found ? 1 : 0)) { + l_settings_remove_group(tls->session_settings, + oldest_session_group); + changed = true; + } + + if (!found) { + TLS_DEBUG("Requested session %s not found in cache, will " + "start a new session", session_id_str); + goto call_back; + } + + loaded = tls_load_cached_session(tls, target_group_name, + session_id, session_id_size, + session_id_str); + + /* + * If tls_load_cached_session() returned false it will have called + * session_update_cb for us. + */ + if (!loaded) + changed = false; + +call_back: + if (changed && tls->session_update_cb) { + tls->in_callback = true; + tls->session_update_cb(tls->session_update_user_data); + tls->in_callback = false; + } + + return loaded; +} + +#define SWITCH_ENUM_TO_STR(val) \ + case (val): \ + return L_STRINGIFY(val); + +static const char *tls_handshake_type_to_str(enum tls_handshake_type type) +{ + static char buf[100]; + + switch (type) { + SWITCH_ENUM_TO_STR(TLS_HELLO_REQUEST) + SWITCH_ENUM_TO_STR(TLS_CLIENT_HELLO) + SWITCH_ENUM_TO_STR(TLS_SERVER_HELLO) + SWITCH_ENUM_TO_STR(TLS_CERTIFICATE) + SWITCH_ENUM_TO_STR(TLS_SERVER_KEY_EXCHANGE) + SWITCH_ENUM_TO_STR(TLS_CERTIFICATE_REQUEST) + SWITCH_ENUM_TO_STR(TLS_SERVER_HELLO_DONE) + SWITCH_ENUM_TO_STR(TLS_CERTIFICATE_VERIFY) + SWITCH_ENUM_TO_STR(TLS_CLIENT_KEY_EXCHANGE) + SWITCH_ENUM_TO_STR(TLS_FINISHED) + } + + snprintf(buf, sizeof(buf), "tls_handshake_type(%i)", type); + return buf; +} + +static void tls_send_alert(struct l_tls *tls, bool fatal, + enum l_tls_alert_desc alert_desc) +{ + uint8_t buf[2]; + + TLS_DEBUG("Sending a %s Alert: %s", fatal ? "Fatal" : "Warning", + l_tls_alert_to_str(alert_desc)); + + buf[0] = fatal ? 2 : 1; + buf[1] = alert_desc; + + tls_tx_record(tls, TLS_CT_ALERT, buf, 2); +} + +/* + * Callers make sure this is about the last function before returning + * from the stack frames up to the exported library call so that the + * user-supplied disconnected callback here is free to use l_tls_free + * for example. + */ +void tls_disconnect(struct l_tls *tls, enum l_tls_alert_desc desc, + enum l_tls_alert_desc local_desc) +{ + bool forget_session = false; + /* Save session_id_size before tls_reset_handshake() */ + size_t session_id_size = tls->session_id_size; + + if ((desc || local_desc) && tls->session_settings && + session_id_size && !tls->session_id_new) + /* + * RFC5246 Section 7.2: "Alert messages with a level of fatal + * result in the immediate termination of the connection. In + * this case, other connections corresponding to the session + * may continue, but the session identifier MUST be + * invalidated, preventing the failed session from being used + * to establish new connections." + * + * and 7.2.1: "Note that as of TLS 1.1, failure to properly + * close a connection no longer requires that a session not + * be resumed." + * + * I.e. we need to remove the session from the cache here but + * not on l_tls_close(). + */ + forget_session = true; + + tls_send_alert(tls, true, desc); + + tls_reset_handshake(tls); + tls_cleanup_handshake(tls); + + tls_reset_cipher_spec(tls, 0); + tls_reset_cipher_spec(tls, 1); + + tls->negotiated_version = 0; + tls->ready = false; + tls->renegotiation_info.secure_renegotiation = false; + + if (forget_session) { + tls_forget_cached_session(tls, NULL, tls->session_id, + session_id_size, true); + + if (tls->pending_destroy) + return; + } + + tls->disconnected(local_desc ?: desc, local_desc && !desc, + tls->user_data); +} + +void tls_tx_handshake(struct l_tls *tls, int type, uint8_t *buf, size_t length) +{ + int i; + + TLS_DEBUG("Sending a %s of %zi bytes", + tls_handshake_type_to_str(type), + length - TLS_HANDSHAKE_HEADER_SIZE); + + /* Fill in the handshake header */ + + buf[0] = type; + buf[1] = (length - TLS_HANDSHAKE_HEADER_SIZE) >> 16; + buf[2] = (length - TLS_HANDSHAKE_HEADER_SIZE) >> 8; + buf[3] = (length - TLS_HANDSHAKE_HEADER_SIZE) >> 0; + + for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++) + if (tls->handshake_hash[i]) + l_checksum_update(tls->handshake_hash[i], buf, length); + + tls_tx_record(tls, TLS_CT_HANDSHAKE, buf, length); +} + +static ssize_t tls_append_hello_extensions(struct l_tls *tls, + struct l_queue *extensions, + uint8_t *buf, size_t len) +{ + uint8_t *ptr = buf; + uint8_t *extensions_len_ptr = ptr; + bool client_hello = !tls->server; + unsigned int i = 0; + const struct l_queue_entry *entry = l_queue_get_entries(extensions); + + if (len < 2) + return -ENOSPC; + + ptr += 2; + len -= 2; + + while (1) { + const struct tls_hello_extension *extension; + ssize_t ext_len; + ssize_t (*ext_write)(struct l_tls *tls, + uint8_t *buf, size_t len); + + if (client_hello) { + extension = &tls_extensions[i++]; + if (!extension->name) + break; + + ext_write = extension->client_write; + } else { + uint16_t ext_id; + + if (!entry) + break; + + ext_id = L_PTR_TO_UINT(entry->data); + entry = entry->next; + + for (i = 0; tls_extensions[i].name; i++) + if (tls_extensions[i].id == ext_id) + break; + + extension = &tls_extensions[i]; + if (!extension->name) + continue; + + ext_write = extension->server_write; + } + + /* + * Note: could handle NULL client_write with non-NULL + * server_handle or server_handle_absent as "server-oriented" + * extension (7.4.1.4) and write empty extension_data and + * similarly require empty extension_data in + * tls_handle_client_hello if client_handle NULL. + */ + if (!ext_write) + continue; + + if (len < 4) + return -ENOSPC; + + ext_len = ext_write(tls, ptr + 4, len - 4); + if (ext_len == -ENOMSG) + continue; + + if (ext_len < 0) { + TLS_DEBUG("%s extension's %s_write: %s", + extension->name, + client_hello ? "client" : "server", + strerror(-ext_len)); + return ext_len; + } + + l_put_be16(extension->id, ptr + 0); + l_put_be16(ext_len, ptr + 2); + ptr += 4 + ext_len; + len -= 4 + ext_len; + } + + if (ptr > extensions_len_ptr + 2) + l_put_be16(ptr - (extensions_len_ptr + 2), extensions_len_ptr); + else /* Skip the length if no extensions */ + ptr = extensions_len_ptr; + + return ptr - buf; +} + +static bool tls_send_client_hello(struct l_tls *tls) +{ + uint8_t buf[1024 + L_ARRAY_SIZE(tls_compression_pref)]; + uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; + uint8_t *len_ptr; + unsigned int i; + ssize_t r; + struct tls_cipher_suite **suite; + + /* Fill in the Client Hello body */ + + *ptr++ = (uint8_t) (tls->client_version >> 8); + *ptr++ = (uint8_t) (tls->client_version >> 0); + + tls_write_random(tls->pending.client_random); + memcpy(ptr, tls->pending.client_random, 32); + ptr += 32; + + if (tls->session_id_size) { + *ptr++ = tls->session_id_size; + memcpy(ptr, tls->session_id, tls->session_id_size); + ptr += tls->session_id_size; + } else + *ptr++ = 0; + + len_ptr = ptr; + ptr += 2; + + for (suite = tls->cipher_suite_pref_list; *suite; suite++) { + const char *error; + + if (!tls_cipher_suite_is_compatible(tls, *suite, &error)) { + TLS_DEBUG("non-fatal: %s", error); + continue; + } + + *ptr++ = (*suite)->id[0]; + *ptr++ = (*suite)->id[1]; + } + + if (ptr == len_ptr + 2) { + TLS_DEBUG("No compatible cipher suites, check kernel config, " + "certificate's key type and TLS version range"); + return false; + } + + l_put_be16((ptr - len_ptr - 2), len_ptr); + *ptr++ = L_ARRAY_SIZE(tls_compression_pref); + + for (i = 0; i < L_ARRAY_SIZE(tls_compression_pref); i++) + *ptr++ = tls_compression_pref[i].id; + + r = tls_append_hello_extensions(tls, NULL, + ptr, buf + sizeof(buf) - ptr); + if (r < 0) + return false; + + ptr += r; + + tls_tx_handshake(tls, TLS_CLIENT_HELLO, buf, ptr - buf); + return true; +} + +static bool tls_send_server_hello(struct l_tls *tls, struct l_queue *extensions) +{ + uint8_t buf[1024]; + uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; + ssize_t r; + + /* Fill in the Server Hello body */ + + *ptr++ = tls->negotiated_version >> 8; + *ptr++ = tls->negotiated_version >> 0; + + tls_write_random(tls->pending.server_random); + memcpy(ptr, tls->pending.server_random, 32); + ptr += 32; + + if (tls->session_id_size) { + *ptr++ = tls->session_id_size; + memcpy(ptr, tls->session_id, tls->session_id_size); + ptr += tls->session_id_size; + } else + *ptr++ = 0; + + *ptr++ = tls->pending.cipher_suite->id[0]; + *ptr++ = tls->pending.cipher_suite->id[1]; + + *ptr++ = tls->pending.compression_method->id; + + r = tls_append_hello_extensions(tls, extensions, + ptr, buf + sizeof(buf) - ptr); + if (r < 0) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Error appending extensions: %s", + strerror(-r)); + return false; + } + + ptr += r; + + tls_tx_handshake(tls, TLS_SERVER_HELLO, buf, ptr - buf); + return true; +} + +static bool tls_cert_list_add_size(struct l_cert *cert, void *user_data) +{ + size_t *total = user_data; + size_t der_len; + + l_cert_get_der_data(cert, &der_len); + *total += 3 + der_len; + + return false; +} + +static bool tls_cert_list_append(struct l_cert *cert, void *user_data) +{ + uint8_t **ptr = user_data; + const uint8_t *der; + size_t der_len; + + der = l_cert_get_der_data(cert, &der_len); + *(*ptr)++ = der_len >> 16; + *(*ptr)++ = der_len >> 8; + *(*ptr)++ = der_len >> 0; + memcpy(*ptr, der, der_len); + *ptr += der_len; + + return false; +} + +static bool tls_send_certificate(struct l_tls *tls) +{ + uint8_t *buf, *ptr; + size_t total; + + if (tls->server && !tls->cert) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, TLS_ALERT_BAD_CERT, + "Certificate needed in server mode"); + return false; + } + + /* + * TODO: check that the certificate is compatible with hash and + * signature algorithms lists supplied to us in the Client Hello + * extensions (if we're a 1.2+ server) or in the Certificate Request + * (if we act as a 1.2+ client). + * + * - for the hash and signature_algorithms list, check all + * certs in the cert chain. + * + * - also if !cipher_suite->key_xchg->key_exchange_msg, check that the + * end entity certificate's key type matches and is usable with some + * hash/signature pair. + * + * - on client check if any of the supplied DNs (if any) match + * anything in our cert chain. + */ + + total = 0; + l_certchain_walk_from_leaf(tls->cert, tls_cert_list_add_size, &total); + + buf = l_malloc(128 + total); + ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; + + /* Fill in the Certificate body */ + + *ptr++ = total >> 16; + *ptr++ = total >> 8; + *ptr++ = total >> 0; + l_certchain_walk_from_leaf(tls->cert, tls_cert_list_append, &ptr); + + tls_tx_handshake(tls, TLS_CERTIFICATE, buf, ptr - buf); + + l_free(buf); + + if (tls->cert) + tls->cert_sent = true; + + return true; +} + +/* + * Note: ClientCertificateType.rsa_sign value coincides with the + * SignatureAlgorithm.rsa value but other values in those enum are + * different so we don't mix them, can't extract them from + * tls->pending.cipher_suite->signature. + */ +static uint8_t tls_cert_type_pref[] = { + 1, /* RSA_sign */ +}; + +static bool tls_send_certificate_request(struct l_tls *tls) +{ + uint8_t *buf, *ptr, *dn_ptr; + size_t len; + const struct l_queue_entry *entry; + unsigned int i; + size_t dn_total = 0; + + for (entry = l_queue_get_entries(tls->ca_certs); entry; + entry = entry->next) { + struct l_cert *ca_cert = entry->data; + size_t dn_size; + + if (l_cert_get_dn(ca_cert, &dn_size)) + dn_total += 10 + dn_size; + } + + len = 256 + L_ARRAY_SIZE(tls_cert_type_pref) + dn_total; + buf = l_malloc(len); + ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; + + /* Fill in the Certificate Request body */ + + *ptr++ = L_ARRAY_SIZE(tls_cert_type_pref); + for (i = 0; i < L_ARRAY_SIZE(tls_cert_type_pref); i++) + *ptr++ = tls_cert_type_pref[i]; + + if (tls->negotiated_version >= L_TLS_V12) { + ssize_t ret = tls_write_signature_algorithms(tls, ptr, + buf + len - ptr); + + if (ret < 0) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "tls_write_signature_algorithms: %s", + strerror(-ret)); + l_free(buf); + return false; + } + + ptr += ret; + } + + dn_ptr = ptr; + ptr += 2; /* Leave space for the total DN size */ + + for (entry = l_queue_get_entries(tls->ca_certs); entry; + entry = entry->next) { + struct l_cert *ca_cert = entry->data; + size_t dn_size; + const uint8_t *dn = l_cert_get_dn(ca_cert, &dn_size); + uint8_t *cur_dn_ptr = ptr; + + if (!dn) + continue; + + ptr += 2; /* Leave space for current DN size */ + *ptr++ = ASN1_ID_SEQUENCE; /* DER outer SEQUENCE tag */ + asn1_write_definite_length(&ptr, dn_size); /* length */ + memcpy(ptr, dn, dn_size); /* value */ + ptr += dn_size; + l_put_be16(ptr - cur_dn_ptr - 2, cur_dn_ptr); + } + + l_put_be16(ptr - dn_ptr - 2, dn_ptr); /* DistinguishedNames size */ + + tls_tx_handshake(tls, TLS_CERTIFICATE_REQUEST, buf, ptr - buf); + + l_free(buf); + + return true; +} + +static void tls_send_server_hello_done(struct l_tls *tls) +{ + uint8_t buf[32]; + + /* No body */ + + tls_tx_handshake(tls, TLS_SERVER_HELLO_DONE, buf, + TLS_HANDSHAKE_HEADER_SIZE); +} + +static void tls_update_key_block(struct l_tls *tls) +{ + uint8_t seed[64]; + int key_block_size = 0; + + if (tls->pending.cipher_suite->encryption) + key_block_size += 2 * + tls->pending.cipher_suite->encryption->key_length; + + if (tls->pending.cipher_suite->mac) + key_block_size += 2 * + tls->pending.cipher_suite->mac->mac_length; + + if (tls->pending.cipher_suite->encryption && + tls->negotiated_version <= L_TLS_V10 && + tls->pending.cipher_suite->encryption->cipher_type == + TLS_CIPHER_BLOCK) + key_block_size += 2 * + tls->pending.cipher_suite->encryption->iv_length; + + if (tls->pending.cipher_suite->encryption) + key_block_size += 2 * tls->pending.cipher_suite->encryption-> + fixed_iv_length; + + /* Reverse order from the master secret seed */ + memcpy(seed + 0, tls->pending.server_random, 32); + memcpy(seed + 32, tls->pending.client_random, 32); + + tls_prf_get_bytes(tls, tls->pending.master_secret, 48, + "key expansion", seed, 64, + tls->pending.key_block, key_block_size); + explicit_bzero(seed, 64); +} + +void tls_generate_master_secret(struct l_tls *tls, + const uint8_t *pre_master_secret, + int pre_master_secret_len) +{ + uint8_t seed[64]; + + memcpy(seed + 0, tls->pending.client_random, 32); + memcpy(seed + 32, tls->pending.server_random, 32); + + tls_prf_get_bytes(tls, pre_master_secret, pre_master_secret_len, + "master secret", seed, 64, + tls->pending.master_secret, 48); + explicit_bzero(seed, 64); + + /* Directly generate the key block while we're at it */ + tls_update_key_block(tls); +} + +static void tls_get_handshake_hash(struct l_tls *tls, + enum handshake_hash_type type, + uint8_t *out) +{ + struct l_checksum *hash = l_checksum_clone(tls->handshake_hash[type]); + + if (!hash) + return; + + l_checksum_get_digest(hash, out, l_checksum_digest_length( + tls_handshake_hash_data[type].l_id)); + l_checksum_free(hash); +} + +static bool tls_get_handshake_hash_by_type(struct l_tls *tls, + enum handshake_hash_type type, + const uint8_t *data, size_t data_len, + uint8_t *out, size_t *out_len) +{ + if (!tls->handshake_hash[type]) + return false; + + if (out_len) + *out_len = l_checksum_digest_length( + tls_handshake_hash_data[type].l_id); + + tls_get_handshake_hash(tls, type, out); + return true; +} + +static bool tls_send_certificate_verify(struct l_tls *tls) +{ + uint8_t buf[2048]; + int i; + ssize_t sign_len; + + /* Fill in the Certificate Verify body */ + + sign_len = tls->pending.cipher_suite->signature->sign(tls, + buf + TLS_HANDSHAKE_HEADER_SIZE, + 2048 - TLS_HANDSHAKE_HEADER_SIZE, + tls_get_handshake_hash_by_type, + NULL, 0); + + if (sign_len < 0) + return false; + + /* Stop maintaining handshake message hashes other than the PRF hash */ + if (tls->negotiated_version >= L_TLS_V12) + for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++) + if (&tls_handshake_hash_data[i] != tls->prf_hmac) + tls_drop_handshake_hash(tls, i); + + tls_tx_handshake(tls, TLS_CERTIFICATE_VERIFY, buf, + sign_len + TLS_HANDSHAKE_HEADER_SIZE); + + return true; +} + +static void tls_send_change_cipher_spec(struct l_tls *tls) +{ + uint8_t buf = 1; + + tls_tx_record(tls, TLS_CT_CHANGE_CIPHER_SPEC, &buf, 1); +} + +size_t tls_verify_data_length(struct l_tls *tls, unsigned int index) +{ + /* + * RFC 5246, Section 7.4.9: + * + * In previous versions of TLS, the verify_data was always 12 octets + * long. In the current version of TLS, it depends on the cipher + * suite. Any cipher suite which does not explicitly specify + * verify_data_length has a verify_data_length equal to 12. + */ + return maxsize(tls->cipher_suite[index]->verify_data_length, 12); +} + +static bool tls_save_verify_data(struct l_tls *tls, bool txrx, + const uint8_t *vd, size_t vdl) +{ + uint8_t *buf; + + if (tls->server == txrx) { + if (vdl > sizeof(tls->renegotiation_info.server_verify_data)) + goto error; + + buf = tls->renegotiation_info.server_verify_data; + } else { + if (vdl > sizeof(tls->renegotiation_info.client_verify_data)) + goto error; + + buf = tls->renegotiation_info.client_verify_data; + } + + memcpy(buf, vd, vdl); + return true; + +error: + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "tls->renegotiation_info.*verify too small for %s, " + "report an ell bug", tls->cipher_suite[txrx]->name); + return false; +} + +static bool tls_send_finished(struct l_tls *tls) +{ + uint8_t buf[512]; + uint8_t *ptr = buf + TLS_HANDSHAKE_HEADER_SIZE; + uint8_t seed[HANDSHAKE_HASH_MAX_SIZE * 2]; + size_t vdl = tls_verify_data_length(tls, 1); + size_t seed_len; + + if (tls->negotiated_version >= L_TLS_V12) { + /* Same hash type as that used for the PRF (usually SHA256) */ + tls_get_handshake_hash(tls, tls->prf_hmac->type, seed); + seed_len = l_checksum_digest_length(tls->prf_hmac->l_id); + } else { + tls_get_handshake_hash(tls, HANDSHAKE_HASH_MD5, seed + 0); + tls_get_handshake_hash(tls, HANDSHAKE_HASH_SHA1, seed + 16); + seed_len = 36; + } + + tls_prf_get_bytes(tls, tls->pending.master_secret, 48, + tls->server ? "server finished" : + "client finished", + seed, seed_len, + ptr, vdl); + + if (!tls_save_verify_data(tls, 1, ptr, vdl)) + return false; + + ptr += vdl; + + tls_tx_handshake(tls, TLS_FINISHED, buf, ptr - buf); + return true; +} + +static bool tls_verify_finished(struct l_tls *tls, const uint8_t *received, + size_t len) +{ + size_t vdl = tls_verify_data_length(tls, 0); + uint8_t expected[vdl]; + uint8_t *seed; + size_t seed_len; + + if (len != vdl) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "TLS_FINISHED length not %zu", vdl); + + return false; + } + + if (tls->negotiated_version >= L_TLS_V12) { + enum handshake_hash_type hash = tls->prf_hmac->type; + + seed = tls->prev_digest[hash]; + seed_len = l_checksum_digest_length(tls->prf_hmac->l_id); + } else { + seed = alloca(36); + memcpy(seed + 0, tls->prev_digest[HANDSHAKE_HASH_MD5], 16); + memcpy(seed + 16, tls->prev_digest[HANDSHAKE_HASH_SHA1], 20); + seed_len = 36; + } + + tls_prf_get_bytes(tls, tls->pending.master_secret, 48, + tls->server ? "client finished" : + "server finished", + seed, seed_len, + expected, vdl); + + if (memcmp(received, expected, len)) { + TLS_DISCONNECT(TLS_ALERT_DECRYPT_ERROR, 0, + "TLS_FINISHED contents don't match"); + + return false; + } + + if (!tls_save_verify_data(tls, 0, received, vdl)) + return false; + + return true; +} + +static bool tls_ptr_match(const void *a, const void *b) +{ + return a == b; +} + +static bool tls_handle_hello_extensions(struct l_tls *tls, + const uint8_t *buf, size_t len, + struct l_queue *seen) +{ + unsigned int i; + const struct tls_hello_extension *extension; + bool client_hello = tls->server; + uint16_t extensions_size; + + if (!len) + return true; + + if (len < 2 || len > 2 + 65535) + goto decode_error; + + extensions_size = l_get_be16(buf); + len -= 2; + buf += 2; + + if (len != extensions_size) + goto decode_error; + + while (len) { + uint16_t ext_id; + size_t ext_len; + bool (*handler)(struct l_tls *tls, + const uint8_t *buf, size_t len); + + if (len < 4) + goto decode_error; + + ext_id = l_get_be16(buf + 0); + ext_len = l_get_be16(buf + 2); + buf += 4; + len -= 4; + + if (ext_len > len) + goto decode_error; + + /* + * RFC 5246, Section 7.4.1.4: "There MUST NOT be more than + * one extension of the same type." + */ + if (l_queue_find(seen, tls_ptr_match, L_UINT_TO_PTR(ext_id))) { + TLS_DEBUG("Duplicate extension %u", ext_id); + goto decode_error; + } + + l_queue_push_tail(seen, L_UINT_TO_PTR(ext_id)); + + extension = NULL; + + for (i = 0; tls_extensions[i].name; i++) + if (tls_extensions[i].id == ext_id) { + extension = &tls_extensions[i]; + break; + } + + if (!extension) + goto next; + + handler = client_hello ? + extension->client_handle : extension->server_handle; + + /* + * RFC 5246, Section 7.4.1.4: "If a client receives an + * extension type in ServerHello that it did not request in + * the associated ClientHello, it MUST abort the handshake + * with an unsupported_extension fatal alert." + * There are however servers that include an unsolicited + * Supported Point Format extension where the handshake + * still completes fine if the extension is ignored so we + * do this instead. + */ + if (!client_hello && !handler) { + TLS_DEBUG("non-fatal: %s extension not expected in " + "a ServerHello", extension->name); + goto next; + } + + if (!handler(tls, buf, ext_len)) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "Hello %s extension parse error", + extension->name); + return false; + } + +next: + buf += ext_len; + len -= ext_len; + } + + /* + * Trigger any actions needed when an extension is missing and its + * handler has not been called yet. + */ + for (i = 0; tls_extensions[i].name; i++) { + bool (*handler)(struct l_tls *tls); + + extension = &tls_extensions[i]; + handler = client_hello ? + extension->client_handle_absent : + extension->server_handle_absent; + + if (!handler) + continue; + + if (l_queue_find(seen, tls_ptr_match, + L_UINT_TO_PTR(extension->id))) + continue; + + if (!handler(tls)) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "Hello %s extension missing", + extension->name); + return false; + } + } + + return true; + +decode_error: + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "Hello extensions decode error"); + return false; +} + +static void tls_server_resume_error(struct l_tls *tls) +{ + /* + * When Client Hello parameters don't match the parameters of the + * cached session that was requested by the client, we'll probably + * start and cache a new session. Even though RFC 5246 doesn't + * specifically mandate that the requested session be forgotten + * (there's no fatal Alert in that case), we overwrite the old + * session's entry in the cache with the new session's data to + * avoid keeping many sessions related to one client in the cache. + * In theory this allows an attacker to connect as a client and + * invalidate a legitimate client's session entry in our cache, + * DoSing the session resumption mechanism so that clients have + * to go through the full handshake. In practice there are many + * ways for an attacker to do that even without this. + * + * Our client mode only caches one last session anyway, other + * implementations may work that way too. + */ + memcpy(tls->session_id_replaced, tls->session_id, tls->session_id_size); + tls->session_id_size_replaced = tls->session_id_size; + + tls->session_id_size = 0; + tls->session_id_new = false; + l_free(l_steal_ptr(tls->session_peer_identity)); +} + +/* RFC 5746 */ +static const uint8_t tls_empty_renegotiation_info_scsv[2] = { 0x00, 0xff }; +static const uint16_t tls_renegotiation_info_id = 0xff01; + +static void tls_handle_client_hello(struct l_tls *tls, + const uint8_t *buf, size_t len) +{ + uint16_t cipher_suites_size; + uint8_t session_id_size, compression_methods_size; + const uint8_t *cipher_suites; + const uint8_t *compression_methods; + int i; + struct l_queue *extensions_offered = NULL; + enum l_tls_alert_desc alert_desc = TLS_ALERT_HANDSHAKE_FAIL; + bool resuming = false; + _auto_(l_free) char *session_id_str = NULL; + struct tls_cipher_suite *backup_suite = NULL; + struct tls_compression_method *backup_cm = NULL; + + /* Do we have enough for ProtocolVersion + Random + SessionID size? */ + if (len < 2 + 32 + 1) + goto decode_error; + + memcpy(tls->pending.client_random, buf + 2, 32); + session_id_size = buf[34]; + len -= 35; + + if (unlikely(session_id_size > 32)) + goto decode_error; + + /* + * Do we have enough to hold the actual session ID + 2 byte field for + * cipher_suite len + minimum of a single cipher suite identifier + */ + if (len < (size_t) session_id_size + 4) + goto decode_error; + + len -= session_id_size + 2; + + cipher_suites_size = l_get_be16(buf + 35 + session_id_size); + cipher_suites = buf + 37 + session_id_size; + + /* + * Check that size is not odd, more than 0 and we have enough + * data in the packet for cipher_suites_size + 2 bytes for + * compression_methods_size + a single compression method + */ + if (len < (size_t) cipher_suites_size + 2 || + (cipher_suites_size & 1) || cipher_suites_size == 0) + goto decode_error; + + len -= cipher_suites_size + 1; + + compression_methods_size = cipher_suites[cipher_suites_size]; + compression_methods = cipher_suites + cipher_suites_size + 1; + + if (len < (size_t) compression_methods_size || + compression_methods_size == 0) + goto decode_error; + + len -= compression_methods_size; + + if (session_id_size && tls->session_settings && + tls_load_cached_server_session(tls, buf + 35, + session_id_size)) { + /* + * Attempt a session resumption but note later checks may + * spoil this. + */ + resuming = true; + session_id_str = l_util_hexstring(tls->session_id, + tls->session_id_size); + } + + if (tls->pending_destroy) + return; + + extensions_offered = l_queue_new(); + + if (!tls_handle_hello_extensions(tls, compression_methods + + compression_methods_size, + len, extensions_offered)) + goto cleanup; + + /* Save client_version for Premaster Secret verification */ + tls->client_version = l_get_be16(buf); + + if (tls->client_version < tls->min_version) { + TLS_DISCONNECT(TLS_ALERT_PROTOCOL_VERSION, 0, + "Client version too low: %02x", + tls->client_version); + goto cleanup; + } + + tls->negotiated_version = tls->client_version > tls->max_version ? + tls->max_version : tls->client_version; + + /* Stop maintaining handshake message hashes other than MD1 and SHA. */ + if (tls->negotiated_version < L_TLS_V12) + for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++) + if (i != HANDSHAKE_HASH_SHA1 && i != HANDSHAKE_HASH_MD5) + tls_drop_handshake_hash(tls, i); + + TLS_DEBUG("Negotiated TLS " TLS_VER_FMT, + TLS_VER_ARGS(tls->negotiated_version)); + + if (!tls->cipher_suite_pref_list) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "No usable cipher suites"); + goto cleanup; + } + + if (!tls->renegotiation_info.secure_renegotiation || tls->ready) { + for (i = 0; i < cipher_suites_size; i += 2) + if (l_get_be16(cipher_suites + i) == l_get_be16( + tls_empty_renegotiation_info_scsv)) + break; + + if (i < cipher_suites_size) { + if (unlikely(tls->ready)) { + TLS_DISCONNECT(TLS_ALERT_ILLEGAL_PARAM, 0, + "Empty renegotiation_info in " + "renegotiation Client Hello"); + goto cleanup; + } + + /* + * RFC 5746 Section 3.6, act as if we had received an + * empty renegotiation_info extension. + */ + tls->renegotiation_info.secure_renegotiation = true; + l_queue_push_tail(extensions_offered, L_UINT_TO_PTR( + tls_renegotiation_info_id)); + } + } + + /* Select a cipher suite according to client's preference list */ + while (cipher_suites_size) { + struct tls_cipher_suite *suite = + tls_find_cipher_suite(cipher_suites); + struct tls_cipher_suite **iter; + const char *error; + + for (iter = tls->cipher_suite_pref_list; *iter; iter++) + if (*iter == suite) + break; + + if (!suite) + TLS_DEBUG("non-fatal: Cipher suite %04x unknown", + l_get_be16(cipher_suites)); + else if (!tls_cipher_suite_is_compatible(tls, suite, &error)) + TLS_DEBUG("non-fatal: %s", error); + else if (!*iter) { + /* + * We have at least one matching compatible suite but + * it is not allowed in this security profile. If the + * handshake ends up failing then we blame the security + * profile. + */ + alert_desc = TLS_ALERT_INSUFFICIENT_SECURITY; + TLS_DEBUG("non-fatal: Cipher suite %s disallowed " + "by config", suite->name); + } else if (resuming && memcmp(tls->session_cipher_suite_id, + suite->id, 2)) { + /* + * For now skip this cipher suite because we're trying + * to find the one from the cached session state. But + * keep it as a backup in case we end up starting a new + * session. + */ + if (!backup_suite) + backup_suite = suite; + } else { + tls->pending.cipher_suite = suite; + break; + } + + cipher_suites += 2; + cipher_suites_size -= 2; + } + + if (unlikely(!cipher_suites_size && backup_suite)) { + TLS_DEBUG("Cached session %s's cipher suite %04x " + "unavailable, will start a new session", + session_id_str, + l_get_be16(tls->session_cipher_suite_id)); + tls->pending.cipher_suite = backup_suite; + resuming = false; + tls_server_resume_error(tls); + } else if (unlikely(!cipher_suites_size)) { + TLS_DISCONNECT(alert_desc, 0, + "No common cipher suites matching negotiated " + "TLS version and our certificate's key type"); + goto cleanup; + } + + if (!tls_set_prf_hmac(tls)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Error selecting the PRF HMAC"); + goto cleanup; + } + + /* Select a compression method */ + + /* CompressionMethod.null must be present in the vector */ + while (compression_methods_size) { + struct tls_compression_method *cm = + tls_find_compression_method(*compression_methods); + + if (!cm) + TLS_DEBUG("non-fatal: Compression %02x unknown", + *compression_methods); + else if (resuming && *compression_methods != + tls->session_compression_method_id) { + /* + * For now skip this compression method because we're + * trying to find the one from the cached session state. + * But keep it as a backup in case we end up starting + * a new * session. + */ + if (!backup_cm) + backup_cm = cm; + } else { + tls->pending.compression_method = cm; + break; + } + + compression_methods++; + compression_methods_size--; + } + + if (unlikely(!compression_methods_size && backup_cm)) { + TLS_DEBUG("Cached session %s's compression method %02x " + "unavailable, will start a new session", + session_id_str, + tls->session_compression_method_id); + tls->pending.compression_method = backup_cm; + + if (backup_suite) + tls->pending.cipher_suite = backup_suite; + + resuming = false; + tls_server_resume_error(tls); + } else if (unlikely(!compression_methods_size)) { + TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, + "No common compression methods"); + goto cleanup; + } + + if (resuming) + TLS_DEBUG("Negotiated resumption of cached session %s", + session_id_str); + + TLS_DEBUG("Negotiated %s", tls->pending.cipher_suite->name); + TLS_DEBUG("Negotiated %s", tls->pending.compression_method->name); + + if (!resuming && tls->session_settings) { + tls->session_id_new = true; + tls->session_id_size = 32; + l_getrandom(tls->session_id, 32); + } + + if (!tls_send_server_hello(tls, extensions_offered)) + goto cleanup; + + l_queue_destroy(extensions_offered, NULL); + + if (resuming) { + const char *error; + + tls_update_key_block(tls); + tls_send_change_cipher_spec(tls); + + if (!tls_change_cipher_spec(tls, 1, &error)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "change_cipher_spec: %s", error); + return; + } + + if (!tls_send_finished(tls)) + return; + + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC); + return; + } + + if (tls->pending.cipher_suite->signature && tls->cert) + if (!tls_send_certificate(tls)) + return; + + if (tls->pending.cipher_suite->key_xchg->send_server_key_exchange) + if (!tls->pending.cipher_suite->key_xchg-> + send_server_key_exchange(tls)) + return; + + /* TODO: don't bother if configured to not authenticate client */ + if (tls->pending.cipher_suite->signature && tls->ca_certs) + if (!tls_send_certificate_request(tls)) + return; + + tls_send_server_hello_done(tls); + + if (tls->pending.cipher_suite->signature && tls->ca_certs) + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CERTIFICATE); + else + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_KEY_EXCHANGE); + + return; + +decode_error: + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "ClientHello decode error"); + +cleanup: + l_queue_destroy(extensions_offered, NULL); +} + +static void tls_handle_server_hello(struct l_tls *tls, + const uint8_t *buf, size_t len) +{ + uint8_t session_id_size, cipher_suite_id[2], compression_method_id; + const char *error; + struct tls_cipher_suite **iter; + int i; + struct l_queue *extensions_seen; + bool result; + uint16_t version; + bool resuming = false; + + /* Do we have enough for ProtocolVersion + Random + SessionID len ? */ + if (len < 2 + 32 + 1) + goto decode_error; + + version = l_get_be16(buf); + memcpy(tls->pending.server_random, buf + 2, 32); + session_id_size = buf[34]; + len -= 35; + + /* Do we have enough for SessionID + CipherSuite ID + Compression ID */ + if (len < (size_t) session_id_size + 2 + 1) + goto decode_error; + + cipher_suite_id[0] = buf[35 + session_id_size + 0]; + cipher_suite_id[1] = buf[35 + session_id_size + 1]; + compression_method_id = buf[35 + session_id_size + 2]; + len -= session_id_size + 2 + 1; + + if (session_id_size > 32) + goto decode_error; + + if (tls->session_id_size) { + _auto_(l_free) char *session_id_str = + l_util_hexstring(tls->session_id, tls->session_id_size); + + if (session_id_size == tls->session_id_size && + !memcmp(buf + 35, tls->session_id, + session_id_size)) { + TLS_DEBUG("Negotiated resumption of cached session %s", + session_id_str); + resuming = true; + } else { + TLS_DEBUG("Server decided not to resume cached session " + "%s, sent %s session ID", + session_id_str, + session_id_size ? "a new" : "no"); + tls->session_id_size = 0; + } + } + + if (session_id_size && !resuming && tls->session_settings) { + tls->session_id_new = true; + tls->session_id_size = session_id_size; + memcpy(tls->session_id, buf + 35, session_id_size); + } + + extensions_seen = l_queue_new(); + result = tls_handle_hello_extensions(tls, buf + 38 + session_id_size, + len, extensions_seen); + l_queue_destroy(extensions_seen, NULL); + + if (!result) + return; + + if (version < tls->min_version || version > tls->max_version) { + TLS_DISCONNECT(version < tls->min_version ? + TLS_ALERT_PROTOCOL_VERSION : + TLS_ALERT_ILLEGAL_PARAM, 0, + "Unsupported version %02x", version); + return; + } + + tls->negotiated_version = version; + + /* Stop maintaining handshake message hashes other than MD1 and SHA. */ + if (tls->negotiated_version < L_TLS_V12) + for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++) + if (i != HANDSHAKE_HASH_SHA1 && i != HANDSHAKE_HASH_MD5) + tls_drop_handshake_hash(tls, i); + + TLS_DEBUG("Negotiated TLS " TLS_VER_FMT, + TLS_VER_ARGS(tls->negotiated_version)); + + /* Set the new cipher suite and compression method structs */ + tls->pending.cipher_suite = tls_find_cipher_suite(cipher_suite_id); + if (!tls->pending.cipher_suite) { + TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, + "Unknown cipher suite %04x", + l_get_be16(cipher_suite_id)); + return; + } + + for (iter = tls->cipher_suite_pref_list; *iter; iter++) + if (*iter == tls->pending.cipher_suite) + break; + if (!*iter) { + TLS_DISCONNECT(TLS_ALERT_INSUFFICIENT_SECURITY, 0, + "Selected cipher suite %s disallowed by config", + tls->pending.cipher_suite->name); + return; + } + + if (!tls_cipher_suite_is_compatible(tls, tls->pending.cipher_suite, + &error)) { + TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, + "Selected cipher suite not compatible: %s", + error); + return; + } + + if (!tls_set_prf_hmac(tls)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Error selecting the PRF HMAC"); + return; + } + + TLS_DEBUG("Negotiated %s", tls->pending.cipher_suite->name); + + tls->pending.compression_method = + tls_find_compression_method(compression_method_id); + if (!tls->pending.compression_method) { + TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, + "Unknown compression method %i", + compression_method_id); + return; + } + + TLS_DEBUG("Negotiated %s", tls->pending.compression_method->name); + + if (resuming) { + /* + * Now that we've validated the Server Hello parameters and + * know that they're supported by this version of ell and + * consistent with the current configuration, ensure that + * they're identical with the ones in the cached session + * being resumed. This serves as a sanity check for + * rare situations like a corrupt session cache file or + * a file written by a newer ell version. + */ + if (tls->negotiated_version != tls->client_version || + memcmp(cipher_suite_id, + tls->session_cipher_suite_id, 2) || + compression_method_id != + tls->session_compression_method_id) { + TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, + "Session parameters don't match"); + return; + } + + tls_update_key_block(tls); + + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC); + } else if (tls->pending.cipher_suite->signature) + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CERTIFICATE); + else + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_KEY_EXCHANGE); + + return; + +decode_error: + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "ServerHello decode error"); +} + +static void tls_handle_certificate(struct l_tls *tls, + const uint8_t *buf, size_t len) +{ + size_t total; + _auto_(l_certchain_free) struct l_certchain *certchain = NULL; + struct l_cert *leaf; + size_t der_len; + const uint8_t *der; + bool dummy; + const char *error_str; + char *subject_str; + + if (len < 3) + goto decode_error; + + /* Length checks */ + total = *buf++ << 16; + total |= *buf++ << 8; + total |= *buf++ << 0; + if (total + 3 != len) + goto decode_error; + + if (tls_parse_certificate_list(buf, total, &certchain) < 0) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "Error decoding peer certificate chain"); + + return; + } + + /* + * "Note that a client MAY send no certificates if it does not have any + * appropriate certificate to send in response to the server's + * authentication request." -- for now we unconditionally accept + * an empty certificate chain from the client. Later on we need to + * make this configurable, if we don't want to authenticate the + * client then also don't bother sending a Certificate Request. + */ + if (!certchain) { + if (!tls->server) { + TLS_DISCONNECT(TLS_ALERT_HANDSHAKE_FAIL, 0, + "Server sent no certificate chain"); + + return; + } + + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_KEY_EXCHANGE); + + return; + } + + if (tls->cert_dump_path) { + int r = pem_write_certificate_chain(certchain, + tls->cert_dump_path); + + if (r < 0) + TLS_DEBUG("Error %i (%s) writing the peer certchain " + "to %s", + -r, strerror(-r), tls->cert_dump_path); + else + TLS_DEBUG("Peer certchain written to %s", + tls->cert_dump_path); + } + + /* + * Validate the certificate chain's consistency and validate it + * against our CAs if we have any. + */ + if (!l_certchain_verify(certchain, tls->ca_certs, &error_str)) { + if (tls->ca_certs) { + TLS_DISCONNECT(TLS_ALERT_BAD_CERT, 0, + "Peer certchain verification failed " + "consistency check%s: %s", + tls->ca_certs ? + " or against local CA certs" : "", + error_str); + + return; + } + + /* + * Until the mainstream kernel can handle the occasionally + * used certificates without the AKID extension (both root, + * which is legal, and non-root, which is iffy but still + * happens) don't fail on peer certificate chain verification + * failure when CA certificates were not provided. Knowing + * that the chain is self-consistent alone doesn't + * authenticate the peer in any way. Only warn when it looks + * like the chain is bad but parses and we can get the peer + * public key from it below. + */ + TLS_DEBUG("Peer certchain verification failed (%s.) No local " + "CA certs provided so proceeding anyway. This " + "failure can signal a security issue or a " + "known kernel problem with some certificates.", + error_str); + } + + /* + * RFC5246 7.4.2: + * "The end entity certificate's public key (and associated + * restrictions) MUST be compatible with the selected key exchange + * algorithm." + */ + leaf = l_certchain_get_leaf(certchain); + if (!tls->pending.cipher_suite->signature-> + validate_cert_key_type(leaf)) { + TLS_DISCONNECT(TLS_ALERT_UNSUPPORTED_CERT, 0, + "Peer certificate key type incompatible with " + "pending cipher suite %s", + tls->pending.cipher_suite->name); + + return; + } + + if (tls->subject_mask && !tls_cert_domains_match_mask(leaf, + tls->subject_mask, + &subject_str)) { + char *mask = l_strjoinv(tls->subject_mask, '|'); + + TLS_DISCONNECT(TLS_ALERT_BAD_CERT, 0, + "Peer certificate's subject domain " + "doesn't match mask %s: %s", mask, subject_str); + l_free(mask); + l_free(subject_str); + + return; + } + + /* Save the end-entity certificate and free the chain */ + der = l_cert_get_der_data(leaf, &der_len); + tls->peer_cert = l_cert_new_from_der(der, der_len); + + tls->peer_pubkey = l_cert_get_pubkey(tls->peer_cert); + if (!tls->peer_pubkey) { + TLS_DISCONNECT(TLS_ALERT_UNSUPPORTED_CERT, 0, + "Error loading peer public key to kernel"); + + return; + } + + switch (l_cert_get_pubkey_type(tls->peer_cert)) { + case L_CERT_KEY_RSA: + if (!l_key_get_info(tls->peer_pubkey, L_KEY_RSA_PKCS1_V1_5, + L_CHECKSUM_NONE, + &tls->peer_pubkey_size, &dummy)) + goto pubkey_unsupported; + break; + case L_CERT_KEY_ECC: + if (!l_key_get_info(tls->peer_pubkey, L_KEY_ECDSA_X962, + L_CHECKSUM_SHA1, + &tls->peer_pubkey_size, &dummy)) + goto pubkey_unsupported; + break; + case L_CERT_KEY_UNKNOWN: + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Unknown public key type"); + return; + } + + tls->peer_pubkey_size /= 8; + + if (tls->server || tls->pending.cipher_suite->key_xchg-> + handle_server_key_exchange) + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_KEY_EXCHANGE); + else + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO_DONE); + + return; + +pubkey_unsupported: + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "Can't l_key_get_info for peer public key"); + return; +decode_error: + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "TLS_CERTIFICATE decode error"); +} + +static void tls_handle_certificate_request(struct l_tls *tls, + const uint8_t *buf, size_t len) +{ + unsigned int cert_type_len, dn_len, i; + + tls->cert_requested = 1; + + cert_type_len = *buf++; + if (len < 1 + cert_type_len + 2) + goto decode_error; + + for (i = 0; i < sizeof(tls_cert_type_pref); i++) + if (memchr(buf, tls_cert_type_pref[i], cert_type_len)) + break; + + if (i == sizeof(tls_cert_type_pref)) { + TLS_DISCONNECT(TLS_ALERT_UNSUPPORTED_CERT, 0, + "Requested certificate types not supported"); + return; + } + + buf += cert_type_len; + len -= 1 + cert_type_len; + + /* + * TODO: parse and save certificate_types, + * supported_signature_algorithms and certificate_authorities + * lists for use in tls_send_certificate. + */ + + if (tls->negotiated_version >= L_TLS_V12) { + enum handshake_hash_type hash; + ssize_t ret = tls_parse_signature_algorithms(tls, buf, len); + + if (ret == -ENOTSUP) { + TLS_DISCONNECT(TLS_ALERT_UNSUPPORTED_CERT, 0, + "No supported signature hash type"); + return; + } + + if (ret < 0) + goto decode_error; + + len -= ret; + buf += ret; + + /* + * We can now safely stop maintaining handshake message + * hashes other than the PRF hash and the one selected for + * signing. + */ + for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) + if (&tls_handshake_hash_data[hash] != tls->prf_hmac && + hash != tls->signature_hash) + tls_drop_handshake_hash(tls, hash); + } + + dn_len = l_get_be16(buf); + if (2 + dn_len != len) + goto decode_error; + + return; + +decode_error: + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "CertificateRequest decode error"); +} + +static void tls_handle_server_hello_done(struct l_tls *tls, + const uint8_t *buf, size_t len) +{ + const char *error; + + if (len) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "ServerHello not empty"); + return; + } + + if (tls->cert_requested) + if (!tls_send_certificate(tls)) + return; + + if (!tls->pending.cipher_suite->key_xchg->send_client_key_exchange(tls)) + return; + + if (tls->cert_sent) + if (!tls_send_certificate_verify(tls)) + return; + + tls_send_change_cipher_spec(tls); + + if (!tls_change_cipher_spec(tls, 1, &error)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "change_cipher_spec: %s", error); + return; + } + + if (!tls_send_finished(tls)) + return; + + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC); +} + +static bool tls_get_prev_digest_by_type(struct l_tls *tls, + enum handshake_hash_type type, + const uint8_t *data, size_t data_len, + uint8_t *out, size_t *out_len) +{ + size_t len; + + if (!tls->handshake_hash[type]) + return false; + + len = l_checksum_digest_length(tls_handshake_hash_data[type].l_id); + memcpy(out, tls->prev_digest[type], len); + + if (out_len) + *out_len = len; + + return 0; +} + +static void tls_handle_certificate_verify(struct l_tls *tls, + const uint8_t *buf, size_t len) +{ + int i; + + if (!tls->pending.cipher_suite->signature->verify(tls, buf, len, + tls_get_prev_digest_by_type, + NULL, 0)) + return; + + /* Stop maintaining handshake message hashes other than the PRF hash */ + if (tls->negotiated_version >= L_TLS_V12) + for (i = 0; i < __HANDSHAKE_HASH_COUNT; i++) + if (&tls_handshake_hash_data[i] != tls->prf_hmac) + tls_drop_handshake_hash(tls, i); + + /* + * The client's certificate is now verified based on the following + * logic: + * - If we received an (expected) Certificate Verify, we must have + * sent a Certificate Request. + * - If we sent a Certificate Request that's because + * tls->ca_certs is non-NULL. + * - If tls->ca_certs is non-NULL then tls_handle_certificate + * will have checked the whole certificate chain to be valid and + * additionally trusted by our CAs if known. + * - Additionally cipher_suite->signature->verify has just confirmed + * that the peer owns the end-entity certificate because it was + * able to sign the contents of the handshake messages and that + * signature could be verified with the public key from that + * certificate. + */ + tls->peer_authenticated = true; + + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC); +} + +struct dn_element_info { + const char *str; + const struct asn1_oid oid; +}; + +static const struct dn_element_info dn_elements[] = { + { "CN", { 3, { 0x55, 0x04, 0x03 } } }, + { "SN", { 3, { 0x55, 0x04, 0x04 } } }, + { "serialNumber", { 3, { 0x55, 0x04, 0x05 } } }, + { "C", { 3, { 0x55, 0x04, 0x06 } } }, + { "ST", { 3, { 0x55, 0x04, 0x07 } } }, + { "L", { 3, { 0x55, 0x04, 0x08 } } }, + { "street", { 3, { 0x55, 0x04, 0x09 } } }, + { "O", { 3, { 0x55, 0x04, 0x0a } } }, + { "OU", { 3, { 0x55, 0x04, 0x0b } } }, + { "title", { 3, { 0x55, 0x04, 0x0c } } }, + { "telephoneNumber", { 3, { 0x55, 0x04, 0x14 } } }, + { "givenName", { 3, { 0x55, 0x04, 0x2a } } }, + { "initials", { 3, { 0x55, 0x04, 0x2b } } }, + { "emailAddress", { + 9, + { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01 } + } }, + { "domainComponent", { + 10, + { 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19 } + } }, + {} +}; + +static void tls_str_escape_append(struct l_string *out, char *str, size_t len) +{ + while (len--) { + switch (*str) { + case '\\': + case '/': + case '=': + l_string_append_c(out, '\\'); + l_string_append_c(out, *str); + break; + default: + l_string_append_c(out, *str); + break; + } + + str++; + } +} + +static char *tls_get_peer_identity_str(struct l_cert *cert) +{ + const uint8_t *dn, *end; + size_t dn_size; + struct l_string *id_str; + + if (!cert) + return NULL; + + dn = l_cert_get_dn(cert, &dn_size); + if (!dn) + return NULL; + + id_str = l_string_new(200); + + end = dn + dn_size; + while (dn < end) { + const uint8_t *set, *seq, *oid, *name; + uint8_t tag; + size_t len, oid_len, name_len; + const struct dn_element_info *info; + + set = asn1_der_find_elem(dn, end - dn, 0, &tag, &len); + if (!set || tag != ASN1_ID_SET) + goto error; + + dn = set + len; + + seq = asn1_der_find_elem(set, len, 0, &tag, &len); + if (!seq || tag != ASN1_ID_SEQUENCE) + goto error; + + oid = asn1_der_find_elem(seq, len, 0, &tag, &oid_len); + if (!oid || tag != ASN1_ID_OID) + goto error; + + name = asn1_der_find_elem(seq, len, 1, &tag, &name_len); + if (!name || (tag != ASN1_ID_PRINTABLESTRING && + tag != ASN1_ID_UTF8STRING && + tag != ASN1_ID_IA5STRING)) + continue; + + for (info = dn_elements; info->str; info++) + if (asn1_oid_eq(&info->oid, oid_len, oid)) + break; + if (!info->str) + continue; + + l_string_append_c(id_str, '/'); + l_string_append(id_str, info->str); + l_string_append_c(id_str, '='); + tls_str_escape_append(id_str, (char *) name, name_len); + } + + return l_string_unwrap(id_str); + +error: + l_string_free(id_str); + return NULL; +} + +static void tls_finished(struct l_tls *tls) +{ + _auto_(l_free) char *peer_cert_identity = NULL; + char *peer_identity = NULL; + uint64_t peer_cert_expiry; + bool resuming = tls->session_id_size && !tls->session_id_new; + bool session_update = false; + bool renegotiation = tls->ready; + + if (tls->peer_authenticated && !resuming) { + peer_cert_identity = tls_get_peer_identity_str(tls->peer_cert); + if (!peer_cert_identity) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "tls_get_peer_identity_str failed"); + return; + } + + peer_identity = peer_cert_identity; + + if (tls->session_id_new && + !l_cert_get_valid_times(tls->peer_cert, NULL, + &peer_cert_expiry)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "l_cert_get_valid_times failed"); + return; + } + } else if (tls->peer_authenticated && resuming) + peer_identity = tls->session_peer_identity; + + if (tls->session_settings && tls->session_id_new) { + _auto_(l_free) char *session_id_str = + l_util_hexstring(tls->session_id, tls->session_id_size); + uint64_t expiry = tls->session_lifetime ? + time_realtime_now() + tls->session_lifetime : 0; + const char *group_name = + tls_get_cache_group_name(tls, tls->session_id, + tls->session_id_size); + + if (tls->peer_authenticated && + (!expiry || peer_cert_expiry < expiry)) + expiry = peer_cert_expiry; + + if (!tls->server) + l_settings_set_bytes(tls->session_settings, group_name, + "SessionID", tls->session_id, + tls->session_id_size); + + l_settings_set_bytes(tls->session_settings, group_name, + "SessionMasterSecret", + tls->pending.master_secret, 48); + l_settings_set_int(tls->session_settings, group_name, + "SessionVersion", + tls->negotiated_version); + l_settings_set_bytes(tls->session_settings, group_name, + "SessionCipherSuite", + tls->pending.cipher_suite->id, 2); + l_settings_set_uint(tls->session_settings, group_name, + "SessionCompressionMethod", + tls->pending.compression_method->id); + + if (expiry) + l_settings_set_uint64(tls->session_settings, + group_name, + "SessionExpiryTime", expiry); + else + /* We may be overwriting an older session's data */ + l_settings_remove_key(tls->session_settings, + group_name, + "SessionExpiryTime"); + + if (tls->peer_authenticated) + l_settings_set_string(tls->session_settings, + group_name, + "SessionPeerIdentity", + peer_identity); + else + /* We may be overwriting an older session's data */ + l_settings_remove_key(tls->session_settings, + group_name, + "SessionPeerIdentity"); + + TLS_DEBUG("Saving new session %s to cache", session_id_str); + session_update = true; + + if (tls->session_id_size_replaced) { + tls_forget_cached_session(tls, NULL, + tls->session_id_replaced, + tls->session_id_size_replaced, + false); + tls->session_id_size_replaced = 0; + } + } + + /* Free up the resources used in the handshake */ + tls_reset_handshake(tls); + + TLS_SET_STATE(TLS_HANDSHAKE_DONE); + tls->ready = true; + tls->session_resumed = resuming; + + if (session_update && tls->session_update_cb) { + tls->in_callback = true; + tls->session_update_cb(tls->session_update_user_data); + tls->in_callback = false; + + if (tls->pending_destroy) + return; + } + + if (!renegotiation) { + tls->in_callback = true; + tls->ready_handle(peer_identity, tls->user_data); + tls->in_callback = false; + } + + tls_cleanup_handshake(tls); +} + +static void tls_handle_handshake(struct l_tls *tls, int type, + const uint8_t *buf, size_t len) +{ + bool resuming; + + TLS_DEBUG("Handling a %s of %zi bytes", + tls_handshake_type_to_str(type), len); + + switch (type) { + case TLS_HELLO_REQUEST: + if (tls->server) { + TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, + "Message invalid in server mode"); + break; + } + + if (len != 0) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "HelloRequest not empty"); + break; + } + + /* + * May be sent by the server at any time but "SHOULD be ignored + * by the client if it arrives in the middle of a handshake" + * and "MAY be ignored by the client if it does not wish to + * renegotiate a session". + */ + if (tls->state != TLS_HANDSHAKE_DONE) { + TLS_DEBUG("Message invalid in state %s", + tls_handshake_state_to_str(tls->state)); + break; + } + + if (!tls_send_client_hello(tls)) + break; + + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO); + break; + + case TLS_CLIENT_HELLO: + if (!tls->server) { + TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, + "Message invalid in client mode"); + break; + } + + if (tls->state != TLS_HANDSHAKE_WAIT_HELLO && + tls->state != TLS_HANDSHAKE_DONE) { + TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, + "Message invalid in state %s", + tls_handshake_state_to_str(tls->state)); + break; + } + + tls_handle_client_hello(tls, buf, len); + + break; + + case TLS_SERVER_HELLO: + if (tls->server) { + TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, + "Message invalid in server mode"); + break; + } + + if (tls->state != TLS_HANDSHAKE_WAIT_HELLO) { + TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, + "Message invalid in state %s", + tls_handshake_state_to_str(tls->state)); + break; + } + + tls_handle_server_hello(tls, buf, len); + + break; + + case TLS_CERTIFICATE: + if (tls->state != TLS_HANDSHAKE_WAIT_CERTIFICATE) { + TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, + "Message invalid in state %s", + tls_handshake_state_to_str(tls->state)); + break; + } + + tls_handle_certificate(tls, buf, len); + + break; + + case TLS_SERVER_KEY_EXCHANGE: + if (tls->server) { + TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, + "Message invalid in server mode"); + break; + } + + if (tls->state != TLS_HANDSHAKE_WAIT_KEY_EXCHANGE) { + TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, + "Message invalid in state %s", + tls_handshake_state_to_str(tls->state)); + break; + } + + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO_DONE); + + tls->pending.cipher_suite->key_xchg->handle_server_key_exchange( + tls, buf, len); + + break; + + case TLS_CERTIFICATE_REQUEST: + if (tls->server) { + TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, + "Message invalid in server mode"); + break; + } + + /* + * Server sends this optionally so in the WAIT_HELLO_DONE + * state we accept either this or a Server Hello Done (below). + */ + if (tls->state != TLS_HANDSHAKE_WAIT_HELLO_DONE || + tls->cert_requested || + !tls->pending.cipher_suite->signature) { + TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, + "Message invalid in current state " + "or certificate check not supported " + "in pending cipher suite"); + break; + } + + tls_handle_certificate_request(tls, buf, len); + + break; + + case TLS_SERVER_HELLO_DONE: + if (tls->state != TLS_HANDSHAKE_WAIT_HELLO_DONE) { + TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, + "Message invalid in state %s", + tls_handshake_state_to_str(tls->state)); + break; + } + + tls_handle_server_hello_done(tls, buf, len); + + break; + + case TLS_CERTIFICATE_VERIFY: + if (tls->state != TLS_HANDSHAKE_WAIT_CERTIFICATE_VERIFY) { + TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, + "Message invalid in state %s", + tls_handshake_state_to_str(tls->state)); + break; + } + + tls_handle_certificate_verify(tls, buf, len); + + break; + + case TLS_CLIENT_KEY_EXCHANGE: + if (!tls->server) { + TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, + "Message invalid in client mode"); + break; + } + + if (tls->state != TLS_HANDSHAKE_WAIT_KEY_EXCHANGE) { + TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, + "Message invalid in state %s", + tls_handshake_state_to_str(tls->state)); + break; + } + + /* + * If we accepted a client Certificate message with a + * certificate that has signing capability (TODO: check + * usage bitmask), Certificate Verify is received next. It + * sounds as if this is mandatory for the client although + * this isn't 100% clear. + */ + if (tls->peer_pubkey) + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CERTIFICATE_VERIFY); + else + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC); + + tls->pending.cipher_suite->key_xchg->handle_client_key_exchange( + tls, buf, len); + + break; + + case TLS_FINISHED: + if (tls->state != TLS_HANDSHAKE_WAIT_FINISHED) { + TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, + "Message invalid in state %s", + tls_handshake_state_to_str(tls->state)); + break; + } + + if (!tls_verify_finished(tls, buf, len)) + break; + + resuming = tls->session_id_size && !tls->session_id_new; + + if ((tls->server && !resuming) || (!tls->server && resuming)) { + const char *error; + + tls_send_change_cipher_spec(tls); + if (!tls_change_cipher_spec(tls, 1, &error)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "change_cipher_spec: %s", + error); + break; + } + + if (!tls_send_finished(tls)) + break; + } + + /* + * When starting a new session on the client, the server's + * certificate is now verified regardless of the key exchange + * method, based on the following logic: + * + * - tls->ca_certs is non-NULL so tls_handle_certificate + * (always called on the client) must have veritifed the + * server's certificate chain to be valid and additionally + * trusted by our CA. + * + * - the peer owns the end-entity certificate because: + * either: + * + * * (RSA key exchange algorithm case) the correct + * receival of this Finished message confirms the + * possession of the master secret, it is verified by + * both the successful decryption and the MAC of this + * message (either should be enough) because we entered + * the TLS_HANDSHAKE_WAIT_FINISHED state only after + * encryption and MAC were enabled in ChangeCipherSpec. + * To obtain the master secret the server must have been + * able to decrypt the pre_master_secret which we had + * encrypted with the public key from that certificate. + * + * * (ECDHE and DHE key exchange algorithms) server was + * able to sign the client random together with the + * ServerKeyExchange parameters using its certified key + * pair. + * + * If we're resuming a cached session, we have authenticated + * this peer before and the successful decryption of this + * message confirms their identity hasn't changed. + */ + if (tls->cipher_suite[0]->signature && + ((!tls->server && !resuming && tls->ca_certs) || + (resuming && tls->session_peer_identity))) + tls->peer_authenticated = true; + + tls_finished(tls); + + break; + + default: + TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, + "Invalid message"); + } +} + +LIB_EXPORT struct l_tls *l_tls_new(bool server, + l_tls_write_cb_t app_data_handler, + l_tls_write_cb_t tx_handler, + l_tls_ready_cb_t ready_handler, + l_tls_disconnect_cb_t disconnect_handler, + void *user_data) +{ + struct l_tls *tls; + + if (!l_key_is_supported(L_KEY_FEATURE_CRYPTO)) + return NULL; + + tls = l_new(struct l_tls, 1); + tls->server = server; + tls->rx = app_data_handler; + tls->tx = tx_handler; + tls->ready_handle = ready_handler; + tls->disconnected = disconnect_handler; + tls->user_data = user_data; + tls->cipher_suite_pref_list = tls_cipher_suite_pref; + tls->min_version = TLS_MIN_VERSION; + tls->max_version = TLS_MAX_VERSION; + tls->session_lifetime = 24 * 3600 * L_USEC_PER_SEC; + + /* If we're the server wait for the Client Hello already */ + if (tls->server) + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO); + else + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_START); + + return tls; +} + +LIB_EXPORT void l_tls_free(struct l_tls *tls) +{ + enum handshake_hash_type hash; + + if (unlikely(!tls)) + return; + + if (tls->in_callback) { + tls->pending_destroy = true; + return; + } + + l_tls_set_cacert(tls, NULL); + l_tls_set_auth_data(tls, NULL, NULL); + l_tls_set_domain_mask(tls, NULL); + l_tls_set_cert_dump_path(tls, NULL); + l_tls_set_session_cache(tls, NULL, NULL, 0, 0, NULL, NULL); + + tls_reset_handshake(tls); + tls_cleanup_handshake(tls); + + tls_reset_cipher_spec(tls, 0); + tls_reset_cipher_spec(tls, 1); + + if (tls->record_buf) + l_free(tls->record_buf); + + if (tls->message_buf) + l_free(tls->message_buf); + + for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) + tls_drop_handshake_hash(tls, hash); + + if (tls->debug_destroy) + tls->debug_destroy(tls->debug_data); + + if (tls->cipher_suite_pref_list != tls_cipher_suite_pref) + l_free(tls->cipher_suite_pref_list); + + l_free(tls); +} + +LIB_EXPORT void l_tls_write(struct l_tls *tls, const uint8_t *data, size_t len) +{ + if (unlikely(!tls->ready)) { + return; + } + + tls_tx_record(tls, TLS_CT_APPLICATION_DATA, data, len); +} + +bool tls_handle_message(struct l_tls *tls, const uint8_t *message, + int len, enum tls_content_type type, uint16_t version) +{ + enum handshake_hash_type hash; + const char *error; + + switch (type) { + case TLS_CT_CHANGE_CIPHER_SPEC: + if (len != 1 || message[0] != 0x01) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "ChangeCipherSpec msg decode error"); + + return false; + } + + if (tls->state != TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC) { + TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, + "ChangeCipherSpec invalid in state %s", + tls_handshake_state_to_str(tls->state)); + + return false; + } + + if (!tls_change_cipher_spec(tls, 0, &error)) { + TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0, + "change_cipher_spec: %s", error); + + return false; + } + + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_FINISHED); + + return true; + + case TLS_CT_ALERT: + /* Verify AlertLevel */ + if (message[0] != 0x01 && message[0] != 0x02) { + TLS_DISCONNECT(TLS_ALERT_DECODE_ERROR, 0, + "Received bad AlertLevel %i", + message[0]); + + return false; + } + + /* + * On a fatal alert we are obligated to respond with a + * fatal alert and disconnect but also not complain if + * the connection has been torn down by the peer before + * we were able to send our alert. However on a non-fatal + * alert (warning) we're also allowed to panic and send + * a fatal alert, then disconnect, so we do that + * regardless of the alert level. + */ + TLS_DISCONNECT(TLS_ALERT_CLOSE_NOTIFY, message[1], + "Peer sent a %s Alert: %s", + message[0] == 0x02 ? "Fatal" : "Warning", + l_tls_alert_to_str(message[1])); + + return false; + + case TLS_CT_HANDSHAKE: + /* Start hashing the handshake contents on first message */ + if (tls->server && message[0] == TLS_CLIENT_HELLO && + (tls->state == TLS_HANDSHAKE_WAIT_HELLO || + tls->state == TLS_HANDSHAKE_DONE)) + if (!tls_init_handshake_hash(tls)) + return false; + + /* + * Corner case: When handling a Certificate Verify or a + * Finished message we need access to the messages hash from + * before this message was transmitted on the Tx side so we + * can verify it matches the hash the sender included in the + * message. We save it here for that purpose. Everywhere + * else we need to update the hash before handling the new + * message because 1. we may need the new hash to build our + * own Certificate Verify or Finished messages, and 2. we + * update the message hash with newly transmitted messages + * inside tls_tx_handshake which may be called as part of + * handling incoming message, and if we didn't call + * l_checksum_update before, the calls would end up being + * out of order. + */ + if (message[0] == TLS_CERTIFICATE_VERIFY || + message[0] == TLS_FINISHED) + for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) { + if (!tls->handshake_hash[hash]) + continue; + + tls_get_handshake_hash(tls, hash, + tls->prev_digest[hash]); + } + + /* + * RFC 5246, Section 7.4.1.1: + * This message MUST NOT be included in the message hashes + * that are maintained throughout the handshake and used in + * the Finished messages and the certificate verify message. + */ + if (message[0] != TLS_HELLO_REQUEST) + for (hash = 0; hash < __HANDSHAKE_HASH_COUNT; hash++) { + if (!tls->handshake_hash[hash]) + continue; + + l_checksum_update(tls->handshake_hash[hash], + message, len); + } + + tls_handle_handshake(tls, message[0], + message + TLS_HANDSHAKE_HEADER_SIZE, + len - TLS_HANDSHAKE_HEADER_SIZE); + + if (tls->pending_destroy) { + l_tls_free(tls); + return false; + } + + return true; + + case TLS_CT_APPLICATION_DATA: + if (!tls->ready) { + TLS_DISCONNECT(TLS_ALERT_UNEXPECTED_MESSAGE, 0, + "Application data message before " + "handshake finished"); + + return false; + } + + if (!len) + return true; + + tls->in_callback = true; + tls->rx(message, len, tls->user_data); + tls->in_callback = false; + + if (tls->pending_destroy) { + l_tls_free(tls); + return false; + } + + return true; + } + + return false; +} + +LIB_EXPORT bool l_tls_start(struct l_tls *tls) +{ + if (tls->max_version < tls->min_version) + return false; + + if (!tls->cipher_suite_pref_list) + return false; + + /* This is a nop in server mode */ + if (tls->server) + return true; + + if (tls->state != TLS_HANDSHAKE_WAIT_START) { + TLS_DEBUG("Call invalid in state %s", + tls_handshake_state_to_str(tls->state)); + return false; + } + + if (!tls_init_handshake_hash(tls)) + return false; + + /* + * If we're going to try resuming a cached session, send the Client + * Hello with the version we think is supported. + * + * RFC5246 Appendix E.1: + * "Whenever a client already knows the highest protocol version known + * to a server (for example, when resuming a session), it SHOULD + * initiate the connection in that native protocol." + * + * Don't directly set tls->{min,max}_version as that would make the + * handshake fail if the server decides to start a new session with + * a new version instead of resuming, which it is allowed to do. + */ + tls->client_version = tls->max_version; + tls_load_cached_client_session(tls); + + if (tls->pending_destroy) { + l_tls_free(tls); + return false; + } + + if (!tls_send_client_hello(tls)) + return false; + + TLS_SET_STATE(TLS_HANDSHAKE_WAIT_HELLO); + return true; +} + +LIB_EXPORT void l_tls_close(struct l_tls *tls) +{ + tls->record_buf_len = 0; + tls->message_buf_len = 0; + + TLS_DISCONNECT(TLS_ALERT_CLOSE_NOTIFY, 0, "Closing session"); +} + +LIB_EXPORT void l_tls_reset(struct l_tls *tls) +{ + /* + * Similar to l_tls_close but without sending the alert or a + * disconnect callback. + */ + + tls_reset_handshake(tls); + tls_cleanup_handshake(tls); + + tls_reset_cipher_spec(tls, 0); + tls_reset_cipher_spec(tls, 1); + + tls->negotiated_version = 0; + tls->ready = false; + tls->record_flush = true; + tls->record_buf_len = 0; + tls->message_buf_len = 0; +} + +LIB_EXPORT bool l_tls_set_cacert(struct l_tls *tls, struct l_queue *ca_certs) +{ + if (tls->ca_certs) { + l_queue_destroy(tls->ca_certs, + (l_queue_destroy_func_t) l_cert_free); + tls->ca_certs = NULL; + } + + if (ca_certs) { + if (!l_key_is_supported(L_KEY_FEATURE_RESTRICT)) { + TLS_DEBUG("keyctl restrict support missing, " + "check kernel configuration"); + return false; + } + + tls->ca_certs = ca_certs; + } + + return true; +} + +LIB_EXPORT bool l_tls_set_auth_data(struct l_tls *tls, + struct l_certchain *certchain, + struct l_key *priv_key) +{ + if (tls->cert) { + l_certchain_free(tls->cert); + tls->cert = NULL; + } + + if (tls->priv_key) { + l_key_free(tls->priv_key); + tls->priv_key = NULL; + tls->priv_key_size = 0; + } + + if (certchain) + tls->cert = certchain; + + if (priv_key) { + bool is_public = true; + + tls->priv_key = priv_key; + + if (!l_key_get_info(tls->priv_key, L_KEY_RSA_PKCS1_V1_5, + L_CHECKSUM_NONE, &tls->priv_key_size, + &is_public) || is_public) { + TLS_DEBUG("Not a private key or l_key_get_info failed"); + tls->cert = NULL; + tls->priv_key = NULL; + tls->priv_key_size = 0; + return false; + } + + tls->priv_key_size /= 8; + } + + return true; +} + +bool tls_set_cipher_suites(struct l_tls *tls, const char **suite_list) +{ + struct tls_cipher_suite **suite; + + if (tls->cipher_suite_pref_list != tls_cipher_suite_pref) + l_free(tls->cipher_suite_pref_list); + + if (!suite_list) { + /* Use our default cipher suite preference list */ + tls->cipher_suite_pref_list = tls_cipher_suite_pref; + return true; + } + + tls->cipher_suite_pref_list = l_new(struct tls_cipher_suite *, + l_strv_length((char **) suite_list) + 1); + suite = tls->cipher_suite_pref_list; + + for (; *suite_list; suite_list++) { + unsigned int i; + + for (i = 0; tls_cipher_suite_pref[i]; i++) + if (!strcmp(tls_cipher_suite_pref[i]->name, + *suite_list)) + break; + + if (tls_cipher_suite_pref[i]) + *suite++ = tls_cipher_suite_pref[i]; + else + TLS_DEBUG("Cipher suite %s is not supported", + *suite_list); + } + + if (suite > tls->cipher_suite_pref_list) + return true; + + TLS_DEBUG("None of the supplied suite names is supported"); + l_free(suite); + tls->cipher_suite_pref_list = NULL; + return false; +} + +LIB_EXPORT void l_tls_set_version_range(struct l_tls *tls, + enum l_tls_version min_version, + enum l_tls_version max_version) +{ + tls->min_version = + (min_version && min_version > TLS_MIN_VERSION) ? + min_version : TLS_MIN_VERSION; + tls->max_version = + (max_version && max_version < TLS_MAX_VERSION) ? + max_version : TLS_MAX_VERSION; +} + +/** + * l_tls_set_domain_mask: + * @tls: TLS object being configured + * @mask: NULL-terminated array of domain masks + * + * Sets a mask for domain names contained in the peer certificate + * (eg. the subject Common Name) to be matched against. If none of the + * domains match the any mask, authentication will fail. At least one + * domain has to match at least one mask from the list. + * + * The masks are each split into segments at the dot characters and each + * segment must match the corresponding label of the domain name -- + * a domain name is a sequence of labels joined by dots. An asterisk + * segment in the mask matches any label. An asterisk segment at the + * beginning of the mask matches one or more consecutive labels from + * the beginning of the domain string. + */ +LIB_EXPORT void l_tls_set_domain_mask(struct l_tls *tls, char **mask) +{ + l_strv_free(tls->subject_mask); + + tls->subject_mask = l_strv_copy(mask); +} + +/** + * l_tls_set_session_cache: + * @tls: TLS object being configured + * @settings: l_settings object to read and write session data from/to or + * NULL to disable caching session states. The object must remain valid + * until this method is called with a different value. + * @group_prefix: prefix to build group names inside @settings. Note: + * existing settings in groups starting with the prefix may be + * overwritten or removed. + * @lifetime: a CLOCK_REALTIME-based microsecond resolution lifetime for + * cached sessions. The RFC recommends 24 hours. + * @max_sessions: limit on the number of sessions in the cache, or 0 for + * unlimited. Ignored in client mode. + * @update_cb: a callback to be invoked whenever the settings in @settings + * have been updated and may need to be written to persistent storage if + * desired, or NULL. + * @user_data: user data pointer to pass to @update_cb. + * + * Enables caching and resuming session states as described in RFC 5246 for + * faster setup. l_tls will maintain the required session state data in + * @settings including removing expired or erroneous sessions. + * + * A client's cache contains at most one session state since the client + * must request one specific Session ID from the server when resuming a + * session. The resumption will only work while the state is cached by + * both the server and the client so clients should keep separate @settings + * objects or use separate groups inside one object for every discrete + * server they may want to connect to. + * + * Multiple l_tls clients connecting to the same server can share one cache + * to allow reusing an established session that is still active (actual + * concurrency is not supported as there's no locking.) + */ +LIB_EXPORT void l_tls_set_session_cache(struct l_tls *tls, + struct l_settings *settings, + const char *group_prefix, + uint64_t lifetime, + unsigned int max_sessions, + l_tls_session_update_cb_t update_cb, + void *user_data) +{ + if (unlikely(!tls)) + return; + + tls->session_settings = settings; + tls->session_lifetime = lifetime; + tls->session_count_max = max_sessions; + tls->session_update_cb = update_cb; + tls->session_update_user_data = user_data; + + l_free(tls->session_prefix); + tls->session_prefix = l_strdup(group_prefix); +} + +LIB_EXPORT bool l_tls_get_session_resumed(struct l_tls *tls) +{ + if (unlikely(!tls || !tls->ready)) + return false; + + return tls->session_resumed; +} + +LIB_EXPORT const char *l_tls_alert_to_str(enum l_tls_alert_desc desc) +{ + switch (desc) { + case TLS_ALERT_CLOSE_NOTIFY: + return "close_notify"; + case TLS_ALERT_UNEXPECTED_MESSAGE: + return "unexpected_message"; + case TLS_ALERT_BAD_RECORD_MAC: + return "bad_record_mac"; + case TLS_ALERT_DECRYPT_FAIL_RESERVED: + return "decryption_failure_RESERVED"; + case TLS_ALERT_RECORD_OVERFLOW: + return "record_overflow"; + case TLS_ALERT_DECOMPRESS_FAIL: + return "decompression_failure"; + case TLS_ALERT_HANDSHAKE_FAIL: + return "handshake_failure"; + case TLS_ALERT_NO_CERT_RESERVED: + return "no_certificate_RESERVED"; + case TLS_ALERT_BAD_CERT: + return "bad_certificate"; + case TLS_ALERT_UNSUPPORTED_CERT: + return "unsupported_certificate"; + case TLS_ALERT_CERT_REVOKED: + return "certificate_revoked"; + case TLS_ALERT_CERT_EXPIRED: + return "certificate_expired"; + case TLS_ALERT_CERT_UNKNOWN: + return "certificate_unknown"; + case TLS_ALERT_ILLEGAL_PARAM: + return "illegal_parameter"; + case TLS_ALERT_UNKNOWN_CA: + return "unknown_ca"; + case TLS_ALERT_ACCESS_DENIED: + return "access_denied"; + case TLS_ALERT_DECODE_ERROR: + return "decode_error"; + case TLS_ALERT_DECRYPT_ERROR: + return "decrypt_error"; + case TLS_ALERT_EXPORT_RES_RESERVED: + return "export_restriction_RESERVED"; + case TLS_ALERT_PROTOCOL_VERSION: + return "protocol_version"; + case TLS_ALERT_INSUFFICIENT_SECURITY: + return "insufficient_security"; + case TLS_ALERT_INTERNAL_ERROR: + return "internal_error"; + case TLS_ALERT_USER_CANCELED: + return "user_canceled"; + case TLS_ALERT_NO_RENEGOTIATION: + return "no_renegotiation"; + case TLS_ALERT_UNSUPPORTED_EXTENSION: + return "unsupported_extension"; + } + + return NULL; +} + +const char *tls_handshake_state_to_str(enum tls_handshake_state state) +{ + static char buf[100]; + + switch (state) { + SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_START) + SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_HELLO) + SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_CERTIFICATE) + SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_KEY_EXCHANGE) + SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_HELLO_DONE) + SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_CERTIFICATE_VERIFY) + SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_CHANGE_CIPHER_SPEC) + SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_WAIT_FINISHED) + SWITCH_ENUM_TO_STR(TLS_HANDSHAKE_DONE) + } + + snprintf(buf, sizeof(buf), "tls_handshake_state(%i)", state); + return buf; +} + +int tls_parse_certificate_list(const void *data, size_t len, + struct l_certchain **out_certchain) +{ + const uint8_t *buf = data; + struct l_certchain *chain = NULL; + + while (len) { + struct l_cert *cert; + size_t cert_len; + + if (len < 3) + goto decode_error; + + cert_len = *buf++ << 16; + cert_len |= *buf++ << 8; + cert_len |= *buf++ << 0; + + if (cert_len + 3 > len) + goto decode_error; + + cert = l_cert_new_from_der(buf, cert_len); + if (!cert) + goto decode_error; + + if (!chain) { + chain = certchain_new_from_leaf(cert); + if (!chain) + goto decode_error; + } else + certchain_link_issuer(chain, cert); + + buf += cert_len; + len -= cert_len + 3; + } + + if (out_certchain) + *out_certchain = chain; + else + l_certchain_free(chain); + + return 0; + +decode_error: + l_certchain_free(chain); + return -EBADMSG; +} + +LIB_EXPORT bool l_tls_set_debug(struct l_tls *tls, l_tls_debug_cb_t function, + void *user_data, l_tls_destroy_cb_t destroy) +{ + if (unlikely(!tls)) + return false; + + if (tls->debug_destroy) + tls->debug_destroy(tls->debug_data); + + tls->debug_handler = function; + tls->debug_destroy = destroy; + tls->debug_data = user_data; + + return true; +} + +LIB_EXPORT bool l_tls_set_cert_dump_path(struct l_tls *tls, const char *path) +{ + l_free(tls->cert_dump_path); + tls->cert_dump_path = path ? l_strdup(path) : NULL; + return true; +} diff --git a/ell/tls.h b/ell/tls.h new file mode 100644 index 0000000000000000000000000000000000000000..f283316cff940438e733bc92201d24459c4de782 --- /dev/null +++ b/ell/tls.h @@ -0,0 +1,141 @@ +/* + * Embedded Linux library + * Copyright (C) 2015 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_TLS_H +#define __ELL_TLS_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum l_tls_version { + L_TLS_V10 = ((3 << 8) | 1), + L_TLS_V11 = ((3 << 8) | 2), + L_TLS_V12 = ((3 << 8) | 3), + L_TLS_V13 = ((3 << 8) | 4), /* Not supported */ +}; + +struct l_tls; +struct l_key; +struct l_certchain; +struct l_queue; +struct l_settings; + +enum l_tls_alert_desc { + TLS_ALERT_CLOSE_NOTIFY = 0, + TLS_ALERT_UNEXPECTED_MESSAGE = 10, + TLS_ALERT_BAD_RECORD_MAC = 20, + TLS_ALERT_DECRYPT_FAIL_RESERVED = 21, + TLS_ALERT_RECORD_OVERFLOW = 22, + TLS_ALERT_DECOMPRESS_FAIL = 30, + TLS_ALERT_HANDSHAKE_FAIL = 40, + TLS_ALERT_NO_CERT_RESERVED = 41, + TLS_ALERT_BAD_CERT = 42, + TLS_ALERT_UNSUPPORTED_CERT = 43, + TLS_ALERT_CERT_REVOKED = 44, + TLS_ALERT_CERT_EXPIRED = 45, + TLS_ALERT_CERT_UNKNOWN = 46, + TLS_ALERT_ILLEGAL_PARAM = 47, + TLS_ALERT_UNKNOWN_CA = 48, + TLS_ALERT_ACCESS_DENIED = 49, + TLS_ALERT_DECODE_ERROR = 50, + TLS_ALERT_DECRYPT_ERROR = 51, + TLS_ALERT_EXPORT_RES_RESERVED = 60, + TLS_ALERT_PROTOCOL_VERSION = 70, + TLS_ALERT_INSUFFICIENT_SECURITY = 71, + TLS_ALERT_INTERNAL_ERROR = 80, + TLS_ALERT_USER_CANCELED = 90, + TLS_ALERT_NO_RENEGOTIATION = 100, + TLS_ALERT_UNSUPPORTED_EXTENSION = 110, +}; + +typedef void (*l_tls_write_cb_t)(const uint8_t *data, size_t len, + void *user_data); +typedef void (*l_tls_ready_cb_t)(const char *peer_identity, void *user_data); +typedef void (*l_tls_disconnect_cb_t)(enum l_tls_alert_desc reason, + bool remote, void *user_data); +typedef void (*l_tls_debug_cb_t)(const char *str, void *user_data); +typedef void (*l_tls_destroy_cb_t)(void *user_data); +typedef void (*l_tls_session_update_cb_t)(void *user_data); + +/* + * app_data_handler gets called with newly received decrypted data. + * tx_handler gets called to send TLS payloads off to remote end. + * ready_handler gets called when l_tls_write calls are first accepted. + */ +struct l_tls *l_tls_new(bool server, l_tls_write_cb_t app_data_handler, + l_tls_write_cb_t tx_handler, + l_tls_ready_cb_t ready_handler, + l_tls_disconnect_cb_t disconnect_handler, + void *user_data); + +void l_tls_free(struct l_tls *tls); + +/* Begin sending connection setup messages to the server */ +bool l_tls_start(struct l_tls *tls); + +/* Properly disconnect a connected session */ +void l_tls_close(struct l_tls *tls); + +/* Reset to initial state without a graceful disconnect or callback */ +void l_tls_reset(struct l_tls *tls); + +/* Submit plaintext data to be encrypted and transmitted */ +void l_tls_write(struct l_tls *tls, const uint8_t *data, size_t len); + +/* Submit TLS payload from underlying transport to be decrypted */ +void l_tls_handle_rx(struct l_tls *tls, const uint8_t *data, size_t len); + +/* + * If peer is to be authenticated, supply the CA certificates. On success + * the l_tls object takes ownership of the queue and the individual l_cert + * objects and they should not be freed by the caller afterwards. + */ +bool l_tls_set_cacert(struct l_tls *tls, struct l_queue *ca_certs); + +/* + * If we are to be authenticated, supply our certificate and private key. + * On the client this is optional. On success, the l_tls object takes + * ownership of the certchain and the key objects and they should not be + * freed by the caller afterwards. + * TODO: it may also be useful for the caller to be able to supply one + * certificate of each type so they can be used depending on which is compatible + * with the negotiated parameters. + */ +bool l_tls_set_auth_data(struct l_tls *tls, + struct l_certchain *certchain, + struct l_key *priv_key); + +void l_tls_set_version_range(struct l_tls *tls, + enum l_tls_version min_version, + enum l_tls_version max_version); + +void l_tls_set_domain_mask(struct l_tls *tls, char **mask); + +void l_tls_set_session_cache(struct l_tls *tls, struct l_settings *settings, + const char *group_prefix, uint64_t lifetime, + unsigned int max_sessions, + l_tls_session_update_cb_t update_cb, + void *user_data); +bool l_tls_get_session_resumed(struct l_tls *tls); + +const char *l_tls_alert_to_str(enum l_tls_alert_desc desc); + +enum l_checksum_type; + +bool l_tls_prf_get_bytes(struct l_tls *tls, bool use_master_secret, + const char *label, uint8_t *buf, size_t len); + +bool l_tls_set_debug(struct l_tls *tls, l_tls_debug_cb_t function, + void *user_data, l_tls_destroy_cb_t destroy); +bool l_tls_set_cert_dump_path(struct l_tls *tls, const char *path); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_TLS_H */ diff --git a/ell/useful.h b/ell/useful.h new file mode 100644 index 0000000000000000000000000000000000000000..504ea089cb217b76b853def17c60ec5c6a7bd70a --- /dev/null +++ b/ell/useful.h @@ -0,0 +1,89 @@ +/* + * Embedded Linux library + * Copyright (C) 2021 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#define align_len(len, boundary) (((len)+(boundary)-1) & ~((boundary)-1)) + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +#define SWAP(l, r) \ + do { typeof(l) __tmp = (l); (l) = (r); (r) = __tmp; } while (0) + +#ifndef __always_inline +#define __always_inline inline __attribute__((always_inline)) +#endif + +static inline size_t minsize(size_t a, size_t b) +{ + if (a <= b) + return a; + + return b; +} + +static inline size_t maxsize(size_t a, size_t b) +{ + if (a >= b) + return a; + + return b; +} + +static inline void set_bit(void *addr, unsigned int bit) +{ + unsigned char *field = addr; + field[bit / 8] |= 1U << (bit % 8); +} + +static inline int test_bit(const void *addr, unsigned int bit) +{ + const unsigned char *field = addr; + return (field[bit / 8] & (1U << (bit % 8))) != 0; +} + +static inline unsigned char bit_field(const unsigned char oct, + unsigned int start, unsigned int n_bits) +{ + unsigned char mask = (1U << n_bits) - 1U; + return (oct >> start) & mask; +} + +/* Must be called with n >= 2 and n <= ULONG_MAX / 2 + 1 */ +static inline unsigned long roundup_pow_of_two(unsigned long n) +{ + return 1UL << (sizeof(unsigned long) * 8 - __builtin_clzl(n - 1)); +} + +#define DIV_ROUND_CLOSEST(x, divisor) \ +({ \ + typeof(divisor) _d = (divisor); \ + typeof(x) _x = (x) + _d / 2; \ + _x / _d; \ +}) + +#ifndef _auto_ +#define _auto_(func) \ + __L_AUTODESTRUCT(func) +#endif + +/* + * Trick the compiler into thinking that var might be changed somehow by + * the asm + */ +#define DO_NOT_OPTIMIZE(var) \ + __asm__ ("" : "=r" (var) : "0" (var)); + +static inline int secure_select(int select_left, int l, int r) +{ + int mask = -(!!select_left); + + return r ^ ((l ^ r) & mask); +} + +#define struct_alloc(structname, ...) \ + (struct structname *) l_memdup(&(struct structname) { __VA_ARGS__ }, \ + sizeof(struct structname)) diff --git a/ell/utf8.c b/ell/utf8.c new file mode 100644 index 0000000000000000000000000000000000000000..f230176ab2aa44fa40cfea333e155848610936ae --- /dev/null +++ b/ell/utf8.c @@ -0,0 +1,547 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * Copyright (C) 2024 Cruise, LLC + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <wchar.h> + +#include "strv.h" +#include "utf8.h" +#include "private.h" +#include "useful.h" + +/** + * SECTION:utf8 + * @short_description: UTF-8 utility function + * + * UTF-8 string handling support + */ + +LIB_EXPORT unsigned char l_ascii_table[256] = { + [0x00 ... 0x08] = L_ASCII_CNTRL, + [0x09 ... 0x0D] = L_ASCII_CNTRL | L_ASCII_SPACE, + [0x0E ... 0x1F] = L_ASCII_CNTRL, + [0x20] = L_ASCII_PRINT | L_ASCII_SPACE, + [0x21 ... 0x2F] = L_ASCII_PRINT | L_ASCII_PUNCT, + [0x30 ... 0x39] = L_ASCII_DIGIT | L_ASCII_XDIGIT | L_ASCII_PRINT, + [0x3A ... 0x40] = L_ASCII_PRINT | L_ASCII_PUNCT, + [0x41 ... 0x46] = L_ASCII_PRINT | L_ASCII_XDIGIT | L_ASCII_UPPER, + [0x47 ... 0x5A] = L_ASCII_PRINT | L_ASCII_UPPER, + [0x5B ... 0x60] = L_ASCII_PRINT | L_ASCII_PUNCT, + [0x61 ... 0x66] = L_ASCII_PRINT | L_ASCII_XDIGIT | L_ASCII_LOWER, + [0x67 ... 0x7A] = L_ASCII_PRINT | L_ASCII_LOWER, + [0x7B ... 0x7E] = L_ASCII_PRINT | L_ASCII_PUNCT, + [0x7F] = L_ASCII_CNTRL, + [0x80 ... 0xFF] = 0, +}; + +/** + * l_ascii_strdown + * @str: a pointer to an ASCII string + * @len: maximum bytes to process or negative if string is null terminated + * + * Returns: Newly allocated string with all upper case characters converted + * to lower case. + **/ +LIB_EXPORT char *l_ascii_strdown(const char *str, ssize_t len) +{ + size_t slen; + size_t i; + char *ret; + + if (!str) + return NULL; + + if (len < 0) + slen = strlen(str); + else + slen = len; + + ret = l_malloc(slen + 1); + + for (i = 0; i < slen && str[i]; i++) + ret[i] = l_ascii_tolower(str[i]); + + ret[i] = '\0'; + + return ret; +} + +/** + * l_ascii_strup + * @str: a pointer to an ASCII string + * @len: maximum bytes to process or negative if string is null terminated + * + * Returns: Newly allocated string with all lower case characters converted + * to upper case. + **/ +LIB_EXPORT char *l_ascii_strup(const char *str, ssize_t len) +{ + size_t slen; + size_t i; + char *ret; + + if (!str) + return NULL; + + if (len < 0) + slen = strlen(str); + else + slen = len; + + ret = l_malloc(slen + 1); + + for (i = 0; i < slen && str[i]; i++) + ret[i] = l_ascii_toupper(str[i]); + + ret[i] = '\0'; + + return ret; +} + +static inline bool __attribute__ ((always_inline)) + valid_unicode(wchar_t c) +{ + if (c <= 0xd7ff) + return true; + + if (c < 0xe000 || c > 0x10ffff) + return false; + + if (c >= 0xfdd0 && c <= 0xfdef) + return false; + + if ((c & 0xfffe) == 0xfffe) + return false; + + return true; +} + +/** + * l_utf8_get_codepoint + * @str: a pointer to codepoint data + * @len: maximum bytes to read + * @cp: destination for codepoint + * + * Returns: number of bytes read, or -1 for invalid coddepoint + **/ +LIB_EXPORT int l_utf8_get_codepoint(const char *str, size_t len, wchar_t *cp) +{ + static const wchar_t mins[3] = { 1 << 7, 1 << 11, 1 << 16 }; + unsigned int expect_bytes; + wchar_t val; + size_t i; + + if (len == 0) + return 0; + + if ((signed char) str[0] > 0) { + *cp = str[0]; + return 1; + } + + expect_bytes = __builtin_clz(~((unsigned int)str[0] << 24)); + + if (expect_bytes < 2 || expect_bytes > 4) + goto error; + + if (expect_bytes > len) + goto error; + + val = str[0] & (0xff >> (expect_bytes + 1)); + + for (i = 1; i < expect_bytes; i++) { + if ((str[i] & 0xc0) != 0x80) + goto error; + + val <<= 6; + val |= str[i] & 0x3f; + } + + if (val < mins[expect_bytes - 2]) + goto error; + + if (valid_unicode(val) == false) + goto error; + + *cp = val; + return expect_bytes; + +error: + return -1; +} + +/** + * l_utf8_validate: + * @str: a pointer to character data + * @len: max bytes to validate + * @end: return location for end of valid data + * + * Validates UTF-8 encoded text. If @end is non-NULL, then the end of + * the valid range will be stored there (i.e. the start of the first + * invalid character if some bytes were invalid, or the end of the text + * being validated otherwise). + * + * Returns: Whether the text was valid UTF-8 + **/ +LIB_EXPORT bool l_utf8_validate(const char *str, size_t len, const char **end) +{ + size_t pos = 0; + int ret; + wchar_t val; + + while (pos < len && str[pos]) { + ret = l_utf8_get_codepoint(str + pos, len - pos, &val); + + if (ret < 0) + goto error; + + pos += ret; + } + +error: + if (end) + *end = str + pos; + + if (pos != len) + return false; + + return true; +} + +/** + * l_utf8_strlen: + * @str: a pointer to character data + * + * Computes the number of UTF-8 characters (not bytes) in the string given + * by @str. + * + * Returns: The number of UTF-8 characters in the string + **/ +LIB_EXPORT size_t l_utf8_strlen(const char *str) +{ + size_t l = 0; + size_t i; + unsigned char b; + + for (i = 0; str[i]; i++) { + b = str[i]; + + if ((b >> 6) == 2) + l += 1; + } + + return i - l; +} + +static inline int __attribute__ ((always_inline)) + utf8_length(wchar_t c) +{ + if (c <= 0x7f) + return 1; + + if (c <= 0x7ff) + return 2; + + if (c <= 0xffff) + return 3; + + return 4; +} + +static inline uint16_t __attribute__ ((always_inline)) + surrogate_value(uint16_t h, uint16_t l) +{ + return 0x10000 + (h - 0xd800) * 0x400 + l - 0xdc00; +} + +/* + * l_utf8_from_wchar: + * @c: a wide-character to convert + * @out_buf: Buffer to write out to + * + * Assumes c is valid unicode and out_buf contains enough space for a single + * utf8 character (maximum 4 bytes) + * Returns: number of characters written + */ +LIB_EXPORT size_t l_utf8_from_wchar(wchar_t c, char *out_buf) +{ + int len = utf8_length(c); + int i; + + if (len == 1) { + out_buf[0] = c; + return 1; + } + + for (i = len - 1; i; i--) { + out_buf[i] = (c & 0x3f) | 0x80; + c >>= 6; + } + + out_buf[0] = (0xff << (8 - len)) | c; + return len; +} + +/** + * l_utf8_from_utf16: + * @utf16: Array of UTF16 characters + * @utf16_size: The size of the @utf16 array in bytes. Must be a multiple of 2. + * + * Returns: A newly-allocated buffer containing UTF16 encoded string converted + * to UTF8. The UTF8 string will always be null terminated, even if the + * original UTF16 string was not. + **/ +LIB_EXPORT char *l_utf8_from_utf16(const void *utf16, ssize_t utf16_size) +{ + char *utf8; + size_t utf8_len = 0; + wchar_t high_surrogate = 0; + ssize_t i = 0; + uint16_t in; + wchar_t c; + + if (unlikely(utf16_size % 2)) + return NULL; + + while (utf16_size < 0 || i < utf16_size) { + in = l_get_u16(utf16 + i); + + if (!in) + break; + + if (in >= 0xdc00 && in < 0xe000) { + if (high_surrogate) + c = surrogate_value(high_surrogate, in); + else + return NULL; + + high_surrogate = 0; + } else { + if (high_surrogate) + return NULL; + + if (in >= 0xd800 && in < 0xdc00) { + high_surrogate = in; + goto next; + } + + c = in; + } + + if (!valid_unicode(c)) + return NULL; + + utf8_len += utf8_length(c); +next: + i += 2; + } + + if (high_surrogate) + return NULL; + + utf8 = l_malloc(utf8_len + 1); + utf8_len = 0; + i = 0; + + while (utf16_size < 0 || i < utf16_size) { + in = l_get_u16(utf16 + i); + + if (!in) + break; + + if (in >= 0xd800 && in < 0xdc00) { + high_surrogate = in; + i += 2; + in = l_get_u16(utf16 + i); + c = surrogate_value(high_surrogate, in); + } else + c = in; + + utf8_len += l_utf8_from_wchar(c, utf8 + utf8_len); + i += 2; + } + + utf8[utf8_len] = '\0'; + + return utf8; +} + +/** + * l_utf8_to_utf16: + * @utf8: UTF8 formatted string + * @out_size: The size in bytes of the converted utf16 string + * + * Converts a UTF8 formatted string to UTF16. It is assumed that the string + * is valid UTF8 and no sanity checking is performed. + * + * Returns: A newly-allocated buffer containing UTF8 encoded string converted + * to UTF16. The UTF16 string will always be null terminated. + **/ +LIB_EXPORT void *l_utf8_to_utf16(const char *utf8, size_t *out_size) +{ + const char *c; + wchar_t wc; + int len; + uint16_t *utf16; + size_t n_utf16; + + if (unlikely(!utf8)) + return NULL; + + c = utf8; + n_utf16 = 0; + + while (*c) { + len = l_utf8_get_codepoint(c, 4, &wc); + if (len < 0) + return NULL; + + if (wc < 0x10000) + n_utf16 += 1; + else + n_utf16 += 2; + + c += len; + } + + utf16 = l_malloc((n_utf16 + 1) * 2); + c = utf8; + n_utf16 = 0; + + while (*c) { + len = l_utf8_get_codepoint(c, 4, &wc); + + if (wc >= 0x10000) { + utf16[n_utf16++] = (wc - 0x1000) / 0x400 + 0xd800; + utf16[n_utf16++] = (wc - 0x1000) % 0x400 + 0xdc00; + } else + utf16[n_utf16++] = wc; + + c += len; + } + + utf16[n_utf16] = 0; + + if (out_size) + *out_size = (n_utf16 + 1) * 2; + + return utf16; +} + +/** + * l_utf8_from_ucs2be: + * @ucs2be: Array of UCS2 characters in big-endian format + * @ucs2be_size: The size of the @ucs2 array in bytes. Must be a multiple of 2. + * + * Returns: A newly-allocated buffer containing UCS2BE encoded string converted + * to UTF8. The UTF8 string will always be null terminated, even if the + * original UCS2BE string was not. + **/ +LIB_EXPORT char *l_utf8_from_ucs2be(const void *ucs2be, ssize_t ucs2be_size) +{ + char *utf8; + size_t utf8_len = 0; + ssize_t i = 0; + uint16_t in; + + if (unlikely(ucs2be_size % 2)) + return NULL; + + while (ucs2be_size < 0 || i < ucs2be_size) { + in = l_get_be16(ucs2be + i); + + if (!in) + break; + + if (in >= 0xd800 && in < 0xe000) + return NULL; + + if (!valid_unicode(in)) + return NULL; + + utf8_len += utf8_length(in); + i += 2; + } + + utf8 = l_malloc(utf8_len + 1); + utf8_len = 0; + i = 0; + + while (ucs2be_size < 0 || i < ucs2be_size) { + in = l_get_be16(ucs2be + i); + + if (!in) + break; + + utf8_len += l_utf8_from_wchar(in, utf8 + utf8_len); + i += 2; + } + + utf8[utf8_len] = '\0'; + + return utf8; +} + +/** + * l_utf8_to_ucs2be: + * @utf8: UTF8 formatted string + * @out_size: The size in bytes of the converted ucs2be string + * + * Converts a UTF8 formatted string to UCS2BE. It is assumed that the string + * is valid UTF8 and no sanity checking is performed. + * + * Returns: A newly-allocated buffer containing UTF8 encoded string converted + * to UCS2BE. The UCS2BE string will always be null terminated. + **/ +LIB_EXPORT void *l_utf8_to_ucs2be(const char *utf8, size_t *out_size) +{ + const char *c; + wchar_t wc; + int len; + uint16_t *ucs2be; + size_t n_ucs2be; + + if (unlikely(!utf8)) + return NULL; + + c = utf8; + n_ucs2be = 0; + + while (*c) { + len = l_utf8_get_codepoint(c, 4, &wc); + if (len < 0) + return NULL; + + if (wc >= 0x10000) + return NULL; + + n_ucs2be += 1; + c += len; + } + + ucs2be = l_malloc((n_ucs2be + 1) * 2); + c = utf8; + n_ucs2be = 0; + + while (*c) { + len = l_utf8_get_codepoint(c, 4, &wc); + ucs2be[n_ucs2be++] = L_CPU_TO_BE16(wc); + c += len; + } + + ucs2be[n_ucs2be] = 0; + + if (out_size) + *out_size = (n_ucs2be + 1) * 2; + + return ucs2be; +} diff --git a/ell/utf8.h b/ell/utf8.h new file mode 100644 index 0000000000000000000000000000000000000000..a1dd40b31c6e902c349b048eb4f22bb5027b9e42 --- /dev/null +++ b/ell/utf8.h @@ -0,0 +1,125 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * Copyright (C) 2024 Cruise, LLC + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_UTF8_H +#define __ELL_UTF8_H + +#include <stdbool.h> +#include <wchar.h> +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern unsigned char l_ascii_table[]; + +enum l_ascii { + L_ASCII_CNTRL = 0x80, + L_ASCII_PRINT = 0x40, + L_ASCII_PUNCT = 0x20, + L_ASCII_SPACE = 0x10, + L_ASCII_XDIGIT = 0x08, + L_ASCII_UPPER = 0x04, + L_ASCII_LOWER = 0x02, + L_ASCII_DIGIT = 0x01, + L_ASCII_ALPHA = L_ASCII_LOWER | L_ASCII_UPPER, + L_ASCII_ALNUM = L_ASCII_ALPHA | L_ASCII_DIGIT, + L_ASCII_GRAPH = L_ASCII_ALNUM | L_ASCII_PUNCT, +}; + +#define l_ascii_isalnum(c) \ + ((l_ascii_table[(unsigned char) (c)] & L_ASCII_ALNUM) != 0) + +#define l_ascii_isalpha(c) \ + ((l_ascii_table[(unsigned char) (c)] & L_ASCII_ALPHA) != 0) + +#define l_ascii_iscntrl(c) \ + ((l_ascii_table[(unsigned char) (c)] & L_ASCII_CNTRL) != 0) + +#define l_ascii_isdigit(c) \ + ((l_ascii_table[(unsigned char) (c)] & L_ASCII_DIGIT) != 0) + +#define l_ascii_isgraph(c) \ + ((l_ascii_table[(unsigned char) (c)] & L_ASCII_GRAPH) != 0) + +#define l_ascii_islower(c) \ + ((l_ascii_table[(unsigned char) (c)] & L_ASCII_LOWER) != 0) + +#define l_ascii_isprint(c) \ + ((l_ascii_table[(unsigned char) (c)] & L_ASCII_PRINT) != 0) + +#define l_ascii_ispunct(c) \ + ((l_ascii_table[(unsigned char) (c)] & L_ASCII_PUNCT) != 0) + +#define l_ascii_isspace(c) \ + ((l_ascii_table[(unsigned char) (c)] & L_ASCII_SPACE) != 0) + +#define l_ascii_isupper(c) \ + ((l_ascii_table[(unsigned char) (c)] & L_ASCII_UPPER) != 0) + +#define l_ascii_isxdigit(c) \ + ((l_ascii_table[(unsigned char) (c)] & L_ASCII_XDIGIT) != 0) + +#if __STDC_VERSION__ <= 199409L +#define inline __inline__ +#endif + +static inline __attribute__ ((always_inline)) + bool l_ascii_isblank(unsigned char c) +{ + if (c == ' ' || c == '\t') + return true; + + return false; +} + +static inline __attribute__ ((always_inline)) bool l_ascii_isascii(int c) +{ + if (c <= 127) + return true; + + return false; +} + +static inline __attribute__ ((always_inline)) char l_ascii_toupper(char c) +{ + if (!l_ascii_islower(c)) + return c; + + return c - 32; +} + +static inline __attribute__ ((always_inline)) char l_ascii_tolower(char c) +{ + if (!l_ascii_isupper(c)) + return c; + + return c + 32; +} + +char *l_ascii_strdown(const char *str, ssize_t len); +char *l_ascii_strup(const char *str, ssize_t len); + +bool l_utf8_validate(const char *src, size_t len, const char **end); +size_t l_utf8_strlen(const char *str); + +int l_utf8_get_codepoint(const char *str, size_t len, wchar_t *cp); +size_t l_utf8_from_wchar(wchar_t c, char *out_buf); + +char *l_utf8_from_utf16(const void *utf16, ssize_t utf16_size); +void *l_utf8_to_utf16(const char *utf8, size_t *out_size); + +char *l_utf8_from_ucs2be(const void *ucs2be, ssize_t ucs2be_size); +void *l_utf8_to_ucs2be(const char *utf8, size_t *out_size); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_UTF8_H */ diff --git a/ell/util.c b/ell/util.c new file mode 100644 index 0000000000000000000000000000000000000000..f474098c082bd2495af59e80cc339ec15a2ceb3d --- /dev/null +++ b/ell/util.c @@ -0,0 +1,832 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <stdint.h> +#include <errno.h> +#include <unistd.h> + +#include "utf8.h" +#include "util.h" +#include "useful.h" +#include "private.h" + +/** + * SECTION:util + * @short_description: Utility functions + * + * Utility functions + */ + +#define STRLOC __FILE__ ":" L_STRINGIFY(__LINE__) + +/** + * l_malloc: + * @size: memory size to allocate + * + * If for any reason the memory allocation fails, then execution will be + * halted via abort(). + * + * In case @size is 0 then #NULL will be returned. + * + * Returns: pointer to allocated memory + **/ +LIB_EXPORT void *l_malloc(size_t size) +{ + if (likely(size)) { + void *ptr; + + ptr = malloc(size); + if (ptr) + return ptr; + + fprintf(stderr, "%s:%s(): failed to allocate %zd bytes\n", + STRLOC, __func__, size); + abort(); + } + + return NULL; +} + +/** + * l_realloc: + * @mem: previously allocated memory, or NULL + * @size: memory size to allocate + * + * If for any reason the memory allocation fails, then execution will be + * halted via abort(). + * + * In case @mem is NULL, this function acts like l_malloc. + * In case @size is 0 then #NULL will be returned. + * + * Returns: pointer to allocated memory + **/ +LIB_EXPORT void *l_realloc(void *mem, size_t size) +{ + if (likely(size)) { + void *ptr; + + ptr = realloc(mem, size); + if (ptr) + return ptr; + + fprintf(stderr, "%s:%s(): failed to re-allocate %zd bytes\n", + STRLOC, __func__, size); + abort(); + } else + l_free(mem); + + return NULL; +} + +/** + * l_memdup: + * @mem: pointer to memory you want to duplicate + * @size: memory size + * + * If for any reason the memory allocation fails, then execution will be + * halted via abort(). + * + * In case @size is 0 then #NULL will be returned. + * + * Returns: pointer to duplicated memory buffer + **/ +LIB_EXPORT void *l_memdup(const void *mem, size_t size) +{ + void *ptr; + + ptr = l_malloc(size); + + memcpy(ptr, mem, size); + + return ptr; +} + +/** + * l_free: + * @ptr: memory pointer + * + * Free the allocated memory area. + **/ +LIB_EXPORT void l_free(void *ptr) +{ + free(ptr); +} + +/** + * l_strdup: + * @str: string pointer + * + * Allocates and duplicates string + * + * Returns: a newly allocated string + **/ +LIB_EXPORT char *l_strdup(const char *str) +{ + if (likely(str)) { + char *tmp; + + tmp = strdup(str); + if (tmp) + return tmp; + + fprintf(stderr, "%s:%s(): failed to allocate string\n", + STRLOC, __func__); + abort(); + } + + return NULL; +} + +/** + * l_strndup: + * @str: string pointer + * @max: Maximum number of characters to copy + * + * Allocates and duplicates string. If the string is longer than @max + * characters, only @max are copied and a null terminating character + * is added. + * + * Returns: a newly allocated string + **/ +LIB_EXPORT char *l_strndup(const char *str, size_t max) +{ + if (likely(str)) { + char *tmp; + + tmp = strndup(str, max); + if (tmp) + return tmp; + + fprintf(stderr, "%s:%s(): failed to allocate string\n", + STRLOC, __func__); + abort(); + } + + return NULL; +} + +/** + * l_strdup_printf: + * @format: string format + * @...: parameters to insert into format string + * + * Returns: a newly allocated string + **/ +LIB_EXPORT char *l_strdup_printf(const char *format, ...) +{ + va_list args; + char *str; + int len; + + va_start(args, format); + len = vasprintf(&str, format, args); + va_end(args); + + if (len < 0) { + fprintf(stderr, "%s:%s(): failed to allocate string\n", + STRLOC, __func__); + abort(); + + return NULL; + } + + return str; +} + +/** + * l_strdup_vprintf: + * @format: string format + * @args: parameters to insert into format string + * + * Returns: a newly allocated string + **/ +LIB_EXPORT char *l_strdup_vprintf(const char *format, va_list args) +{ + char *str; + int len; + + len = vasprintf(&str, format, args); + + if (len < 0) { + fprintf(stderr, "%s:%s(): failed to allocate string\n", + STRLOC, __func__); + abort(); + + return NULL; + } + + return str; +} + +/** + * l_strlcpy: + * @dst: Destination buffer for string + * @src: Source buffer containing null-terminated string to copy + * @len: Maximum destination buffer space to use + * + * Copies a string from the @src buffer to the @dst buffer, using no + * more than @len bytes in @dst. @dst is guaranteed to be + * null-terminated. The caller can determine if the copy was truncated by + * checking if the return value is greater than or equal to @len. + * + * NOTE: Passing in a NULL string results in a no-op + * + * Returns: The length of the @src string, not including the null + * terminator. + */ +LIB_EXPORT size_t l_strlcpy(char *dst, const char *src, size_t len) +{ + size_t src_len = src ? strlen(src) : 0; + + if (!src) + goto done; + + if (len) { + if (src_len < len) { + len = src_len + 1; + } else { + len -= 1; + dst[len] = '\0'; + } + + memcpy(dst, src, len); + } + +done: + return src_len; +} + +/** + * l_str_has_prefix: + * @str: A string to be examined + * @delim: Prefix string + * + * Determines if the string given by @str is prefixed by string given by + * @prefix. + * + * Returns: True if @str was prefixed by @prefix. False otherwise. + */ +LIB_EXPORT bool l_str_has_prefix(const char *str, const char *prefix) +{ + size_t str_len; + size_t prefix_len; + + if (unlikely(!str)) + return false; + + if (unlikely(!prefix)) + return false; + + str_len = strlen(str); + prefix_len = strlen(prefix); + + if (str_len < prefix_len) + return false; + + return !strncmp(str, prefix, prefix_len); +} + +/** + * l_str_has_suffix: + * @str: A string to be examined + * @suffix: Suffix string + * + * Determines if the string given by @str ends with the specified @suffix. + * + * Returns: True if @str ends with the specified @suffix. False otherwise. + */ +LIB_EXPORT bool l_str_has_suffix(const char *str, const char *suffix) +{ + size_t str_len; + size_t suffix_len; + size_t len_diff; + + if (unlikely(!str)) + return false; + + if (unlikely(!suffix)) + return false; + + str_len = strlen(str); + suffix_len = strlen(suffix); + + if (str_len < suffix_len) + return false; + + len_diff = str_len - suffix_len; + + return !strcmp(&str[len_diff], suffix); +} + +/** + * l_streq0: + * @a: First operand + * @b: Second operand + * + * Returns: True if @a and @b are both NULL or both non-NULL and identical + * according to strcmp. False otherwise. + */ +LIB_EXPORT bool l_streq0(const char *a, const char *b) +{ + return a == b || (a && b && !strcmp(a, b)); +} + +static char *hexstring_common(const unsigned char *buf, size_t len, + const char hexdigits[static 16]) +{ + char *str; + size_t i; + + if (unlikely(!buf) || unlikely(!len)) + return NULL; + + str = l_malloc(len * 2 + 1); + + for (i = 0; i < len; i++) { + str[(i * 2) + 0] = hexdigits[buf[i] >> 4]; + str[(i * 2) + 1] = hexdigits[buf[i] & 0xf]; + } + + str[len * 2] = '\0'; + + return str; +} + +static char *hexstringv_common(const struct iovec *iov, size_t n_iov, + const char hexdigits[static 16]) +{ + char *str; + size_t i, j, c; + size_t len; + + if (unlikely(!iov || !n_iov)) + return NULL; + + for (i = 0, len = 0; i < n_iov; i++) + len += iov[i].iov_len; + + str = l_malloc(len * 2 + 1); + c = 0; + + for (i = 0; i < n_iov; i++) { + const uint8_t *buf = iov[i].iov_base; + + for (j = 0; j < iov[i].iov_len; j++) { + str[c++] = hexdigits[buf[j] >> 4]; + str[c++] = hexdigits[buf[j] & 0xf]; + } + } + + str[len * 2] = '\0'; + + return str; +} + +/** + * l_util_hexstring: + * @buf: buffer pointer + * @len: length of buffer + * + * Returns: a newly allocated hex string. Note that the string will contain + * lower case hex digits a-f. If you require upper case hex digits, use + * @l_util_hexstring_upper + **/ +LIB_EXPORT char *l_util_hexstring(const void *buf, size_t len) +{ + static const char hexdigits[] = "0123456789abcdef"; + return hexstring_common(buf, len, hexdigits); +} + +/** + * l_util_hexstring_upper: + * @buf: buffer pointer + * @len: length of buffer + * + * Returns: a newly allocated hex string. Note that the string will contain + * upper case hex digits a-f. If you require lower case hex digits, use + * @l_util_hexstring + **/ +LIB_EXPORT char *l_util_hexstring_upper(const void *buf, size_t len) +{ + static const char hexdigits[] = "0123456789ABCDEF"; + return hexstring_common(buf, len, hexdigits); +} + +/** + * l_util_hexstringv: + * @iov: iovec + * @n_iov: length of the iovec + * + * Returns: a newly allocated hex string. Note that the string will contain + * lower case hex digits a-f. If you require upper case hex digits, use + * @l_util_hexstringv_upper + **/ +LIB_EXPORT char *l_util_hexstringv(const struct iovec *iov, size_t n_iov) +{ + static const char hexdigits[] = "0123456789abcdef"; + return hexstringv_common(iov, n_iov, hexdigits); +} + +/** + * l_util_hexstringv_upper: + * @iov: iovec + * @n_iov: length of the iovec + * + * Returns: a newly allocated hex string. Note that the string will contain + * upper case hex digits a-f. If you require lower case hex digits, use + * @l_util_hexstringv + **/ +LIB_EXPORT char *l_util_hexstringv_upper(const struct iovec *iov, size_t n_iov) +{ + static const char hexdigits[] = "0123456789ABCDEF"; + return hexstringv_common(iov, n_iov, hexdigits); +} + +/** + * l_util_from_hexstring: + * @str: Null-terminated string containing the hex-encoded bytes + * @out_len: Number of bytes decoded + * + * Returns: a newly allocated byte array. Empty strings are treated as + * an error condition. + **/ +LIB_EXPORT unsigned char *l_util_from_hexstring(const char *str, + size_t *out_len) +{ + size_t i, j; + size_t len; + char c; + unsigned char *buf; + + if (unlikely(!str)) + return NULL; + + for (i = 0; str[i]; i++) { + c = str[i]; + + if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || + (c >= 'a' && c <= 'f')) + continue; + + return NULL; + } + + if (!i) + return NULL; + + if ((i % 2) != 0) + return NULL; + + len = i; + buf = l_malloc(i >> 1); + + for (i = 0, j = 0; i < len; i++, j++) { + c = str[i]; + + if (c >= '0' && c <= '9') + buf[j] = c - '0'; + else if (c >= 'A' && c <= 'F') + buf[j] = 10 + c - 'A'; + else if (c >= 'a' && c <= 'f') + buf[j] = 10 + c - 'a'; + + i += 1; + c = str[i]; + + if (c >= '0' && c <= '9') + buf[j] = buf[j] * 16 + c - '0'; + else if (c >= 'A' && c <= 'F') + buf[j] = buf[j] * 16 + 10 + c - 'A'; + else if (c >= 'a' && c <= 'f') + buf[j] = buf[j] * 16 + 10 + c - 'a'; + } + + if (out_len) + *out_len = j; + + return buf; +} + +static void hexdump(const char dir, const unsigned char *buf, size_t len, + l_util_hexdump_func_t function, void *user_data) +{ + static const char hexdigits[] = "0123456789abcdef"; + char str[68]; + size_t i; + + if (unlikely(!len)) + return; + + str[0] = dir; + + for (i = 0; i < len; i++) { + str[((i % 16) * 3) + 1] = ' '; + str[((i % 16) * 3) + 2] = hexdigits[buf[i] >> 4]; + str[((i % 16) * 3) + 3] = hexdigits[buf[i] & 0xf]; + str[(i % 16) + 51] = l_ascii_isprint(buf[i]) ? buf[i] : '.'; + + if ((i + 1) % 16 == 0) { + str[49] = ' '; + str[50] = ' '; + str[67] = '\0'; + function(str, user_data); + str[0] = ' '; + } + } + + if (i % 16 > 0) { + size_t j; + for (j = (i % 16); j < 16; j++) { + str[(j * 3) + 1] = ' '; + str[(j * 3) + 2] = ' '; + str[(j * 3) + 3] = ' '; + str[j + 51] = ' '; + } + str[49] = ' '; + str[50] = ' '; + str[67] = '\0'; + function(str, user_data); + } +} + +LIB_EXPORT void l_util_hexdump(bool in, const void *buf, size_t len, + l_util_hexdump_func_t function, void *user_data) +{ + if (likely(!function)) + return; + + hexdump(in ? '<' : '>', buf, len, function, user_data); +} + +LIB_EXPORT void l_util_hexdump_two(bool in, const void *buf1, size_t len1, + const void *buf2, size_t len2, + l_util_hexdump_func_t function, void *user_data) +{ + if (likely(!function)) + return; + + hexdump(in ? '<' : '>', buf1, len1, function, user_data); + hexdump(' ', buf2, len2, function, user_data); +} + +LIB_EXPORT void l_util_hexdumpv(bool in, const struct iovec *iov, + size_t n_iov, + l_util_hexdump_func_t function, + void *user_data) +{ + static const char hexdigits[] = "0123456789abcdef"; + char str[68]; + size_t i; + size_t len; + size_t c; + const uint8_t *buf; + + if (likely(!function)) + return; + + if (unlikely(!iov || !n_iov)) + return; + + str[0] = in ? '<' : '>'; + + for (i = 0, len = 0; i < n_iov; i++) + len += iov[i].iov_len; + + c = 0; + buf = iov[0].iov_base; + + for (i = 0; i < len; i++, c++) { + if (c == iov[0].iov_len) { + c = 0; + iov += 1; + buf = iov[0].iov_base; + } + + str[((i % 16) * 3) + 1] = ' '; + str[((i % 16) * 3) + 2] = hexdigits[buf[c] >> 4]; + str[((i % 16) * 3) + 3] = hexdigits[buf[c] & 0xf]; + str[(i % 16) + 51] = l_ascii_isprint(buf[c]) ? buf[c] : '.'; + + if ((i + 1) % 16 == 0) { + str[49] = ' '; + str[50] = ' '; + str[67] = '\0'; + function(str, user_data); + str[0] = ' '; + } + } + + if (i % 16 > 0) { + size_t j; + for (j = (i % 16); j < 16; j++) { + str[(j * 3) + 1] = ' '; + str[(j * 3) + 2] = ' '; + str[(j * 3) + 3] = ' '; + str[j + 51] = ' '; + } + str[49] = ' '; + str[50] = ' '; + str[67] = '\0'; + function(str, user_data); + } +} + +LIB_EXPORT void l_util_debug(l_util_hexdump_func_t function, void *user_data, + const char *format, ...) +{ + va_list args; + char *str; + int len; + + if (likely(!function)) + return; + + if (unlikely(!format)) + return; + + va_start(args, format); + len = vasprintf(&str, format, args); + va_end(args); + + if (unlikely(len < 0)) + return; + + function(str, user_data); + + free(str); +} + +/** + * l_util_get_debugfs_path: + * + * Returns: a pointer to mount point of debugfs + **/ +LIB_EXPORT const char *l_util_get_debugfs_path(void) +{ + static char path[PATH_MAX + 1]; + static bool found = false; + char type[100]; + FILE *fp; + + if (found) + return path; + + fp = fopen("/proc/mounts", "r"); + if (!fp) + return NULL; + + while (fscanf(fp, "%*s %" L_STRINGIFY(PATH_MAX) "s %99s %*s %*d %*d\n", + path, type) == 2) { + if (!strcmp(type, "debugfs")) { + found = true; + break; + } + } + + fclose(fp); + + if (!found) + return NULL; + + return path; +} + +LIB_EXPORT bool l_memeq(const void *field, size_t size, uint8_t byte) +{ + const uint8_t *mem = field; + size_t i; + + for (i = 0; i < size; i++) + if (mem[i] != byte) + return false; + + return true; +} + +__attribute__((noinline)) static int __secure_memeq(const void *field, + size_t size, uint8_t byte) +{ + unsigned int diff = 0; + size_t i; + + for (i = 0; i < size; i++) { + diff |= ((uint8_t *) field)[i] ^ byte; + DO_NOT_OPTIMIZE(diff); + } + + return diff; +} + +LIB_EXPORT bool l_secure_memeq(const void *field, size_t size, uint8_t byte) +{ + return __secure_memeq(field, size, byte) == 0 ? true : false; +} + +static int safe_atou(const char *s, int base, unsigned int *out_u) +{ + unsigned long int r; + unsigned int t; + char *endp; + + errno = 0; + + t = r = strtoul(s, &endp, base); + if (unlikely(errno > 0)) + return -errno; + + if (endp == s || *endp != '\0') + return -EINVAL; + + if (unlikely(r != t)) + return -ERANGE; + + if (out_u) + *out_u = t; + + return 0; +} + +LIB_EXPORT int l_safe_atou32(const char *s, uint32_t *out_u) +{ + if (unlikely(!s)) + return -EINVAL; + + if (!l_ascii_isdigit(s[0])) + return -EINVAL; + + /* Don't allow leading zeros */ + if (s[0] == '0' && s[1] != '\0') + return -EINVAL; + + return safe_atou(s, 10, out_u); +} + +LIB_EXPORT int l_safe_atox8(const char *s, uint8_t *out_x) +{ + uint32_t x; + int r; + + r = l_safe_atox32(s, &x); + if (r < 0) + return r; + + if (x > UINT8_MAX) + return -ERANGE; + + if (out_x) + *out_x = x; + + return 0; +} + +LIB_EXPORT int l_safe_atox16(const char *s, uint16_t *out_x) +{ + uint32_t x; + int r; + + r = l_safe_atox32(s, &x); + if (r < 0) + return r; + + if (x > UINT16_MAX) + return -ERANGE; + + if (out_x) + *out_x = x; + + return 0; +} + +LIB_EXPORT int l_safe_atox32(const char *s, uint32_t *out_x) +{ + if (unlikely(!s)) + return -EINVAL; + + if (!l_ascii_isxdigit(s[0])) + return -EINVAL; + + return safe_atou(s, 16, out_x); +} + +LIB_EXPORT size_t l_util_pagesize(void) +{ + static size_t page_size = 0; + + if (likely(page_size > 0)) + return page_size; + + page_size = sysconf(_SC_PAGESIZE); + return page_size; +} diff --git a/ell/util.h b/ell/util.h new file mode 100644 index 0000000000000000000000000000000000000000..c56f182292fa10c3b2fe4493ca2c09c00539c52f --- /dev/null +++ b/ell/util.h @@ -0,0 +1,524 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_UTIL_H +#define __ELL_UTIL_H + +#include <string.h> +#include <stdbool.h> +#include <stdarg.h> +#include <inttypes.h> +#include <endian.h> +#include <byteswap.h> +#include <unistd.h> +#include <errno.h> +#include <sys/uio.h> +#include <ell/cleanup.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define l_container_of(ptr, type, member) ({ \ +_Pragma("GCC diagnostic push") \ +_Pragma("GCC diagnostic ignored \"-Wcast-align\"") \ + const __typeof__(((type *) 0)->member) *__mptr = (ptr); \ + (type *)((char *) __mptr - offsetof(type, member)); \ +_Pragma("GCC diagnostic pop") \ + }) + +#define L_STRINGIFY(val) L_STRINGIFY_ARG(val) +#define L_STRINGIFY_ARG(contents) #contents + +#define L_WARN_ON(condition) __extension__ ({ \ + bool r = !!(condition); \ + if (__builtin_expect(r, 0)) \ + l_warn("WARNING: %s:%s() condition %s failed", \ + __FILE__, __func__, \ + #condition); \ + r; \ + }) + +/* + * If ELL headers and iterfaces end up getting compiled in a C++ + * environment, even though ELL itself is a C source based and is + * compiled as such, certain assignments may be flagged by the C++ + * compiler as errors or warnings. The following portable casts should + * be used in such cases, with a preference towards L_PERMISSIVE_CAST + * where possible since it is not a cast in C and, therefore, will not + * mask otherwise-legitimate warnings in that environment. + */ +#ifdef __cplusplus +#define L_CONST_CAST(t, v) const_cast<t>(v) +#define L_REINTERPRET_CAST(t, v) reinterpret_cast<t>(v) +#define L_STATIC_CAST(t, v) static_cast<t>(v) +#define L_PERMISSIVE_CAST(t, v) L_STATIC_CAST(t, v) +#else +#define L_CONST_CAST(t, v) ((t)(v)) +#define L_REINTERPRET_CAST(t, v) ((t)(v)) +#define L_STATIC_CAST(t, v) ((t)(v)) +#define L_PERMISSIVE_CAST(t, v) (v) +#endif + +#define L_PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p))) +#define L_UINT_TO_PTR(u) ((void *) ((uintptr_t) (u))) + +#define L_PTR_TO_INT(p) ((int) ((intptr_t) (p))) +#define L_INT_TO_PTR(u) ((void *) ((intptr_t) (u))) + +#define L_GET_UNALIGNED(ptr) __extension__ \ +({ \ + struct __attribute__((packed)) { \ + __typeof__(*(ptr)) __v; \ + } *__p = (__typeof__(__p)) (ptr); \ + __p->__v; \ +}) + +#define L_PUT_UNALIGNED(val, ptr) \ +do { \ + struct __attribute__((packed)) { \ + __typeof__(*(ptr)) __v; \ + } *__p = (__typeof__(__p)) (ptr); \ + __p->__v = (val); \ +} while(0) + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define L_LE16_TO_CPU(val) (val) +#define L_LE32_TO_CPU(val) (val) +#define L_LE64_TO_CPU(val) (val) +#define L_CPU_TO_LE16(val) (val) +#define L_CPU_TO_LE32(val) (val) +#define L_CPU_TO_LE64(val) (val) +#define L_BE16_TO_CPU(val) bswap_16(val) +#define L_BE32_TO_CPU(val) bswap_32(val) +#define L_BE64_TO_CPU(val) bswap_64(val) +#define L_CPU_TO_BE16(val) bswap_16(val) +#define L_CPU_TO_BE32(val) bswap_32(val) +#define L_CPU_TO_BE64(val) bswap_64(val) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define L_LE16_TO_CPU(val) bswap_16(val) +#define L_LE32_TO_CPU(val) bswap_32(val) +#define L_LE64_TO_CPU(val) bswap_64(val) +#define L_CPU_TO_LE16(val) bswap_16(val) +#define L_CPU_TO_LE32(val) bswap_32(val) +#define L_CPU_TO_LE64(val) bswap_64(val) +#define L_BE16_TO_CPU(val) (val) +#define L_BE32_TO_CPU(val) (val) +#define L_BE64_TO_CPU(val) (val) +#define L_CPU_TO_BE16(val) (val) +#define L_CPU_TO_BE32(val) (val) +#define L_CPU_TO_BE64(val) (val) +#else +#error "Unknown byte order" +#endif + +#if __STDC_VERSION__ <= 199409L +#define inline __inline__ +#endif + +static inline uint8_t l_get_u8(const void *ptr) +{ + return *((const uint8_t *) ptr); +} + +static inline void l_put_u8(uint8_t val, void *ptr) +{ + *((uint8_t *) ptr) = val; +} + +static inline uint16_t l_get_u16(const void *ptr) +{ + return L_GET_UNALIGNED((const uint16_t *) ptr); +} + +static inline void l_put_u16(uint16_t val, void *ptr) +{ + L_PUT_UNALIGNED(val, (uint16_t *) ptr); +} + +static inline uint32_t l_get_u32(const void *ptr) +{ + return L_GET_UNALIGNED((const uint32_t *) ptr); +} + +static inline void l_put_u32(uint32_t val, void *ptr) +{ + L_PUT_UNALIGNED(val, (uint32_t *) ptr); +} + +static inline uint64_t l_get_u64(const void *ptr) +{ + return L_GET_UNALIGNED((const uint64_t *) ptr); +} + +static inline void l_put_u64(uint64_t val, void *ptr) +{ + L_PUT_UNALIGNED(val, (uint64_t *) ptr); +} + +static inline int16_t l_get_s16(const void *ptr) +{ + return L_GET_UNALIGNED((const int16_t *) ptr); +} + +static inline int32_t l_get_s32(const void *ptr) +{ + return L_GET_UNALIGNED((const int32_t *) ptr); +} + +static inline int64_t l_get_s64(const void *ptr) +{ + return L_GET_UNALIGNED((const int64_t *) ptr); +} + +static inline uint16_t l_get_le16(const void *ptr) +{ + return L_LE16_TO_CPU(L_GET_UNALIGNED((const uint16_t *) ptr)); +} + +static inline uint16_t l_get_be16(const void *ptr) +{ + return L_BE16_TO_CPU(L_GET_UNALIGNED((const uint16_t *) ptr)); +} + +static inline uint32_t l_get_le32(const void *ptr) +{ + return L_LE32_TO_CPU(L_GET_UNALIGNED((const uint32_t *) ptr)); +} + +static inline uint32_t l_get_be32(const void *ptr) +{ + return L_BE32_TO_CPU(L_GET_UNALIGNED((const uint32_t *) ptr)); +} + +static inline uint64_t l_get_le64(const void *ptr) +{ + return L_LE64_TO_CPU(L_GET_UNALIGNED((const uint64_t *) ptr)); +} + +static inline uint64_t l_get_be64(const void *ptr) +{ + return L_BE64_TO_CPU(L_GET_UNALIGNED((const uint64_t *) ptr)); +} + +static inline void l_put_le16(uint16_t val, void *ptr) +{ + L_PUT_UNALIGNED(L_CPU_TO_LE16(val), (uint16_t *) ptr); +} + +static inline void l_put_be16(uint16_t val, const void *ptr) +{ + L_PUT_UNALIGNED(L_CPU_TO_BE16(val), (uint16_t *) ptr); +} + +static inline void l_put_le32(uint32_t val, void *ptr) +{ + L_PUT_UNALIGNED(L_CPU_TO_LE32(val), (uint32_t *) ptr); +} + +static inline void l_put_be32(uint32_t val, void *ptr) +{ + L_PUT_UNALIGNED(L_CPU_TO_BE32(val), (uint32_t *) ptr); +} + +static inline void l_put_le64(uint64_t val, void *ptr) +{ + L_PUT_UNALIGNED(L_CPU_TO_LE64(val), (uint64_t *) ptr); +} + +static inline void l_put_be64(uint64_t val, void *ptr) +{ + L_PUT_UNALIGNED(L_CPU_TO_BE64(val), (uint64_t *) ptr); +} + +#define L_AUTO_FREE_VAR(vartype,varname) \ + vartype varname __attribute__((cleanup(auto_free))) + +#define L_ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +void *l_malloc(size_t size) __attribute__ ((warn_unused_result, malloc)); +void *l_memdup(const void *mem, size_t size) + __attribute__ ((warn_unused_result, malloc)); +void l_free(void *ptr); +DEFINE_CLEANUP_FUNC(l_free); + +void *l_realloc(void *mem, size_t size) + __attribute__ ((warn_unused_result, malloc)); + +static inline void auto_free(void *a) +{ + void **p = (void **)a; + l_free(*p); +} + +#define l_steal_ptr(ptr) \ + (__extension__ ({ typeof(ptr) _tmp = (ptr); (ptr) = NULL; _tmp; })) + +/** + * l_new: + * @type: type of structure + * @count: amount of structures + * + * Returns: pointer to allocated memory + **/ +#define l_new(type, count) \ + (type *) (__extension__ ({ \ + size_t __n = (size_t) (count); \ + size_t __s = sizeof(type); \ + void *__p; \ + __p = l_malloc(__n * __s); \ + memset(__p, 0, __n * __s); \ + __p; \ + })) + +/** + * l_newa: + * @type: type of structure + * @count: amount of structures + * + * Allocates stack space for @count structures of @type. Memory is allocated + * using alloca and initialized to 0. + * + * Returns: Pointer to memory allocated on the stack. + */ +#define l_newa(type, count) \ + (type *) (__extension__ ({ \ + size_t __n = (size_t) (count); \ + size_t __s = sizeof(type); \ + void *__p; \ + __p = alloca(__n * __s); \ + memset(__p, 0, __n * __s); \ + __p; \ + })) + +char *l_strdup(const char *str); +char *l_strndup(const char *str, size_t max); +char *l_strdup_printf(const char *format, ...) + __attribute__((format(printf, 1, 2))); +char *l_strdup_vprintf(const char *format, va_list args) + __attribute__((format(printf, 1, 0))); + +size_t l_strlcpy(char* dst, const char *src, size_t len); + +bool l_str_has_prefix(const char *str, const char *prefix); +bool l_str_has_suffix(const char *str, const char *suffix); +bool l_streq0(const char *a, const char *b); + +char *l_util_hexstring(const void *buf, size_t len); +char *l_util_hexstring_upper(const void *buf, size_t len); +char *l_util_hexstringv(const struct iovec *iov, size_t n_iov); +char *l_util_hexstringv_upper(const struct iovec *iov, size_t n_iov); +unsigned char *l_util_from_hexstring(const char *str, size_t *out_len); + +typedef void (*l_util_hexdump_func_t) (const char *str, void *user_data); + +void l_util_hexdump(bool in, const void *buf, size_t len, + l_util_hexdump_func_t function, void *user_data); +void l_util_hexdump_two(bool in, const void *buf1, size_t len1, + const void *buf2, size_t len2, + l_util_hexdump_func_t function, void *user_data); +void l_util_hexdumpv(bool in, const struct iovec *iov, size_t n_iov, + l_util_hexdump_func_t function, + void *user_data); +void l_util_debug(l_util_hexdump_func_t function, void *user_data, + const char *format, ...) + __attribute__((format(printf, 3, 4))); + +const char *l_util_get_debugfs_path(void); + +#define L_TFR(expression) \ + (__extension__ \ + ({ long int __result; \ + do __result = (long int) (expression); \ + while (__result == -1L && errno == EINTR); \ + __result; })) + +/* Enables declaring _auto_(close) int fd = <-1 or L_TFR(open(...))>; */ +inline __attribute__((always_inline)) void _l_close_cleanup(void *p) +{ + int fd = *(int *) p; + + if (fd >= 0) + L_TFR(close(fd)); +} + +#define _L_IN_SET_CMP(val, type, cmp, ...) __extension__ ({ \ + const type __v = (val); \ + const typeof(__v) __elems[] = {__VA_ARGS__}; \ + size_t __i; \ + const size_t __n = L_ARRAY_SIZE(__elems); \ + bool __r = false; \ + for (__i = 0; __i < __n && !__r; __i++) \ + __r = (cmp); \ + __r; \ + }) + +/* Warning: evaluates all set elements even after @val has matched one */ +#define L_IN_SET(val, ...) \ + _L_IN_SET_CMP((val), __auto_type, __v == __elems[__i], ##__VA_ARGS__) + +#define L_IN_STRSET(val, ...) \ + _L_IN_SET_CMP((val), char *, __v == __elems[__i] || \ + (__v && __elems[__i] && \ + !strcmp(__v, __elems[__i])), ##__VA_ARGS__) + +#define _L_BIT_TO_MASK(bits, nr) __extension__ ({ \ + typeof(*(bits)) _one = 1U; \ + const unsigned int _shift = (nr) % (sizeof(_one) * 8); \ + _one << _shift; \ +}) + +#define _L_BIT_TO_OFFSET(bits, nr) __extension__ ({ \ + __auto_type _bits = (bits); \ + const size_t _offset = (nr) / (sizeof(*_bits) * 8); \ + _bits + _offset; \ +}) + +#define L_BIT_SET(bits, nr) __extension__ ({ \ + size_t _nr = (nr); \ + __auto_type _offset = _L_BIT_TO_OFFSET(bits, _nr); \ + *_offset |= _L_BIT_TO_MASK(_offset, _nr); \ +}) + +#define L_BIT_CLEAR(bits, nr) __extension__ ({ \ + size_t _nr = (nr); \ + __auto_type _offset = _L_BIT_TO_OFFSET(bits, _nr); \ + *_offset &= ~_L_BIT_TO_MASK(_offset, _nr); \ +}) + +#define L_BIT_TEST(bits, nr) __extension__ ({ \ + size_t _nr = (nr); \ + __auto_type _offset = _L_BIT_TO_OFFSET(bits, _nr); \ + (*_offset & _L_BIT_TO_MASK(_offset, _nr)) != 0; \ +}) + +#define L_BITS_SET(bits, ...) __extension__ ({ \ + const unsigned int __elems[] = {__VA_ARGS__}; \ + size_t __i; \ + for (__i = 0; __i < L_ARRAY_SIZE(__elems); __i++) \ + L_BIT_SET(bits, __elems[__i]); \ +}) + +#define L_BITS_CLEAR(bits, ...) __extension__ ({ \ + const unsigned int __elems[] = {__VA_ARGS__}; \ + size_t __i; \ + for (__i = 0; __i < L_ARRAY_SIZE(__elems); __i++) \ + L_BIT_CLEAR(bits, __elems[__i]); \ +}) + +/* + * Taken from https://github.com/chmike/cst_time_memcmp, adding a volatile to + * ensure the compiler does not try to optimize the constant time behavior. + * The code has been modified to add comments and project specific code + * styling. + * This specific piece of code is subject to the following copyright: + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Christophe Meessen + * + * 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. + * + * This function performs a secure memory comparison of two buffers of size + * bytes, representing an integer (byte order is big endian). It returns + * a negative, zero or positif value if a < b, a == b or a > b respectively. + */ +static inline int l_secure_memcmp(const void *a, const void *b, + size_t size) +{ + const volatile uint8_t *aa = + L_PERMISSIVE_CAST(const volatile uint8_t *, a); + const volatile uint8_t *bb = + L_PERMISSIVE_CAST(const volatile uint8_t *, b); + int res = 0, diff, mask; + + /* + * We will compare all bytes, starting with the less significant. When + * we find a non-zero difference, we update the result accordingly. + */ + if (size > 0) { + /* + * The following couple of lines can be summarized as a + * constant time/memory access version of: + * if (diff != 0) res = diff; + * + * From the previous operation, we know that diff is in + * [-255, 255] + * + * The following figure show the possible value of mask, based + * on different cases of diff: + * + * diff | diff-1 | ~diff | ((diff-1) & ~diff) | mask + * ------|------------|------------|--------------------|------ + * < 0 | 0xFFFFFFXX | 0x000000YY | 0x000000ZZ | 0 + * == 0 | 0xFFFFFFFF | 0xFFFFFFFF | 0xFFFFFFFF | 0xF..F + * > 0 | 0x000000XX | 0xFFFFFFYY | 0x000000ZZ | 0 + * + * Hence, the mask allows to keep res when diff == 0, and to + * set res to diff otherwise. + */ + do { + --size; + diff = aa[size] - bb[size]; + mask = (((diff - 1) & ~diff) >> 8); + res = (res & mask) | diff; + } while (size != 0); + } + + return res; +} + +bool l_memeq(const void *field, size_t size, uint8_t byte); +bool l_secure_memeq(const void *field, size_t size, uint8_t byte); + +static inline bool l_memeqzero(const void *field, size_t size) +{ + return l_memeq(field, size, 0); +} + +static inline void l_secure_select(bool select_left, + const void *left, const void *right, + void *out, size_t len) +{ + const uint8_t *l = L_PERMISSIVE_CAST(const uint8_t *, left); + const uint8_t *r = L_PERMISSIVE_CAST(const uint8_t *, right); + uint8_t *o = L_PERMISSIVE_CAST(uint8_t *, out); + uint8_t mask = -(!!select_left); + size_t i; + + for (i = 0; i < len; i++) + o[i] = r[i] ^ ((l[i] ^ r[i]) & mask); +} + +int l_safe_atou32(const char *s, uint32_t *out_u); +int l_safe_atox32(const char *s, uint32_t *out_u); +int l_safe_atox16(const char *s, uint16_t *out_u); +int l_safe_atox8(const char *s, uint8_t *out_u); + +size_t l_util_pagesize(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_UTIL_H */ diff --git a/ell/uuid.c b/ell/uuid.c new file mode 100644 index 0000000000000000000000000000000000000000..851bae4c8b2a4afdd94c0fadb3c6256bad5bc622 --- /dev/null +++ b/ell/uuid.c @@ -0,0 +1,246 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2014 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <stdio.h> + +#include "checksum.h" +#include "random.h" +#include "private.h" +#include "useful.h" +#include "uuid.h" + +const uint8_t L_UUID_NAMESPACE_DNS[16] = { + 0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, +}; + +const uint8_t L_UUID_NAMESPACE_URL[16] = { + 0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, +}; + +const uint8_t L_UUID_NAMESPACE_OID[16] = { + 0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, +}; + +const uint8_t L_UUID_NAMESPACE_X500[16] = { + 0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, +}; + +/* RFC 4122, Section 4.3 */ +static bool name_from_namespace(int version, const uint8_t nsid[16], + const void *name, + size_t name_size, uint8_t out_uuid[16]) +{ + enum l_checksum_type type; + struct l_checksum *hash; + struct iovec iov[2]; + + if (unlikely(!out_uuid)) + return false; + + switch (version) { + case 3: + type = L_CHECKSUM_MD5; + break; + case 5: + type = L_CHECKSUM_SHA1; + break; + default: + return false; + } + + hash = l_checksum_new(type); + if (!hash) + return false; + + iov[0].iov_base = (void *) nsid; + iov[0].iov_len = 16; + iov[1].iov_base = (void *) name; + iov[1].iov_len = name_size; + + /* Compute the hash of the name space ID concatenated with the name. */ + l_checksum_updatev(hash, iov, 2); + + /* o Set octets zero through 3 of the time_low field to octets zero + * through 3 of the hash. + * + * o Set octets zero and one of the time_mid field to octets 4 and 5 of + * the hash. + * + * o Set octets zero and one of the time_hi_and_version field to octets + * 6 and 7 of the hash. + * o Set the four most significant bits (bits 12 through 15) of the + * time_hi_and_version field to the appropriate 4-bit version number + * from Section 4.1.3. + * + * o Set the clock_seq_hi_and_reserved field to octet 8 of the hash. + * o Set the two most significant bits (bits 6 and 7) of the + * clock_seq_hi_and_reserved to zero and one, respectively. + * + * o Set the clock_seq_low field to octet 9 of the hash. + * + * o Set octets zero through five of the node field to octets 10 + * through 15 of the hash. + */ + + l_checksum_get_digest(hash, out_uuid, 16); + + /* Set 4 MSB bits of time_hi_and_version field */ + out_uuid[6] &= 0x0f; + out_uuid[6] |= version << 4; + + /* Set 2 MSB of clock_seq_hi_and_reserved to 10 */ + out_uuid[8] &= 0x3f; + out_uuid[8] |= 0x80; + + l_checksum_free(hash); + + return true; +} + +LIB_EXPORT bool l_uuid_v3(const uint8_t nsid[16], const void *name, + size_t name_size, uint8_t out_uuid[16]) +{ + return name_from_namespace(3, nsid, name, name_size, out_uuid); +} + +LIB_EXPORT bool l_uuid_v5(const uint8_t nsid[16], const void *name, + size_t name_size, uint8_t out_uuid[16]) +{ + return name_from_namespace(5, nsid, name, name_size, out_uuid); +} + +/* RFC 4122, Section 4.4 */ +LIB_EXPORT bool l_uuid_v4(uint8_t out_uuid[16]) +{ + if (unlikely(!out_uuid)) + return false; + + if (!l_getrandom(out_uuid, 16)) + return false; + + /* + * o Set the two most significant bits (bits 6 and 7) of the + * clock_seq_hi_and_reserved to zero and one, respectively. + * + * o Set the four most significant bits (bits 12 through 15) of the + * time_hi_and_version field to the 4-bit version number from + * Section 4.1.3. + * + * o Set all the other bits to randomly (or pseudo-randomly) chosen + * values. + */ + + /* Set 4 MSB bits of time_hi_and_version field */ + out_uuid[6] &= 0x0f; + out_uuid[6] |= 4 << 4; + + /* Set 2 MSB of clock_seq_hi_and_reserved to 10 */ + out_uuid[8] &= 0x3f; + out_uuid[8] |= 0x80; + + return true; +} + +/** + * l_uuid_is_valid: + * @uuid: UUID to check. + * + * Checks whether the given UUID is valid according to RFC 4122. This function + * checks that the version field is set properly and the variant of the UUID + * is set to RFC 4122. + * + * Returns: Whether the UUID is valid + **/ +LIB_EXPORT bool l_uuid_is_valid(const uint8_t uuid[16]) +{ + unsigned int version; + unsigned int variant; + + if (!uuid) + return false; + + variant = uuid[8] >> 6; + if (variant != 2) + return false; + + version = uuid[6] >> 4; + if (version < 1 || version > 5) + return false; + + return true; +} + +LIB_EXPORT enum l_uuid_version l_uuid_get_version(const uint8_t uuid[16]) +{ + unsigned int version; + + version = uuid[6] >> 4; + return version; +} + +LIB_EXPORT bool l_uuid_to_string(const uint8_t uuid[16], + char *dest, size_t dest_size) +{ + int n; + + n = snprintf(dest, dest_size, "%02x%02x%02x%02x-%02x%02x-%02x%02x-" + "%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], + uuid[6], uuid[7], + uuid[8], uuid[9], + uuid[10], uuid[11], uuid[12], + uuid[13], uuid[14], uuid[15]); + + if (n < 0 || (size_t) n >= dest_size) + return false; + + return true; +} + +LIB_EXPORT bool l_uuid_from_string(const char *src, uint8_t uuid[16]) +{ + uint8_t buf[16]; + int n; + + /* + * textual representation: 32 hex digits + 4 group separators + */ + if (strlen(src) < 16 * 2 + 4) + return false; + + n = sscanf(src, + "%02hhx%02hhx%02hhx%02hhx-" + "%02hhx%02hhx-" + "%02hhx%02hhx-" + "%02hhx%02hhx-" + "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", + &buf[0], &buf[1], &buf[2], &buf[3], + &buf[4], &buf[5], + &buf[6], &buf[7], + &buf[8], &buf[9], + &buf[10], &buf[11], &buf[12], + &buf[13], &buf[14], &buf[15]); + + if (n != 16) + return false; + + if (!l_uuid_is_valid(buf)) + return false; + + memcpy(uuid, buf, sizeof(buf)); + return true; +} diff --git a/ell/uuid.h b/ell/uuid.h new file mode 100644 index 0000000000000000000000000000000000000000..a3173b014b4a1ef8d2db1f13b1107a5d7ceaa43b --- /dev/null +++ b/ell/uuid.h @@ -0,0 +1,47 @@ +/* + * Embedded Linux library + * Copyright (C) 2011-2015 Intel Corporation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __ELL_UUID_H +#define __ELL_UUID_H + +#include <stdbool.h> +#include <inttypes.h> + +#ifdef __cplusplus +extern "C" { +#endif + +enum l_uuid_version { + L_UUID_VERSION_1_TIME = 1, + L_UUID_VERSION_2_DCE = 2, + L_UUID_VERSION_3_MD5 = 3, + L_UUID_VERSION_4_RANDOM = 4, + L_UUID_VERSION_5_SHA1 = 5, +}; + +extern const uint8_t L_UUID_NAMESPACE_DNS[]; +extern const uint8_t L_UUID_NAMESPACE_URL[]; +extern const uint8_t L_UUID_NAMESPACE_OID[]; +extern const uint8_t L_UUID_NAMESPACE_X500[]; + +bool l_uuid_v3(const uint8_t nsid[16], const void *name, size_t name_size, + uint8_t out_uuid[16]); +bool l_uuid_v4(uint8_t out_uuid[16]); +bool l_uuid_v5(const uint8_t nsid[16], const void *name, size_t name_size, + uint8_t out_uuid[16]); + +bool l_uuid_is_valid(const uint8_t uuid[16]); +enum l_uuid_version l_uuid_get_version(const uint8_t uuid[16]); + +bool l_uuid_to_string(const uint8_t uuid[16], char *dest, size_t dest_size); +bool l_uuid_from_string(const char *src, uint8_t uuid[16]); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_UTIL_H */ diff --git a/emulator/amp.c b/emulator/amp.c index 49d2df7b39df4b6579b99750a6cdce5afabc829c..6daf00189f3a22814dd185455c11500807b05b72 100644 --- a/emulator/amp.c +++ b/emulator/amp.c @@ -680,7 +680,8 @@ static void cmd_read_local_amp_assoc(struct bt_amp *amp, { const struct bt_hci_cmd_read_local_amp_assoc *cmd = data; struct bt_hci_rsp_read_local_amp_assoc rsp; - uint16_t len_so_far, remain_assoc_len, fragment_len; + uint16_t len_so_far, remain_assoc_len; + size_t fragment_len; if (cmd->phy_handle != amp->phy_handle) { cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS, diff --git a/emulator/btdev.c b/emulator/btdev.c index 549f93645684464586aa18bab62bf639caef5fec..5752a2fb02473d4e88f70cd7346939ff6dfe2069 100644 --- a/emulator/btdev.c +++ b/emulator/btdev.c @@ -5,6 +5,7 @@ * * Copyright (C) 2011-2012 Intel Corporation * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org> + * Copyright 2023-2024 NXP * * */ @@ -41,6 +42,9 @@ #define RL_SIZE 16 #define CIS_SIZE 3 #define BIS_SIZE 3 +#define CIG_SIZE 3 + +#define MAX_PA_DATA_LEN 252 #define has_bredr(btdev) (!((btdev)->features[4] & 0x20)) #define has_le(btdev) (!!((btdev)->features[4] & 0x40)) @@ -60,6 +64,7 @@ struct hook { #define MAX_HOOK_ENTRIES 16 #define MAX_EXT_ADV_SETS 3 +#define MAX_PENDING_CONN 16 struct btdev_conn { uint16_t handle; @@ -100,6 +105,12 @@ struct le_ext_adv { unsigned int id; }; +struct le_cig { + struct bt_hci_cmd_le_set_cig_params params; + struct bt_hci_cis_params cis[CIS_SIZE]; + bool activated; +} __attribute__ ((packed)); + struct btdev { enum btdev_type type; uint16_t id; @@ -137,6 +148,8 @@ struct btdev { uint8_t feat_page_2[8]; uint16_t acl_mtu; uint16_t acl_max_pkt; + uint16_t sco_mtu; + uint16_t sco_max_pkt; uint16_t iso_mtu; uint16_t iso_max_pkt; uint8_t country_code; @@ -198,15 +211,12 @@ struct btdev { uint16_t le_pa_min_interval; uint16_t le_pa_max_interval; uint8_t le_pa_data_len; - uint8_t le_pa_data[31]; + uint8_t le_pa_data[MAX_PA_DATA_LEN]; struct bt_hci_cmd_le_pa_create_sync pa_sync_cmd; uint16_t le_pa_sync_handle; uint8_t big_handle; uint8_t le_ltk[16]; - struct { - struct bt_hci_cmd_le_set_cig_params params; - struct bt_hci_cis_params cis[CIS_SIZE]; - } __attribute__ ((packed)) le_cig; + struct le_cig le_cig[CIG_SIZE]; uint8_t le_iso_path[2]; /* Real time length of AL array */ @@ -218,6 +228,8 @@ struct btdev { uint8_t le_rl_enable; uint16_t le_rl_timeout; + struct btdev *pending_conn[MAX_PENDING_CONN]; + uint8_t le_local_sk256[32]; uint16_t sync_train_interval; @@ -309,6 +321,18 @@ static inline int del_btdev(struct btdev *btdev) return index; } +static inline bool valid_btdev(struct btdev *btdev) +{ + int i; + + for (i = 0; i < MAX_BTDEV_ENTRIES; i++) { + if (btdev_list[i] == btdev) + return true; + } + + return false; +} + static inline struct btdev *find_btdev_by_bdaddr(const uint8_t *bdaddr) { int i; @@ -554,6 +578,8 @@ static void btdev_reset(struct btdev *btdev) btdev->le_scan_enable = 0x00; btdev->le_adv_enable = 0x00; btdev->le_pa_enable = 0x00; + btdev->le_pa_sync_handle = 0x0000; + btdev->big_handle = 0xff; al_clear(btdev); rl_clear(btdev); @@ -629,9 +655,9 @@ static int cmd_read_buffer_size(struct btdev *dev, const void *data, rsp.status = BT_HCI_ERR_SUCCESS; rsp.acl_mtu = cpu_to_le16(dev->acl_mtu); - rsp.sco_mtu = 0; + rsp.sco_mtu = cpu_to_le16(dev->sco_mtu); rsp.acl_max_pkt = cpu_to_le16(dev->acl_max_pkt); - rsp.sco_max_pkt = cpu_to_le16(0); + rsp.sco_max_pkt = cpu_to_le16(dev->sco_max_pkt); cmd_complete(dev, BT_HCI_CMD_READ_BUFFER_SIZE, &rsp, sizeof(rsp)); @@ -745,7 +771,9 @@ static int cmd_disconnect_complete(struct btdev *dev, const void *data, return 0; } - disconnect_complete(dev, conn->handle, BT_HCI_ERR_SUCCESS, cmd->reason); + /* Local host has different reason (Core v5.3 Vol 4 Part E Sec 7.1.6) */ + disconnect_complete(dev, conn->handle, BT_HCI_ERR_SUCCESS, + BT_HCI_ERR_LOCAL_HOST_TERM); if (conn->link) disconnect_complete(conn->link->dev, conn->link->handle, @@ -1204,10 +1232,39 @@ static struct btdev_conn *conn_link_bis(struct btdev *dev, struct btdev *remote, return conn; } +static void pending_conn_add(struct btdev *btdev, struct btdev *remote) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(btdev->pending_conn); ++i) { + if (!btdev->pending_conn[i]) { + btdev->pending_conn[i] = remote; + return; + } + } +} + +static bool pending_conn_del(struct btdev *btdev, struct btdev *remote) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(btdev->pending_conn); ++i) { + if (btdev->pending_conn[i] == remote) { + btdev->pending_conn[i] = NULL; + return true; + } + } + return false; +} + static void conn_complete(struct btdev *btdev, const uint8_t *bdaddr, uint8_t status) { struct bt_hci_evt_conn_complete cc; + struct btdev *remote = find_btdev_by_bdaddr(bdaddr); + + if (!remote) + return; if (!status) { struct btdev_conn *conn; @@ -1216,6 +1273,8 @@ static void conn_complete(struct btdev *btdev, if (!conn) return; + pending_conn_del(conn->link->dev, btdev); + cc.status = status; memcpy(cc.bdaddr, btdev->bdaddr, 6); cc.encr_mode = 0x00; @@ -1233,6 +1292,8 @@ static void conn_complete(struct btdev *btdev, cc.link_type = 0x01; } + pending_conn_del(btdev, remote); + cc.status = status; memcpy(cc.bdaddr, bdaddr, 6); cc.encr_mode = 0x00; @@ -1240,6 +1301,28 @@ static void conn_complete(struct btdev *btdev, send_event(btdev, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc)); } +struct page_timeout_data { + struct btdev *btdev; + uint8_t bdaddr[6]; + unsigned int timeout_id; +}; + +static bool page_timeout(void *user_data) +{ + struct page_timeout_data *pt_data = user_data; + struct btdev *btdev = pt_data->btdev; + const uint8_t *bdaddr = pt_data->bdaddr; + + timeout_remove(pt_data->timeout_id); + pt_data->timeout_id = 0; + + if (valid_btdev(btdev)) + conn_complete(btdev, bdaddr, BT_HCI_ERR_PAGE_TIMEOUT); + + free(pt_data); + return false; +} + static int cmd_create_conn_complete(struct btdev *dev, const void *data, uint8_t len) { @@ -1253,9 +1336,22 @@ static int cmd_create_conn_complete(struct btdev *dev, const void *data, memcpy(cr.dev_class, dev->dev_class, 3); cr.link_type = 0x01; + pending_conn_add(dev, remote); + send_event(remote, BT_HCI_EVT_CONN_REQUEST, &cr, sizeof(cr)); } else { - conn_complete(dev, cmd->bdaddr, BT_HCI_ERR_PAGE_TIMEOUT); + struct page_timeout_data *pt_data = + new0(struct page_timeout_data, 1); + + pt_data->btdev = dev; + memcpy(pt_data->bdaddr, cmd->bdaddr, 6); + + /* Send page timeout after 5.12 seconds to emulate real + * paging. + */ + pt_data->timeout_id = timeout_add(5120, + page_timeout, + pt_data, NULL); } return 0; @@ -1289,16 +1385,24 @@ static int cmd_add_sco_conn(struct btdev *dev, const void *data, uint8_t len) cc.encr_mode = 0x00; done: + pending_conn_del(dev, conn->link->dev); + send_event(dev, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc)); return 0; } +static bool match_bdaddr(const void *data, const void *match_data) +{ + const struct btdev_conn *conn = data; + const uint8_t *bdaddr = match_data; + + return !memcmp(conn->link->dev->bdaddr, bdaddr, 6); +} + static int cmd_create_conn_cancel(struct btdev *dev, const void *data, uint8_t len) { - cmd_status(dev, BT_HCI_ERR_SUCCESS, BT_HCI_CMD_CREATE_CONN_CANCEL); - return 0; } @@ -1306,8 +1410,37 @@ static int cmd_create_conn_cancel_complete(struct btdev *dev, const void *data, uint8_t len) { const struct bt_hci_cmd_create_conn_cancel *cmd = data; + struct bt_hci_rsp_create_conn_cancel rp; + struct btdev *remote = find_btdev_by_bdaddr(cmd->bdaddr); + struct btdev_conn *conn; - conn_complete(dev, cmd->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID); + /* BLUETOOTH CORE SPECIFICATION Version 5.4 | Vol 4, Part E page 1848 + * + * If the connection is already established, and the + * HCI_Connection_Complete event has been sent, then the Controller + * shall return an HCI_Command_Complete event with the error code + * Connection Already Exists (0x0B). If the HCI_Create_Connection_Cancel + * command is sent to the Controller without a preceding + * HCI_Create_Connection command to the same device, the BR/EDR + * Controller shall return an HCI_Command_Complete event with the error + * code Unknown Connection Identifier (0x02). + */ + if (pending_conn_del(dev, remote)) { + rp.status = BT_HCI_ERR_SUCCESS; + } else { + conn = queue_find(dev->conns, match_bdaddr, cmd->bdaddr); + if (conn) + rp.status = BT_HCI_ERR_CONN_ALREADY_EXISTS; + else + rp.status = BT_HCI_ERR_UNKNOWN_CONN_ID; + } + + memcpy(rp.bdaddr, cmd->bdaddr, sizeof(rp.bdaddr)); + + cmd_complete(dev, BT_HCI_CMD_CREATE_CONN_CANCEL, &rp, sizeof(rp)); + + if (!rp.status) + conn_complete(dev, cmd->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID); return 0; } @@ -1365,14 +1498,6 @@ static int cmd_link_key_reply(struct btdev *dev, const void *data, uint8_t len) return 0; } -static bool match_bdaddr(const void *data, const void *match_data) -{ - const struct btdev_conn *conn = data; - const uint8_t *bdaddr = match_data; - - return !memcmp(conn->link->dev->bdaddr, bdaddr, 6); -} - static void auth_complete(struct btdev_conn *conn, uint8_t status) { struct bt_hci_evt_auth_complete ev; @@ -2614,7 +2739,7 @@ static int cmd_enhanced_setup_sync_conn(struct btdev *dev, const void *data, if (cmd->tx_coding_format[0] > 5) status = BT_HCI_ERR_INVALID_PARAMETERS; - cmd_status(dev, status, BT_HCI_EVT_SYNC_CONN_COMPLETE); + cmd_status(dev, status, BT_HCI_CMD_ENHANCED_SETUP_SYNC_CONN); return 0; } @@ -2641,6 +2766,8 @@ static int cmd_enhanced_setup_sync_conn_complete(struct btdev *dev, goto done; } + /* TODO: HCI_Connection_Request connection flow */ + cc.status = BT_HCI_ERR_SUCCESS; memcpy(cc.bdaddr, conn->link->dev->bdaddr, 6); @@ -2660,7 +2787,7 @@ done: static int cmd_setup_sync_conn(struct btdev *dev, const void *data, uint8_t len) { - cmd_status(dev, BT_HCI_ERR_SUCCESS, BT_HCI_EVT_SYNC_CONN_COMPLETE); + cmd_status(dev, BT_HCI_ERR_SUCCESS, BT_HCI_CMD_SETUP_SYNC_CONN); return 0; } @@ -5106,9 +5233,13 @@ static int cmd_set_pa_data(struct btdev *dev, const void *data, { const struct bt_hci_cmd_le_set_pa_data *cmd = data; uint8_t status = BT_HCI_ERR_SUCCESS; + uint8_t data_len = cmd->data_len; + + if (data_len > MAX_PA_DATA_LEN) + data_len = MAX_PA_DATA_LEN; - dev->le_pa_data_len = cmd->data_len; - memcpy(dev->le_pa_data, cmd->data, 31); + dev->le_pa_data_len = data_len; + memcpy(dev->le_pa_data, cmd->data, data_len); cmd_complete(dev, BT_HCI_CMD_LE_SET_PA_DATA, &status, sizeof(status)); @@ -5154,7 +5285,7 @@ static void send_pa(struct btdev *dev, const struct btdev *remote, { struct __packed { struct bt_hci_le_pa_report ev; - uint8_t data[31]; + uint8_t data[247]; } pdu; memset(&pdu.ev, 0, sizeof(pdu.ev)); @@ -5756,6 +5887,36 @@ static int cmd_read_iso_tx_sync(struct btdev *dev, const void *data, return -ENOTSUP; } +static int find_cig(struct btdev *dev, uint8_t cig_id) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(dev->le_cig); ++i) + if (dev->le_cig[i].params.cig_id == cig_id) + return i; + return -1; +} + +static uint16_t make_cis_handle(uint8_t cig_idx, uint8_t cis_idx) +{ + /* Put CIG+CIS idxs to handle so don't need to track separately */ + return ISO_HANDLE + cig_idx*CIS_SIZE + cis_idx; +} + +static int parse_cis_handle(uint16_t handle, int *cis_idx) +{ + int cig_idx; + + if (handle < ISO_HANDLE || handle >= ISO_HANDLE + CIS_SIZE*CIG_SIZE) + return -1; + + cig_idx = (handle - ISO_HANDLE) / CIS_SIZE; + if (cis_idx) + *cis_idx = (handle - ISO_HANDLE) % CIS_SIZE; + + return cig_idx; +} + static int cmd_set_cig_params(struct btdev *dev, const void *data, uint8_t len) { @@ -5765,12 +5926,15 @@ static int cmd_set_cig_params(struct btdev *dev, const void *data, uint16_t handle[CIS_SIZE]; } __attribute__ ((packed)) rsp; int i = 0; + int cig_idx; uint32_t interval; uint16_t latency; memset(&rsp, 0, sizeof(rsp)); - if (cmd->num_cis > ARRAY_SIZE(dev->le_cig.cis)) { + rsp.params.cig_id = cmd->cig_id; + + if (cmd->num_cis > ARRAY_SIZE(dev->le_cig[0].cis)) { rsp.params.status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; goto done; } @@ -5819,39 +5983,35 @@ static int cmd_set_cig_params(struct btdev *dev, const void *data, goto done; } - if (dev->le_cig.params.cig_id != 0xff && - dev->le_cig.params.cig_id != cmd->cig_id) { - rsp.params.status = BT_HCI_ERR_INVALID_PARAMETERS; + cig_idx = find_cig(dev, cmd->cig_id); + if (cig_idx < 0) + cig_idx = find_cig(dev, 0xff); + if (cig_idx < 0) { + rsp.params.status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; goto done; } - memcpy(&dev->le_cig, data, len); + /* BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E + * page 2553 + * + * If the Host issues this command when the CIG is not in the + * configurable state, the Controller shall return the error + * code Command Disallowed (0x0C). + */ + if (dev->le_cig[cig_idx].activated) { + rsp.params.status = BT_HCI_ERR_COMMAND_DISALLOWED; + goto done; + } rsp.params.status = BT_HCI_ERR_SUCCESS; - rsp.params.cig_id = cmd->cig_id; for (i = 0; i < cmd->num_cis; i++) { - struct btdev_conn *iso; - rsp.params.num_handles++; - rsp.handle[i] = cpu_to_le16(ISO_HANDLE + i); - - /* BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E - * page 2553 - * - * If the Host issues this command when the CIG is not in the - * configurable state, the Controller shall return the error - * code Command Disallowed (0x0C). - */ - iso = queue_find(dev->conns, match_handle, - UINT_TO_PTR(cpu_to_le16(rsp.handle[i]))); - if (iso) { - rsp.params.status = BT_HCI_ERR_INVALID_PARAMETERS; - i = 0; - goto done; - } + rsp.handle[i] = cpu_to_le16(make_cis_handle(cig_idx, i)); } + memcpy(&dev->le_cig[cig_idx], data, len); + done: cmd_complete(dev, BT_HCI_CMD_LE_SET_CIG_PARAMS, &rsp, sizeof(rsp.params) + (i * sizeof(uint16_t))); @@ -5868,43 +6028,106 @@ static int cmd_set_cig_params_test(struct btdev *dev, const void *data, static int cmd_create_cis(struct btdev *dev, const void *data, uint8_t len) { + const struct bt_hci_cmd_le_create_cis *cmd = data; + int i, j; + + for (i = 0; i < cmd->num_cis; i++) { + const struct bt_hci_cis *cis = &cmd->cis[i]; + struct btdev_conn *acl; + struct btdev_conn *iso; + int cig_idx, cis_idx; + + /* Check for errors (Core v5.3 Vol 4 Part E Sec. 7.8.99) */ + for (j = 0; j < i; j++) + if (cis->cis_handle == cmd->cis[j].cis_handle) + return -EINVAL; + + cig_idx = parse_cis_handle(le16_to_cpu(cis->cis_handle), + &cis_idx); + if (cig_idx < 0) + return -ENOENT; + if (cis_idx >= dev->le_cig[cig_idx].params.num_cis) + return -ENOENT; + + acl = queue_find(dev->conns, match_handle, + UINT_TO_PTR(le16_to_cpu(cis->acl_handle))); + if (!acl) + return -ENOENT; + + iso = queue_find(dev->conns, match_handle, + UINT_TO_PTR(le16_to_cpu(cis->cis_handle))); + if (iso) + return -EEXIST; + } + cmd_status(dev, BT_HCI_ERR_SUCCESS, BT_HCI_CMD_LE_CREATE_CIS); return 0; } +static uint8_t le_cis_interval(uint8_t sdu_interval[3]) +{ + /* ISO Interval (slots of 1.25 ms) = SDU_Interval (us) */ + return get_le24(sdu_interval) / 1250; +} + +static uint32_t le_cis_latecy(uint8_t ft, uint8_t iso_interval, + uint8_t sdu_interval[3]) +{ + uint32_t latency; + uint32_t interval = get_le24(sdu_interval); + + /* Transport_Latency = FT × ISO_Interval - SDU_Interval */ + latency = ft * (iso_interval * 1250) - interval; + + return latency >= interval ? latency : interval; +} + static void le_cis_estabilished(struct btdev *dev, struct btdev_conn *conn, uint8_t status) { struct bt_hci_evt_le_cis_established evt; + int cig_idx, cis_idx = -1; memset(&evt, 0, sizeof(evt)); evt.status = status; evt.conn_handle = conn ? cpu_to_le16(conn->handle) : 0x0000; + cig_idx = conn ? parse_cis_handle(conn->link->handle, &cis_idx) : -1; + if (cig_idx < 0 && !evt.status) + evt.status = BT_HCI_ERR_UNSPECIFIED_ERROR; + if (!evt.status) { struct btdev *remote = conn->link->dev; + struct le_cig *le_cig = &remote->le_cig[cig_idx]; + + memset(evt.cig_sync_delay, 0, sizeof(evt.cig_sync_delay)); + memset(evt.cis_sync_delay, 0, sizeof(evt.cis_sync_delay)); - /* TODO: Figure out if these values makes sense */ - memcpy(evt.cig_sync_delay, remote->le_cig.params.c_interval, - sizeof(remote->le_cig.params.c_interval)); - memcpy(evt.cis_sync_delay, remote->le_cig.params.p_interval, - sizeof(remote->le_cig.params.p_interval)); - memcpy(evt.c_latency, &remote->le_cig.params.c_interval, - sizeof(remote->le_cig.params.c_interval)); - memcpy(evt.p_latency, &remote->le_cig.params.p_interval, - sizeof(remote->le_cig.params.p_interval)); - evt.c_phy = remote->le_cig.cis[0].c_phy; - evt.p_phy = remote->le_cig.cis[0].p_phy; + evt.c_phy = le_cig->cis[cis_idx].c_phy; + evt.p_phy = le_cig->cis[cis_idx].p_phy; evt.nse = 0x01; evt.c_bn = 0x01; evt.p_bn = 0x01; - evt.c_ft = 0x01; - evt.p_ft = 0x01; - evt.c_mtu = remote->le_cig.cis[0].c_sdu; - evt.p_mtu = remote->le_cig.cis[0].p_sdu; - evt.interval = remote->le_cig.params.c_latency; + evt.c_ft = 0x02; + evt.p_ft = 0x02; + evt.c_mtu = le_cig->cis[cis_idx].c_sdu; + evt.p_mtu = le_cig->cis[cis_idx].p_sdu; + evt.interval = le_cis_interval(le_cig->params.c_interval); + + /* BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 6, Part G + * page 3050: + * + * Transport_Latency_C_To_P = CIG_Sync_Delay + FT_C_To_P × + * ISO_Interval - SDU_Interval_C_To_P + * Transport_Latency_P_To_C = CIG_Sync_Delay + FT_P_To_C × + * ISO_Interval - SDU_Interval_P_To_C + */ + put_le24(le_cis_latecy(evt.c_ft, evt.interval, + le_cig->params.c_interval), evt.c_latency); + put_le24(le_cis_latecy(evt.p_ft, evt.interval, + le_cig->params.p_interval), evt.p_latency); } le_meta_event(dev, BT_HCI_EVT_LE_CIS_ESTABLISHED, &evt, sizeof(evt)); @@ -5925,9 +6148,20 @@ static int cmd_create_cis_complete(struct btdev *dev, const void *data, struct btdev_conn *acl; struct btdev_conn *iso; struct bt_hci_evt_le_cis_req evt; + struct le_cig *le_cig; + int cig_idx, cis_idx; + + cig_idx = parse_cis_handle(le16_to_cpu(cis->cis_handle), + &cis_idx); + if (cig_idx < 0) { + le_cis_estabilished(dev, NULL, + BT_HCI_ERR_UNKNOWN_CONN_ID); + break; + } + le_cig = &dev->le_cig[cig_idx]; acl = queue_find(dev->conns, match_handle, - UINT_TO_PTR(cpu_to_le16(cis->acl_handle))); + UINT_TO_PTR(le16_to_cpu(cis->acl_handle))); if (!acl) { le_cis_estabilished(dev, NULL, BT_HCI_ERR_UNKNOWN_CONN_ID); @@ -5935,9 +6169,9 @@ static int cmd_create_cis_complete(struct btdev *dev, const void *data, } iso = queue_find(dev->conns, match_handle, - UINT_TO_PTR(cpu_to_le16(cis->cis_handle))); + UINT_TO_PTR(le16_to_cpu(cis->cis_handle))); if (!iso) { - iso = conn_add_cis(acl, cpu_to_le16(cis->cis_handle)); + iso = conn_add_cis(acl, le16_to_cpu(cis->cis_handle)); if (!iso) { le_cis_estabilished(dev, NULL, BT_HCI_ERR_UNKNOWN_CONN_ID); @@ -5947,8 +6181,10 @@ static int cmd_create_cis_complete(struct btdev *dev, const void *data, evt.acl_handle = cpu_to_le16(acl->handle); evt.cis_handle = cpu_to_le16(iso->handle); - evt.cig_id = iso->dev->le_cig.params.cig_id; - evt.cis_id = iso->dev->le_cig.cis[0].cis_id; + evt.cig_id = le_cig->params.cig_id; + evt.cis_id = le_cig->cis[cis_idx].cis_id; + + le_cig->activated = true; le_meta_event(iso->link->dev, BT_HCI_EVT_LE_CIS_REQ, &evt, sizeof(evt)); @@ -5957,20 +6193,37 @@ static int cmd_create_cis_complete(struct btdev *dev, const void *data, return 0; } +static bool match_handle_cig_idx(const void *data, const void *match_data) +{ + const struct btdev_conn *conn = data; + int cig_idx = PTR_TO_INT(match_data); + + return cig_idx >= 0 && parse_cis_handle(conn->handle, NULL) == cig_idx; +} + static int cmd_remove_cig(struct btdev *dev, const void *data, uint8_t len) { const struct bt_hci_cmd_le_remove_cig *cmd = data; struct bt_hci_rsp_le_remove_cig rsp; + struct btdev_conn *conn = NULL; + int idx; - memset(&dev->le_cig, 0, sizeof(dev->le_cig)); memset(&rsp, 0, sizeof(rsp)); rsp.cig_id = cmd->cig_id; - if (dev->le_cig.params.cig_id == cmd->cig_id) + idx = find_cig(dev, cmd->cig_id); + conn = queue_find(dev->conns, match_handle_cig_idx, INT_TO_PTR(idx)); + + if (idx >= 0 && !conn) { + memset(&dev->le_cig[idx], 0, sizeof(struct le_cig)); + dev->le_cig[idx].params.cig_id = 0xff; rsp.status = BT_HCI_ERR_SUCCESS; - else + } else if (conn) { + rsp.status = BT_HCI_ERR_COMMAND_DISALLOWED; + } else { rsp.status = BT_HCI_ERR_UNKNOWN_CONN_ID; + } cmd_complete(dev, BT_HCI_CMD_LE_REMOVE_CIG, &rsp, sizeof(rsp)); @@ -6028,35 +6281,49 @@ static int cmd_create_big_complete(struct btdev *dev, const void *data, const struct bt_hci_cmd_le_create_big *cmd = data; const struct bt_hci_bis *bis = &cmd->bis; int i; + struct bt_hci_evt_le_big_complete evt; + uint16_t *bis_handle; + uint8_t *pdu; + uint8_t pdu_len; + + pdu_len = sizeof(evt) + cmd->num_bis * sizeof(*bis_handle); + + pdu = malloc(pdu_len); + if (!pdu) + return -ENOMEM; + + bis_handle = (uint16_t *)(pdu + sizeof(evt)); + + memset(&evt, 0, sizeof(evt)); for (i = 0; i < cmd->num_bis; i++) { struct btdev_conn *conn; - struct { - struct bt_hci_evt_le_big_complete evt; - uint16_t handle; - } pdu; - - memset(&pdu, 0, sizeof(pdu)); - conn = conn_add_bis(dev, ISO_HANDLE, bis); + conn = conn_add_bis(dev, ISO_HANDLE + i, bis); if (!conn) { - pdu.evt.status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; + evt.status = BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; goto done; } - pdu.evt.handle = cmd->handle; - pdu.evt.num_bis++; - pdu.evt.phy = bis->phy; - pdu.evt.max_pdu = bis->sdu; - memcpy(pdu.evt.sync_delay, bis->sdu_interval, 3); - memcpy(pdu.evt.latency, bis->sdu_interval, 3); - pdu.evt.interval = bis->latency / 1.25; - pdu.handle = cpu_to_le16(conn->handle); + *bis_handle = cpu_to_le16(conn->handle); + bis_handle++; + } + + evt.handle = cmd->handle; + evt.phy = bis->phy; + evt.max_pdu = bis->sdu; + memcpy(evt.sync_delay, bis->sdu_interval, 3); + memcpy(evt.latency, bis->sdu_interval, 3); + evt.interval = bis->latency / 1.25; + evt.num_bis = cmd->num_bis; done: - le_meta_event(dev, BT_HCI_EVT_LE_BIG_COMPLETE, &pdu, - sizeof(pdu)); - } + memcpy(pdu, &evt, sizeof(evt)); + + le_meta_event(dev, BT_HCI_EVT_LE_BIG_COMPLETE, pdu, + pdu_len); + + free(pdu); return 0; } @@ -6161,6 +6428,13 @@ static int cmd_big_create_sync_complete(struct btdev *dev, const void *data, dev->big_handle = cmd->handle; bis = conn->data; + if (bis->encryption != cmd->encryption) { + pdu.ev.status = BT_HCI_ERR_ENC_MODE_NOT_ACCEPTABLE; + le_meta_event(dev, BT_HCI_EVT_LE_BIG_SYNC_ESTABILISHED, &pdu, + sizeof(pdu.ev)); + return 0; + } + pdu.ev.handle = cmd->handle; memcpy(pdu.ev.latency, bis->sdu_interval, sizeof(pdu.ev.interval)); pdu.ev.nse = 0x01; @@ -6210,9 +6484,13 @@ static int cmd_big_term_sync(struct btdev *dev, const void *data, uint8_t len) 0x16); conn_remove(conn); + break; } done: + if (rsp.status == BT_HCI_ERR_SUCCESS) + dev->big_handle = 0xff; + cmd_complete(dev, BT_HCI_CMD_LE_BIG_TERM_SYNC, &rsp, sizeof(rsp)); return 0; @@ -6833,6 +7111,7 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id) { struct btdev *btdev; int index; + unsigned int i; btdev = malloc(sizeof(*btdev)); if (!btdev) @@ -6898,11 +7177,16 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id) btdev->acl_mtu = 192; btdev->acl_max_pkt = 1; + btdev->sco_mtu = 72; + btdev->sco_max_pkt = 1; + btdev->iso_mtu = 251; btdev->iso_max_pkt = 1; - btdev->le_cig.params.cig_id = 0xff; btdev->big_handle = 0xff; + for (i = 0; i < ARRAY_SIZE(btdev->le_cig); ++i) + btdev->le_cig[i].params.cig_id = 0xff; + btdev->country_code = 0x00; index = add_btdev(btdev); @@ -7061,6 +7345,12 @@ static const struct btdev_cmd *run_cmd(struct btdev *btdev, case -EPERM: status = BT_HCI_ERR_COMMAND_DISALLOWED; break; + case -EEXIST: + status = BT_HCI_ERR_CONN_ALREADY_EXISTS; + break; + case -ENOENT: + status = BT_HCI_ERR_UNKNOWN_CONN_ID; + break; default: status = BT_HCI_ERR_UNSPECIFIED_ERROR; break; @@ -7075,16 +7365,17 @@ static const struct btdev_cmd *vnd_cmd(struct btdev *btdev, uint8_t op, const struct btdev_cmd *cmd, const void *data, uint8_t len) { + uint8_t opcode = ((const uint8_t *)data)[0]; + for (; cmd && cmd->func; cmd++) { - if (cmd->opcode != ((uint8_t *)data)[0]) + if (cmd->opcode != opcode) continue; return run_cmd(btdev, cmd, data, len); } util_debug(btdev->debug_callback, btdev->debug_data, - "Unsupported Vendor subcommand 0x%2.2x\n", - ((uint8_t *)data)[0]); + "Unsupported Vendor subcommand 0x%2.2x", opcode); cmd_status(btdev, BT_HCI_ERR_UNKNOWN_COMMAND, op); @@ -7110,7 +7401,7 @@ static const struct btdev_cmd *default_cmd(struct btdev *btdev, uint16_t opcode, } util_debug(btdev->debug_callback, btdev->debug_data, - "Unsupported command 0x%4.4x\n", opcode); + "Unsupported command 0x%4.4x", opcode); cmd_status(btdev, BT_HCI_ERR_UNKNOWN_COMMAND, opcode); @@ -7298,7 +7589,7 @@ void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len) break; default: util_debug(btdev->debug_callback, btdev->debug_data, - "Unsupported packet 0x%2.2x\n", pkt_type); + "Unsupported packet 0x%2.2x", pkt_type); break; } } diff --git a/emulator/bthost.c b/emulator/bthost.c index b05198953506d3d7c0ee0b88f59a42a56485d5c3..95160506d0c4479101c34e5731b982e3a805b1cb 100644 --- a/emulator/bthost.c +++ b/emulator/bthost.c @@ -5,6 +5,7 @@ * * Copyright (C) 2011-2012 Intel Corporation * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org> + * Copyright 2023-2024 NXP * * */ @@ -26,6 +27,7 @@ #include "src/shared/util.h" #include "src/shared/tester.h" #include "src/shared/queue.h" +#include "src/shared/ad.h" #include "monitor/bt.h" #include "monitor/rfcomm.h" #include "bthost.h" @@ -38,6 +40,8 @@ #define acl_flags(h) (h >> 12) #define iso_flags_pb(f) (f & 0x0003) +#define iso_flags_ts(f) ((f >> 2) & 0x0001) +#define iso_flags_pack(pb, ts) (((pb) & 0x03) | (((ts) & 0x01) << 2)) #define iso_data_len_pack(h, f) ((uint16_t) ((h) | ((f) << 14))) #define L2CAP_FEAT_FIXED_CHAN 0x00000080 @@ -56,7 +60,7 @@ /* RFCOMM FCS calculation */ #define CRC(data) (rfcomm_crc_table[rfcomm_crc_table[0xff ^ data[0]] ^ data[1]]) -static unsigned char rfcomm_crc_table[256] = { +static const unsigned char rfcomm_crc_table[256] = { 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75, 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b, 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69, @@ -159,11 +163,21 @@ struct btconn { void *recv_data; }; +enum l2cap_mode { + L2CAP_MODE_OTHER, + L2CAP_MODE_LE_CRED, + L2CAP_MODE_LE_ENH_CRED, +}; + struct l2conn { + struct l2conn *next; uint16_t scid; uint16_t dcid; uint16_t psm; - struct l2conn *next; + enum l2cap_mode mode; + uint16_t data_len; + uint16_t recv_len; + void *recv_data; }; struct rcconn { @@ -181,6 +195,9 @@ struct l2cap_pending_req { struct l2cap_conn_cb_data { uint16_t psm; + uint16_t mtu; + uint16_t mps; + uint16_t credits; bthost_l2cap_connect_cb func; bthost_l2cap_disconnect_cb disconn_func; void *user_data; @@ -224,6 +241,7 @@ struct bthost { void *cmd_complete_data; bthost_new_conn_cb new_conn_cb; void *new_conn_data; + bthost_accept_conn_cb accept_iso_cb; bthost_new_conn_cb new_iso_cb; void *new_iso_data; struct rfcomm_connection_data *rfcomm_conn_data; @@ -271,6 +289,7 @@ struct bthost *bthost_create(void) static void l2conn_free(struct l2conn *conn) { + free(conn->recv_data); free(conn); } @@ -356,6 +375,7 @@ static struct l2conn *bthost_add_l2cap_conn(struct bthost *bthost, l2conn->psm = psm; l2conn->scid = scid; l2conn->dcid = dcid; + l2conn->mode = L2CAP_MODE_OTHER; l2conn->next = conn->l2conns; conn->l2conns = l2conn; @@ -411,6 +431,19 @@ static struct l2conn *btconn_find_l2cap_conn_by_scid(struct btconn *conn, return NULL; } +static struct l2conn *btconn_find_l2cap_conn_by_dcid(struct btconn *conn, + uint16_t dcid) +{ + struct l2conn *l2conn; + + for (l2conn = conn->l2conns; l2conn != NULL; l2conn = l2conn->next) { + if (l2conn->dcid == dcid) + return l2conn; + } + + return NULL; +} + static struct l2cap_conn_cb_data *bthost_find_l2cap_cb_by_psm( struct bthost *bthost, uint16_t psm) { @@ -605,14 +638,24 @@ static void send_iov(struct bthost *bthost, uint16_t handle, uint16_t cid, } static void send_acl(struct bthost *bthost, uint16_t handle, uint16_t cid, - const void *data, uint16_t len) + bool sdu_hdr, const void *data, uint16_t len) { - struct iovec iov; + struct iovec iov[2]; + uint16_t sdu; + int num = 0; + + if (sdu_hdr) { + sdu = cpu_to_le16(len); + iov[num].iov_base = &sdu; + iov[num].iov_len = sizeof(sdu); + num++; + } - iov.iov_base = (void *) data; - iov.iov_len = len; + iov[num].iov_base = (void *) data; + iov[num].iov_len = len; + num++; - send_iov(bthost, handle, cid, &iov, 1); + send_iov(bthost, handle, cid, iov, num); } static uint8_t l2cap_sig_send(struct bthost *bthost, struct btconn *conn, @@ -707,12 +750,19 @@ void bthost_send_cid(struct bthost *bthost, uint16_t handle, uint16_t cid, const void *data, uint16_t len) { struct btconn *conn; + struct l2conn *l2conn; + bool sdu_hdr = false; conn = bthost_find_conn(bthost, handle); if (!conn) return; - send_acl(bthost, handle, cid, data, len); + l2conn = btconn_find_l2cap_conn_by_dcid(conn, cid); + if (l2conn && (l2conn->mode == L2CAP_MODE_LE_CRED || + l2conn->mode == L2CAP_MODE_LE_ENH_CRED)) + sdu_hdr = true; + + send_acl(bthost, handle, cid, sdu_hdr, data, len); } void bthost_send_cid_v(struct bthost *bthost, uint16_t handle, uint16_t cid, @@ -727,42 +777,59 @@ void bthost_send_cid_v(struct bthost *bthost, uint16_t handle, uint16_t cid, send_iov(bthost, handle, cid, iov, iovcnt); } -static void send_iso(struct bthost *bthost, uint16_t handle, - const struct iovec *iov, int iovcnt) +static void send_iso(struct bthost *bthost, uint16_t handle, bool ts, + uint16_t sn, uint32_t timestamp, uint8_t pkt_status, + const struct iovec *iov, int iovcnt) { struct bt_hci_iso_hdr iso_hdr; struct bt_hci_iso_data_start data_hdr; uint8_t pkt = BT_H4_ISO_PKT; - struct iovec pdu[3 + iovcnt]; + struct iovec pdu[4 + iovcnt]; + uint16_t flags, dlen; int i, len = 0; - static uint16_t sn; for (i = 0; i < iovcnt; i++) { - pdu[3 + i].iov_base = iov[i].iov_base; - pdu[3 + i].iov_len = iov[i].iov_len; + pdu[4 + i].iov_base = iov[i].iov_base; + pdu[4 + i].iov_len = iov[i].iov_len; len += iov[i].iov_len; } pdu[0].iov_base = &pkt; pdu[0].iov_len = sizeof(pkt); - iso_hdr.handle = acl_handle_pack(handle, 0x02); - iso_hdr.dlen = cpu_to_le16(len + sizeof(data_hdr)); + flags = iso_flags_pack(0x02, ts); + dlen = len + sizeof(data_hdr); + if (ts) + dlen += sizeof(timestamp); + + iso_hdr.handle = acl_handle_pack(handle, flags); + iso_hdr.dlen = cpu_to_le16(dlen); pdu[1].iov_base = &iso_hdr; pdu[1].iov_len = sizeof(iso_hdr); - data_hdr.sn = cpu_to_le16(sn++); - data_hdr.slen = cpu_to_le16(iso_data_len_pack(len, 0)); + if (ts) { + timestamp = cpu_to_le32(timestamp); - pdu[2].iov_base = &data_hdr; - pdu[2].iov_len = sizeof(data_hdr); + pdu[2].iov_base = ×tamp; + pdu[2].iov_len = sizeof(timestamp); + } else { + pdu[2].iov_base = NULL; + pdu[2].iov_len = 0; + } - send_packet(bthost, pdu, 3 + iovcnt); + data_hdr.sn = cpu_to_le16(sn); + data_hdr.slen = cpu_to_le16(iso_data_len_pack(len, pkt_status)); + + pdu[3].iov_base = &data_hdr; + pdu[3].iov_len = sizeof(data_hdr); + + send_packet(bthost, pdu, 4 + iovcnt); } -void bthost_send_iso(struct bthost *bthost, uint16_t handle, - const struct iovec *iov, int iovcnt) +void bthost_send_iso(struct bthost *bthost, uint16_t handle, bool ts, + uint16_t sn, uint32_t timestamp, uint8_t pkt_status, + const struct iovec *iov, int iovcnt) { struct btconn *conn; @@ -770,7 +837,7 @@ void bthost_send_iso(struct bthost *bthost, uint16_t handle, if (!conn) return; - send_iso(bthost, handle, iov, iovcnt); + send_iso(bthost, handle, ts, sn, timestamp, pkt_status, iov, iovcnt); } bool bthost_l2cap_req(struct bthost *bthost, uint16_t handle, uint8_t code, @@ -1465,12 +1532,25 @@ static void evt_le_cis_req(struct bthost *bthost, const void *data, uint8_t len) { const struct bt_hci_evt_le_cis_req *ev = data; struct bt_hci_cmd_le_accept_cis cmd; + struct bt_hci_cmd_le_reject_cis rej; if (len < sizeof(*ev)) return; - memset(&cmd, 0, sizeof(cmd)); + if (bthost->accept_iso_cb) { + memset(&rej, 0, sizeof(rej)); + rej.reason = bthost->accept_iso_cb(le16_to_cpu(ev->cis_handle), + bthost->new_iso_data); + if (rej.reason) { + rej.handle = ev->cis_handle; + send_command(bthost, BT_HCI_CMD_LE_REJECT_CIS, + &rej, sizeof(rej)); + return; + } + } + + memset(&cmd, 0, sizeof(cmd)); cmd.handle = ev->cis_handle; send_command(bthost, BT_HCI_CMD_LE_ACCEPT_CIS, &cmd, sizeof(cmd)); @@ -1745,7 +1825,7 @@ static void rfcomm_sabm_send(struct bthost *bthost, struct btconn *conn, cmd.length = RFCOMM_LEN8(0); cmd.fcs = rfcomm_fcs2((uint8_t *)&cmd); - send_acl(bthost, conn->handle, l2conn->dcid, &cmd, sizeof(cmd)); + send_acl(bthost, conn->handle, l2conn->dcid, false, &cmd, sizeof(cmd)); } static bool l2cap_conn_rsp(struct bthost *bthost, struct btconn *conn, @@ -2076,6 +2156,7 @@ static bool l2cap_le_conn_req(struct bthost *bthost, struct btconn *conn, uint8_t ident, const void *data, uint16_t len) { const struct bt_l2cap_pdu_le_conn_req *req = data; + struct l2cap_conn_cb_data *cb_data; struct bt_l2cap_pdu_le_conn_rsp rsp; uint16_t psm; @@ -2086,18 +2167,32 @@ static bool l2cap_le_conn_req(struct bthost *bthost, struct btconn *conn, memset(&rsp, 0, sizeof(rsp)); - rsp.mtu = 23; - rsp.mps = 23; - rsp.credits = 1; - - if (bthost_find_l2cap_cb_by_psm(bthost, psm)) + cb_data = bthost_find_l2cap_cb_by_psm(bthost, psm); + if (cb_data) { rsp.dcid = cpu_to_le16(conn->next_cid++); - else + rsp.mtu = cpu_to_le16(cb_data->mtu) ? : cpu_to_le16(23); + rsp.mps = cpu_to_le16(cb_data->mps) ? : cpu_to_le16(23); + rsp.credits = cpu_to_le16(cb_data->credits) ? : cpu_to_le16(1); + } else rsp.result = cpu_to_le16(0x0002); /* PSM Not Supported */ l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_LE_CONN_RSP, ident, &rsp, sizeof(rsp)); + if (!rsp.result) { + struct l2conn *l2conn; + + l2conn = bthost_add_l2cap_conn(bthost, conn, + le16_to_cpu(rsp.dcid), + le16_to_cpu(req->scid), + le16_to_cpu(psm)); + l2conn->mode = L2CAP_MODE_LE_CRED; + + if (cb_data && l2conn->psm == cb_data->psm && cb_data->func) + cb_data->func(conn->handle, l2conn->dcid, + cb_data->user_data); + } + return true; } @@ -2105,11 +2200,14 @@ static bool l2cap_le_conn_rsp(struct bthost *bthost, struct btconn *conn, uint8_t ident, const void *data, uint16_t len) { const struct bt_l2cap_pdu_le_conn_rsp *rsp = data; + struct l2conn *l2conn; if (len < sizeof(*rsp)) return false; /* TODO add L2CAP connection before with proper PSM */ - bthost_add_l2cap_conn(bthost, conn, 0, le16_to_cpu(rsp->dcid), 0); + l2conn = bthost_add_l2cap_conn(bthost, conn, 0, + le16_to_cpu(rsp->dcid), 0); + l2conn->mode = L2CAP_MODE_LE_CRED; return true; } @@ -2162,16 +2260,19 @@ static bool l2cap_ecred_conn_rsp(struct bthost *bthost, struct btconn *conn, uint16_t scid[5]; } __attribute__ ((packed)) *rsp = data; int num_scid, i; + struct l2conn *l2conn; if (len < sizeof(*rsp)) return false; num_scid = len / sizeof(*rsp->scid); - for (i = 0; i < num_scid; i++) + for (i = 0; i < num_scid; i++) { /* TODO add L2CAP connection before with proper PSM */ - bthost_add_l2cap_conn(bthost, conn, 0, + l2conn = bthost_add_l2cap_conn(bthost, conn, 0, le16_to_cpu(rsp->scid[i]), 0); + l2conn->mode = L2CAP_MODE_LE_ENH_CRED; + } return true; @@ -2299,7 +2400,7 @@ static void rfcomm_ua_send(struct bthost *bthost, struct btconn *conn, cmd.length = RFCOMM_LEN8(0); cmd.fcs = rfcomm_fcs2((uint8_t *)&cmd); - send_acl(bthost, conn->handle, l2conn->dcid, &cmd, sizeof(cmd)); + send_acl(bthost, conn->handle, l2conn->dcid, false, &cmd, sizeof(cmd)); } static void rfcomm_dm_send(struct bthost *bthost, struct btconn *conn, @@ -2313,7 +2414,7 @@ static void rfcomm_dm_send(struct bthost *bthost, struct btconn *conn, cmd.length = RFCOMM_LEN8(0); cmd.fcs = rfcomm_fcs2((uint8_t *)&cmd); - send_acl(bthost, conn->handle, l2conn->dcid, &cmd, sizeof(cmd)); + send_acl(bthost, conn->handle, l2conn->dcid, false, &cmd, sizeof(cmd)); } static void rfcomm_sabm_recv(struct bthost *bthost, struct btconn *conn, @@ -2602,12 +2703,97 @@ static void process_rfcomm(struct bthost *bthost, struct btconn *conn, } } +static void append_l2conn_data(struct bthost *bthost, struct l2conn *conn, + const void *data, uint16_t len) +{ + if (!conn->recv_data) { + bthost_debug(bthost, "Unexpected L2CAP SDU data: sCID 0x%4.4x ", + conn->scid); + return; + } + + if (conn->recv_len + len > conn->data_len) { + bthost_debug(bthost, "Unexpected L2CAP SDU data: sCID 0x%4.4x ", + conn->scid); + return; + } + + memcpy(conn->recv_data + conn->recv_len, data, len); + conn->recv_len += len; + + bthost_debug(bthost, "L2CAP SDU data: %u/%u bytes", conn->recv_len, + conn->data_len); +} + +static void free_l2conn_data(struct l2conn *conn) +{ + free(conn->recv_data); + conn->recv_data = NULL; + conn->recv_len = 0; + conn->data_len = 0; +} + +static void new_l2conn_data(struct bthost *bthost, struct l2conn *conn, + uint16_t len) +{ + free(conn->recv_data); + conn->recv_data = malloc(len); + conn->recv_len = 0; + conn->data_len = len; +} + +static bool process_l2cap_conn(struct bthost *bthost, struct btconn *conn, + struct l2conn *l2conn, struct iovec *data) +{ + struct bt_l2cap_pdu_le_flowctl_creds creds; + uint16_t sdu; + + if (!l2conn) + return true; + + switch (l2conn->mode) { + case L2CAP_MODE_LE_CRED: + case L2CAP_MODE_LE_ENH_CRED: + break; + case L2CAP_MODE_OTHER: + return true; + } + + /* Credit-based flow control */ + + creds.cid = cpu_to_le16(l2conn->scid); + creds.credits = cpu_to_le16(1); + l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_LE_FLOWCTL_CREDS, 0, + &creds, sizeof(creds)); + + if (!l2conn->data_len) { + if (!util_iov_pull_le16(data, &sdu)) { + free_l2conn_data(l2conn); + bthost_debug(bthost, "L2CAP invalid SDU"); + return false; + } + new_l2conn_data(bthost, l2conn, sdu); + } + + append_l2conn_data(bthost, l2conn, data->iov_base, data->iov_len); + + if (l2conn->recv_len < l2conn->data_len) + return false; /* SDU incomplete */ + + l2conn->data_len = 0; + data->iov_base = l2conn->recv_data; + data->iov_len = l2conn->recv_len; + + return true; +} + static void process_l2cap(struct bthost *bthost, struct btconn *conn, - const void *data, uint16_t len) + const void *buf, uint16_t len) { - const struct bt_l2cap_hdr *l2_hdr = data; + const struct bt_l2cap_hdr *l2_hdr = buf; struct cid_hook *hook; struct l2conn *l2conn; + struct iovec data; uint16_t cid, l2_len; l2_len = le16_to_cpu(l2_hdr->len); @@ -2620,31 +2806,37 @@ static void process_l2cap(struct bthost *bthost, struct btconn *conn, bthost_debug(bthost, "L2CAP data: %u bytes", l2_len); cid = le16_to_cpu(l2_hdr->cid); + l2conn = btconn_find_l2cap_conn_by_scid(conn, cid); + + data.iov_base = (void *)l2_hdr->data; + data.iov_len = l2_len; + + if (!process_l2cap_conn(bthost, conn, l2conn, &data)) + return; hook = find_cid_hook(conn, cid); if (hook) { - hook->func(l2_hdr->data, l2_len, hook->user_data); + hook->func(data.iov_base, data.iov_len, hook->user_data); return; } switch (cid) { case 0x0001: - l2cap_sig(bthost, conn, l2_hdr->data, l2_len); + l2cap_sig(bthost, conn, data.iov_base, data.iov_len); break; case 0x0005: - l2cap_le_sig(bthost, conn, l2_hdr->data, l2_len); + l2cap_le_sig(bthost, conn, data.iov_base, data.iov_len); break; case 0x0006: - smp_data(conn->smp_data, l2_hdr->data, l2_len); + smp_data(conn->smp_data, data.iov_base, data.iov_len); break; case 0x0007: - smp_bredr_data(conn->smp_data, l2_hdr->data, l2_len); + smp_bredr_data(conn->smp_data, data.iov_base, data.iov_len); break; default: - l2conn = btconn_find_l2cap_conn_by_scid(conn, cid); if (l2conn && l2conn->psm == 0x0003) - process_rfcomm(bthost, conn, l2conn, l2_hdr->data, - l2_len); + process_rfcomm(bthost, conn, l2conn, data.iov_base, + data.iov_len); else bthost_debug(bthost, "Packet for unknown CID 0x%04x (%u)", @@ -2893,9 +3085,10 @@ void bthost_set_connect_cb(struct bthost *bthost, bthost_new_conn_cb cb, bthost->new_conn_data = user_data; } -void bthost_set_iso_cb(struct bthost *bthost, bthost_new_conn_cb cb, - void *user_data) +void bthost_set_iso_cb(struct bthost *bthost, bthost_accept_conn_cb accept, + bthost_new_conn_cb cb, void *user_data) { + bthost->accept_iso_cb = accept; bthost->new_iso_cb = cb; bthost->new_iso_data = user_data; } @@ -3092,6 +3285,73 @@ void bthost_set_pa_params(struct bthost *bthost) send_command(bthost, BT_HCI_CMD_LE_SET_PA_PARAMS, &cp, sizeof(cp)); } +static void set_pa_data(struct bthost *bthost, const uint8_t *data, + uint8_t len, uint8_t offset) +{ + struct bt_hci_cmd_le_set_pa_data *cp; + uint8_t buf[sizeof(*cp) + BT_PA_MAX_DATA_LEN]; + size_t data_len; + + cp = (void *)buf; + + memset(cp, 0, sizeof(*cp)); + memset(cp->data, 0, BT_PA_MAX_DATA_LEN); + + cp->handle = 1; + + if (len - offset > BT_PA_MAX_DATA_LEN) { + data_len = BT_PA_MAX_DATA_LEN; + + if (!offset) + cp->operation = 0x01; + else + cp->operation = 0x00; + } else { + data_len = len - offset; + + if (!offset) + cp->operation = 0x03; + else + cp->operation = 0x02; + } + + memcpy(cp->data, data + offset, data_len); + cp->data_len = data_len; + + send_command(bthost, BT_HCI_CMD_LE_SET_PA_DATA, buf, + sizeof(*cp) + cp->data_len); + + if (cp->operation == 0x01 || cp->operation == 0x00) { + offset += cp->data_len; + set_pa_data(bthost, data, len, offset); + } +} + +void bthost_set_pa_data(struct bthost *bthost, const uint8_t *data, + uint8_t len) +{ + set_pa_data(bthost, data, len, 0); +} + +void bthost_set_base(struct bthost *bthost, const uint8_t *data, uint8_t len) +{ + struct bt_ad *ad; + bt_uuid_t uuid; + uint8_t *pa_data; + size_t pa_len; + + bt_uuid16_create(&uuid, BAA_SERVICE); + + ad = bt_ad_new(); + bt_ad_set_max_len(ad, BT_PA_MAX_DATA_LEN); + bt_ad_add_service_data(ad, &uuid, (void *)data, len); + + pa_data = bt_ad_generate(ad, &pa_len); + bthost_set_pa_data(bthost, pa_data, pa_len); + + bt_ad_unref(ad); +} + void bthost_set_pa_enable(struct bthost *bthost, uint8_t enable) { struct bt_hci_cmd_le_set_pa_enable cp; @@ -3102,7 +3362,8 @@ void bthost_set_pa_enable(struct bthost *bthost, uint8_t enable) send_command(bthost, BT_HCI_CMD_LE_SET_PA_ENABLE, &cp, sizeof(cp)); } -void bthost_create_big(struct bthost *bthost, uint8_t num_bis) +void bthost_create_big(struct bthost *bthost, uint8_t num_bis, + uint8_t enc, const uint8_t *bcode) { struct bt_hci_cmd_le_create_big cp; @@ -3115,6 +3376,8 @@ void bthost_create_big(struct bthost *bthost, uint8_t num_bis) cp.bis.latency = cpu_to_le16(10); cp.bis.rtn = 0x02; cp.bis.phy = 0x02; + cp.bis.encryption = enc; + memcpy(cp.bis.bcode, bcode, sizeof(cp.bis.bcode)); send_command(bthost, BT_HCI_CMD_LE_CREATE_BIG, &cp, sizeof(cp)); } @@ -3144,22 +3407,24 @@ void bthost_set_cig_params(struct bthost *bthost, uint8_t cig_id, cp = malloc(sizeof(*cp) + sizeof(*cp->cis)); memset(cp, 0, sizeof(*cp) + sizeof(*cp->cis)); cp->cig_id = cig_id; - put_le24(qos->in.interval ? qos->in.interval : qos->out.interval, - cp->c_interval); - put_le24(qos->out.interval ? qos->out.interval : qos->in.interval, - cp->p_interval); - cp->c_latency = cpu_to_le16(qos->in.latency ? qos->in.latency : - qos->out.latency); - cp->p_latency = cpu_to_le16(qos->out.latency ? qos->out.latency : - qos->in.latency); + put_le24(qos->ucast.in.interval ? qos->ucast.in.interval : + qos->ucast.out.interval, cp->c_interval); + put_le24(qos->ucast.out.interval ? qos->ucast.out.interval : + qos->ucast.in.interval, cp->p_interval); + cp->c_latency = cpu_to_le16(qos->ucast.in.latency ? + qos->ucast.in.latency : qos->ucast.out.latency); + cp->p_latency = cpu_to_le16(qos->ucast.out.latency ? + qos->ucast.out.latency : qos->ucast.in.latency); cp->num_cis = 0x01; cp->cis[0].cis_id = cis_id; - cp->cis[0].c_sdu = qos->in.sdu; - cp->cis[0].p_sdu = qos->out.sdu; - cp->cis[0].c_phy = qos->in.phy ? qos->in.phy : qos->out.phy; - cp->cis[0].p_phy = qos->out.phy ? qos->out.phy : qos->in.phy; - cp->cis[0].c_rtn = qos->in.rtn; - cp->cis[0].p_rtn = qos->out.rtn; + cp->cis[0].c_sdu = qos->ucast.in.sdu; + cp->cis[0].p_sdu = qos->ucast.out.sdu; + cp->cis[0].c_phy = qos->ucast.in.phy ? qos->ucast.in.phy : + qos->ucast.out.phy; + cp->cis[0].p_phy = qos->ucast.out.phy ? qos->ucast.out.phy : + qos->ucast.in.phy; + cp->cis[0].c_rtn = qos->ucast.in.rtn; + cp->cis[0].p_rtn = qos->ucast.out.rtn; send_command(bthost, BT_HCI_CMD_LE_SET_CIG_PARAMS, cp, sizeof(*cp) + sizeof(*cp->cis)); @@ -3250,7 +3515,8 @@ uint64_t bthost_conn_get_fixed_chan(struct bthost *bthost, uint16_t handle) return conn->fixed_chan; } -void bthost_add_l2cap_server(struct bthost *bthost, uint16_t psm, +void bthost_add_l2cap_server_custom(struct bthost *bthost, uint16_t psm, + uint16_t mtu, uint16_t mps, uint16_t credits, bthost_l2cap_connect_cb func, bthost_l2cap_disconnect_cb disconn_func, void *user_data) @@ -3262,6 +3528,9 @@ void bthost_add_l2cap_server(struct bthost *bthost, uint16_t psm, return; data->psm = psm; + data->mtu = mtu; + data->mps = mps; + data->credits = credits; data->user_data = user_data; data->func = func; data->disconn_func = disconn_func; @@ -3270,6 +3539,15 @@ void bthost_add_l2cap_server(struct bthost *bthost, uint16_t psm, bthost->new_l2cap_conn_data = data; } +void bthost_add_l2cap_server(struct bthost *bthost, uint16_t psm, + bthost_l2cap_connect_cb func, + bthost_l2cap_disconnect_cb disconn_func, + void *user_data) +{ + bthost_add_l2cap_server_custom(bthost, psm, 0, 0, 0, func, + disconn_func, user_data); +} + void bthost_set_sc_support(struct bthost *bthost, bool enable) { struct bt_hci_cmd_write_secure_conn_support cmd; @@ -3454,7 +3732,7 @@ void bthost_send_rfcomm_data(struct bthost *bthost, uint16_t handle, } uih_frame[uih_len - 1] = rfcomm_fcs((void *)hdr); - send_acl(bthost, handle, rcconn->scid, uih_frame, uih_len); + send_acl(bthost, handle, rcconn->scid, false, uih_frame, uih_len); free(uih_frame); } diff --git a/emulator/bthost.h b/emulator/bthost.h index 2cfdef766e4d57579a65661df614553f407a3c06..2c5b0d5164cc33140a69bacab03828b29544b604 100644 --- a/emulator/bthost.h +++ b/emulator/bthost.h @@ -5,6 +5,7 @@ * * Copyright (C) 2011-2012 Intel Corporation * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org> + * Copyright 2023-2024 NXP * * */ @@ -44,13 +45,14 @@ typedef void (*bthost_cmd_complete_cb) (uint16_t opcode, uint8_t status, void bthost_set_cmd_complete_cb(struct bthost *bthost, bthost_cmd_complete_cb cb, void *user_data); +typedef uint8_t (*bthost_accept_conn_cb) (uint16_t handle, void *user_data); typedef void (*bthost_new_conn_cb) (uint16_t handle, void *user_data); void bthost_set_connect_cb(struct bthost *bthost, bthost_new_conn_cb cb, void *user_data); -void bthost_set_iso_cb(struct bthost *bthost, bthost_new_conn_cb cb, - void *user_data); +void bthost_set_iso_cb(struct bthost *bthost, bthost_accept_conn_cb accept, + bthost_new_conn_cb cb, void *user_data); void bthost_hci_connect(struct bthost *bthost, const uint8_t *bdaddr, uint8_t addr_type); @@ -78,8 +80,9 @@ void bthost_send_cid(struct bthost *bthost, uint16_t handle, uint16_t cid, const void *data, uint16_t len); void bthost_send_cid_v(struct bthost *bthost, uint16_t handle, uint16_t cid, const struct iovec *iov, int iovcnt); -void bthost_send_iso(struct bthost *bthost, uint16_t handle, - const struct iovec *iov, int iovcnt); +void bthost_send_iso(struct bthost *bthost, uint16_t handle, bool ts, + uint16_t sn, uint32_t timestamp, uint8_t pkt_status, + const struct iovec *iov, int iovcnt); typedef void (*bthost_l2cap_rsp_cb) (uint8_t code, const void *data, uint16_t len, void *user_data); @@ -99,8 +102,12 @@ void bthost_set_ext_adv_data(struct bthost *bthost, const uint8_t *data, void bthost_set_ext_adv_params(struct bthost *bthost); void bthost_set_ext_adv_enable(struct bthost *bthost, uint8_t enable); void bthost_set_pa_params(struct bthost *bthost); +void bthost_set_pa_data(struct bthost *bthost, const uint8_t *data, + uint8_t len); +void bthost_set_base(struct bthost *bthost, const uint8_t *data, uint8_t len); void bthost_set_pa_enable(struct bthost *bthost, uint8_t enable); -void bthost_create_big(struct bthost *bthost, uint8_t num_bis); +void bthost_create_big(struct bthost *bthost, uint8_t num_bis, uint8_t enc, + const uint8_t *bcode); bool bthost_search_ext_adv_addr(struct bthost *bthost, const uint8_t *addr); void bthost_set_cig_params(struct bthost *bthost, uint8_t cig_id, @@ -129,6 +136,11 @@ void bthost_add_l2cap_server(struct bthost *bthost, uint16_t psm, bthost_l2cap_connect_cb func, bthost_l2cap_disconnect_cb disconn_func, void *user_data); +void bthost_add_l2cap_server_custom(struct bthost *bthost, uint16_t psm, + uint16_t mtu, uint16_t mps, uint16_t credits, + bthost_l2cap_connect_cb func, + bthost_l2cap_disconnect_cb disconn_func, + void *user_data); void bthost_set_sc_support(struct bthost *bthost, bool enable); diff --git a/emulator/hciemu.c b/emulator/hciemu.c index dcfed9be77331d8ec69a285d58ddb722e81a495f..f13b4bda1e926a2e55b5415dda62fe72e0c406cb 100644 --- a/emulator/hciemu.c +++ b/emulator/hciemu.c @@ -21,6 +21,7 @@ #include <stdbool.h> #include <errno.h> #include <sys/socket.h> +#include <sys/ioctl.h> #include <glib.h> @@ -41,6 +42,7 @@ struct hciemu_client { guint start_source; guint host_source; guint source; + int sock[2]; }; struct hciemu { @@ -54,6 +56,8 @@ struct hciemu { hciemu_debug_func_t debug_callback; hciemu_destroy_func_t debug_destroy; void *debug_data; + + unsigned int flush_id; }; struct hciemu_command_hook { @@ -186,14 +190,7 @@ static gboolean receive_btdev(GIOChannel *channel, GIOCondition condition, if (len < 1) return FALSE; - switch (buf[0]) { - case BT_H4_CMD_PKT: - case BT_H4_ACL_PKT: - case BT_H4_SCO_PKT: - case BT_H4_ISO_PKT: - btdev_receive_h4(btdev, buf, len); - break; - } + btdev_receive_h4(btdev, buf, len); return TRUE; } @@ -338,6 +335,9 @@ static struct hciemu_client *hciemu_client_new(struct hciemu *hciemu, return NULL; } + client->sock[0] = sv[0]; + client->sock[1] = sv[1]; + client->source = create_source_btdev(sv[0], client->dev); client->host_source = create_source_bthost(sv[1], client->host); client->start_source = g_idle_add(start_host, client); @@ -435,6 +435,9 @@ void hciemu_unref(struct hciemu *hciemu) queue_destroy(hciemu->post_command_hooks, destroy_command_hook); queue_destroy(hciemu->clients, hciemu_client_destroy); + if (hciemu->flush_id) + g_source_remove(hciemu->flush_id); + vhci_close(hciemu->vhci); free(hciemu); @@ -547,6 +550,15 @@ const uint8_t *hciemu_client_bdaddr(struct hciemu_client *client) return btdev_get_bdaddr(client->dev); } +bool hciemu_set_client_bdaddr(struct hciemu_client *client, + const uint8_t *bdaddr) +{ + if (!client) + return NULL; + + return btdev_set_bdaddr(client->dev, bdaddr); +} + const uint8_t *hciemu_get_client_bdaddr(struct hciemu *hciemu) { struct hciemu_client *client; @@ -744,3 +756,47 @@ bool hciemu_del_hook(struct hciemu *hciemu, enum hciemu_hook_type type, return btdev_del_hook(dev, hook_type, opcode); } + +static bool client_is_pending(const void *data, const void *match_data) +{ + struct hciemu_client *client = (struct hciemu_client *)data; + int used, i; + + if (!client->source || !client->host_source) + return false; + + for (i = 0; i < 2; ++i) { + if (!ioctl(client->sock[i], TIOCOUTQ, &used) && used > 0) + return true; + if (!ioctl(client->sock[i], TIOCINQ, &used) && used > 0) + return true; + } + + return false; +} + +static gboolean flush_client_events(gpointer user_data) +{ + struct hciemu *hciemu = user_data; + + if (queue_find(hciemu->clients, client_is_pending, NULL)) + return TRUE; + + hciemu->flush_id = 0; + + util_debug(hciemu->debug_callback, hciemu->debug_data, "vhci: resume"); + if (hciemu->vhci) + vhci_pause_input(hciemu->vhci, false); + + return FALSE; +} + +void hciemu_flush_client_events(struct hciemu *hciemu) +{ + if (hciemu->flush_id || !hciemu->vhci) + return; + + util_debug(hciemu->debug_callback, hciemu->debug_data, "vhci: pause"); + vhci_pause_input(hciemu->vhci, true); + hciemu->flush_id = g_idle_add(flush_client_events, hciemu); +} diff --git a/emulator/hciemu.h b/emulator/hciemu.h index 3a06ca57800d9cc148da5da0f0c9aebab39a2647..dba920fdd7715d7f4139af52322be08868c65526 100644 --- a/emulator/hciemu.h +++ b/emulator/hciemu.h @@ -39,6 +39,8 @@ void hciemu_unref(struct hciemu *hciemu); struct hciemu_client *hciemu_get_client(struct hciemu *hciemu, int num); struct bthost *hciemu_client_host(struct hciemu_client *client); const uint8_t *hciemu_client_bdaddr(struct hciemu_client *client); +bool hciemu_set_client_bdaddr(struct hciemu_client *client, + const uint8_t *bdaddr); typedef void (*hciemu_debug_func_t)(const char *str, void *user_data); typedef void (*hciemu_destroy_func_t)(void *user_data); @@ -48,6 +50,9 @@ bool hciemu_set_debug(struct hciemu *hciemu, hciemu_debug_func_t callback, struct vhci *hciemu_get_vhci(struct hciemu *hciemu); struct bthost *hciemu_client_get_host(struct hciemu *hciemu); +/* Process pending client events before new VHCI events */ +void hciemu_flush_client_events(struct hciemu *hciemu); + const char *hciemu_get_address(struct hciemu *hciemu); uint8_t *hciemu_get_features(struct hciemu *hciemu); diff --git a/emulator/serial.c b/emulator/serial.c index c9e6d7cd67c843c7d0a12fee66df614d8d1806e6..b74556b135473faf3d546c35f752cb9c43a25b04 100644 --- a/emulator/serial.c +++ b/emulator/serial.c @@ -21,6 +21,7 @@ #include <stdlib.h> #include <string.h> #include <fcntl.h> +#include <limits.h> #include <sys/param.h> #include <sys/epoll.h> #include <sys/uio.h> diff --git a/emulator/vhci.c b/emulator/vhci.c index a12b11e0f30576bdd4af2403c22f9bc376f4fe75..cab35354549ebeee7f277e6466645ae74f63d9be 100644 --- a/emulator/vhci.c +++ b/emulator/vhci.c @@ -22,6 +22,8 @@ #include <sys/uio.h> #include <fcntl.h> #include <unistd.h> +#include <dirent.h> +#include <limits.h> #include "lib/bluetooth.h" #include "lib/hci.h" @@ -32,6 +34,7 @@ #include "vhci.h" #define DEBUGFS_PATH "/sys/kernel/debug/bluetooth" +#define DEVCORE_PATH "/sys/class/devcoredump" struct vhci { enum btdev_type type; @@ -72,14 +75,7 @@ static bool vhci_read_callback(struct io *io, void *user_data) if (len < 1) return false; - switch (buf[0]) { - case BT_H4_CMD_PKT: - case BT_H4_ACL_PKT: - case BT_H4_SCO_PKT: - case BT_H4_ISO_PKT: - btdev_receive_h4(vhci->btdev, buf, len); - break; - } + btdev_receive_h4(vhci->btdev, buf, len); return true; } @@ -127,14 +123,16 @@ struct vhci *vhci_open(uint8_t type) break; } - if (write(fd, &req, sizeof(req)) < 0) { + if (write(fd, &req, sizeof(req)) != sizeof(req)) { close(fd); return NULL; } memset(&rsp, 0, sizeof(rsp)); - if (read(fd, &rsp, sizeof(rsp)) < 0) { + if (read(fd, &rsp, sizeof(rsp)) != sizeof(rsp) || + rsp.pkt_type != HCI_VENDOR_PKT || + rsp.opcode != req.opcode) { close(fd); return NULL; } @@ -176,6 +174,15 @@ void vhci_close(struct vhci *vhci) vhci_destroy(vhci); } +bool vhci_pause_input(struct vhci *vhci, bool paused) +{ + if (paused) + return io_set_read_handler(vhci->io, NULL, NULL, NULL); + else + return io_set_read_handler(vhci->io, vhci_read_callback, vhci, + NULL); +} + struct btdev *vhci_get_btdev(struct vhci *vhci) { if (!vhci) @@ -184,7 +191,7 @@ struct btdev *vhci_get_btdev(struct vhci *vhci) return vhci->btdev; } -static int vhci_debugfs_write(struct vhci *vhci, char *option, void *data, +static int vhci_debugfs_write(struct vhci *vhci, char *option, const void *data, size_t len) { char path[64]; @@ -267,3 +274,60 @@ int vhci_set_force_static_address(struct vhci *vhci, bool enable) return vhci_debugfs_write(vhci, "force_static_address", &val, sizeof(val)); } + +int vhci_force_devcd(struct vhci *vhci, const void *data, size_t len) +{ + return vhci_debugfs_write(vhci, "force_devcoredump", data, len); +} + +int vhci_read_devcd(struct vhci *vhci, void *buf, size_t size) +{ + DIR *dir; + struct dirent *entry; + char filename[PATH_MAX]; + int fd; + int ret; + + dir = opendir(DEVCORE_PATH); + if (dir == NULL) + return -errno; + + while ((entry = readdir(dir)) != NULL) { + if (strstr(entry->d_name, "devcd")) + break; + } + + if (entry == NULL) { + ret = -ENOENT; + goto close_dir; + } + + sprintf(filename, DEVCORE_PATH "/%s/data", entry->d_name); + fd = open(filename, O_RDWR); + if (fd < 0) { + ret = -errno; + goto close_dir; + } + + ret = read(fd, buf, size); + if (ret < 0) { + ret = -errno; + goto close_file; + } + + /* Once the devcoredump is read, write anything to it to mark it for + * cleanup. + */ + if (write(fd, "0", 1) < 0) { + ret = -errno; + goto close_file; + } + +close_file: + close(fd); + +close_dir: + closedir(dir); + + return ret; +} diff --git a/emulator/vhci.h b/emulator/vhci.h index 6da56cb589fe5d1db61c98723215b4234f576de1..12c4b55a0c11fd229c88294575aa4a8d31ecb3ea 100644 --- a/emulator/vhci.h +++ b/emulator/vhci.h @@ -29,3 +29,6 @@ int vhci_set_msft_opcode(struct vhci *vhci, uint16_t opcode); int vhci_set_aosp_capable(struct vhci *vhci, bool enable); int vhci_set_emu_opcode(struct vhci *vhci, uint16_t opcode); int vhci_set_force_static_address(struct vhci *vhci, bool enable); +int vhci_force_devcd(struct vhci *vhci, const void *data, size_t len); +int vhci_read_devcd(struct vhci *vhci, void *buf, size_t size); +bool vhci_pause_input(struct vhci *vhci, bool paused); diff --git a/gdbus/client.c b/gdbus/client.c index 3b7faa4e434c015e850c688509467675103c17f1..deeb01dabffdd8b0c366bdd805234ce199200ba0 100644 --- a/gdbus/client.c +++ b/gdbus/client.c @@ -4,6 +4,7 @@ * D-Bus helper library * * Copyright (C) 2004-2011 Marcel Holtmann <marcel@holtmann.org> + * Copyright 2024 NXP * * */ @@ -15,6 +16,7 @@ #define _GNU_SOURCE #include <stdio.h> #include <string.h> +#include <stdarg.h> #include <glib.h> #include <dbus/dbus.h> @@ -208,6 +210,44 @@ void g_dbus_dict_append_array(DBusMessageIter *dict, n_elements); } +static void append_dict_variant(DBusMessageIter *iter, char *entry, int type, + void *val, ...) +{ + DBusMessageIter variant, dict; + va_list args; + int array_type, size; + + dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &variant); + + dbus_message_iter_open_container(&variant, 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); + + va_start(args, val); + + if (type == DBUS_TYPE_ARRAY) { + array_type = va_arg(args, int); + size = va_arg(args, int); + g_dbus_dict_append_array(&dict, entry, array_type, val, size); + } else + g_dbus_dict_append_entry(&dict, entry, type, val); + + va_end(args); + + dbus_message_iter_close_container(&variant, &dict); + + dbus_message_iter_close_container(iter, &variant); +} + static void iter_append_iter(DBusMessageIter *base, DBusMessageIter *iter) { int type; @@ -885,6 +925,81 @@ gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy, return TRUE; } +gboolean g_dbus_proxy_set_property_dict(GDBusProxy *proxy, + const char *name, GDBusResultFunction function, + void *user_data, GDBusDestroyFunction destroy, + char *entry, ...) +{ + struct set_property_data *data; + GDBusClient *client; + DBusMessage *msg; + DBusMessageIter iter; + DBusPendingCall *call; + va_list args; + int type, array_type, size; + void *value; + + if (proxy == NULL || name == NULL) + return FALSE; + + client = proxy->client; + if (client == NULL) + return FALSE; + + data = g_try_new0(struct set_property_data, 1); + if (data == NULL) + return FALSE; + + data->function = function; + data->user_data = user_data; + data->destroy = destroy; + + msg = dbus_message_new_method_call(client->service_name, + proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Set"); + if (msg == NULL) { + g_free(data); + return FALSE; + } + + dbus_message_iter_init_append(msg, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, + &proxy->interface); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name); + + va_start(args, entry); + + while (entry != NULL) { + type = va_arg(args, int); + if (type == DBUS_TYPE_ARRAY) { + array_type = va_arg(args, int); + size = va_arg(args, int); + value = va_arg(args, void *); + append_dict_variant(&iter, entry, type, &value, + array_type, size); + } else { + value = va_arg(args, void *); + append_dict_variant(&iter, entry, type, &value); + } + entry = va_arg(args, char *); + } + + va_end(args); + + if (g_dbus_send_message_with_reply(client->dbus_conn, msg, + &call, -1) == FALSE) { + dbus_message_unref(msg); + g_free(data); + return FALSE; + } + + dbus_pending_call_set_notify(call, set_property_reply, data, g_free); + dbus_pending_call_unref(call); + + dbus_message_unref(msg); + + return TRUE; +} + gboolean g_dbus_proxy_set_property_array(GDBusProxy *proxy, const char *name, int type, const void *value, size_t size, GDBusResultFunction function, diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h index 28b80229646c37c1cded7729735986e716f1be62..49ea587db3764f0eeafedbd671cd5dba378be178 100644 --- a/gdbus/gdbus.h +++ b/gdbus/gdbus.h @@ -4,6 +4,7 @@ * D-Bus helper library * * Copyright (C) 2004-2011 Marcel Holtmann <marcel@holtmann.org> + * Copyright 2024 NXP * * */ @@ -72,6 +73,7 @@ typedef void (* GDBusSecurityFunction) (DBusConnection *connection, enum GDBusFlags { G_DBUS_FLAG_ENABLE_EXPERIMENTAL = (1 << 0), + G_DBUS_FLAG_ENABLE_TESTING = (1 << 1), }; enum GDBusMethodFlags { @@ -79,16 +81,19 @@ enum GDBusMethodFlags { G_DBUS_METHOD_FLAG_NOREPLY = (1 << 1), G_DBUS_METHOD_FLAG_ASYNC = (1 << 2), G_DBUS_METHOD_FLAG_EXPERIMENTAL = (1 << 3), + G_DBUS_METHOD_FLAG_TESTING = (1 << 4), }; enum GDBusSignalFlags { G_DBUS_SIGNAL_FLAG_DEPRECATED = (1 << 0), G_DBUS_SIGNAL_FLAG_EXPERIMENTAL = (1 << 1), + G_DBUS_SIGNAL_FLAG_TESTING = (1 << 2), }; enum GDBusPropertyFlags { G_DBUS_PROPERTY_FLAG_DEPRECATED = (1 << 0), G_DBUS_PROPERTY_FLAG_EXPERIMENTAL = (1 << 1), + G_DBUS_PROPERTY_FLAG_TESTING = (1 << 2), }; enum GDBusSecurityFlags { @@ -186,6 +191,20 @@ struct GDBusSecurityTable { .function = _function, \ .flags = G_DBUS_METHOD_FLAG_ASYNC | G_DBUS_METHOD_FLAG_EXPERIMENTAL +#define GDBUS_TESTING_METHOD(_name, _in_args, _out_args, _function) \ + .name = _name, \ + .in_args = _in_args, \ + .out_args = _out_args, \ + .function = _function, \ + .flags = G_DBUS_METHOD_FLAG_TESTING + +#define GDBUS_TESTING_ASYNC_METHOD(_name, _in_args, _out_args, _function) \ + .name = _name, \ + .in_args = _in_args, \ + .out_args = _out_args, \ + .function = _function, \ + .flags = G_DBUS_METHOD_FLAG_ASYNC | G_DBUS_METHOD_FLAG_TESTING + #define GDBUS_NOREPLY_METHOD(_name, _in_args, _out_args, _function) \ .name = _name, \ .in_args = _in_args, \ @@ -207,9 +226,20 @@ struct GDBusSecurityTable { .args = _args, \ .flags = G_DBUS_SIGNAL_FLAG_EXPERIMENTAL +#define GDBUS_TESTING_SIGNAL(_name, _args) \ + .name = _name, \ + .args = _args, \ + .flags = G_DBUS_SIGNAL_FLAG_EXPERIMENTAL + void g_dbus_set_flags(int flags); int g_dbus_get_flags(void); +typedef void (*g_dbus_destroy_func_t)(void *user_data); +typedef void (*g_dbus_debug_func_t)(const char *str, void *user_data); + +void g_dbus_set_debug(g_dbus_debug_func_t cb, void *user_data, + g_dbus_destroy_func_t destroy); + gboolean g_dbus_register_interface(DBusConnection *connection, const char *path, const char *name, const GDBusMethodTable *methods, @@ -284,6 +314,7 @@ guint g_dbus_add_properties_watch(DBusConnection *connection, gboolean g_dbus_remove_watch(DBusConnection *connection, guint tag); void g_dbus_remove_all_watches(DBusConnection *connection); +const char *g_dbus_pending_property_get_sender(GDBusPendingPropertySet id); void g_dbus_pending_property_success(GDBusPendingPropertySet id); void g_dbus_pending_property_error_valist(GDBusPendingReply id, const char *name, const char *format, va_list args); @@ -339,6 +370,11 @@ gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy, GDBusResultFunction function, void *user_data, GDBusDestroyFunction destroy); +gboolean g_dbus_proxy_set_property_dict(GDBusProxy *proxy, + const char *name, GDBusResultFunction function, + void *user_data, GDBusDestroyFunction destroy, + char *entry, ...); + gboolean g_dbus_proxy_set_property_array(GDBusProxy *proxy, const char *name, int type, const void *value, size_t size, GDBusResultFunction function, diff --git a/gdbus/object.c b/gdbus/object.c index f7c8c2be5d875e5718d1682d9616abeebc82b322..84f116bf1a053664f7416f61867eee444cfb7f4f 100644 --- a/gdbus/object.c +++ b/gdbus/object.c @@ -14,11 +14,13 @@ #include <stdio.h> #include <string.h> +#include <stdbool.h> #include <glib.h> #include <dbus/dbus.h> #include "gdbus.h" +#include "src/shared/util.h" #define info(fmt...) #define error(fmt...) @@ -71,9 +73,16 @@ struct property_data { DBusMessage *message; }; +struct debug_data { + g_dbus_debug_func_t func; + g_dbus_destroy_func_t destroy; + void *data; +}; + static int global_flags = 0; static struct generic_data *root; static GSList *pending = NULL; +static struct debug_data debug = { NULL, NULL, NULL }; static gboolean process_changes(gpointer user_data); static void process_properties_from_interface(struct generic_data *data, @@ -115,6 +124,28 @@ static gboolean check_experimental(int flags, int flag) return !(global_flags & G_DBUS_FLAG_ENABLE_EXPERIMENTAL); } +static bool check_testing(int flags, int flag) +{ + if (!(flags & flag)) + return false; + + return !(global_flags & G_DBUS_FLAG_ENABLE_TESTING); +} + +static void g_dbus_debug(const char *format, ...) +{ + va_list va; + char str[MAX_INPUT]; + + if (!format || !debug.func) + return; + + va_start(va, format); + vsnprintf(str, sizeof(str), format, va); + debug.func(str, debug.data); + va_end(va); +} + static void generate_interface_xml(GString *gstr, struct interface_data *iface) { const GDBusMethodTable *method; @@ -126,6 +157,9 @@ static void generate_interface_xml(GString *gstr, struct interface_data *iface) G_DBUS_METHOD_FLAG_EXPERIMENTAL)) continue; + if (check_testing(method->flags, G_DBUS_METHOD_FLAG_TESTING)) + continue; + g_string_append_printf(gstr, "<method name=\"%s\">", method->name); print_arguments(gstr, method->in_args, "in"); @@ -146,6 +180,9 @@ static void generate_interface_xml(GString *gstr, struct interface_data *iface) G_DBUS_SIGNAL_FLAG_EXPERIMENTAL)) continue; + if (check_testing(signal->flags, G_DBUS_SIGNAL_FLAG_TESTING)) + continue; + g_string_append_printf(gstr, "<signal name=\"%s\">", signal->name); print_arguments(gstr, signal->args, NULL); @@ -163,6 +200,10 @@ static void generate_interface_xml(GString *gstr, struct interface_data *iface) G_DBUS_PROPERTY_FLAG_EXPERIMENTAL)) continue; + if (check_testing(property->flags, + G_DBUS_PROPERTY_FLAG_TESTING)) + continue; + g_string_append_printf(gstr, "<property name=\"%s\"" " type=\"%s\" access=\"%s%s\">", property->name, property->type, @@ -411,28 +452,45 @@ static gboolean check_privilege(DBusConnection *conn, DBusMessage *msg, static GDBusPendingPropertySet next_pending_property = 1; static GSList *pending_property_set; +static int pending_property_data_compare_id(const void *data, + const void *user_data) +{ + const struct property_data *propdata = data; + const GDBusPendingPropertySet *id = user_data; + return propdata->id - *id; +} + static struct property_data *remove_pending_property_data( GDBusPendingPropertySet id) { struct property_data *propdata; GSList *l; - for (l = pending_property_set; l != NULL; l = l->next) { - propdata = l->data; - if (propdata->id != id) - continue; - - break; - } - + l = g_slist_find_custom(pending_property_set, &id, + pending_property_data_compare_id); if (l == NULL) return NULL; + propdata = l->data; pending_property_set = g_slist_delete_link(pending_property_set, l); return propdata; } +const char *g_dbus_pending_property_get_sender(GDBusPendingPropertySet id) +{ + struct property_data *propdata; + GSList *l; + + l = g_slist_find_custom(pending_property_set, &id, + pending_property_data_compare_id); + if (l == NULL) + return NULL; + + propdata = l->data; + return dbus_message_get_sender(propdata->message); +} + void g_dbus_pending_property_success(GDBusPendingPropertySet id) { struct property_data *propdata; @@ -518,6 +576,9 @@ static void append_properties(struct interface_data *data, G_DBUS_PROPERTY_FLAG_EXPERIMENTAL)) continue; + if (check_testing(p->flags, G_DBUS_PROPERTY_FLAG_TESTING)) + continue; + if (p->get == NULL) continue; @@ -543,6 +604,22 @@ static void append_interface(gpointer data, gpointer user_data) dbus_message_iter_close_container(array, &entry); } +static const char *dbus_message_type_string(DBusMessage *msg) +{ + return dbus_message_type_to_string(dbus_message_get_type(msg)); +} + +static void g_dbus_send_unref(DBusConnection *conn, DBusMessage *msg) +{ + g_dbus_debug("[%s] %s.%s", + dbus_message_type_string(msg), + dbus_message_get_interface(msg), + dbus_message_get_member(msg)); + + dbus_connection_send(conn, msg, NULL); + dbus_message_unref(msg); +} + static void emit_interfaces_added(struct generic_data *data) { DBusMessage *signal; @@ -583,9 +660,8 @@ static void emit_interfaces_added(struct generic_data *data) dbus_message_iter_close_container(&iter, &array); - /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */ - dbus_connection_send(data->conn, signal, NULL); - dbus_message_unref(signal); + /* Use g_dbus_send_unref to avoid recursive calls to g_dbus_flush */ + g_dbus_send_unref(data->conn, signal); } static struct interface_data *find_interface(GSList *interfaces, @@ -749,6 +825,9 @@ static inline const GDBusPropertyTable *find_property(const GDBusPropertyTable * G_DBUS_PROPERTY_FLAG_EXPERIMENTAL)) break; + if (check_testing(p->flags, G_DBUS_PROPERTY_FLAG_TESTING)) + break; + return p; } @@ -977,9 +1056,8 @@ static void emit_interfaces_removed(struct generic_data *data) dbus_message_iter_close_container(&iter, &array); - /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */ - dbus_connection_send(data->conn, signal, NULL); - dbus_message_unref(signal); + /* Use g_dbus_send_unref to avoid recursive calls to g_dbus_flush */ + g_dbus_send_unref(data->conn, signal); } static void remove_pending(struct generic_data *data) @@ -1044,6 +1122,13 @@ static DBusHandlerResult generic_message(DBusConnection *connection, const GDBusMethodTable *method; const char *interface; + g_dbus_debug("[%s:%s] > %s.%s [#%d]", + dbus_message_get_sender(message), + dbus_message_type_string(message), + dbus_message_get_interface(message), + dbus_message_get_member(message), + dbus_message_get_serial(message)); + interface = dbus_message_get_interface(message); iface = find_interface(data->interfaces, interface); @@ -1061,6 +1146,9 @@ static DBusHandlerResult generic_message(DBusConnection *connection, G_DBUS_METHOD_FLAG_EXPERIMENTAL)) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + if (check_testing(method->flags, G_DBUS_METHOD_FLAG_TESTING)) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + if (g_dbus_args_have_signature(method->in_args, message) == FALSE) continue; @@ -1190,18 +1278,26 @@ static gboolean add_interface(struct generic_data *data, if (!check_experimental(method->flags, G_DBUS_METHOD_FLAG_EXPERIMENTAL)) goto done; + + if (!check_testing(method->flags, G_DBUS_METHOD_FLAG_TESTING)) + goto done; } for (signal = signals; signal && signal->name; signal++) { if (!check_experimental(signal->flags, G_DBUS_SIGNAL_FLAG_EXPERIMENTAL)) goto done; + if (!check_testing(signal->flags, G_DBUS_SIGNAL_FLAG_TESTING)) + goto done; } for (property = properties; property && property->name; property++) { if (!check_experimental(property->flags, G_DBUS_PROPERTY_FLAG_EXPERIMENTAL)) goto done; + if (!check_testing(property->flags, + G_DBUS_PROPERTY_FLAG_TESTING)) + goto done; } /* Nothing to register */ @@ -1523,6 +1619,35 @@ gboolean g_dbus_send_message(DBusConnection *connection, DBusMessage *message) /* Flush pending signal to guarantee message order */ g_dbus_flush(connection); + switch (dbus_message_get_type(message)) { + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + g_dbus_debug("[%s:%s] < [#%d]", + dbus_message_get_destination(message), + dbus_message_type_string(message), + dbus_message_get_reply_serial(message)); + break; + case DBUS_MESSAGE_TYPE_ERROR: + g_dbus_debug("[%s:%s] < %s [#%d]", + dbus_message_get_destination(message), + dbus_message_type_string(message), + dbus_message_get_error_name(message), + dbus_message_get_reply_serial(message)); + break; + case DBUS_MESSAGE_TYPE_SIGNAL: + g_dbus_debug("[%s] %s.%s", + dbus_message_type_string(message), + dbus_message_get_interface(message), + dbus_message_get_member(message)); + break; + default: + g_dbus_debug("[%s:%s] < %s.%s", + dbus_message_get_destination(message), + dbus_message_type_string(message), + dbus_message_get_interface(message), + dbus_message_get_member(message)); + break; + } + result = dbus_connection_send(connection, message, NULL); out: @@ -1548,6 +1673,12 @@ gboolean g_dbus_send_message_with_reply(DBusConnection *connection, return FALSE; } + g_dbus_debug("[%s:%s] < %s.%s", + dbus_message_get_destination(message), + dbus_message_type_string(message), + dbus_message_get_interface(message), + dbus_message_get_member(message)); + return ret; } @@ -1720,9 +1851,8 @@ static void process_properties_from_interface(struct generic_data *data, g_slist_free(iface->pending_prop); iface->pending_prop = NULL; - /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */ - dbus_connection_send(data->conn, signal, NULL); - dbus_message_unref(signal); + /* Use g_dbus_send_unref to avoid recursive calls to g_dbus_flush */ + g_dbus_send_unref(data->conn, signal); } static void process_property_changes(struct generic_data *data) @@ -1849,3 +1979,14 @@ int g_dbus_get_flags(void) { return global_flags; } + +void g_dbus_set_debug(g_dbus_debug_func_t cb, void *user_data, + g_dbus_destroy_func_t destroy) +{ + if (debug.destroy) + debug.destroy(debug.data); + + debug.func = cb; + debug.destroy = destroy; + debug.data = user_data; +} diff --git a/gdbus/watch.c b/gdbus/watch.c index 25f367613a52ac4bce3a730649826222548a8d09..22f77ea7286145234e678acf7ffd5fe41f940de4 100644 --- a/gdbus/watch.c +++ b/gdbus/watch.c @@ -123,29 +123,51 @@ static struct filter_data *filter_data_find(DBusConnection *connection) return NULL; } -static void format_rule(struct filter_data *data, char *rule, size_t size) +static gboolean format_rule(struct filter_data *data, char *rule, size_t size) { const char *sender; - int offset; + int offset, ret; offset = snprintf(rule, size, "type='signal'"); + if (offset < 0) + return FALSE; sender = data->name ? : data->owner; - if (sender) - offset += snprintf(rule + offset, size - offset, + if (sender) { + ret = snprintf(rule + offset, size - offset, ",sender='%s'", sender); - if (data->path) - offset += snprintf(rule + offset, size - offset, + if (ret < 0) + return FALSE; + offset += ret; + } + if (data->path) { + ret = snprintf(rule + offset, size - offset, ",path='%s'", data->path); - if (data->interface) - offset += snprintf(rule + offset, size - offset, + if (ret < 0) + return FALSE; + offset += ret; + } + if (data->interface) { + ret = snprintf(rule + offset, size - offset, ",interface='%s'", data->interface); - if (data->member) - offset += snprintf(rule + offset, size - offset, + if (ret < 0) + return FALSE; + offset += ret; + } + if (data->member) { + ret = snprintf(rule + offset, size - offset, ",member='%s'", data->member); - if (data->argument) - snprintf(rule + offset, size - offset, + if (ret < 0) + return FALSE; + offset += ret; + } + if (data->argument) { + ret = snprintf(rule + offset, size - offset, ",arg0='%s'", data->argument); + if (ret < 0) + return FALSE; + } + return TRUE; } static gboolean add_match(struct filter_data *data, diff --git a/gobex/gobex-header.c b/gobex/gobex-header.c index 002ba886172509cb45ba1a215d399b17e4db004c..f368f0e22d424231af73752bdd9f4fe8c38b412e 100644 --- a/gobex/gobex-header.c +++ b/gobex/gobex-header.c @@ -62,6 +62,34 @@ static glong utf8_to_utf16(gunichar2 **utf16, const char *utf8) { return utf16_len; } +static glong utf16_to_utf8(char **utf8, const gunichar2 *utf16, guint16 len, + GError **err) +{ + glong utf8_len; + guint16 utf16_len, i; + gunichar2 *buf; + + if (*utf16 == '\0') { + *utf8 = NULL; + return 0; + } + + /* OBEX requires network byteorder (big endian) UTF-16 + * but g_utf16_to_utf8 expects host-byteorder UTF-8 + */ + utf16_len = len / sizeof(gunichar2); + buf = alloca(sizeof(gunichar2) * (utf16_len + 1)); + for (i = 0; i < utf16_len; i++) + (buf)[i] = g_ntohs(utf16[i]); + buf[utf16_len] = '\0'; + + *utf8 = g_utf16_to_utf8(buf, -1, NULL, &utf8_len, err); + if (*utf8 == NULL) + utf8_len = -1; + + return utf8_len; +} + static guint8 *put_bytes(guint8 *to, const void *from, gsize count) { memcpy(to, from, count); @@ -130,7 +158,7 @@ GObexHeader *g_obex_header_decode(const void *data, gsize len, GObexHeader *header; const guint8 *ptr = data; guint16 hdr_len; - gsize str_len; + glong str_len; GError *conv_err = NULL; if (len < 2) { @@ -177,13 +205,14 @@ GObexHeader *g_obex_header_decode(const void *data, gsize len, goto failed; } - header->v.string = g_convert((const char *) ptr, hdr_len - 5, - "UTF-8", "UTF-16BE", - NULL, &str_len, &conv_err); - if (header->v.string == NULL) { + str_len = utf16_to_utf8(&header->v.string, + (const gunichar2 *) ptr, + hdr_len - 5, + &conv_err); + if (str_len < 0) { g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR, - "Unicode conversion failed: %s", + "UTF16 to UTF8 conversion failed: %s", conv_err->message); g_error_free(conv_err); goto failed; diff --git a/gobex/gobex.c b/gobex/gobex.c index e9b89ceadb399e9ec00666d2b6e639e7aa0d15c3..07e46627ab39b807e4e36c3e4061b4898481ef4d 100644 --- a/gobex/gobex.c +++ b/gobex/gobex.c @@ -122,7 +122,7 @@ struct setpath_data { guint8 constants; } __attribute__ ((packed)); -static struct error_code { +static const struct error_code { guint8 code; const char *name; } obex_errors[] = { @@ -169,7 +169,7 @@ static struct error_code { const char *g_obex_strerror(guint8 err_code) { - struct error_code *error; + const struct error_code *error; for (error = obex_errors; error->name != NULL; error++) { if (error->code == err_code) @@ -317,6 +317,15 @@ static void set_srm(GObex *obex, guint8 op, guint8 srm) struct srm_config *config = obex->srm; gboolean enable; + switch (srm) { + case G_OBEX_SRM_ENABLE: + case G_OBEX_SRM_DISABLE: + case G_OBEX_SRM_INDICATE: + break; + default: + return; + } + if (config == NULL) { if (srm == G_OBEX_SRM_DISABLE) return; @@ -1423,7 +1432,7 @@ failed: return FALSE; } -static GDebugKey keys[] = { +static const GDebugKey keys[] = { { "error", G_OBEX_DEBUG_ERROR }, { "command", G_OBEX_DEBUG_COMMAND }, { "transfer", G_OBEX_DEBUG_TRANSFER }, @@ -1443,7 +1452,8 @@ GObex *g_obex_new(GIOChannel *io, GObexTransportType transport_type, const char *env = g_getenv("GOBEX_DEBUG"); if (env) { - gobex_debug = g_parse_debug_string(env, keys, 7); + gobex_debug = g_parse_debug_string(env, keys, + G_N_ELEMENTS(keys)); g_setenv("G_MESSAGES_DEBUG", "gobex", FALSE); } else gobex_debug = G_OBEX_DEBUG_NONE; @@ -1610,7 +1620,7 @@ guint g_obex_setpath(GObex *obex, const char *path, GObexResponseFunc func, memset(&data, 0, sizeof(data)); - if (path != NULL && strncmp("..", path, 2) == 0) { + if (path != NULL && strlen(path) >= 2 && strncmp("..", path, 2) == 0) { data.flags = 0x03; folder = (path[2] == '/') ? &path[3] : NULL; } else { diff --git a/install-sh b/install-sh new file mode 100755 index 0000000000000000000000000000000000000000..ec298b53740270ce82b326c4c2deaa5dcdec4596 --- /dev/null +++ b/install-sh @@ -0,0 +1,541 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2020-11-14.01; # UTC + +# 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. + +tab=' ' +nl=' +' +IFS=" $tab$nl" + +# Set DOITPROG to "echo" to test this script. + +doit=${DOITPROG-} +doit_exec=${doit:-exec} + +# 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_mkdir= + +# Desired mode of installed file. +mode=0755 + +# Create dirs (including intermediate dirs) using mode 755. +# This is like GNU 'install' as of coreutils 8.32 (2020). +mkdir_umask=22 + +backupsuffix= +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +is_target_a_directory=possibly + +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 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. + -p pass -p to $cpprog. + -s $stripprog installed files. + -S SUFFIX attempt to back up existing files, with suffix SUFFIX. + -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 + +By default, rm is invoked with -f; when overridden with RMPROG, +it's up to you to specify -f if you want it. + +If -S is not specified, no backups are attempted. + +Email bug reports to bug-automake@gnu.org. +Automake home page: https://www.gnu.org/software/automake/ +" + +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 + *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -p) cpprog="$cpprog -p";; + + -s) stripcmd=$stripprog;; + + -S) backupsuffix="$2" + shift;; + + -t) + is_target_a_directory=always + dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; + + -T) is_target_a_directory=never;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +# We allow the use of options -d and -T together, by making -d +# take the precedence; this is for compatibility with GNU install. + +if test -n "$dir_arg"; then + if test -n "$dst_arg"; then + echo "$0: target directory not allowed when installing a directory." >&2 + exit 1 + fi +fi + +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 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + 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 + if test $# -gt 1 || test "$is_target_a_directory" = always; then + if test ! -d "$dst_arg"; then + echo "$0: $dst_arg: Is not a directory." >&2 + exit 1 + fi + fi +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + + # 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 problematic for 'test' and other utilities. + case $src in + -* | [=\(\)!]) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + # Don't chown directories that already exist. + if test $dstdir_status = 0; then + chowncmd="" + fi + 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 + + # If destination is a directory, append the input filename. + if test -d "$dst"; then + if test "$is_target_a_directory" = never; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dstbase=`basename "$src"` + case $dst in + */) dst=$dst$dstbase;; + *) dst=$dst/$dstbase;; + esac + dstdir_status=0 + else + dstdir=`dirname "$dst"` + test -d "$dstdir" + dstdir_status=$? + fi + fi + + case $dstdir in + */) dstdirslash=$dstdir;; + *) dstdirslash=$dstdir/;; + esac + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # 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 + # The $RANDOM variable is not portable (e.g., dash). Use it + # here however when possible just to lower collision chance. + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + + trap ' + ret=$? + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null + exit $ret + ' 0 + + # Because "mkdir -p" follows existing symlinks and we likely work + # directly in world-writeable /tmp, make sure that the '$tmpdir' + # directory is successfully created first before we actually test + # 'mkdir -p'. + if (umask $mkdir_umask && + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/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-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null + fi + trap '' 0;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # 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 + + oIFS=$IFS + IFS=/ + set -f + set fnord $dstdir + shift + set +f + IFS=$oIFS + + prefixes= + + for d + do + test X"$d" = X && 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=${dstdirslash}_inst.$$_ + rmtmp=${dstdirslash}_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 && + { test -z "$stripcmd" || { + # Create $dsttmp read-write so that cp doesn't create it read-only, + # which would cause strip to fail. + if test -z "$doit"; then + : >"$dsttmp" # No need to fork-exec 'touch'. + else + $doit touch "$dsttmp" + fi + } + } && + $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` && + set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + set +f && + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # If $backupsuffix is set, and the file being installed + # already exists, attempt a backup. Don't worry if it fails, + # e.g., if mv doesn't support -f. + if test -n "$backupsuffix" && test -f "$dst"; then + $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null + fi + + # 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 "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd "$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 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/lib/bluetooth.h b/lib/bluetooth.h index af5fbcfbc3dfbf5bb658f4fb07b7f8a9cd29082a..073ed875df9862fa05e4ba196c04f6f9ae106eb2 100644 --- a/lib/bluetooth.h +++ b/lib/bluetooth.h @@ -6,6 +6,7 @@ * Copyright (C) 2000-2001 Qualcomm Incorporated * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org> + * Copyright 2023 NXP * * */ @@ -140,12 +141,21 @@ struct bt_voice { #define BT_PKT_STATUS 16 #define BT_SCM_PKT_STATUS 0x03 +#define BT_SCM_ERROR 0x04 #define BT_ISO_QOS 17 #define BT_ISO_QOS_CIG_UNSET 0xff #define BT_ISO_QOS_CIS_UNSET 0xff +#define BT_ISO_QOS_BIG_UNSET 0xff +#define BT_ISO_QOS_BIS_UNSET 0xff + +#define BT_ISO_SYNC_TIMEOUT 0x07d0 /* 20 secs */ + +#define BT_ISO_QOS_GROUP_UNSET 0xff +#define BT_ISO_QOS_STREAM_UNSET 0xff + struct bt_iso_io_qos { uint32_t interval; uint16_t latency; @@ -154,23 +164,46 @@ struct bt_iso_io_qos { uint8_t rtn; }; -struct bt_iso_qos { - union { - uint8_t cig; - uint8_t big; - }; - union { - uint8_t cis; - uint8_t bis; - }; - union { - uint8_t sca; - uint8_t sync_interval; - }; +struct bt_iso_ucast_qos { + uint8_t cig; + uint8_t cis; + uint8_t sca; + uint8_t packing; + uint8_t framing; + struct bt_iso_io_qos in; + struct bt_iso_io_qos out; +}; + +struct bt_iso_bcast_qos { + uint8_t big; + uint8_t bis; + uint8_t sync_factor; uint8_t packing; uint8_t framing; struct bt_iso_io_qos in; struct bt_iso_io_qos out; + uint8_t encryption; + uint8_t bcode[16]; + uint8_t options; + uint16_t skip; + uint16_t sync_timeout; + uint8_t sync_cte_type; + uint8_t mse; + uint16_t timeout; +}; + +/* (HCI_MAX_PER_AD_LENGTH - EIR_SERVICE_DATA_LENGTH) */ +#define BASE_MAX_LENGTH 248 +struct bt_iso_base { + uint8_t base_len; + uint8_t base[BASE_MAX_LENGTH]; +}; + +struct bt_iso_qos { + union { + struct bt_iso_ucast_qos ucast; + struct bt_iso_bcast_qos bcast; + }; }; #define BT_CODEC 19 @@ -207,6 +240,8 @@ enum { #define BT_ISO_BASE 20 +#define BT_POLL_ERRQUEUE 21 + /* Byte order conversions */ #if __BYTE_ORDER == __LITTLE_ENDIAN #define htobs(d) (d) diff --git a/lib/hci.c b/lib/hci.c index 5228c2ad2338f60077b12ccc940c5e0a9ddc6226..937e65d48aa50c8c94b281e39517a4604daef928 100644 --- a/lib/hci.c +++ b/lib/hci.c @@ -42,7 +42,7 @@ typedef struct { unsigned int val; } hci_map; -static char *hci_bit2str(hci_map *m, unsigned int val) +static char *hci_bit2str(const hci_map *m, unsigned int val) { char *str = malloc(120); char *ptr = str; @@ -59,10 +59,10 @@ static char *hci_bit2str(hci_map *m, unsigned int val) return str; } -static int hci_str2bit(hci_map *map, char *str, unsigned int *val) +static int hci_str2bit(const hci_map *map, char *str, unsigned int *val) { char *t, *ptr; - hci_map *m; + const hci_map *m; int set; if (!str || !(str = ptr = strdup(str))) @@ -83,7 +83,7 @@ static int hci_str2bit(hci_map *map, char *str, unsigned int *val) return set; } -static char *hci_uint2str(hci_map *m, unsigned int val) +static char *hci_uint2str(const hci_map *m, unsigned int val) { char *str = malloc(50); char *ptr = str; @@ -102,10 +102,10 @@ static char *hci_uint2str(hci_map *m, unsigned int val) return str; } -static int hci_str2uint(hci_map *map, char *str, unsigned int *val) +static int hci_str2uint(const hci_map *map, char *str, unsigned int *val) { char *t, *ptr; - hci_map *m; + const hci_map *m; int set = 0; if (!str) @@ -127,7 +127,7 @@ static int hci_str2uint(hci_map *map, char *str, unsigned int *val) return set; } -char *hci_bustostr(int bus) +const char *hci_bustostr(int bus) { switch (bus) { case HCI_VIRTUAL: @@ -157,7 +157,7 @@ char *hci_bustostr(int bus) } } -char *hci_dtypetostr(int type) +const char *hci_dtypetostr(int type) { return hci_bustostr(type & 0x0f); } @@ -175,7 +175,7 @@ char *hci_typetostr(int type) } /* HCI dev flags mapping */ -static hci_map dev_flags_map[] = { +static const hci_map dev_flags_map[] = { { "UP", HCI_UP }, { "INIT", HCI_INIT }, { "RUNNING", HCI_RUNNING }, @@ -192,7 +192,7 @@ char *hci_dflagstostr(uint32_t flags) { char *str = bt_malloc(50); char *ptr = str; - hci_map *m = dev_flags_map; + const hci_map *m = dev_flags_map; if (!str) return NULL; @@ -211,7 +211,7 @@ char *hci_dflagstostr(uint32_t flags) } /* HCI packet type mapping */ -static hci_map pkt_type_map[] = { +static const hci_map pkt_type_map[] = { { "DM1", HCI_DM1 }, { "DM3", HCI_DM3 }, { "DM5", HCI_DM5 }, @@ -230,7 +230,7 @@ static hci_map pkt_type_map[] = { { NULL } }; -static hci_map sco_ptype_map[] = { +static const hci_map sco_ptype_map[] = { { "HV1", 0x0001 }, { "HV2", 0x0002 }, { "HV3", 0x0004 }, @@ -265,7 +265,7 @@ int hci_strtoscoptype(char *str, unsigned int *val) } /* Link policy mapping */ -static hci_map link_policy_map[] = { +static const hci_map link_policy_map[] = { { "NONE", 0 }, { "RSWITCH", HCI_LP_RSWITCH }, { "HOLD", HCI_LP_HOLD }, @@ -285,7 +285,7 @@ int hci_strtolp(char *str, unsigned int *val) } /* Link mode mapping */ -static hci_map link_mode_map[] = { +static const hci_map link_mode_map[] = { { "NONE", 0 }, { "ACCEPT", HCI_LM_ACCEPT }, { "CENTRAL", HCI_LM_MASTER }, @@ -332,7 +332,7 @@ int hci_strtolm(char *str, unsigned int *val) } /* Command mapping */ -static hci_map commands_map[] = { +static const hci_map commands_map[] = { { "Inquiry", 0 }, { "Inquiry Cancel", 1 }, { "Periodic Inquiry Mode", 2 }, @@ -605,7 +605,7 @@ char *hci_cmdtostr(unsigned int cmd) char *hci_commandstostr(uint8_t *commands, char *pref, int width) { unsigned int maxwidth = width - 3; - hci_map *m; + const hci_map *m; char *off, *ptr, *str; int size = 10; @@ -645,7 +645,7 @@ char *hci_commandstostr(uint8_t *commands, char *pref, int width) } /* Version mapping */ -static hci_map ver_map[] = { +static const hci_map ver_map[] = { { "1.0b", 0x00 }, { "1.1", 0x01 }, { "1.2", 0x02 }, @@ -658,6 +658,8 @@ static hci_map ver_map[] = { { "5.0", 0x09 }, { "5.1", 0x0a }, { "5.2", 0x0b }, + { "5.3", 0x0c }, + { "5.4", 0x0d }, { NULL } }; @@ -681,7 +683,7 @@ int lmp_strtover(char *str, unsigned int *ver) return hci_str2uint(ver_map, str, ver); } -static hci_map pal_map[] = { +static const hci_map pal_map[] = { { "3.0", 0x01 }, { NULL } }; @@ -697,7 +699,7 @@ int pal_strtover(char *str, unsigned int *ver) } /* LMP features mapping */ -static hci_map lmp_features_map[8][9] = { +static const hci_map lmp_features_map[8][9] = { { /* Byte 0 */ { "<3-slot packets>", LMP_3SLOT }, /* Bit 0 */ { "<5-slot packets>", LMP_5SLOT }, /* Bit 1 */ @@ -792,7 +794,7 @@ char *lmp_featurestostr(uint8_t *features, char *pref, int width) int i, size = 10; for (i = 0; i < 8; i++) { - hci_map *m = lmp_features_map[i]; + const hci_map *m = lmp_features_map[i]; while (m->str) { if (m->val & features[i]) @@ -814,7 +816,7 @@ char *lmp_featurestostr(uint8_t *features, char *pref, int width) off = ptr; for (i = 0; i < 8; i++) { - hci_map *m = lmp_features_map[i]; + const hci_map *m = lmp_features_map[i]; while (m->str) { if (m->val & features[i]) { diff --git a/lib/hci_lib.h b/lib/hci_lib.h index 6b1a548b55a7c25d84d633a51960b231dd24716e..baf3d3e12dd5faee79e64943650d2ae58f8fff13 100644 --- a/lib/hci_lib.h +++ b/lib/hci_lib.h @@ -132,9 +132,9 @@ int hci_le_read_remote_features(int dd, uint16_t handle, uint8_t *features, int int hci_for_each_dev(int flag, int(*func)(int dd, int dev_id, long arg), long arg); int hci_get_route(bdaddr_t *bdaddr); -char *hci_bustostr(int bus); +const char *hci_bustostr(int bus); char *hci_typetostr(int type); -char *hci_dtypetostr(int type); +const char *hci_dtypetostr(int type); char *hci_dflagstostr(uint32_t flags); char *hci_ptypetostr(unsigned int ptype); int hci_strtoptype(char *str, unsigned int *val); diff --git a/lib/l2cap.h b/lib/l2cap.h index 9197800df44aabab353cdc523ac0e98a10265bbc..62cc04b57ae92f8ec34551a44ef3a7a87697ba90 100644 --- a/lib/l2cap.h +++ b/lib/l2cap.h @@ -184,6 +184,8 @@ typedef struct { #define L2CAP_MODE_FLOWCTL 0x02 #define L2CAP_MODE_ERTM 0x03 #define L2CAP_MODE_STREAMING 0x04 +#define L2CAP_MODE_LE_FLOWCTL 0x80 +#define L2CAP_MODE_ECRED 0x81 #define L2CAP_SERVTYPE_NOTRAFFIC 0x00 #define L2CAP_SERVTYPE_BESTEFFORT 0x01 diff --git a/lib/mgmt.h b/lib/mgmt.h index 796190cd9ad2bc883d06384590f4a8ec29f47b63..8f92b77315e310cfdc1dee0dbe2271df92aa327f 100644 --- a/lib/mgmt.h +++ b/lib/mgmt.h @@ -12,6 +12,10 @@ #define __packed __attribute__((packed)) #endif +#ifndef BIT +#define BIT(n) (1 << (n)) +#endif + #define MGMT_INDEX_NONE 0xFFFF #define MGMT_STATUS_SUCCESS 0x00 @@ -78,24 +82,28 @@ struct mgmt_rp_read_index_list { #define MGMT_MAX_NAME_LENGTH (248 + 1) #define MGMT_MAX_SHORT_NAME_LENGTH (10 + 1) -#define MGMT_SETTING_POWERED 0x00000001 -#define MGMT_SETTING_CONNECTABLE 0x00000002 -#define MGMT_SETTING_FAST_CONNECTABLE 0x00000004 -#define MGMT_SETTING_DISCOVERABLE 0x00000008 -#define MGMT_SETTING_BONDABLE 0x00000010 -#define MGMT_SETTING_LINK_SECURITY 0x00000020 -#define MGMT_SETTING_SSP 0x00000040 -#define MGMT_SETTING_BREDR 0x00000080 -#define MGMT_SETTING_HS 0x00000100 -#define MGMT_SETTING_LE 0x00000200 -#define MGMT_SETTING_ADVERTISING 0x00000400 -#define MGMT_SETTING_SECURE_CONN 0x00000800 -#define MGMT_SETTING_DEBUG_KEYS 0x00001000 -#define MGMT_SETTING_PRIVACY 0x00002000 -#define MGMT_SETTING_CONFIGURATION 0x00004000 -#define MGMT_SETTING_STATIC_ADDRESS 0x00008000 -#define MGMT_SETTING_PHY_CONFIGURATION 0x00010000 -#define MGMT_SETTING_WIDEBAND_SPEECH 0x00020000 +#define MGMT_SETTING_POWERED BIT(0) +#define MGMT_SETTING_CONNECTABLE BIT(1) +#define MGMT_SETTING_FAST_CONNECTABLE BIT(2) +#define MGMT_SETTING_DISCOVERABLE BIT(3) +#define MGMT_SETTING_BONDABLE BIT(4) +#define MGMT_SETTING_LINK_SECURITY BIT(5) +#define MGMT_SETTING_SSP BIT(6) +#define MGMT_SETTING_BREDR BIT(7) +#define MGMT_SETTING_HS BIT(8) +#define MGMT_SETTING_LE BIT(9) +#define MGMT_SETTING_ADVERTISING BIT(10) +#define MGMT_SETTING_SECURE_CONN BIT(11) +#define MGMT_SETTING_DEBUG_KEYS BIT(12) +#define MGMT_SETTING_PRIVACY BIT(13) +#define MGMT_SETTING_CONFIGURATION BIT(14) +#define MGMT_SETTING_STATIC_ADDRESS BIT(15) +#define MGMT_SETTING_PHY_CONFIGURATION BIT(16) +#define MGMT_SETTING_WIDEBAND_SPEECH BIT(17) +#define MGMT_SETTING_CIS_CENTRAL BIT(18) +#define MGMT_SETTING_CIS_PERIPHERAL BIT(19) +#define MGMT_SETTING_ISO_BROADCASTER BIT(20) +#define MGMT_SETTING_ISO_SYNC_RECEIVER BIT(21) #define MGMT_OP_READ_INFO 0x0004 struct mgmt_rp_read_info { @@ -493,23 +501,23 @@ struct mgmt_rp_add_advertising { uint8_t instance; } __packed; -#define MGMT_ADV_FLAG_CONNECTABLE (1 << 0) -#define MGMT_ADV_FLAG_DISCOV (1 << 1) -#define MGMT_ADV_FLAG_LIMITED_DISCOV (1 << 2) -#define MGMT_ADV_FLAG_MANAGED_FLAGS (1 << 3) -#define MGMT_ADV_FLAG_TX_POWER (1 << 4) -#define MGMT_ADV_FLAG_APPEARANCE (1 << 5) -#define MGMT_ADV_FLAG_LOCAL_NAME (1 << 6) -#define MGMT_ADV_FLAG_SEC_1M (1 << 7) -#define MGMT_ADV_FLAG_SEC_2M (1 << 8) -#define MGMT_ADV_FLAG_SEC_CODED (1 << 9) -#define MGMT_ADV_FLAG_CAN_SET_TX_POWER (1 << 10) -#define MGMT_ADV_FLAG_HW_OFFLOAD (1 << 11) -#define MGMT_ADV_PARAM_DURATION (1 << 12) -#define MGMT_ADV_PARAM_TIMEOUT (1 << 13) -#define MGMT_ADV_PARAM_INTERVALS (1 << 14) -#define MGMT_ADV_PARAM_TX_POWER (1 << 15) -#define MGMT_ADV_PARAM_SCAN_RSP (1 << 16) +#define MGMT_ADV_FLAG_CONNECTABLE BIT(0) +#define MGMT_ADV_FLAG_DISCOV BIT(1) +#define MGMT_ADV_FLAG_LIMITED_DISCOV BIT(2) +#define MGMT_ADV_FLAG_MANAGED_FLAGS BIT(3) +#define MGMT_ADV_FLAG_TX_POWER BIT(4) +#define MGMT_ADV_FLAG_APPEARANCE BIT(5) +#define MGMT_ADV_FLAG_LOCAL_NAME BIT(6) +#define MGMT_ADV_FLAG_SEC_1M BIT(7) +#define MGMT_ADV_FLAG_SEC_2M BIT(8) +#define MGMT_ADV_FLAG_SEC_CODED BIT(9) +#define MGMT_ADV_FLAG_CAN_SET_TX_POWER BIT(10) +#define MGMT_ADV_FLAG_HW_OFFLOAD BIT(11) +#define MGMT_ADV_PARAM_DURATION BIT(12) +#define MGMT_ADV_PARAM_TIMEOUT BIT(13) +#define MGMT_ADV_PARAM_INTERVALS BIT(14) +#define MGMT_ADV_PARAM_TX_POWER BIT(15) +#define MGMT_ADV_PARAM_SCAN_RSP BIT(16) #define MGMT_ADV_FLAG_SEC_MASK (MGMT_ADV_FLAG_SEC_1M | MGMT_ADV_FLAG_SEC_2M | \ MGMT_ADV_FLAG_SEC_CODED) @@ -561,21 +569,21 @@ struct mgmt_rp_get_phy_confguration { uint32_t selected_phys; } __packed; -#define MGMT_PHY_BR_1M_1SLOT 0x00000001 -#define MGMT_PHY_BR_1M_3SLOT 0x00000002 -#define MGMT_PHY_BR_1M_5SLOT 0x00000004 -#define MGMT_PHY_EDR_2M_1SLOT 0x00000008 -#define MGMT_PHY_EDR_2M_3SLOT 0x00000010 -#define MGMT_PHY_EDR_2M_5SLOT 0x00000020 -#define MGMT_PHY_EDR_3M_1SLOT 0x00000040 -#define MGMT_PHY_EDR_3M_3SLOT 0x00000080 -#define MGMT_PHY_EDR_3M_5SLOT 0x00000100 -#define MGMT_PHY_LE_1M_TX 0x00000200 -#define MGMT_PHY_LE_1M_RX 0x00000400 -#define MGMT_PHY_LE_2M_TX 0x00000800 -#define MGMT_PHY_LE_2M_RX 0x00001000 -#define MGMT_PHY_LE_CODED_TX 0x00002000 -#define MGMT_PHY_LE_CODED_RX 0x00004000 +#define MGMT_PHY_BR_1M_1SLOT BIT(0) +#define MGMT_PHY_BR_1M_3SLOT BIT(1) +#define MGMT_PHY_BR_1M_5SLOT BIT(2) +#define MGMT_PHY_EDR_2M_1SLOT BIT(3) +#define MGMT_PHY_EDR_2M_3SLOT BIT(4) +#define MGMT_PHY_EDR_2M_5SLOT BIT(5) +#define MGMT_PHY_EDR_3M_1SLOT BIT(6) +#define MGMT_PHY_EDR_3M_3SLOT BIT(7) +#define MGMT_PHY_EDR_3M_5SLOT BIT(8) +#define MGMT_PHY_LE_1M_TX BIT(9) +#define MGMT_PHY_LE_1M_RX BIT(10) +#define MGMT_PHY_LE_2M_TX BIT(11) +#define MGMT_PHY_LE_2M_RX BIT(12) +#define MGMT_PHY_LE_CODED_TX BIT(13) +#define MGMT_PHY_LE_CODED_RX BIT(14) #define MGMT_PHY_LE_TX_MASK (MGMT_PHY_LE_1M_TX | MGMT_PHY_LE_2M_TX | \ MGMT_PHY_LE_CODED_TX) @@ -889,10 +897,12 @@ struct mgmt_ev_auth_failed { uint8_t status; } __packed; -#define MGMT_DEV_FOUND_CONFIRM_NAME 0x01 -#define MGMT_DEV_FOUND_LEGACY_PAIRING 0x02 -#define MGMT_DEV_FOUND_NOT_CONNECTABLE 0x04 -#define MGMT_DEV_FOUND_NAME_REQUEST_FAILED 0x10 +#define MGMT_DEV_FOUND_CONFIRM_NAME BIT(0) +#define MGMT_DEV_FOUND_LEGACY_PAIRING BIT(1) +#define MGMT_DEV_FOUND_NOT_CONNECTABLE BIT(2) +#define MGMT_DEV_FOUND_INITIATED_CONN BIT(3) +#define MGMT_DEV_FOUND_NAME_REQUEST_FAILED BIT(4) +#define MGMT_DEV_FOUND_SCAN_RSP BIT(5) #define MGMT_EV_DEVICE_FOUND 0x0012 struct mgmt_ev_device_found { @@ -1228,6 +1238,9 @@ static const char *mgmt_ev[] = { "Advertisement Monitor Device Lost", "Mesh Packet Found", "Mesh Packet Complete", + "PA Sync Established", + "BIG Sync Established", + "BIG Sync Lost", }; static const char *mgmt_status[] = { diff --git a/lib/sdp.c b/lib/sdp.c index 844ae0d25432d512b14ad28bfae7e48bea4e6cab..411a95b8a7d3cf2d767bc8764f385cd568a486ea 100644 --- a/lib/sdp.c +++ b/lib/sdp.c @@ -47,7 +47,7 @@ #define SDPDBG(fmt...) #endif -static uint128_t bluetooth_base_uuid = { +static const uint128_t bluetooth_base_uuid = { .data = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB } }; @@ -65,10 +65,10 @@ static int sdp_gen_buffer(sdp_buf_t *buf, sdp_data_t *d); /* Message structure. */ struct tupla { int index; - char *str; + const char *str; }; -static struct tupla Protocol[] = { +static const struct tupla Protocol[] = { { SDP_UUID, "SDP" }, { UDP_UUID, "UDP" }, { RFCOMM_UUID, "RFCOMM" }, @@ -97,7 +97,7 @@ static struct tupla Protocol[] = { { 0 } }; -static struct tupla ServiceClass[] = { +static const struct tupla ServiceClass[] = { { SDP_SERVER_SVCLASS_ID, "SDP Server" }, { BROWSE_GRP_DESC_SVCLASS_ID, "Browse Group Descriptor" }, { PUBLIC_BROWSE_GROUP, "Public Browse Group" }, @@ -176,9 +176,9 @@ static struct tupla ServiceClass[] = { #define Profile ServiceClass -static char *string_lookup(struct tupla *pt0, int index) +static const char *string_lookup(const struct tupla *pt0, int index) { - struct tupla *pt; + const struct tupla *pt; for (pt = pt0; pt->index; pt++) if (pt->index == index) @@ -187,7 +187,8 @@ static char *string_lookup(struct tupla *pt0, int index) return ""; } -static char *string_lookup_uuid(struct tupla *pt0, const uuid_t *uuid) +static const char *string_lookup_uuid(const struct tupla *pt0, + const uuid_t *uuid) { uuid_t tmp_uuid; @@ -209,9 +210,10 @@ static char *string_lookup_uuid(struct tupla *pt0, const uuid_t *uuid) * Prints into a string the Protocol UUID * coping a maximum of n characters. */ -static int uuid2str(struct tupla *message, const uuid_t *uuid, char *str, size_t n) +static int uuid2str(const struct tupla *message, const uuid_t *uuid, char *str, + size_t n) { - char *str2; + const char *str2; if (!uuid) { snprintf(str, n, "NULL"); @@ -420,7 +422,7 @@ sdp_data_t *sdp_data_alloc_with_length(uint8_t dtd, const void *value, d->unitSize += length; if (length <= USHRT_MAX) { - d->val.str = malloc(length); + d->val.str = bt_malloc0(length + 1); if (!d->val.str) { free(d); return NULL; @@ -504,15 +506,17 @@ sdp_data_t *sdp_seq_alloc_with_length(void **dtds, void **values, int *length, for (i = 0; i < len; i++) { sdp_data_t *data; - int8_t dtd = *(uint8_t *) dtds[i]; + uint8_t dtd = *(uint8_t *) dtds[i]; if (dtd >= SDP_SEQ8 && dtd <= SDP_ALT32) data = (sdp_data_t *) values[i]; else data = sdp_data_alloc_with_length(dtd, values[i], length[i]); - if (!data) + if (!data) { + sdp_data_free(seq); return NULL; + } if (curr) curr->next = data; @@ -539,8 +543,10 @@ sdp_data_t *sdp_seq_alloc(void **dtds, void **values, int len) else data = sdp_data_alloc(dtd, values[i]); - if (!data) + if (!data) { + sdp_data_free(seq); return NULL; + } if (curr) curr->next = data; @@ -576,6 +582,8 @@ int sdp_attr_add(sdp_record_t *rec, uint16_t attr, sdp_data_t *d) if (p) return -1; + if (!d) + return -1; d->attrId = attr; rec->attrlist = sdp_list_insert_sorted(rec->attrlist, d, sdp_attrid_comp_func); @@ -958,6 +966,8 @@ static void data_seq_free(sdp_data_t *seq) void sdp_data_free(sdp_data_t *d) { + if (!d) + return; switch (d->dtd) { case SDP_SEQ8: case SDP_SEQ16: @@ -1505,7 +1515,7 @@ static void *sdp_data_value(sdp_data_t *data, uint32_t *len) case SDP_TEXT_STR32: val = data->val.str; if (len) - *len = data->unitSize - 1; + *len = data->unitSize - sizeof(uint8_t); break; case SDP_ALT8: case SDP_ALT16: @@ -1527,10 +1537,15 @@ static sdp_data_t *sdp_copy_seq(sdp_data_t *data) for (tmp = data; tmp; tmp = tmp->next) { sdp_data_t *datatmp; void *value; + uint32_t len = 0; - value = sdp_data_value(tmp, NULL); - datatmp = sdp_data_alloc_with_length(tmp->dtd, value, - tmp->unitSize); + value = sdp_data_value(tmp, &len); + datatmp = sdp_data_alloc_with_length(tmp->dtd, value, len); + + if (!datatmp) { + sdp_data_free(seq); + return NULL; + } if (cur) cur->next = datatmp; @@ -2180,16 +2195,21 @@ int sdp_get_int_attr(const sdp_record_t *rec, uint16_t attrid, int *value) } int sdp_get_string_attr(const sdp_record_t *rec, uint16_t attrid, char *value, - int valuelen) + size_t valuelen) { sdp_data_t *sdpdata = sdp_data_get(rec, attrid); - if (sdpdata) - /* Verify that it is what the caller expects */ - if (SDP_IS_TEXT_STR(sdpdata->dtd)) - if ((int) strlen(sdpdata->val.str) < valuelen) { - strcpy(value, sdpdata->val.str); - return 0; - } + + /* Verify that it is what the caller expects */ + if (!sdpdata || !SDP_IS_TEXT_STR(sdpdata->dtd)) + goto fail; + + /* Have to copy the NULL terminator too, so check len < valuelen. */ + if (strlen(sdpdata->val.str) < valuelen) { + strcpy(value, sdpdata->val.str); + return 0; + } + +fail: errno = EINVAL; return -1; } @@ -2292,7 +2312,7 @@ static sdp_data_t *access_proto_to_dataseq(sdp_record_t *rec, sdp_list_t *proto) sdp_list_t *p; seqlen = sdp_list_len(proto); - seqDTDs = malloc(seqlen * sizeof(void *)); + seqDTDs = bt_malloc0(seqlen * sizeof(void *)); if (!seqDTDs) return NULL; @@ -2758,7 +2778,7 @@ uuid_t *sdp_uuid_to_uuid128(const uuid_t *uuid) */ int sdp_uuid128_to_uuid(uuid_t *uuid) { - uint128_t *b = &bluetooth_base_uuid; + const uint128_t *b = &bluetooth_base_uuid; uint128_t *u = &uuid->value.uuid128; uint32_t data; unsigned int i; @@ -3597,7 +3617,7 @@ sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle, /* get attr seq PDU form */ seqlen = gen_attridseq_pdu(pdata, attrids, reqtype == SDP_ATTR_REQ_INDIVIDUAL? SDP_UINT16 : SDP_UINT32); - if (seqlen == -1) { + if (seqlen < 0) { errno = EINVAL; goto end; } @@ -3952,7 +3972,7 @@ int sdp_service_attr_async(sdp_session_t *session, uint32_t handle, sdp_attrreq_ /* get attr seq PDU form */ seqlen = gen_attridseq_pdu(pdata, attrid_list, reqtype == SDP_ATTR_REQ_INDIVIDUAL? SDP_UINT16 : SDP_UINT32); - if (seqlen == -1) { + if (seqlen < 0) { t->err = EINVAL; goto end; } @@ -4074,7 +4094,7 @@ int sdp_service_search_attr_async(sdp_session_t *session, const sdp_list_t *sear /* get attr seq PDU form */ seqlen = gen_attridseq_pdu(pdata, attrid_list, reqtype == SDP_ATTR_REQ_INDIVIDUAL ? SDP_UINT16 : SDP_UINT32); - if (seqlen == -1) { + if (seqlen < 0) { t->err = EINVAL; goto end; } @@ -4458,7 +4478,7 @@ int sdp_service_search_attr_req(sdp_session_t *session, const sdp_list_t *search /* get attr seq PDU form */ seqlen = gen_attridseq_pdu(pdata, attrids, reqtype == SDP_ATTR_REQ_INDIVIDUAL ? SDP_UINT16 : SDP_UINT32); - if (seqlen == -1) { + if (seqlen < 0) { errno = EINVAL; status = -1; goto end; diff --git a/lib/sdp_lib.h b/lib/sdp_lib.h index 22776b678de8d2b68958531396507eceaf16b581..aad664fd6d946afc4eb2185759899dea640801b4 100644 --- a/lib/sdp_lib.h +++ b/lib/sdp_lib.h @@ -141,7 +141,8 @@ int sdp_general_inquiry(inquiry_info *ii, int dev_num, int duration, uint8_t *fo /* flexible extraction of basic attributes - Jean II */ int sdp_get_int_attr(const sdp_record_t *rec, uint16_t attr, int *value); -int sdp_get_string_attr(const sdp_record_t *rec, uint16_t attr, char *value, int valuelen); +int sdp_get_string_attr(const sdp_record_t *rec, uint16_t attr, char *value, + size_t valuelen); /* * Basic sdp data functions @@ -543,32 +544,38 @@ int sdp_get_service_avail(const sdp_record_t *rec, uint8_t *svcAvail); int sdp_get_service_ttl(const sdp_record_t *rec, uint32_t *svcTTLInfo); int sdp_get_database_state(const sdp_record_t *rec, uint32_t *svcDBState); -static inline int sdp_get_service_name(const sdp_record_t *rec, char *str, int len) +static inline int sdp_get_service_name(const sdp_record_t *rec, char *str, + size_t len) { return sdp_get_string_attr(rec, SDP_ATTR_SVCNAME_PRIMARY, str, len); } -static inline int sdp_get_service_desc(const sdp_record_t *rec, char *str, int len) +static inline int sdp_get_service_desc(const sdp_record_t *rec, char *str, + size_t len) { return sdp_get_string_attr(rec, SDP_ATTR_SVCDESC_PRIMARY, str, len); } -static inline int sdp_get_provider_name(const sdp_record_t *rec, char *str, int len) +static inline int sdp_get_provider_name(const sdp_record_t *rec, char *str, + size_t len) { return sdp_get_string_attr(rec, SDP_ATTR_PROVNAME_PRIMARY, str, len); } -static inline int sdp_get_doc_url(const sdp_record_t *rec, char *str, int len) +static inline int sdp_get_doc_url(const sdp_record_t *rec, char *str, + size_t len) { return sdp_get_string_attr(rec, SDP_ATTR_DOC_URL, str, len); } -static inline int sdp_get_clnt_exec_url(const sdp_record_t *rec, char *str, int len) +static inline int sdp_get_clnt_exec_url(const sdp_record_t *rec, char *str, + size_t len) { return sdp_get_string_attr(rec, SDP_ATTR_CLNT_EXEC_URL, str, len); } -static inline int sdp_get_icon_url(const sdp_record_t *rec, char *str, int len) +static inline int sdp_get_icon_url(const sdp_record_t *rec, char *str, + size_t len) { return sdp_get_string_attr(rec, SDP_ATTR_ICON_URL, str, len); } diff --git a/lib/uuid.c b/lib/uuid.c index 1d2e1f7328b80504a732ccd74c00c287dcb0a9db..9a216e7cef609981dabacc66c72442751aa1ffbd 100644 --- a/lib/uuid.c +++ b/lib/uuid.c @@ -120,6 +120,15 @@ int bt_uuid_cmp(const bt_uuid_t *uuid1, const bt_uuid_t *uuid2) return bt_uuid128_cmp(&u1, &u2); } +int bt_uuid16_cmp(const bt_uuid_t *uuid1, uint16_t uuid2) +{ + + if (!uuid1 || (uuid1->type != BT_UUID16)) + return 0; + + return (uuid1->value.u16 == uuid2); +} + /* * convert the UUID to string, copying a maximum of n characters. */ diff --git a/lib/uuid.h b/lib/uuid.h index d5e5665e475ca2f57b56ff00d5b7fd3a4e82291d..479986f061bbbc7cc675173852c8b75d1adb22a0 100644 --- a/lib/uuid.h +++ b/lib/uuid.h @@ -5,6 +5,7 @@ * * Copyright (C) 2011 Nokia Corporation * Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org> + * Copyright 2023 NXP * * */ @@ -156,6 +157,15 @@ extern "C" { #define PAC_SOURCE_UUID "00002bcb-0000-1000-8000-00805f9b34fb" #define PAC_SOURCE_LOC_CHRC_UUID 0x2bcc +#define BCAA_SERVICE 0x1852 +#define BCAA_SERVICE_UUID "00001852-0000-1000-8000-00805f9b34fb" + +#define BAA_SERVICE 0x1851 +#define BAA_SERVICE_UUID "00001851-0000-1000-8000-00805f9b34fb" + +#define ASHA_SERVICE 0xFDF0 +#define ASHA_PROFILE_UUID "0000FDF0-0000-1000-8000-00805f9b34fb" + #define PAC_CONTEXT 0x2bcd #define PAC_SUPPORTED_CONTEXT 0x2bce @@ -164,6 +174,10 @@ extern "C" { #define ASE_SOURCE_UUID 0x2bc5 #define ASE_CP_UUID 0x2bc6 +#define BASS_UUID 0x184f +#define BCAST_AUDIO_SCAN_CP_UUID 0x2bc7 +#define BCAST_RECV_STATE_UUID 0x2bc8 + #define VCS_UUID 0x1844 #define VOL_OFFSET_CS_UUID 0x1845 #define AUDIO_INPUT_CS_UUID 0x1843 @@ -171,6 +185,18 @@ extern "C" { #define VOL_CP_CHRC_UUID 0x2B7E #define VOL_FLAG_CHRC_UUID 0x2B7F +#define VOCS_STATE_CHAR_UUID 0x2B80 +#define VOCS_AUDIO_LOC_CHRC_UUID 0x2B81 +#define VOCS_CP_CHRC_UUID 0x2B82 +#define VOCS_AUDIO_OP_DESC_CHAR_UUID 0x2B83 + +#define AICS_INPUT_STATE_CHAR_UUID 0x2B77 +#define AICS_GAIN_SETTING_PROP_CHAR_UUID 0x2B78 +#define AICS_AUDIO_INPUT_TYPE_CHAR_UUID 0x2B79 +#define AICS_INPUT_STATUS_CHAR_UUID 0X2B7A +#define AICS_AUDIO_INPUT_CP_CHRC_UUID 0X2B7B +#define AICS_INPUT_DESCR_CHAR_UUID 0X2B7C + #define GMCS_UUID 0x1849 #define MEDIA_PLAYER_NAME_CHRC_UUID 0x2b93 #define MEDIA_TRACK_CHNGD_CHRC_UUID 0x2b96 @@ -186,6 +212,39 @@ extern "C" { #define MEDIA_CP_OP_SUPPORTED_CHRC_UUID 0x2ba5 #define MEDIA_CONTENT_CONTROL_ID_CHRC_UUID 0x2bba +/* Coordinated Set Identification Profile(CSIP) */ +#define CSIS_UUID 0x1846 +#define CS_SIRK 0x2B84 +#define CS_SIZE 0x2B85 +#define CS_LOCK 0x2B86 +#define CS_RANK 0x2B87 + + +/* Microphone Control Service(MICS) */ +#define MICS_UUID 0x184D +#define MUTE_CHRC_UUID 0x2BC3 + +/* Call Control Service(TBS/CCS) */ +#define TBS_UUID 0x184B +#define GTBS_UUID 0x184C + +#define BEARER_PROVIDER_NAME_CHRC_UUID 0x2bb3 +#define BEARER_UCI_CHRC_UUID 0x2bb4 +#define BEARER_TECH_CHRC_UUID 0x2bb5 +#define BEARER_URI_SCHEME_CHRC_UUID 0x2bb6 +#define BEARER_SIGNAL_STR_CHRC_UUID 0x2bb7 +#define BEARER_SIGNAL_INTRVL_CHRC_UUID 0x2bb8 +#define CURR_CALL_LIST_CHRC_UUID 0x2bb9 +#define BEARER_CCID_CHRC_UUID 0x2bba +#define CALL_STATUS_FLAG_CHRC_UUID 0x2bbb +#define INCOM_CALL_TARGET_URI_CHRC_UUID 0x2bbc +#define CALL_STATE_CHRC_UUID 0x2bbd +#define CALL_CTRL_POINT_CHRC_UUID 0x2bbe +#define CALL_CTRL_POINT_OPT_OPCODE_CHRC_UUID 0x2bbf +#define TERMINATION_REASON_CHRC_UUID 0x2bc0 +#define INCOMING_CALL_CHRC_UUID 0x2bc1 +#define CALL_FRIENDLY_NAME_CHRC_UUID 0x2bc2 + typedef struct { enum { BT_UUID_UNSPEC = 0, @@ -207,6 +266,7 @@ int bt_uuid32_create(bt_uuid_t *btuuid, uint32_t value); int bt_uuid128_create(bt_uuid_t *btuuid, uint128_t value); int bt_uuid_cmp(const bt_uuid_t *uuid1, const bt_uuid_t *uuid2); +int bt_uuid16_cmp(const bt_uuid_t *uuid1, uint16_t uuid2); void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst); #define MAX_LEN_UUID_STR 37 diff --git a/ltmain.sh b/ltmain.sh new file mode 100755 index 0000000000000000000000000000000000000000..1dea62ab78db2164abb4c4b02a50d2cd3f195077 --- /dev/null +++ b/ltmain.sh @@ -0,0 +1,11436 @@ +#! /usr/bin/env sh +## DO NOT EDIT - This file generated from ./build-aux/ltmain.in +## by inline-source v2019-02-19.15 + +# libtool (GNU libtool) 2.4.7 +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 + +# Copyright (C) 1996-2019, 2021-2022 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. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +PROGRAM=libtool +PACKAGE=libtool +VERSION="2.4.7 Debian-2.4.7-7" +package_revision=2.4.7 + + +## ------ ## +## Usage. ## +## ------ ## + +# Run './libtool --help' for help with using this script from the +# command line. + + +## ------------------------------- ## +## User overridable command paths. ## +## ------------------------------- ## + +# After configure completes, it has a better idea of some of the +# shell tools we need than the defaults used by the functions shared +# with bootstrap, so set those here where they can still be over- +# ridden by the user, but otherwise take precedence. + +: ${AUTOCONF="autoconf"} +: ${AUTOMAKE="automake"} + + +## -------------------------- ## +## Source external libraries. ## +## -------------------------- ## + +# Much of our low-level functionality needs to be sourced from external +# libraries, which are installed to $pkgauxdir. + +# Set a version string for this script. +scriptversion=2019-02-19.15; # UTC + +# General shell script boiler plate, and helper functions. +# Written by Gary V. Vaughan, 2004 + +# This is free software. There is NO warranty; not even for +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Copyright (C) 2004-2019, 2021 Bootstrap Authors +# +# This file is dual licensed under the terms of the MIT license +# <https://opensource.org/license/MIT>, and GPL version 2 or later +# <http://www.gnu.org/licenses/gpl-2.0.html>. You must apply one of +# these licenses when using or redistributing this software or any of +# the files within it. See the URLs above, or the file `LICENSE` +# included in the Bootstrap distribution for the full license texts. + +# Please report bugs or propose patches to: +# <https://github.com/gnulib-modules/bootstrap/issues> + + +## ------ ## +## Usage. ## +## ------ ## + +# Evaluate this file near the top of your script to gain access to +# the functions and variables defined here: +# +# . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh +# +# If you need to override any of the default environment variable +# settings, do that before evaluating this file. + + +## -------------------- ## +## Shell normalisation. ## +## -------------------- ## + +# Some shells need a little help to be as Bourne compatible as possible. +# Before doing anything else, make sure all that help has been provided! + +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do 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 + +# NLS nuisances: We save the old values in case they are required later. +_G_user_locale= +_G_safe_locale= +for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test set = \"\${$_G_var+set}\"; then + save_$_G_var=\$$_G_var + $_G_var=C + export $_G_var + _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\" + _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\" + fi" +done +# These NLS vars are set unconditionally (bootstrap issue #24). Unset those +# in case the environment reset is needed later and the $save_* variant is not +# defined (see the code above). +LC_ALL=C +LANGUAGE=C +export LANGUAGE LC_ALL + +# Make sure IFS has a sensible default +sp=' ' +nl=' +' +IFS="$sp $nl" + +# There are apparently some retarded systems that use ';' as a PATH separator! +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# func_unset VAR +# -------------- +# Portably unset VAR. +# In some shells, an 'unset VAR' statement leaves a non-zero return +# status if VAR is already unset, which might be problematic if the +# statement is used at the end of a function (thus poisoning its return +# value) or when 'set -e' is active (causing even a spurious abort of +# the script in this case). +func_unset () +{ + { eval $1=; (eval unset $1) >/dev/null 2>&1 && eval unset $1 || : ; } +} + + +# Make sure CDPATH doesn't cause `cd` commands to output the target dir. +func_unset CDPATH + +# Make sure ${,E,F}GREP behave sanely. +func_unset GREP_OPTIONS + + +## ------------------------- ## +## Locate command utilities. ## +## ------------------------- ## + + +# func_executable_p FILE +# ---------------------- +# Check that FILE is an executable regular file. +func_executable_p () +{ + test -f "$1" && test -x "$1" +} + + +# func_path_progs PROGS_LIST CHECK_FUNC [PATH] +# -------------------------------------------- +# Search for either a program that responds to --version with output +# containing "GNU", or else returned by CHECK_FUNC otherwise, by +# trying all the directories in PATH with each of the elements of +# PROGS_LIST. +# +# CHECK_FUNC should accept the path to a candidate program, and +# set $func_check_prog_result if it truncates its output less than +# $_G_path_prog_max characters. +func_path_progs () +{ + _G_progs_list=$1 + _G_check_func=$2 + _G_PATH=${3-"$PATH"} + + _G_path_prog_max=0 + _G_path_prog_found=false + _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:} + for _G_dir in $_G_PATH; do + IFS=$_G_save_IFS + test -z "$_G_dir" && _G_dir=. + for _G_prog_name in $_G_progs_list; do + for _exeext in '' .EXE; do + _G_path_prog=$_G_dir/$_G_prog_name$_exeext + func_executable_p "$_G_path_prog" || continue + case `"$_G_path_prog" --version 2>&1` in + *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;; + *) $_G_check_func $_G_path_prog + func_path_progs_result=$func_check_prog_result + ;; + esac + $_G_path_prog_found && break 3 + done + done + done + IFS=$_G_save_IFS + test -z "$func_path_progs_result" && { + echo "no acceptable sed could be found in \$PATH" >&2 + exit 1 + } +} + + +# We want to be able to use the functions in this file before configure +# has figured out where the best binaries are kept, which means we have +# to search for them ourselves - except when the results are already set +# where we skip the searches. + +# Unless the user overrides by setting SED, search the path for either GNU +# sed, or the sed that truncates its output the least. +test -z "$SED" && { + _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for _G_i in 1 2 3 4 5 6 7; do + _G_sed_script=$_G_sed_script$nl$_G_sed_script + done + echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed + _G_sed_script= + + func_check_prog_sed () + { + _G_path_prog=$1 + + _G_count=0 + printf 0123456789 >conftest.in + while : + do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo '' >> conftest.nl + "$_G_path_prog" -f conftest.sed <conftest.nl >conftest.out 2>/dev/null || break + diff conftest.out conftest.nl >/dev/null 2>&1 || break + _G_count=`expr $_G_count + 1` + if test "$_G_count" -gt "$_G_path_prog_max"; then + # Best one so far, save it but keep looking for a better one + func_check_prog_result=$_G_path_prog + _G_path_prog_max=$_G_count + fi + # 10*(2^10) chars as input seems more than enough + test 10 -lt "$_G_count" && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out + } + + func_path_progs "sed gsed" func_check_prog_sed "$PATH:/usr/xpg4/bin" + rm -f conftest.sed + SED=$func_path_progs_result +} + + +# Unless the user overrides by setting GREP, search the path for either GNU +# grep, or the grep that truncates its output the least. +test -z "$GREP" && { + func_check_prog_grep () + { + _G_path_prog=$1 + + _G_count=0 + _G_path_prog_max=0 + printf 0123456789 >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 + "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' <conftest.nl >conftest.out 2>/dev/null || break + diff conftest.out conftest.nl >/dev/null 2>&1 || break + _G_count=`expr $_G_count + 1` + if test "$_G_count" -gt "$_G_path_prog_max"; then + # Best one so far, save it but keep looking for a better one + func_check_prog_result=$_G_path_prog + _G_path_prog_max=$_G_count + fi + # 10*(2^10) chars as input seems more than enough + test 10 -lt "$_G_count" && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out + } + + func_path_progs "grep ggrep" func_check_prog_grep "$PATH:/usr/xpg4/bin" + GREP=$func_path_progs_result +} + + +## ------------------------------- ## +## User overridable command paths. ## +## ------------------------------- ## + +# All uppercase variable names are used for environment variables. These +# variables can be overridden by the user before calling a script that +# uses them if a suitable command of that name is not already available +# in the command search PATH. + +: ${CP="cp -f"} +: ${ECHO="printf %s\n"} +: ${EGREP="$GREP -E"} +: ${FGREP="$GREP -F"} +: ${LN_S="ln -s"} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} + + +## -------------------- ## +## Useful sed snippets. ## +## -------------------- ## + +sed_dirname='s|/[^/]*$||' +sed_basename='s|^.*/||' + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s|\([`"$\\]\)|\\\1|g' + +# Same as above, but do not quote variable references. +sed_double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution that turns a string into a regex matching for the +# string literally. +sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g' + +# Sed substitution that converts a w32 file name or path +# that contains forward slashes, into one that contains +# (escaped) backslashes. A very naive implementation. +sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + +# Re-'\' parameter expansions in output of sed_double_quote_subst that +# were '\'-ed in input to the same. If an odd number of '\' preceded a +# '$' in input to sed_double_quote_subst, that '$' was protected from +# expansion. Since each input '\' is now two '\'s, look for any number +# of runs of four '\'s followed by two '\'s and then a '$'. '\' that '$'. +_G_bs='\\' +_G_bs2='\\\\' +_G_bs4='\\\\\\\\' +_G_dollar='\$' +sed_double_backslash="\ + s/$_G_bs4/&\\ +/g + s/^$_G_bs2$_G_dollar/$_G_bs&/ + s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g + s/\n//g" + +# require_check_ifs_backslash +# --------------------------- +# Check if we can use backslash as IFS='\' separator, and set +# $check_ifs_backshlash_broken to ':' or 'false'. +require_check_ifs_backslash=func_require_check_ifs_backslash +func_require_check_ifs_backslash () +{ + _G_save_IFS=$IFS + IFS='\' + _G_check_ifs_backshlash='a\\b' + for _G_i in $_G_check_ifs_backshlash + do + case $_G_i in + a) + check_ifs_backshlash_broken=false + ;; + '') + break + ;; + *) + check_ifs_backshlash_broken=: + break + ;; + esac + done + IFS=$_G_save_IFS + require_check_ifs_backslash=: +} + + +## ----------------- ## +## Global variables. ## +## ----------------- ## + +# Except for the global variables explicitly listed below, the following +# functions in the '^func_' namespace, and the '^require_' namespace +# variables initialised in the 'Resource management' section, sourcing +# this file will not pollute your global namespace with anything +# else. There's no portable way to scope variables in Bourne shell +# though, so actually running these functions will sometimes place +# results into a variable named after the function, and often use +# temporary variables in the '^_G_' namespace. If you are careful to +# avoid using those namespaces casually in your sourcing script, things +# should continue to work as you expect. And, of course, you can freely +# overwrite any of the functions or variables defined here before +# calling anything to customize them. + +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +# Allow overriding, eg assuming that you follow the convention of +# putting '$debug_cmd' at the start of all your functions, you can get +# bash to show function call trace with: +# +# debug_cmd='echo "${FUNCNAME[0]} $*" >&2' bash your-script-name +debug_cmd=${debug_cmd-":"} +exit_cmd=: + +# By convention, finish your script with: +# +# exit $exit_status +# +# so that you can set exit_status to non-zero if you want to indicate +# something went wrong during execution without actually bailing out at +# the point of failure. +exit_status=$EXIT_SUCCESS + +# 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 "$sed_basename"` + +# Make sure we have an absolute progpath for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=`$ECHO "$progpath" |$SED "$sed_dirname"` + progdir=`cd "$progdir" && pwd` + progpath=$progdir/$progname + ;; + *) + _G_IFS=$IFS + IFS=${PATH_SEPARATOR-:} + for progdir in $PATH; do + IFS=$_G_IFS + test -x "$progdir/$progname" && break + done + IFS=$_G_IFS + test -n "$progdir" || progdir=`pwd` + progpath=$progdir/$progname + ;; +esac + + +## ----------------- ## +## Standard options. ## +## ----------------- ## + +# The following options affect the operation of the functions defined +# below, and should be set appropriately depending on run-time para- +# meters passed on the command line. + +opt_dry_run=false +opt_quiet=false +opt_verbose=false + +# Categories 'all' and 'none' are always available. Append any others +# you will pass as the first argument to func_warning from your own +# code. +warning_categories= + +# By default, display warnings according to 'opt_warning_types'. Set +# 'warning_func' to ':' to elide all warnings, or func_fatal_error to +# treat the next displayed warning as a fatal error. +warning_func=func_warn_and_continue + +# Set to 'all' to display all warnings, 'none' to suppress all +# warnings, or a space delimited list of some subset of +# 'warning_categories' to display only the listed warnings. +opt_warning_types=all + + +## -------------------- ## +## Resource management. ## +## -------------------- ## + +# This section contains definitions for functions that each ensure a +# particular resource (a file, or a non-empty configuration variable for +# example) is available, and if appropriate to extract default values +# from pertinent package files. Call them using their associated +# 'require_*' variable to ensure that they are executed, at most, once. +# +# It's entirely deliberate that calling these functions can set +# variables that don't obey the namespace limitations obeyed by the rest +# of this file, in order that that they be as useful as possible to +# callers. + + +# require_term_colors +# ------------------- +# Allow display of bold text on terminals that support it. +require_term_colors=func_require_term_colors +func_require_term_colors () +{ + $debug_cmd + + test -t 1 && { + # COLORTERM and USE_ANSI_COLORS environment variables take + # precedence, because most terminfo databases neglect to describe + # whether color sequences are supported. + test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"} + + if test 1 = "$USE_ANSI_COLORS"; then + # Standard ANSI escape sequences + tc_reset='[0m' + tc_bold='[1m'; tc_standout='[7m' + tc_red='[31m'; tc_green='[32m' + tc_blue='[34m'; tc_cyan='[36m' + else + # Otherwise trust the terminfo database after all. + test -n "`tput sgr0 2>/dev/null`" && { + tc_reset=`tput sgr0` + test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold` + tc_standout=$tc_bold + test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso` + test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1` + test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2` + test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4` + test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5` + } + fi + } + + require_term_colors=: +} + + +## ----------------- ## +## Function library. ## +## ----------------- ## + +# This section contains a variety of useful functions to call in your +# scripts. Take note of the portable wrappers for features provided by +# some modern shells, which will fall back to slower equivalents on +# less featureful shells. + + +# func_append VAR VALUE +# --------------------- +# Append VALUE onto the existing contents of VAR. + + # _G_HAVE_PLUSEQ_OP + # Can be empty, in which case the shell is probed, "yes" if += is + # useable or anything else if it does not work. + if test -z "$_G_HAVE_PLUSEQ_OP" && \ + __PLUSEQ_TEST="a" && \ + __PLUSEQ_TEST+=" b" 2>/dev/null && \ + test "a b" = "$__PLUSEQ_TEST"; then + _G_HAVE_PLUSEQ_OP=yes + fi + +if test yes = "$_G_HAVE_PLUSEQ_OP" +then + # This is an XSI compatible shell, allowing a faster implementation... + eval 'func_append () + { + $debug_cmd + + eval "$1+=\$2" + }' +else + # ...otherwise fall back to using expr, which is often a shell builtin. + func_append () + { + $debug_cmd + + eval "$1=\$$1\$2" + } +fi + + +# func_append_quoted VAR VALUE +# ---------------------------- +# Quote VALUE and append to the end of shell variable VAR, separated +# by a space. +if test yes = "$_G_HAVE_PLUSEQ_OP"; then + eval 'func_append_quoted () + { + $debug_cmd + + func_quote_arg pretty "$2" + eval "$1+=\\ \$func_quote_arg_result" + }' +else + func_append_quoted () + { + $debug_cmd + + func_quote_arg pretty "$2" + eval "$1=\$$1\\ \$func_quote_arg_result" + } +fi + + +# func_append_uniq VAR VALUE +# -------------------------- +# Append unique VALUE onto the existing contents of VAR, assuming +# entries are delimited by the first character of VALUE. For example: +# +# func_append_uniq options " --another-option option-argument" +# +# will only append to $options if " --another-option option-argument " +# is not already present somewhere in $options already (note spaces at +# each end implied by leading space in second argument). +func_append_uniq () +{ + $debug_cmd + + eval _G_current_value='`$ECHO $'$1'`' + _G_delim=`expr "$2" : '\(.\)'` + + case $_G_delim$_G_current_value$_G_delim in + *"$2$_G_delim"*) ;; + *) func_append "$@" ;; + esac +} + + +# func_arith TERM... +# ------------------ +# Set func_arith_result to the result of evaluating TERMs. + test -z "$_G_HAVE_ARITH_OP" \ + && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \ + && _G_HAVE_ARITH_OP=yes + +if test yes = "$_G_HAVE_ARITH_OP"; then + eval 'func_arith () + { + $debug_cmd + + func_arith_result=$(( $* )) + }' +else + func_arith () + { + $debug_cmd + + func_arith_result=`expr "$@"` + } +fi + + +# func_basename FILE +# ------------------ +# Set func_basename_result to FILE with everything up to and including +# the last / stripped. +if test yes = "$_G_HAVE_XSI_OPS"; then + # If this shell supports suffix pattern removal, then use it to avoid + # forking. Hide the definitions single quotes in case the shell chokes + # on unsupported syntax... + _b='func_basename_result=${1##*/}' + _d='case $1 in + */*) func_dirname_result=${1%/*}$2 ;; + * ) func_dirname_result=$3 ;; + esac' + +else + # ...otherwise fall back to using sed. + _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`' + _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"` + if test "X$func_dirname_result" = "X$1"; then + func_dirname_result=$3 + else + func_append func_dirname_result "$2" + fi' +fi + +eval 'func_basename () +{ + $debug_cmd + + '"$_b"' +}' + + +# func_dirname FILE APPEND NONDIR_REPLACEMENT +# ------------------------------------------- +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +eval 'func_dirname () +{ + $debug_cmd + + '"$_d"' +}' + + +# func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT +# -------------------------------------------------------- +# Perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# For efficiency, we do not delegate to the functions above but instead +# duplicate the functionality here. +eval 'func_dirname_and_basename () +{ + $debug_cmd + + '"$_b"' + '"$_d"' +}' + + +# func_echo ARG... +# ---------------- +# Echo program name prefixed message. +func_echo () +{ + $debug_cmd + + _G_message=$* + + func_echo_IFS=$IFS + IFS=$nl + for _G_line in $_G_message; do + IFS=$func_echo_IFS + $ECHO "$progname: $_G_line" + done + IFS=$func_echo_IFS +} + + +# func_echo_all ARG... +# -------------------- +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + + +# func_echo_infix_1 INFIX ARG... +# ------------------------------ +# Echo program name, followed by INFIX on the first line, with any +# additional lines not showing INFIX. +func_echo_infix_1 () +{ + $debug_cmd + + $require_term_colors + + _G_infix=$1; shift + _G_indent=$_G_infix + _G_prefix="$progname: $_G_infix: " + _G_message=$* + + # Strip color escape sequences before counting printable length + for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan" + do + test -n "$_G_tc" && { + _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"` + _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"` + } + done + _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes + + func_echo_infix_1_IFS=$IFS + IFS=$nl + for _G_line in $_G_message; do + IFS=$func_echo_infix_1_IFS + $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2 + _G_prefix=$_G_indent + done + IFS=$func_echo_infix_1_IFS +} + + +# func_error ARG... +# ----------------- +# Echo program name prefixed message to standard error. +func_error () +{ + $debug_cmd + + $require_term_colors + + func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2 +} + + +# func_fatal_error ARG... +# ----------------------- +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + $debug_cmd + + func_error "$*" + exit $EXIT_FAILURE +} + + +# func_grep EXPRESSION FILENAME +# ----------------------------- +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $debug_cmd + + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_len STRING +# --------------- +# Set func_len_result to the length of STRING. STRING may not +# start with a hyphen. + test -z "$_G_HAVE_XSI_OPS" \ + && (eval 'x=a/b/c; + test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ + && _G_HAVE_XSI_OPS=yes + +if test yes = "$_G_HAVE_XSI_OPS"; then + eval 'func_len () + { + $debug_cmd + + func_len_result=${#1} + }' +else + func_len () + { + $debug_cmd + + func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` + } +fi + + +# func_mkdir_p DIRECTORY-PATH +# --------------------------- +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + $debug_cmd + + _G_directory_path=$1 + _G_dir_list= + + if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then + + # Protect directory names starting with '-' + case $_G_directory_path in + -*) _G_directory_path=./$_G_directory_path ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$_G_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + _G_dir_list=$_G_directory_path:$_G_dir_list + + # If the last portion added has no slash in it, the list is done + case $_G_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"` + done + _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'` + + func_mkdir_p_IFS=$IFS; IFS=: + for _G_dir in $_G_dir_list; do + IFS=$func_mkdir_p_IFS + # mkdir can fail with a 'File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$_G_dir" 2>/dev/null || : + done + IFS=$func_mkdir_p_IFS + + # Bail out if we (or some other process) failed to create a directory. + test -d "$_G_directory_path" || \ + func_fatal_error "Failed to create '$1'" + fi +} + + +# func_mktempdir [BASENAME] +# ------------------------- +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, BASENAME is the basename for that directory. +func_mktempdir () +{ + $debug_cmd + + _G_template=${TMPDIR-/tmp}/${1-$progname} + + if test : = "$opt_dry_run"; then + # Return a directory name, but don't create it in dry-run mode + _G_tmpdir=$_G_template-$$ + else + + # If mktemp works, use that first and foremost + _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null` + + if test ! -d "$_G_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + _G_tmpdir=$_G_template-${RANDOM-0}$$ + + func_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$_G_tmpdir" + umask $func_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$_G_tmpdir" || \ + func_fatal_error "cannot create temporary directory '$_G_tmpdir'" + fi + + $ECHO "$_G_tmpdir" +} + + +# func_normal_abspath PATH +# ------------------------ +# Remove doubled-up and trailing slashes, "." path components, +# and cancel out any ".." path components in PATH after making +# it an absolute path. +func_normal_abspath () +{ + $debug_cmd + + # These SED scripts presuppose an absolute path with a trailing slash. + _G_pathcar='s|^/\([^/]*\).*$|\1|' + _G_pathcdr='s|^/[^/]*||' + _G_removedotparts=':dotsl + s|/\./|/|g + t dotsl + s|/\.$|/|' + _G_collapseslashes='s|/\{1,\}|/|g' + _G_finalslash='s|/*$|/|' + + # Start from root dir and reassemble the path. + func_normal_abspath_result= + func_normal_abspath_tpath=$1 + func_normal_abspath_altnamespace= + case $func_normal_abspath_tpath in + "") + # Empty path, that just means $cwd. + func_stripname '' '/' "`pwd`" + func_normal_abspath_result=$func_stripname_result + return + ;; + # The next three entries are used to spot a run of precisely + # two leading slashes without using negated character classes; + # we take advantage of case's first-match behaviour. + ///*) + # Unusual form of absolute path, do nothing. + ;; + //*) + # Not necessarily an ordinary path; POSIX reserves leading '//' + # and for example Cygwin uses it to access remote file shares + # over CIFS/SMB, so we conserve a leading double slash if found. + func_normal_abspath_altnamespace=/ + ;; + /*) + # Absolute path, do nothing. + ;; + *) + # Relative path, prepend $cwd. + func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath + ;; + esac + + # Cancel out all the simple stuff to save iterations. We also want + # the path to end with a slash for ease of parsing, so make sure + # there is one (and only one) here. + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"` + while :; do + # Processed it all yet? + if test / = "$func_normal_abspath_tpath"; then + # If we ascended to the root using ".." the result may be empty now. + if test -z "$func_normal_abspath_result"; then + func_normal_abspath_result=/ + fi + break + fi + func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$_G_pathcar"` + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$_G_pathcdr"` + # Figure out what to do with it + case $func_normal_abspath_tcomponent in + "") + # Trailing empty path component, ignore it. + ;; + ..) + # Parent dir; strip last assembled component from result. + func_dirname "$func_normal_abspath_result" + func_normal_abspath_result=$func_dirname_result + ;; + *) + # Actual path component, append it. + func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent" + ;; + esac + done + # Restore leading double-slash if one was found on entry. + func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result +} + + +# func_notquiet ARG... +# -------------------- +# Echo program name prefixed message only when not in quiet mode. +func_notquiet () +{ + $debug_cmd + + $opt_quiet || func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + + +# func_relative_path SRCDIR DSTDIR +# -------------------------------- +# Set func_relative_path_result to the relative path from SRCDIR to DSTDIR. +func_relative_path () +{ + $debug_cmd + + func_relative_path_result= + func_normal_abspath "$1" + func_relative_path_tlibdir=$func_normal_abspath_result + func_normal_abspath "$2" + func_relative_path_tbindir=$func_normal_abspath_result + + # Ascend the tree starting from libdir + while :; do + # check if we have found a prefix of bindir + case $func_relative_path_tbindir in + $func_relative_path_tlibdir) + # found an exact match + func_relative_path_tcancelled= + break + ;; + $func_relative_path_tlibdir*) + # found a matching prefix + func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" + func_relative_path_tcancelled=$func_stripname_result + if test -z "$func_relative_path_result"; then + func_relative_path_result=. + fi + break + ;; + *) + func_dirname $func_relative_path_tlibdir + func_relative_path_tlibdir=$func_dirname_result + if test -z "$func_relative_path_tlibdir"; then + # Have to descend all the way to the root! + func_relative_path_result=../$func_relative_path_result + func_relative_path_tcancelled=$func_relative_path_tbindir + break + fi + func_relative_path_result=../$func_relative_path_result + ;; + esac + done + + # Now calculate path; take care to avoid doubling-up slashes. + func_stripname '' '/' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + func_stripname '/' '/' "$func_relative_path_tcancelled" + if test -n "$func_stripname_result"; then + func_append func_relative_path_result "/$func_stripname_result" + fi + + # Normalisation. If bindir is libdir, return '.' else relative path. + if test -n "$func_relative_path_result"; then + func_stripname './' '' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + fi + + test -n "$func_relative_path_result" || func_relative_path_result=. + + : +} + + +# func_quote_portable EVAL ARG +# ---------------------------- +# Internal function to portably implement func_quote_arg. Note that we still +# keep attention to performance here so we as much as possible try to avoid +# calling sed binary (so far O(N) complexity as long as func_append is O(1)). +func_quote_portable () +{ + $debug_cmd + + $require_check_ifs_backslash + + func_quote_portable_result=$2 + + # one-time-loop (easy break) + while true + do + if $1; then + func_quote_portable_result=`$ECHO "$2" | $SED \ + -e "$sed_double_quote_subst" -e "$sed_double_backslash"` + break + fi + + # Quote for eval. + case $func_quote_portable_result in + *[\\\`\"\$]*) + # Fallback to sed for $func_check_bs_ifs_broken=:, or when the string + # contains the shell wildcard characters. + case $check_ifs_backshlash_broken$func_quote_portable_result in + :*|*[\[\*\?]*) + func_quote_portable_result=`$ECHO "$func_quote_portable_result" \ + | $SED "$sed_quote_subst"` + break + ;; + esac + + func_quote_portable_old_IFS=$IFS + for _G_char in '\' '`' '"' '$' + do + # STATE($1) PREV($2) SEPARATOR($3) + set start "" "" + func_quote_portable_result=dummy"$_G_char$func_quote_portable_result$_G_char"dummy + IFS=$_G_char + for _G_part in $func_quote_portable_result + do + case $1 in + quote) + func_append func_quote_portable_result "$3$2" + set quote "$_G_part" "\\$_G_char" + ;; + start) + set first "" "" + func_quote_portable_result= + ;; + first) + set quote "$_G_part" "" + ;; + esac + done + done + IFS=$func_quote_portable_old_IFS + ;; + *) ;; + esac + break + done + + func_quote_portable_unquoted_result=$func_quote_portable_result + case $func_quote_portable_result in + # double-quote args containing shell metacharacters to delay + # word splitting, command substitution and variable expansion + # for a subsequent eval. + # many bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_portable_result=\"$func_quote_portable_result\" + ;; + esac +} + + +# func_quotefast_eval ARG +# ----------------------- +# Quote one ARG (internal). This is equivalent to 'func_quote_arg eval ARG', +# but optimized for speed. Result is stored in $func_quotefast_eval. +if test xyes = `(x=; printf -v x %q yes; echo x"$x") 2>/dev/null`; then + printf -v _GL_test_printf_tilde %q '~' + if test '\~' = "$_GL_test_printf_tilde"; then + func_quotefast_eval () + { + printf -v func_quotefast_eval_result %q "$1" + } + else + # Broken older Bash implementations. Make those faster too if possible. + func_quotefast_eval () + { + case $1 in + '~'*) + func_quote_portable false "$1" + func_quotefast_eval_result=$func_quote_portable_result + ;; + *) + printf -v func_quotefast_eval_result %q "$1" + ;; + esac + } + fi +else + func_quotefast_eval () + { + func_quote_portable false "$1" + func_quotefast_eval_result=$func_quote_portable_result + } +fi + + +# func_quote_arg MODEs ARG +# ------------------------ +# Quote one ARG to be evaled later. MODEs argument may contain zero or more +# specifiers listed below separated by ',' character. This function returns two +# values: +# i) func_quote_arg_result +# double-quoted (when needed), suitable for a subsequent eval +# ii) func_quote_arg_unquoted_result +# has all characters that are still active within double +# quotes backslashified. Available only if 'unquoted' is specified. +# +# Available modes: +# ---------------- +# 'eval' (default) +# - escape shell special characters +# 'expand' +# - the same as 'eval'; but do not quote variable references +# 'pretty' +# - request aesthetic output, i.e. '"a b"' instead of 'a\ b'. This might +# be used later in func_quote to get output like: 'echo "a b"' instead +# of 'echo a\ b'. This is slower than default on some shells. +# 'unquoted' +# - produce also $func_quote_arg_unquoted_result which does not contain +# wrapping double-quotes. +# +# Examples for 'func_quote_arg pretty,unquoted string': +# +# string | *_result | *_unquoted_result +# ------------+-----------------------+------------------- +# " | \" | \" +# a b | "a b" | a b +# "a b" | "\"a b\"" | \"a b\" +# * | "*" | * +# z="${x-$y}" | "z=\"\${x-\$y}\"" | z=\"\${x-\$y}\" +# +# Examples for 'func_quote_arg pretty,unquoted,expand string': +# +# string | *_result | *_unquoted_result +# --------------+---------------------+-------------------- +# z="${x-$y}" | "z=\"${x-$y}\"" | z=\"${x-$y}\" +func_quote_arg () +{ + _G_quote_expand=false + case ,$1, in + *,expand,*) + _G_quote_expand=: + ;; + esac + + case ,$1, in + *,pretty,*|*,expand,*|*,unquoted,*) + func_quote_portable $_G_quote_expand "$2" + func_quote_arg_result=$func_quote_portable_result + func_quote_arg_unquoted_result=$func_quote_portable_unquoted_result + ;; + *) + # Faster quote-for-eval for some shells. + func_quotefast_eval "$2" + func_quote_arg_result=$func_quotefast_eval_result + ;; + esac +} + + +# func_quote MODEs ARGs... +# ------------------------ +# Quote all ARGs to be evaled later and join them into single command. See +# func_quote_arg's description for more info. +func_quote () +{ + $debug_cmd + _G_func_quote_mode=$1 ; shift + func_quote_result= + while test 0 -lt $#; do + func_quote_arg "$_G_func_quote_mode" "$1" + if test -n "$func_quote_result"; then + func_append func_quote_result " $func_quote_arg_result" + else + func_append func_quote_result "$func_quote_arg_result" + fi + shift + done +} + + +# func_stripname PREFIX SUFFIX NAME +# --------------------------------- +# strip PREFIX and SUFFIX from NAME, and store in func_stripname_result. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +if test yes = "$_G_HAVE_XSI_OPS"; then + eval 'func_stripname () + { + $debug_cmd + + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary variable first. + func_stripname_result=$3 + func_stripname_result=${func_stripname_result#"$1"} + func_stripname_result=${func_stripname_result%"$2"} + }' +else + func_stripname () + { + $debug_cmd + + case $2 in + .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;; + *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;; + esac + } +fi + + +# func_show_eval CMD [FAIL_EXP] +# ----------------------------- +# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + $debug_cmd + + _G_cmd=$1 + _G_fail_exp=${2-':'} + + func_quote_arg pretty,expand "$_G_cmd" + eval "func_notquiet $func_quote_arg_result" + + $opt_dry_run || { + eval "$_G_cmd" + _G_status=$? + if test 0 -ne "$_G_status"; then + eval "(exit $_G_status); $_G_fail_exp" + fi + } +} + + +# func_show_eval_locale CMD [FAIL_EXP] +# ------------------------------------ +# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + $debug_cmd + + _G_cmd=$1 + _G_fail_exp=${2-':'} + + $opt_quiet || { + func_quote_arg expand,pretty "$_G_cmd" + eval "func_echo $func_quote_arg_result" + } + + $opt_dry_run || { + eval "$_G_user_locale + $_G_cmd" + _G_status=$? + eval "$_G_safe_locale" + if test 0 -ne "$_G_status"; then + eval "(exit $_G_status); $_G_fail_exp" + fi + } +} + + +# func_tr_sh +# ---------- +# Turn $1 into a string suitable for a shell variable name. +# Result is stored in $func_tr_sh_result. All characters +# not in the set a-zA-Z0-9_ are replaced with '_'. Further, +# if $1 begins with a digit, a '_' is prepended as well. +func_tr_sh () +{ + $debug_cmd + + case $1 in + [0-9]* | *[!a-zA-Z0-9_]*) + func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'` + ;; + * ) + func_tr_sh_result=$1 + ;; + esac +} + + +# func_verbose ARG... +# ------------------- +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $debug_cmd + + $opt_verbose && func_echo "$*" + + : +} + + +# func_warn_and_continue ARG... +# ----------------------------- +# Echo program name prefixed warning message to standard error. +func_warn_and_continue () +{ + $debug_cmd + + $require_term_colors + + func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2 +} + + +# func_warning CATEGORY ARG... +# ---------------------------- +# Echo program name prefixed warning message to standard error. Warning +# messages can be filtered according to CATEGORY, where this function +# elides messages where CATEGORY is not listed in the global variable +# 'opt_warning_types'. +func_warning () +{ + $debug_cmd + + # CATEGORY must be in the warning_categories list! + case " $warning_categories " in + *" $1 "*) ;; + *) func_internal_error "invalid warning category '$1'" ;; + esac + + _G_category=$1 + shift + + case " $opt_warning_types " in + *" $_G_category "*) $warning_func ${1+"$@"} ;; + esac +} + + +# func_sort_ver VER1 VER2 +# ----------------------- +# 'sort -V' is not generally available. +# Note this deviates from the version comparison in automake +# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a +# but this should suffice as we won't be specifying old +# version formats or redundant trailing .0 in bootstrap.conf. +# If we did want full compatibility then we should probably +# use m4_version_compare from autoconf. +func_sort_ver () +{ + $debug_cmd + + printf '%s\n%s\n' "$1" "$2" \ + | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n +} + +# func_lt_ver PREV CURR +# --------------------- +# Return true if PREV and CURR are in the correct order according to +# func_sort_ver, otherwise false. Use it like this: +# +# func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..." +func_lt_ver () +{ + $debug_cmd + + test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q` +} + + +# Local variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" +# time-stamp-time-zone: "UTC" +# End: +#! /bin/sh + +# A portable, pluggable option parser for Bourne shell. +# Written by Gary V. Vaughan, 2010 + +# This is free software. There is NO warranty; not even for +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Copyright (C) 2010-2019, 2021 Bootstrap Authors +# +# This file is dual licensed under the terms of the MIT license +# <https://opensource.org/license/MIT>, and GPL version 2 or later +# <http://www.gnu.org/licenses/gpl-2.0.html>. You must apply one of +# these licenses when using or redistributing this software or any of +# the files within it. See the URLs above, or the file `LICENSE` +# included in the Bootstrap distribution for the full license texts. + +# Please report bugs or propose patches to: +# <https://github.com/gnulib-modules/bootstrap/issues> + +# Set a version string for this script. +scriptversion=2019-02-19.15; # UTC + + +## ------ ## +## Usage. ## +## ------ ## + +# This file is a library for parsing options in your shell scripts along +# with assorted other useful supporting features that you can make use +# of too. +# +# For the simplest scripts you might need only: +# +# #!/bin/sh +# . relative/path/to/funclib.sh +# . relative/path/to/options-parser +# scriptversion=1.0 +# func_options ${1+"$@"} +# eval set dummy "$func_options_result"; shift +# ...rest of your script... +# +# In order for the '--version' option to work, you will need to have a +# suitably formatted comment like the one at the top of this file +# starting with '# Written by ' and ending with '# Copyright'. +# +# For '-h' and '--help' to work, you will also need a one line +# description of your script's purpose in a comment directly above the +# '# Written by ' line, like the one at the top of this file. +# +# The default options also support '--debug', which will turn on shell +# execution tracing (see the comment above debug_cmd below for another +# use), and '--verbose' and the func_verbose function to allow your script +# to display verbose messages only when your user has specified +# '--verbose'. +# +# After sourcing this file, you can plug in processing for additional +# options by amending the variables from the 'Configuration' section +# below, and following the instructions in the 'Option parsing' +# section further down. + +## -------------- ## +## Configuration. ## +## -------------- ## + +# You should override these variables in your script after sourcing this +# file so that they reflect the customisations you have added to the +# option parser. + +# The usage line for option parsing errors and the start of '-h' and +# '--help' output messages. You can embed shell variables for delayed +# expansion at the time the message is displayed, but you will need to +# quote other shell meta-characters carefully to prevent them being +# expanded when the contents are evaled. +usage='$progpath [OPTION]...' + +# Short help message in response to '-h' and '--help'. Add to this or +# override it after sourcing this library to reflect the full set of +# options your script accepts. +usage_message="\ + --debug enable verbose shell tracing + -W, --warnings=CATEGORY + report the warnings falling in CATEGORY [all] + -v, --verbose verbosely report processing + --version print version information and exit + -h, --help print short or long help message and exit +" + +# Additional text appended to 'usage_message' in response to '--help'. +long_help_message=" +Warning categories include: + 'all' show all warnings + 'none' turn off all the warnings + 'error' warnings are treated as fatal errors" + +# Help message printed before fatal option parsing errors. +fatal_help="Try '\$progname --help' for more information." + + + +## ------------------------- ## +## Hook function management. ## +## ------------------------- ## + +# This section contains functions for adding, removing, and running hooks +# in the main code. A hook is just a list of function names that can be +# run in order later on. + +# func_hookable FUNC_NAME +# ----------------------- +# Declare that FUNC_NAME will run hooks added with +# 'func_add_hook FUNC_NAME ...'. +func_hookable () +{ + $debug_cmd + + func_append hookable_fns " $1" +} + + +# func_add_hook FUNC_NAME HOOK_FUNC +# --------------------------------- +# Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must +# first have been declared "hookable" by a call to 'func_hookable'. +func_add_hook () +{ + $debug_cmd + + case " $hookable_fns " in + *" $1 "*) ;; + *) func_fatal_error "'$1' does not accept hook functions." ;; + esac + + eval func_append ${1}_hooks '" $2"' +} + + +# func_remove_hook FUNC_NAME HOOK_FUNC +# ------------------------------------ +# Remove HOOK_FUNC from the list of hook functions to be called by +# FUNC_NAME. +func_remove_hook () +{ + $debug_cmd + + eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`' +} + + +# func_propagate_result FUNC_NAME_A FUNC_NAME_B +# --------------------------------------------- +# If the *_result variable of FUNC_NAME_A _is set_, assign its value to +# *_result variable of FUNC_NAME_B. +func_propagate_result () +{ + $debug_cmd + + func_propagate_result_result=: + if eval "test \"\${${1}_result+set}\" = set" + then + eval "${2}_result=\$${1}_result" + else + func_propagate_result_result=false + fi +} + + +# func_run_hooks FUNC_NAME [ARG]... +# --------------------------------- +# Run all hook functions registered to FUNC_NAME. +# It's assumed that the list of hook functions contains nothing more +# than a whitespace-delimited list of legal shell function names, and +# no effort is wasted trying to catch shell meta-characters or preserve +# whitespace. +func_run_hooks () +{ + $debug_cmd + + _G_rc_run_hooks=false + + case " $hookable_fns " in + *" $1 "*) ;; + *) func_fatal_error "'$1' does not support hook functions." ;; + esac + + eval _G_hook_fns=\$$1_hooks; shift + + for _G_hook in $_G_hook_fns; do + func_unset "${_G_hook}_result" + eval $_G_hook '${1+"$@"}' + func_propagate_result $_G_hook func_run_hooks + if $func_propagate_result_result; then + eval set dummy "$func_run_hooks_result"; shift + fi + done +} + + + +## --------------- ## +## Option parsing. ## +## --------------- ## + +# In order to add your own option parsing hooks, you must accept the +# full positional parameter list from your hook function. You may remove +# or edit any options that you action, and then pass back the remaining +# unprocessed options in '<hooked_function_name>_result', escaped +# suitably for 'eval'. +# +# The '<hooked_function_name>_result' variable is automatically unset +# before your hook gets called; for best performance, only set the +# *_result variable when necessary (i.e. don't call the 'func_quote' +# function unnecessarily because it can be an expensive operation on some +# machines). +# +# Like this: +# +# my_options_prep () +# { +# $debug_cmd +# +# # Extend the existing usage message. +# usage_message=$usage_message' +# -s, --silent don'\''t print informational messages +# ' +# # No change in '$@' (ignored completely by this hook). Leave +# # my_options_prep_result variable intact. +# } +# func_add_hook func_options_prep my_options_prep +# +# +# my_silent_option () +# { +# $debug_cmd +# +# args_changed=false +# +# # Note that, for efficiency, we parse as many options as we can +# # recognise in a loop before passing the remainder back to the +# # caller on the first unrecognised argument we encounter. +# while test $# -gt 0; do +# opt=$1; shift +# case $opt in +# --silent|-s) opt_silent=: +# args_changed=: +# ;; +# # Separate non-argument short options: +# -s*) func_split_short_opt "$_G_opt" +# set dummy "$func_split_short_opt_name" \ +# "-$func_split_short_opt_arg" ${1+"$@"} +# shift +# args_changed=: +# ;; +# *) # Make sure the first unrecognised option "$_G_opt" +# # is added back to "$@" in case we need it later, +# # if $args_changed was set to 'true'. +# set dummy "$_G_opt" ${1+"$@"}; shift; break ;; +# esac +# done +# +# # Only call 'func_quote' here if we processed at least one argument. +# if $args_changed; then +# func_quote eval ${1+"$@"} +# my_silent_option_result=$func_quote_result +# fi +# } +# func_add_hook func_parse_options my_silent_option +# +# +# my_option_validation () +# { +# $debug_cmd +# +# $opt_silent && $opt_verbose && func_fatal_help "\ +# '--silent' and '--verbose' options are mutually exclusive." +# } +# func_add_hook func_validate_options my_option_validation +# +# You'll also need to manually amend $usage_message to reflect the extra +# options you parse. It's preferable to append if you can, so that +# multiple option parsing hooks can be added safely. + + +# func_options_finish [ARG]... +# ---------------------------- +# Finishing the option parse loop (call 'func_options' hooks ATM). +func_options_finish () +{ + $debug_cmd + + func_run_hooks func_options ${1+"$@"} + func_propagate_result func_run_hooks func_options_finish +} + + +# func_options [ARG]... +# --------------------- +# All the functions called inside func_options are hookable. See the +# individual implementations for details. +func_hookable func_options +func_options () +{ + $debug_cmd + + _G_options_quoted=false + + for my_func in options_prep parse_options validate_options options_finish + do + func_unset func_${my_func}_result + func_unset func_run_hooks_result + eval func_$my_func '${1+"$@"}' + func_propagate_result func_$my_func func_options + if $func_propagate_result_result; then + eval set dummy "$func_options_result"; shift + _G_options_quoted=: + fi + done + + $_G_options_quoted || { + # As we (func_options) are top-level options-parser function and + # nobody quoted "$@" for us yet, we need to do it explicitly for + # caller. + func_quote eval ${1+"$@"} + func_options_result=$func_quote_result + } +} + + +# func_options_prep [ARG]... +# -------------------------- +# All initialisations required before starting the option parse loop. +# Note that when calling hook functions, we pass through the list of +# positional parameters. If a hook function modifies that list, and +# needs to propagate that back to rest of this script, then the complete +# modified list must be put in 'func_run_hooks_result' before returning. +func_hookable func_options_prep +func_options_prep () +{ + $debug_cmd + + # Option defaults: + opt_verbose=false + opt_warning_types= + + func_run_hooks func_options_prep ${1+"$@"} + func_propagate_result func_run_hooks func_options_prep +} + + +# func_parse_options [ARG]... +# --------------------------- +# The main option parsing loop. +func_hookable func_parse_options +func_parse_options () +{ + $debug_cmd + + _G_parse_options_requote=false + # this just eases exit handling + while test $# -gt 0; do + # Defer to hook functions for initial option parsing, so they + # get priority in the event of reusing an option name. + func_run_hooks func_parse_options ${1+"$@"} + func_propagate_result func_run_hooks func_parse_options + if $func_propagate_result_result; then + eval set dummy "$func_parse_options_result"; shift + # Even though we may have changed "$@", we passed the "$@" array + # down into the hook and it quoted it for us (because we are in + # this if-branch). No need to quote it again. + _G_parse_options_requote=false + fi + + # Break out of the loop if we already parsed every option. + test $# -gt 0 || break + + # We expect that one of the options parsed in this function matches + # and thus we remove _G_opt from "$@" and need to re-quote. + _G_match_parse_options=: + _G_opt=$1 + shift + case $_G_opt in + --debug|-x) debug_cmd='set -x' + func_echo "enabling shell trace mode" >&2 + $debug_cmd + ;; + + --no-warnings|--no-warning|--no-warn) + set dummy --warnings none ${1+"$@"} + shift + ;; + + --warnings|--warning|-W) + if test $# = 0 && func_missing_arg $_G_opt; then + _G_parse_options_requote=: + break + fi + case " $warning_categories $1" in + *" $1 "*) + # trailing space prevents matching last $1 above + func_append_uniq opt_warning_types " $1" + ;; + *all) + opt_warning_types=$warning_categories + ;; + *none) + opt_warning_types=none + warning_func=: + ;; + *error) + opt_warning_types=$warning_categories + warning_func=func_fatal_error + ;; + *) + func_fatal_error \ + "unsupported warning category: '$1'" + ;; + esac + shift + ;; + + --verbose|-v) opt_verbose=: ;; + --version) func_version ;; + -\?|-h) func_usage ;; + --help) func_help ;; + + # Separate optargs to long options (plugins may need this): + --*=*) func_split_equals "$_G_opt" + set dummy "$func_split_equals_lhs" \ + "$func_split_equals_rhs" ${1+"$@"} + shift + ;; + + # Separate optargs to short options: + -W*) + func_split_short_opt "$_G_opt" + set dummy "$func_split_short_opt_name" \ + "$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + # Separate non-argument short options: + -\?*|-h*|-v*|-x*) + func_split_short_opt "$_G_opt" + set dummy "$func_split_short_opt_name" \ + "-$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + --) _G_parse_options_requote=: ; break ;; + -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; + *) set dummy "$_G_opt" ${1+"$@"}; shift + _G_match_parse_options=false + break + ;; + esac + + if $_G_match_parse_options; then + _G_parse_options_requote=: + fi + done + + if $_G_parse_options_requote; then + # save modified positional parameters for caller + func_quote eval ${1+"$@"} + func_parse_options_result=$func_quote_result + fi +} + + +# func_validate_options [ARG]... +# ------------------------------ +# Perform any sanity checks on option settings and/or unconsumed +# arguments. +func_hookable func_validate_options +func_validate_options () +{ + $debug_cmd + + # Display all warnings if -W was not given. + test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" + + func_run_hooks func_validate_options ${1+"$@"} + func_propagate_result func_run_hooks func_validate_options + + # Bail if the options were screwed! + $exit_cmd $EXIT_FAILURE +} + + + +## ----------------- ## +## Helper functions. ## +## ----------------- ## + +# This section contains the helper functions used by the rest of the +# hookable option parser framework in ascii-betical order. + + +# func_fatal_help ARG... +# ---------------------- +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + $debug_cmd + + eval \$ECHO \""Usage: $usage"\" + eval \$ECHO \""$fatal_help"\" + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + + +# func_help +# --------- +# Echo long help message to standard output and exit. +func_help () +{ + $debug_cmd + + func_usage_message + $ECHO "$long_help_message" + exit 0 +} + + +# func_missing_arg ARGNAME +# ------------------------ +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + $debug_cmd + + func_error "Missing argument for '$1'." + exit_cmd=exit +} + + +# func_split_equals STRING +# ------------------------ +# Set func_split_equals_lhs and func_split_equals_rhs shell variables +# after splitting STRING at the '=' sign. +test -z "$_G_HAVE_XSI_OPS" \ + && (eval 'x=a/b/c; + test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ + && _G_HAVE_XSI_OPS=yes + +if test yes = "$_G_HAVE_XSI_OPS" +then + # This is an XSI compatible shell, allowing a faster implementation... + eval 'func_split_equals () + { + $debug_cmd + + func_split_equals_lhs=${1%%=*} + func_split_equals_rhs=${1#*=} + if test "x$func_split_equals_lhs" = "x$1"; then + func_split_equals_rhs= + fi + }' +else + # ...otherwise fall back to using expr, which is often a shell builtin. + func_split_equals () + { + $debug_cmd + + func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'` + func_split_equals_rhs= + test "x$func_split_equals_lhs=" = "x$1" \ + || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'` + } +fi #func_split_equals + + +# func_split_short_opt SHORTOPT +# ----------------------------- +# Set func_split_short_opt_name and func_split_short_opt_arg shell +# variables after splitting SHORTOPT after the 2nd character. +if test yes = "$_G_HAVE_XSI_OPS" +then + # This is an XSI compatible shell, allowing a faster implementation... + eval 'func_split_short_opt () + { + $debug_cmd + + func_split_short_opt_arg=${1#??} + func_split_short_opt_name=${1%"$func_split_short_opt_arg"} + }' +else + # ...otherwise fall back to using expr, which is often a shell builtin. + func_split_short_opt () + { + $debug_cmd + + func_split_short_opt_name=`expr "x$1" : 'x\(-.\)'` + func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'` + } +fi #func_split_short_opt + + +# func_usage +# ---------- +# Echo short help message to standard output and exit. +func_usage () +{ + $debug_cmd + + func_usage_message + $ECHO "Run '$progname --help |${PAGER-more}' for full usage" + exit 0 +} + + +# func_usage_message +# ------------------ +# Echo short help message to standard output. +func_usage_message () +{ + $debug_cmd + + eval \$ECHO \""Usage: $usage"\" + echo + $SED -n 's|^# || + /^Written by/{ + x;p;x + } + h + /^Written by/q' < "$progpath" + echo + eval \$ECHO \""$usage_message"\" +} + + +# func_version +# ------------ +# Echo version message to standard output and exit. +# The version message is extracted from the calling file's header +# comments, with leading '# ' stripped: +# 1. First display the progname and version +# 2. Followed by the header comment line matching /^# Written by / +# 3. Then a blank line followed by the first following line matching +# /^# Copyright / +# 4. Immediately followed by any lines between the previous matches, +# except lines preceding the intervening completely blank line. +# For example, see the header comments of this file. +func_version () +{ + $debug_cmd + + printf '%s\n' "$progname $scriptversion" + $SED -n ' + /^# Written by /!b + s|^# ||; p; n + + :fwd2blnk + /./ { + n + b fwd2blnk + } + p; n + + :holdwrnt + s|^# || + s|^# *$|| + /^Copyright /!{ + /./H + n + b holdwrnt + } + + s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2| + G + s|\(\n\)\n*|\1|g + p; q' < "$progpath" + + exit $? +} + + +# Local variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-pattern: "30/scriptversion=%:y-%02m-%02d.%02H; # UTC" +# time-stamp-time-zone: "UTC" +# End: + +# Set a version string. +scriptversion='(GNU libtool) 2.4.7' + + +# func_echo ARG... +# ---------------- +# Libtool also displays the current mode in messages, so override +# funclib.sh func_echo with this custom definition. +func_echo () +{ + $debug_cmd + + _G_message=$* + + func_echo_IFS=$IFS + IFS=$nl + for _G_line in $_G_message; do + IFS=$func_echo_IFS + $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line" + done + IFS=$func_echo_IFS +} + + +# func_warning ARG... +# ------------------- +# Libtool warnings are not categorized, so override funclib.sh +# func_warning with this simpler definition. +func_warning () +{ + $debug_cmd + + $warning_func ${1+"$@"} +} + + +## ---------------- ## +## Options parsing. ## +## ---------------- ## + +# Hook in the functions to make sure our own options are parsed during +# the option parsing loop. + +usage='$progpath [OPTION]... [MODE-ARG]...' + +# Short help message in response to '-h'. +usage_message="Options: + --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 + --mode=MODE use operation mode MODE + --no-warnings equivalent to '-Wnone' + --preserve-dup-deps don't remove duplicate dependency libraries + --quiet, --silent don't print informational messages + --tag=TAG use configuration variables from tag TAG + -v, --verbose print more informational messages than default + --version print version information + -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] + -h, --help, --help-all print short, long, or detailed help message +" + +# Additional text appended to 'usage_message' in response to '--help'. +func_help () +{ + $debug_cmd + + func_usage_message + $ECHO "$long_help_message + +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. When passed as first option, +'--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that. +Try '$progname --help --mode=MODE' for a more detailed description of MODE. + +When reporting a bug, please describe a test case to reproduce it and +include the following information: + + host-triplet: $host + shell: $SHELL + compiler: $LTCC + compiler flags: $LTCFLAGS + linker: $LD (gnu? $with_gnu_ld) + version: $progname $scriptversion Debian-2.4.7-7 + automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` + autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` + +Report bugs to <bug-libtool@gnu.org>. +GNU libtool home page: <http://www.gnu.org/s/libtool/>. +General help using GNU software: <http://www.gnu.org/gethelp/>." + exit 0 +} + + +# func_lo2o OBJECT-NAME +# --------------------- +# Transform OBJECT-NAME from a '.lo' suffix to the platform specific +# object suffix. + +lo2o=s/\\.lo\$/.$objext/ +o2lo=s/\\.$objext\$/.lo/ + +if test yes = "$_G_HAVE_XSI_OPS"; then + eval 'func_lo2o () + { + case $1 in + *.lo) func_lo2o_result=${1%.lo}.$objext ;; + * ) func_lo2o_result=$1 ;; + esac + }' + + # func_xform LIBOBJ-OR-SOURCE + # --------------------------- + # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise) + # suffix to a '.lo' libtool-object suffix. + eval 'func_xform () + { + func_xform_result=${1%.*}.lo + }' +else + # ...otherwise fall back to using sed. + func_lo2o () + { + func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"` + } + + func_xform () + { + func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'` + } +fi + + +# func_fatal_configuration ARG... +# ------------------------------- +# Echo program name prefixed message to standard error, followed by +# a configuration failure hint, and exit. +func_fatal_configuration () +{ + func_fatal_error ${1+"$@"} \ + "See the $PACKAGE documentation for more information." \ + "Fatal configuration error." +} + + +# func_config +# ----------- +# Display the configuration for all the tags in this script. +func_config () +{ + re_begincf='^# ### BEGIN LIBTOOL' + re_endcf='^# ### END LIBTOOL' + + # Default configuration. + $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" + + # Now print the configurations for the tags. + for tagname in $taglist; do + $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" + done + + exit $? +} + + +# func_features +# ------------- +# Display the features supported by this script. +func_features () +{ + echo "host: $host" + if test yes = "$build_libtool_libs"; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test yes = "$build_old_libs"; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + + exit $? +} + + +# func_enable_tag TAGNAME +# ----------------------- +# Verify that TAGNAME is valid, and either flag an error and exit, or +# enable the TAGNAME tag. We also add TAGNAME to the global $taglist +# variable here. +func_enable_tag () +{ + # Global variable: + tagname=$1 + + re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" + re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" + sed_extractcf=/$re_begincf/,/$re_endcf/p + + # Validate tagname. + case $tagname in + *[!-_A-Za-z0-9,/]*) + func_fatal_error "invalid tag name: $tagname" + ;; + esac + + # Don't test for the "default" C tag, as we know it's + # there but not specially marked. + case $tagname in + CC) ;; + *) + if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + + +# func_check_version_match +# ------------------------ +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +# libtool_options_prep [ARG]... +# ----------------------------- +# Preparation for options parsed by libtool. +libtool_options_prep () +{ + $debug_mode + + # Option defaults: + opt_config=false + opt_dlopen= + opt_dry_run=false + opt_help=false + opt_mode= + opt_preserve_dup_deps=false + opt_quiet=false + + nonopt= + preserve_args= + + _G_rc_lt_options_prep=: + + _G_rc_lt_options_prep=: + + # Shorthand for --mode=foo, only valid as the first argument + case $1 in + clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; + compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; + execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; + finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; + install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; + link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; + uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; + *) + _G_rc_lt_options_prep=false + ;; + esac + + if $_G_rc_lt_options_prep; then + # Pass back the list of options. + func_quote eval ${1+"$@"} + libtool_options_prep_result=$func_quote_result + fi +} +func_add_hook func_options_prep libtool_options_prep + + +# libtool_parse_options [ARG]... +# --------------------------------- +# Provide handling for libtool specific options. +libtool_parse_options () +{ + $debug_cmd + + _G_rc_lt_parse_options=false + + # Perform our own loop to consume as many options as possible in + # each iteration. + while test $# -gt 0; do + _G_match_lt_parse_options=: + _G_opt=$1 + shift + case $_G_opt in + --dry-run|--dryrun|-n) + opt_dry_run=: + ;; + + --config) func_config ;; + + --dlopen|-dlopen) + opt_dlopen="${opt_dlopen+$opt_dlopen +}$1" + shift + ;; + + --preserve-dup-deps) + opt_preserve_dup_deps=: ;; + + --features) func_features ;; + + --finish) set dummy --mode finish ${1+"$@"}; shift ;; + + --help) opt_help=: ;; + + --help-all) opt_help=': help-all' ;; + + --mode) test $# = 0 && func_missing_arg $_G_opt && break + opt_mode=$1 + case $1 in + # Valid mode arguments: + clean|compile|execute|finish|install|link|relink|uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $_G_opt" + exit_cmd=exit + break + ;; + esac + shift + ;; + + --no-silent|--no-quiet) + opt_quiet=false + func_append preserve_args " $_G_opt" + ;; + + --no-warnings|--no-warning|--no-warn) + opt_warning=false + func_append preserve_args " $_G_opt" + ;; + + --no-verbose) + opt_verbose=false + func_append preserve_args " $_G_opt" + ;; + + --silent|--quiet) + opt_quiet=: + opt_verbose=false + func_append preserve_args " $_G_opt" + ;; + + --tag) test $# = 0 && func_missing_arg $_G_opt && break + opt_tag=$1 + func_append preserve_args " $_G_opt $1" + func_enable_tag "$1" + shift + ;; + + --verbose|-v) opt_quiet=false + opt_verbose=: + func_append preserve_args " $_G_opt" + ;; + + # An option not handled by this hook function: + *) set dummy "$_G_opt" ${1+"$@"} ; shift + _G_match_lt_parse_options=false + break + ;; + esac + $_G_match_lt_parse_options && _G_rc_lt_parse_options=: + done + + if $_G_rc_lt_parse_options; then + # save modified positional parameters for caller + func_quote eval ${1+"$@"} + libtool_parse_options_result=$func_quote_result + fi +} +func_add_hook func_parse_options libtool_parse_options + + + +# libtool_validate_options [ARG]... +# --------------------------------- +# Perform any sanity checks on option settings and/or unconsumed +# arguments. +libtool_validate_options () +{ + # save first non-option argument + if test 0 -lt $#; then + nonopt=$1 + shift + fi + + # preserve --debug + test : = "$debug_cmd" || func_append preserve_args " --debug" + + case $host in + # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452 + # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788 + *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps + ;; + esac + + $opt_help || { + # Sanity checks first: + func_check_version_match + + test yes != "$build_libtool_libs" \ + && test yes != "$build_old_libs" \ + && func_fatal_configuration "not configured to build any kind of library" + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$opt_dlopen" && test execute != "$opt_mode"; then + func_error "unrecognized option '-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help=$help + help="Try '$progname --help --mode=$opt_mode' for more information." + } + + # Pass back the unparsed argument list + func_quote eval ${1+"$@"} + libtool_validate_options_result=$func_quote_result +} +func_add_hook func_validate_options libtool_validate_options + + +# Process options as early as possible so that --help and --version +# can return quickly. +func_options ${1+"$@"} +eval set dummy "$func_options_result"; shift + + + +## ----------- ## +## Main. ## +## ----------- ## + +magic='%%%MAGIC variable%%%' +magic_exe='%%%MAGIC EXE variable%%%' + +# Global variables. +extracted_archives= +extracted_serial=0 + +# 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= + + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + +# func_generated_by_libtool +# True iff stdin has been generated by Libtool. This function is only +# a basic sanity check; it will hardly flush out determined imposters. +func_generated_by_libtool_p () +{ + $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_p file +# True iff FILE is a libtool '.la' library or '.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool '.la' library or '.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if 'file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case $lalib_p_line in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test yes = "$lalib_p" +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + test -f "$1" && + $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $debug_cmd + + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$sp$nl + eval cmd=\"$cmd\" + IFS=$save_ifs + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE 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. +func_source () +{ + $debug_cmd + + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_resolve_sysroot PATH +# Replace a leading = in PATH with a sysroot. Store the result into +# func_resolve_sysroot_result +func_resolve_sysroot () +{ + func_resolve_sysroot_result=$1 + case $func_resolve_sysroot_result in + =*) + func_stripname '=' '' "$func_resolve_sysroot_result" + func_resolve_sysroot_result=$lt_sysroot$func_stripname_result + ;; + esac +} + +# func_replace_sysroot PATH +# If PATH begins with the sysroot, replace it with = and +# store the result into func_replace_sysroot_result. +func_replace_sysroot () +{ + case $lt_sysroot:$1 in + ?*:"$lt_sysroot"*) + func_stripname "$lt_sysroot" '' "$1" + func_replace_sysroot_result='='$func_stripname_result + ;; + *) + # Including no sysroot. + func_replace_sysroot_result=$1 + ;; + esac +} + +# 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 () +{ + $debug_cmd + + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + 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 "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; + # 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. + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case "$@ " in + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) + # 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 + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with '--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=$1 + if test yes = "$build_libtool_libs"; then + write_lobj=\'$2\' + else + write_lobj=none + fi + + if test yes = "$build_old_libs"; then + write_oldobj=\'$3\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T <<EOF +# $write_libobj - a libtool object file +# Generated by $PROGRAM (GNU $PACKAGE) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object=$write_lobj + +# Name of the non-PIC object +non_pic_object=$write_oldobj + +EOF + $MV "${write_libobj}T" "$write_libobj" + } +} + + +################################################## +# FILE NAME AND PATH CONVERSION HELPER FUNCTIONS # +################################################## + +# func_convert_core_file_wine_to_w32 ARG +# Helper function used by file name conversion functions when $build is *nix, +# and $host is mingw, cygwin, or some other w32 environment. Relies on a +# correctly configured wine environment available, with the winepath program +# in $build's $PATH. +# +# ARG is the $build file name to be converted to w32 format. +# Result is available in $func_convert_core_file_wine_to_w32_result, and will +# be empty on error (or when ARG is empty) +func_convert_core_file_wine_to_w32 () +{ + $debug_cmd + + func_convert_core_file_wine_to_w32_result=$1 + if test -n "$1"; then + # Unfortunately, winepath does not exit with a non-zero error code, so we + # are forced to check the contents of stdout. On the other hand, if the + # command is not found, the shell will set an exit code of 127 and print + # *an error message* to stdout. So we must check for both error code of + # zero AND non-empty stdout, which explains the odd construction: + func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null` + if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then + func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | + $SED -e "$sed_naive_backslashify"` + else + func_convert_core_file_wine_to_w32_result= + fi + fi +} +# end: func_convert_core_file_wine_to_w32 + + +# func_convert_core_path_wine_to_w32 ARG +# Helper function used by path conversion functions when $build is *nix, and +# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly +# configured wine environment available, with the winepath program in $build's +# $PATH. Assumes ARG has no leading or trailing path separator characters. +# +# ARG is path to be converted from $build format to win32. +# Result is available in $func_convert_core_path_wine_to_w32_result. +# Unconvertible file (directory) names in ARG are skipped; if no directory names +# are convertible, then the result may be empty. +func_convert_core_path_wine_to_w32 () +{ + $debug_cmd + + # unfortunately, winepath doesn't convert paths, only file names + func_convert_core_path_wine_to_w32_result= + if test -n "$1"; then + oldIFS=$IFS + IFS=: + for func_convert_core_path_wine_to_w32_f in $1; do + IFS=$oldIFS + func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" + if test -n "$func_convert_core_file_wine_to_w32_result"; then + if test -z "$func_convert_core_path_wine_to_w32_result"; then + func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result + else + func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" + fi + fi + done + IFS=$oldIFS + fi +} +# end: func_convert_core_path_wine_to_w32 + + +# func_cygpath ARGS... +# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when +# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) +# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or +# (2), returns the Cygwin file name or path in func_cygpath_result (input +# file name or path is assumed to be in w32 format, as previously converted +# from $build's *nix or MSYS format). In case (3), returns the w32 file name +# or path in func_cygpath_result (input file name or path is assumed to be in +# Cygwin format). Returns an empty string on error. +# +# ARGS are passed to cygpath, with the last one being the file name or path to +# be converted. +# +# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH +# environment variable; do not put it in $PATH. +func_cygpath () +{ + $debug_cmd + + if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then + func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` + if test "$?" -ne 0; then + # on failure, ensure result is empty + func_cygpath_result= + fi + else + func_cygpath_result= + func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'" + fi +} +#end: func_cygpath + + +# func_convert_core_msys_to_w32 ARG +# Convert file name or path ARG from MSYS format to w32 format. Return +# result in func_convert_core_msys_to_w32_result. +func_convert_core_msys_to_w32 () +{ + $debug_cmd + + # awkward: cmd appends spaces to result + func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"` +} +#end: func_convert_core_msys_to_w32 + + +# func_convert_file_check ARG1 ARG2 +# Verify that ARG1 (a file name in $build format) was converted to $host +# format in ARG2. Otherwise, emit an error message, but continue (resetting +# func_to_host_file_result to ARG1). +func_convert_file_check () +{ + $debug_cmd + + if test -z "$2" && test -n "$1"; then + func_error "Could not determine host file name corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_file_result=$1 + fi +} +# end func_convert_file_check + + +# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH +# Verify that FROM_PATH (a path in $build format) was converted to $host +# format in TO_PATH. Otherwise, emit an error message, but continue, resetting +# func_to_host_file_result to a simplistic fallback value (see below). +func_convert_path_check () +{ + $debug_cmd + + if test -z "$4" && test -n "$3"; then + func_error "Could not determine the host path corresponding to" + func_error " '$3'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This is a deliberately simplistic "conversion" and + # should not be "improved". See libtool.info. + if test "x$1" != "x$2"; then + lt_replace_pathsep_chars="s|$1|$2|g" + func_to_host_path_result=`echo "$3" | + $SED -e "$lt_replace_pathsep_chars"` + else + func_to_host_path_result=$3 + fi + fi +} +# end func_convert_path_check + + +# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG +# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT +# and appending REPL if ORIG matches BACKPAT. +func_convert_path_front_back_pathsep () +{ + $debug_cmd + + case $4 in + $1 ) func_to_host_path_result=$3$func_to_host_path_result + ;; + esac + case $4 in + $2 ) func_append func_to_host_path_result "$3" + ;; + esac +} +# end func_convert_path_front_back_pathsep + + +################################################## +# $build to $host FILE NAME CONVERSION FUNCTIONS # +################################################## +# invoked via '$to_host_file_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# Result will be available in $func_to_host_file_result. + + +# func_to_host_file ARG +# Converts the file name ARG from $build format to $host format. Return result +# in func_to_host_file_result. +func_to_host_file () +{ + $debug_cmd + + $to_host_file_cmd "$1" +} +# end func_to_host_file + + +# func_to_tool_file ARG LAZY +# converts the file name ARG from $build format to toolchain format. Return +# result in func_to_tool_file_result. If the conversion in use is listed +# in (the comma separated) LAZY, no conversion takes place. +func_to_tool_file () +{ + $debug_cmd + + case ,$2, in + *,"$to_tool_file_cmd",*) + func_to_tool_file_result=$1 + ;; + *) + $to_tool_file_cmd "$1" + func_to_tool_file_result=$func_to_host_file_result + ;; + esac +} +# end func_to_tool_file + + +# func_convert_file_noop ARG +# Copy ARG to func_to_host_file_result. +func_convert_file_noop () +{ + func_to_host_file_result=$1 +} +# end func_convert_file_noop + + +# func_convert_file_msys_to_w32 ARG +# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_file_result. +func_convert_file_msys_to_w32 () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_to_host_file_result=$func_convert_core_msys_to_w32_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_w32 + + +# func_convert_file_cygwin_to_w32 ARG +# Convert file name ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_file_cygwin_to_w32 () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + # because $build is cygwin, we call "the" cygpath in $PATH; no need to use + # LT_CYGPATH in this case. + func_to_host_file_result=`cygpath -m "$1"` + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_cygwin_to_w32 + + +# func_convert_file_nix_to_w32 ARG +# Convert file name ARG from *nix to w32 format. Requires a wine environment +# and a working winepath. Returns result in func_to_host_file_result. +func_convert_file_nix_to_w32 () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + func_convert_core_file_wine_to_w32 "$1" + func_to_host_file_result=$func_convert_core_file_wine_to_w32_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_w32 + + +# func_convert_file_msys_to_cygwin ARG +# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_file_msys_to_cygwin () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_cygpath -u "$func_convert_core_msys_to_w32_result" + func_to_host_file_result=$func_cygpath_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_cygwin + + +# func_convert_file_nix_to_cygwin ARG +# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed +# in a wine environment, working winepath, and LT_CYGPATH set. Returns result +# in func_to_host_file_result. +func_convert_file_nix_to_cygwin () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. + func_convert_core_file_wine_to_w32 "$1" + func_cygpath -u "$func_convert_core_file_wine_to_w32_result" + func_to_host_file_result=$func_cygpath_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_cygwin + + +############################################# +# $build to $host PATH CONVERSION FUNCTIONS # +############################################# +# invoked via '$to_host_path_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# The result will be available in $func_to_host_path_result. +# +# Path separators are also converted from $build format to $host format. If +# ARG begins or ends with a path separator character, it is preserved (but +# converted to $host format) on output. +# +# All path conversion functions are named using the following convention: +# file name conversion function : func_convert_file_X_to_Y () +# path conversion function : func_convert_path_X_to_Y () +# where, for any given $build/$host combination the 'X_to_Y' value is the +# same. If conversion functions are added for new $build/$host combinations, +# the two new functions must follow this pattern, or func_init_to_host_path_cmd +# will break. + + +# func_init_to_host_path_cmd +# Ensures that function "pointer" variable $to_host_path_cmd is set to the +# appropriate value, based on the value of $to_host_file_cmd. +to_host_path_cmd= +func_init_to_host_path_cmd () +{ + $debug_cmd + + if test -z "$to_host_path_cmd"; then + func_stripname 'func_convert_file_' '' "$to_host_file_cmd" + to_host_path_cmd=func_convert_path_$func_stripname_result + fi +} + + +# func_to_host_path ARG +# Converts the path ARG from $build format to $host format. Return result +# in func_to_host_path_result. +func_to_host_path () +{ + $debug_cmd + + func_init_to_host_path_cmd + $to_host_path_cmd "$1" +} +# end func_to_host_path + + +# func_convert_path_noop ARG +# Copy ARG to func_to_host_path_result. +func_convert_path_noop () +{ + func_to_host_path_result=$1 +} +# end func_convert_path_noop + + +# func_convert_path_msys_to_w32 ARG +# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_path_result. +func_convert_path_msys_to_w32 () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # Remove leading and trailing path separator characters from ARG. MSYS + # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; + # and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result=$func_convert_core_msys_to_w32_result + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_msys_to_w32 + + +# func_convert_path_cygwin_to_w32 ARG +# Convert path ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_path_cygwin_to_w32 () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_cygwin_to_w32 + + +# func_convert_path_nix_to_w32 ARG +# Convert path ARG from *nix to w32 format. Requires a wine environment and +# a working winepath. Returns result in func_to_host_file_result. +func_convert_path_nix_to_w32 () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result=$func_convert_core_path_wine_to_w32_result + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_nix_to_w32 + + +# func_convert_path_msys_to_cygwin ARG +# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_path_msys_to_cygwin () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_msys_to_w32_result" + func_to_host_path_result=$func_cygpath_result + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_msys_to_cygwin + + +# func_convert_path_nix_to_cygwin ARG +# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a +# a wine environment, working winepath, and LT_CYGPATH set. Returns result in +# func_to_host_file_result. +func_convert_path_nix_to_cygwin () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" + func_to_host_path_result=$func_cygpath_result + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_nix_to_cygwin + + +# func_dll_def_p FILE +# True iff FILE is a Windows DLL '.def' file. +# Keep in sync with _LT_DLL_DEF_P in libtool.m4 +func_dll_def_p () +{ + $debug_cmd + + func_dll_def_p_tmp=`$SED -n \ + -e 's/^[ ]*//' \ + -e '/^\(;.*\)*$/d' \ + -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \ + -e q \ + "$1"` + test DEF = "$func_dll_def_p_tmp" +} + + +# func_mode_compile arg... +func_mode_compile () +{ + $debug_cmd + + # 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= + pie_flag= + + 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) + test -n "$libobj" && \ + func_fatal_error "you cannot specify '-o' more than once" + arg_mode=target + continue + ;; + + -pie | -fpie | -fPIE) + func_append pie_flag " $arg" + continue + ;; + + -shared | -static | -prefer-pic | -prefer-non-pic) + func_append 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,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + lastarg= + save_ifs=$IFS; IFS=, + for arg in $args; do + IFS=$save_ifs + func_append_quoted lastarg "$arg" + done + IFS=$save_ifs + func_stripname ' ' '' "$lastarg" + lastarg=$func_stripname_result + + # Add the arguments to base_compile. + func_append 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. + func_append_quoted base_compile "$lastarg" + done # for arg + + case $arg_mode in + arg) + func_fatal_error "you must specify an argument for -Xcompile" + ;; + target) + func_fatal_error "you must specify a target with '-o'" + ;; + *) + # Get the name of the library object. + test -z "$libobj" && { + func_basename "$srcfile" + libobj=$func_basename_result + } + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + case $libobj in + *.[cCFSifmso] | \ + *.ada | *.adb | *.ads | *.asm | \ + *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ + *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) + func_xform "$libobj" + libobj=$func_xform_result + ;; + esac + + case $libobj in + *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; + *) + func_fatal_error "cannot determine name of library object from '$libobj'" + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -shared) + test yes = "$build_libtool_libs" \ + || func_fatal_configuration "cannot build a shared library" + build_old_libs=no + continue + ;; + + -static) + build_libtool_libs=no + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + func_quote_arg pretty "$libobj" + test "X$libobj" != "X$func_quote_arg_result" \ + && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && func_warning "libobj name '$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname=$func_basename_result + xdir=$func_dirname_result + lobj=$xdir$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test yes = "$build_old_libs"; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; 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 no = "$compiler_c_o"; then + output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext + lockfile=$output_obj.lock + 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 yes = "$need_locks"; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test warn = "$need_locks"; 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." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + func_append removelist " $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + func_append removelist " $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 + srcfile=$func_to_tool_file_result + func_quote_arg pretty "$srcfile" + qsrcfile=$func_quote_arg_result + + # Only build a PIC object if we are building libtool libraries. + if test yes = "$build_libtool_libs"; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test no != "$pic_mode"; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + func_append command " -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test warn = "$need_locks" && + 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." + + $opt_dry_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 + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test yes = "$suppress_opt"; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test yes = "$build_old_libs"; then + if test yes != "$pic_mode"; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test yes = "$compiler_c_o"; then + func_append command " -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + func_append command "$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test warn = "$need_locks" && + 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." + + $opt_dry_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 + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test no != "$need_locks"; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { + test compile = "$opt_mode" && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $opt_mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [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: $progname [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 + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to build PIC objects only + -prefer-non-pic try to build non-PIC objects only + -shared do not build a '.o' file suitable for static linking + -static only build a '.o' file suitable for static linking + -Wc,FLAG + -Xcompiler FLAG pass FLAG directly to the compiler + +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: $progname [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: $progname [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: $progname [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 following components of INSTALL-COMMAND are treated specially: + + -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [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 + -bindir BINDIR specify path to binaries directory (for systems where + libraries must be found in the PATH setting at runtime) + -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 + -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes) + -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 + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -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] + -weak LIBNAME declare that the target provides the LIBNAME interface + -Wc,FLAG + -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wa,FLAG + -Xassembler FLAG pass linker-specific FLAG directly to the assembler + -Wl,FLAG + -Xlinker FLAG pass linker-specific FLAG directly to the linker + -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) + +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: $progname [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." + ;; + + *) + func_fatal_help "invalid operation mode '$opt_mode'" + ;; + esac + + echo + $ECHO "Try '$progname --help' for more information about other modes." +} + +# Now that we've collected a possible --mode arg, show help if necessary +if $opt_help; then + if test : = "$opt_help"; then + func_mode_help + else + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + func_mode_help + done + } | $SED -n '1p; 2,$s/^Usage:/ or: /p' + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + echo + func_mode_help + done + } | + $SED '1d + /^When reporting/,/^Report/{ + H + d + } + $x + /information about other modes/d + /more detailed .*MODE/d + s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' + fi + exit $? +fi + + +# func_mode_execute arg... +func_mode_execute () +{ + $debug_cmd + + # The first argument is the command name. + cmd=$nonopt + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $opt_dlopen; do + test -f "$file" \ + || func_fatal_help "'$file' is not a file" + + dir= + case $file in + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "'$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "'$file' was not linked with '-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir=$func_dirname_result + + if test -f "$dir/$objdir/$dlname"; then + func_append dir "/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir=$func_dirname_result + ;; + + *) + func_warning "'-dlopen' is ignored for non-libtool libraries and objects" + 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 + -* | *.la | *.lo ) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file=$progdir/$program + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file=$progdir/$program + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_append_quoted args "$file" + done + + if $opt_dry_run; then + # 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 + else + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE 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 + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd=\$cmd$args + fi +} + +test execute = "$opt_mode" && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $debug_cmd + + libs= + libdirs= + admincmds= + + for opt in "$nonopt" ${1+"$@"} + do + if test -d "$opt"; then + func_append libdirs " $opt" + + elif test -f "$opt"; then + if func_lalib_unsafe_p "$opt"; then + func_append libs " $opt" + else + func_warning "'$opt' is not a valid libtool archive" + fi + + else + func_fatal_error "invalid argument '$opt'" + fi + done + + if test -n "$libs"; then + if test -n "$lt_sysroot"; then + sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` + sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" + else + sysroot_cmd= + fi + + # Remove sysroot references + if $opt_dry_run; then + for lib in $libs; do + echo "removing references to $lt_sysroot and '=' prefixes from $lib" + done + else + tmpdir=`func_mktempdir` + for lib in $libs; do + $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ + > $tmpdir/tmp-la + mv -f $tmpdir/tmp-la $lib + done + ${RM}r "$tmpdir" + fi + fi + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || func_append admincmds " + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_quiet && exit $EXIT_SUCCESS + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + echo "----------------------------------------------------------------------" + 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" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" + echo "pages." + ;; + *) + echo "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + echo "----------------------------------------------------------------------" + fi + exit $EXIT_SUCCESS +} + +test finish = "$opt_mode" && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $debug_cmd + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" || + # Allow the use of GNU shtool's install command. + case $nonopt in *shtool*) :;; *) false;; esac + then + # Aesthetically quote it. + func_quote_arg pretty "$nonopt" + install_prog="$func_quote_arg_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_arg pretty "$arg" + func_append install_prog "$func_quote_arg_result" + install_shared_prog=$install_prog + case " $install_prog " in + *[\\\ /]cp\ *) install_cp=: ;; + *) install_cp=false ;; + esac + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=false + stripme= + no_mode=: + for arg + do + arg2= + if test -n "$dest"; then + func_append files " $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=: ;; + -f) + if $install_cp; then :; else + prev=$arg + fi + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + if test X-m = "X$prev" && test -n "$install_override_mode"; then + arg2=$install_override_mode + no_mode=false + fi + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_arg pretty "$arg" + func_append install_prog " $func_quote_arg_result" + if test -n "$arg2"; then + func_quote_arg pretty "$arg2" + fi + func_append install_shared_prog " $func_quote_arg_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the '$prev' option requires an argument" + + if test -n "$install_override_mode" && $no_mode; then + if $install_cp; then :; else + func_quote_arg pretty "$install_override_mode" + func_append install_shared_prog " -m $func_quote_arg_result" + fi + fi + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=: + if $isdir; then + destdir=$dest + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir=$func_dirname_result + destname=$func_basename_result + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "'$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "'$destdir' must be an absolute directory name" + ;; + 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. + func_append staticlibs " $file" + ;; + + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "'$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) func_append current_libdirs " $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) func_append future_libdirs " $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir=$func_dirname_result + func_append 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 -e "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. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking '$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname=$1 + shift + + srcname=$realname + test -n "$relink_command" && srcname=${realname}T + + # Install the shared library and build the symlinks. + func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme=$stripme + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme= + ;; + esac + ;; + os2*) + case $realname in + *_dll.a) + tstripme= + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_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 + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib=$destdir/$realname + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name=$func_basename_result + instname=$dir/${name}i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && func_append 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 + func_basename "$file" + destfile=$func_basename_result + destfile=$destdir/$destfile + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest=$destfile + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to '$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test yes = "$build_old_libs"; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_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 + func_basename "$file" + destfile=$func_basename_result + 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 + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=.exe + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script '$wrapper'" + + finalize=: + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'` + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "'$lib' has not been installed in '$libdir'" + finalize=false + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test no = "$fast_install" && test -n "$relink_command"; then + $opt_dry_run || { + if $finalize; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file=$func_basename_result + outputname=$tmpdir/$file + # Replace the output file specification. + relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_quiet || { + func_quote_arg expand,pretty "$relink_command" + eval "func_echo $func_quote_arg_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink '$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file=$outputname + else + func_warning "cannot relink '$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "$file$stripped_ext" | $SED "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) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name=$func_basename_result + + # Set up the ranlib parameters. + oldlib=$destdir/$name + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $tool_oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run '$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test install = "$opt_mode" && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $debug_cmd + + my_outputname=$1 + my_originator=$2 + my_pic_p=${3-false} + my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms=${my_outputname}S.c + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist=$output_objdir/$my_outputname.nm + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +#if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) +#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" +#endif + +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined __osf__ +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) + +/* External symbol declarations for the compiler. */\ +" + + if test yes = "$dlself"; then + func_verbose "generating symbol list for '$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_to_tool_file "$progfile" func_convert_file_msys_to_w32 + func_verbose "extracting global C symbols from '$func_to_tool_file_result'" + $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols=$output_objdir/$outputname.exp + $opt_dry_run || { + $RM $export_symbols + eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from '$dlprefile'" + func_basename "$dlprefile" + name=$func_basename_result + case $host in + *cygwin* | *mingw* | *cegcc* ) + # if an import library, we need to obtain dlname + if func_win32_import_lib_p "$dlprefile"; then + func_tr_sh "$dlprefile" + eval "curr_lafile=\$libfile_$func_tr_sh_result" + dlprefile_dlbasename= + if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then + # Use subshell, to avoid clobbering current variable values + dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` + if test -n "$dlprefile_dlname"; then + func_basename "$dlprefile_dlname" + dlprefile_dlbasename=$func_basename_result + else + # no lafile. user explicitly requested -dlpreopen <import library>. + $sharedlib_from_linklib_cmd "$dlprefile" + dlprefile_dlbasename=$sharedlib_from_linklib_result + fi + fi + $opt_dry_run || { + if test -n "$dlprefile_dlbasename"; then + eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' + else + func_warning "Could not compute DLL name from $name" + eval '$ECHO ": $name " >> "$nlist"' + fi + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | + $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" + } + else # not an import lib + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + fi + ;; + *) + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + ;; + esac + done + + $opt_dry_run || { + # 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/$my_dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + func_show_eval '$RM "${nlist}I"' + if test -n "$global_symbol_to_import"; then + eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I' + fi + + echo >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +extern LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[];\ +" + + if test -s "$nlist"I; then + echo >> "$output_objdir/$my_dlsyms" "\ +static void lt_syminit(void) +{ + LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols; + for (; symbol->name; ++symbol) + {" + $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms" + echo >> "$output_objdir/$my_dlsyms" "\ + } +}" + fi + echo >> "$output_objdir/$my_dlsyms" "\ +LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{ {\"$my_originator\", (void *) 0}," + + if test -s "$nlist"I; then + echo >> "$output_objdir/$my_dlsyms" "\ + {\"@INIT@\", (void *) <_syminit}," + fi + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + echo >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + 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*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + $my_pic_p && pic_flag_for_symtable=" $pic_flag" + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) func_append symtab_cflags " $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"' + + # Transform the symbol file into the correct name. + symfileobj=$output_objdir/${my_outputname}S.$objext + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for '$my_dlsyms'" + ;; + 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 "$compile_command" | $SED "s% @SYMFILE@%%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` + fi +} + +# func_cygming_gnu_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is a GNU/binutils-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_gnu_implib_p () +{ + $debug_cmd + + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` + test -n "$func_cygming_gnu_implib_tmp" +} + +# func_cygming_ms_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is an MS-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_ms_implib_p () +{ + $debug_cmd + + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` + test -n "$func_cygming_ms_implib_tmp" +} + +# 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. +# Despite the name, also deal with 64 bit binaries. +func_win32_libid () +{ + $debug_cmd + + 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 + # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + case $nm_interface in + "MS dumpbin") + if func_cygming_ms_implib_p "$1" || + func_cygming_gnu_implib_p "$1" + then + win32_nmres=import + else + win32_nmres= + fi + ;; + *) + func_to_tool_file "$1" func_convert_file_msys_to_w32 + win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | + $SED -n -e ' + 1,100{ + / I /{ + s|.*|import| + p + q + } + }'` + ;; + esac + 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_cygming_dll_for_implib ARG +# +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib () +{ + $debug_cmd + + sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` +} + +# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs +# +# The is the core of a fallback implementation of a +# platform-specific function to extract the name of the +# DLL associated with the specified import library LIBNAME. +# +# SECTION_NAME is either .idata$6 or .idata$7, depending +# on the platform and compiler that created the implib. +# +# Echos the name of the DLL associated with the +# specified import library. +func_cygming_dll_for_implib_fallback_core () +{ + $debug_cmd + + match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` + $OBJDUMP -s --section "$1" "$2" 2>/dev/null | + $SED '/^Contents of section '"$match_literal"':/{ + # Place marker at beginning of archive member dllname section + s/.*/====MARK====/ + p + d + } + # These lines can sometimes be longer than 43 characters, but + # are always uninteresting + /:[ ]*file format pe[i]\{,1\}-/d + /^In archive [^:]*:/d + # Ensure marker is printed + /^====MARK====/p + # Remove all lines with less than 43 characters + /^.\{43\}/!d + # From remaining lines, remove first 43 characters + s/^.\{43\}//' | + $SED -n ' + # Join marker and all lines until next marker into a single line + /^====MARK====/ b para + H + $ b para + b + :para + x + s/\n//g + # Remove the marker + s/^====MARK====// + # Remove trailing dots and whitespace + s/[\. \t]*$// + # Print + /./p' | + # we now have a list, one entry per line, of the stringified + # contents of the appropriate section of all members of the + # archive that possess that section. Heuristic: eliminate + # all those that have a first or second character that is + # a '.' (that is, objdump's representation of an unprintable + # character.) This should work for all archives with less than + # 0x302f exports -- but will fail for DLLs whose name actually + # begins with a literal '.' or a single character followed by + # a '.'. + # + # Of those that remain, print the first one. + $SED -e '/^\./d;/^.\./d;q' +} + +# func_cygming_dll_for_implib_fallback ARG +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# +# This fallback implementation is for use when $DLLTOOL +# does not support the --identify-strict option. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib_fallback () +{ + $debug_cmd + + if func_cygming_gnu_implib_p "$1"; then + # binutils import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` + elif func_cygming_ms_implib_p "$1"; then + # ms-generated import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` + else + # unknown + sharedlib_from_linklib_result= + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $debug_cmd + + f_ex_an_ar_dir=$1; shift + f_ex_an_ar_oldlib=$1 + if test yes = "$lock_old_archive_extraction"; then + lockfile=$f_ex_an_ar_oldlib.lock + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + fi + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ + 'stat=$?; rm -f "$lockfile"; exit $stat' + if test yes = "$lock_old_archive_extraction"; then + $opt_dry_run || rm -f "$lockfile" + fi + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $debug_cmd + + my_gentop=$1; shift + my_oldlibs=${1+"$@"} + my_oldobjs= + my_xlib= + my_xabs= + my_xdir= + + 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 + func_basename "$my_xlib" + my_xlib=$func_basename_result + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + 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 + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + func_basename "$darwin_archive" + darwin_base_archive=$func_basename_result + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches; do + func_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've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` + done + + func_extract_archives_result=$my_oldobjs +} + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory where it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=${1-no} + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE) $VERSION +# +# 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. +sed_quote_subst='$sed_quote_subst' + +# Be 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 variables: + generated_by_libtool_version='$macro_version' + 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 + file=\"\$0\"" + + func_quote_arg pretty "$ECHO" + qECHO=$func_quote_arg_result + $ECHO "\ + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + ECHO=$qECHO + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ that is used only on +# windows platforms, and (c) all begin with the string "--lt-" +# (application programs are unlikely to have options that match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's $0 value, followed by "$@". +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=\$0 + shift + for lt_opt + do + case \"\$lt_opt\" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` + test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. + lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` + cat \"\$lt_dump_D/\$lt_dump_F\" + exit 0 + ;; + --lt-*) + \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n \"\$lt_option_debug\"; then + echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\" + lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from \$@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + case \" \$* \" in + *\\ --lt-*) + for lt_wr_arg + do + case \$lt_wr_arg in + --lt-*) ;; + *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; + esac + shift + done ;; + esac + func_exec_program_core \${1+\"\$@\"} +} + + # Parse options + func_parse_lt_options \"\$0\" \${1+\"\$@\"} + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"\$file\" | $SED '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 \"\$file\" | $SED '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 \"\$file\" | $SED 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test yes = "$fast_install"; then + $ECHO "\ + 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 "\ + + # 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 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # fixup the dll searchpath if we need to. + # + # Fix the DLL searchpath if we need to. Do this before prepending + # to shlibpath, because on Windows, both are PATH and uninstalled + # libraries must come first. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + # Export our shlibpath_var if we have one. + if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # 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 \"\$$shlibpath_var\" | $SED 's/::*\$//'\` + + export $shlibpath_var +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. + func_exec_program \${1+\"\$@\"} + 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 1 + fi +fi\ +" +} + + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat <<EOF + +/* $cwrappersource - temporary wrapper executable for $objdir/$outputname + Generated by $PROGRAM (GNU $PACKAGE) $VERSION + + 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. +*/ +EOF + cat <<"EOF" +#ifdef _MSC_VER +# define _CRT_SECURE_NO_DEPRECATE 1 +#endif +#include <stdio.h> +#include <stdlib.h> +#ifdef _MSC_VER +# include <direct.h> +# include <process.h> +# include <io.h> +#else +# include <unistd.h> +# include <stdint.h> +# ifdef __CYGWIN__ +# include <io.h> +# endif +#endif +#include <malloc.h> +#include <stdarg.h> +#include <assert.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> + +#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) + +/* declarations of non-ANSI functions */ +#if defined __MINGW32__ +# ifdef __STRICT_ANSI__ +int _putenv (const char *); +# endif +#elif defined __CYGWIN__ +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +/* #elif defined other_platform || defined ... */ +#endif + +/* portability defines, excluding path handling macros */ +#if defined _MSC_VER +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +# define S_IXUSR _S_IEXEC +#elif defined __MINGW32__ +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +#elif defined __CYGWIN__ +# define HAVE_SETENV +# define FOPEN_WB "wb" +/* #elif defined other platforms ... */ +#endif + +#if defined PATH_MAX +# define LT_PATHMAX PATH_MAX +#elif defined MAXPATHLEN +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +/* path handling portability macros */ +#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 +# define FOPEN_WB "wb" +# 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 */ + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free (stale); stale = 0; } \ +} while (0) + +#if defined LT_DEBUGWRAPPER +static int lt_debug = 1; +#else +static int lt_debug = 0; +#endif + +const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_debugprintf (const char *file, int line, const char *fmt, ...); +void lt_fatal (const char *file, int line, const char *message, ...); +static const char *nonnull (const char *s); +static const char *nonempty (const char *s); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); +void lt_dump_script (FILE *f); +EOF + + cat <<EOF +#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) +# define externally_visible volatile +#else +# define externally_visible __attribute__((externally_visible)) volatile +#endif +externally_visible const char * MAGIC_EXE = "$magic_exe"; +const char * LIB_PATH_VARNAME = "$shlibpath_var"; +EOF + + if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + func_to_host_path "$temp_rpath" + cat <<EOF +const char * LIB_PATH_VALUE = "$func_to_host_path_result"; +EOF + else + cat <<"EOF" +const char * LIB_PATH_VALUE = ""; +EOF + fi + + if test -n "$dllsearchpath"; then + func_to_host_path "$dllsearchpath:" + cat <<EOF +const char * EXE_PATH_VARNAME = "PATH"; +const char * EXE_PATH_VALUE = "$func_to_host_path_result"; +EOF + else + cat <<"EOF" +const char * EXE_PATH_VARNAME = ""; +const char * EXE_PATH_VALUE = ""; +EOF + fi + + if test yes = "$fast_install"; then + cat <<EOF +const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */ +EOF + else + cat <<EOF +const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */ +EOF + fi + + + cat <<"EOF" + +#define LTWRAPPER_OPTION_PREFIX "--lt-" + +static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX; +static const char *dumpscript_opt = LTWRAPPER_OPTION_PREFIX "dump-script"; +static const char *debug_opt = LTWRAPPER_OPTION_PREFIX "debug"; + +int +main (int argc, char *argv[]) +{ + char **newargz; + int newargc; + char *tmp_pathspec; + char *actual_cwrapper_path; + char *actual_cwrapper_name; + char *target_name; + char *lt_argv_zero; + int rval = 127; + + int i; + + program_name = (char *) xstrdup (base_name (argv[0])); + newargz = XMALLOC (char *, (size_t) argc + 1); + + /* very simple arg parsing; don't want to rely on getopt + * also, copy all non cwrapper options to newargz, except + * argz[0], which is handled differently + */ + newargc=0; + for (i = 1; i < argc; i++) + { + if (STREQ (argv[i], dumpscript_opt)) + { +EOF + case $host in + *mingw* | *cygwin* ) + # make stdout use "unix" line endings + echo " setmode(1,_O_BINARY);" + ;; + esac + + cat <<"EOF" + lt_dump_script (stdout); + return 0; + } + if (STREQ (argv[i], debug_opt)) + { + lt_debug = 1; + continue; + } + if (STREQ (argv[i], ltwrapper_option_prefix)) + { + /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX + namespace, but it is not one of the ones we know about and + have already dealt with, above (inluding dump-script), then + report an error. Otherwise, targets might begin to believe + they are allowed to use options in the LTWRAPPER_OPTION_PREFIX + namespace. The first time any user complains about this, we'll + need to make LTWRAPPER_OPTION_PREFIX a configure-time option + or a configure.ac-settable value. + */ + lt_fatal (__FILE__, __LINE__, + "unrecognized %s option: '%s'", + ltwrapper_option_prefix, argv[i]); + } + /* otherwise ... */ + newargz[++newargc] = xstrdup (argv[i]); + } + newargz[++newargc] = NULL; + +EOF + cat <<EOF + /* The GNU banner must be the first non-error debug message */ + lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE) $VERSION\n"); +EOF + cat <<"EOF" + lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]); + lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name); + + tmp_pathspec = find_executable (argv[0]); + if (tmp_pathspec == NULL) + lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]); + lt_debugprintf (__FILE__, __LINE__, + "(main) found exe (before symlink chase) at: %s\n", + tmp_pathspec); + + actual_cwrapper_path = chase_symlinks (tmp_pathspec); + lt_debugprintf (__FILE__, __LINE__, + "(main) found exe (after symlink chase) at: %s\n", + actual_cwrapper_path); + XFREE (tmp_pathspec); + + actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path)); + strendzap (actual_cwrapper_path, actual_cwrapper_name); + + /* wrapper name transforms */ + strendzap (actual_cwrapper_name, ".exe"); + tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1); + XFREE (actual_cwrapper_name); + actual_cwrapper_name = tmp_pathspec; + tmp_pathspec = 0; + + /* target_name transforms -- use actual target program name; might have lt- prefix */ + target_name = xstrdup (base_name (TARGET_PROGRAM_NAME)); + strendzap (target_name, ".exe"); + tmp_pathspec = lt_extend_str (target_name, ".exe", 1); + XFREE (target_name); + target_name = tmp_pathspec; + tmp_pathspec = 0; + + lt_debugprintf (__FILE__, __LINE__, + "(main) libtool target name: %s\n", + target_name); +EOF + + cat <<EOF + newargz[0] = + XMALLOC (char, (strlen (actual_cwrapper_path) + + strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1)); + strcpy (newargz[0], actual_cwrapper_path); + strcat (newargz[0], "$objdir"); + strcat (newargz[0], "/"); +EOF + + cat <<"EOF" + /* stop here, and copy so we don't have to do this twice */ + tmp_pathspec = xstrdup (newargz[0]); + + /* do NOT want the lt- prefix here, so use actual_cwrapper_name */ + strcat (newargz[0], actual_cwrapper_name); + + /* DO want the lt- prefix here if it exists, so use target_name */ + lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1); + XFREE (tmp_pathspec); + tmp_pathspec = NULL; +EOF + + case $host_os in + mingw*) + cat <<"EOF" + { + char* p; + while ((p = strchr (newargz[0], '\\')) != NULL) + { + *p = '/'; + } + while ((p = strchr (lt_argv_zero, '\\')) != NULL) + { + *p = '/'; + } + } +EOF + ;; + esac + + cat <<"EOF" + XFREE (target_name); + XFREE (actual_cwrapper_path); + XFREE (actual_cwrapper_name); + + lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */ + lt_setenv ("DUALCASE", "1"); /* for MSK sh */ + /* Update the DLL searchpath. EXE_PATH_VALUE ($dllsearchpath) must + be prepended before (that is, appear after) LIB_PATH_VALUE ($temp_rpath) + because on Windows, both *_VARNAMEs are PATH but uninstalled + libraries must come first. */ + lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE); + lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE); + + lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n", + nonnull (lt_argv_zero)); + for (i = 0; i < newargc; i++) + { + lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n", + i, nonnull (newargz[i])); + } + +EOF + + case $host_os in + mingw*) + cat <<"EOF" + /* execv doesn't actually work on mingw as expected on unix */ + newargz = prepare_spawn (newargz); + rval = (int) _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz); + if (rval == -1) + { + /* failed to start process */ + lt_debugprintf (__FILE__, __LINE__, + "(main) failed to launch target \"%s\": %s\n", + lt_argv_zero, nonnull (strerror (errno))); + return 127; + } + return rval; +EOF + ;; + *) + cat <<"EOF" + execv (lt_argv_zero, newargz); + return rval; /* =127, but avoids unused variable warning */ +EOF + ;; + esac + + cat <<"EOF" +} + +void * +xmalloc (size_t num) +{ + void *p = (void *) malloc (num); + if (!p) + lt_fatal (__FILE__, __LINE__, "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; + + lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n", + nonempty (path)); + if ((!path) || (!*path)) + return 0; + + if ((stat (path, &st) >= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", + nonempty (path)); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +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]; + size_t tmp_len; + char *concat_name; + + lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", + nonempty (wrapper)); + + 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 = (size_t) (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 (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + 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 (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + 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 * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + lt_debugprintf (__FILE__, __LINE__, + "checking path component for symlinks: %s\n", + tmp_pathspec); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + lt_fatal (__FILE__, __LINE__, + "error accessing file \"%s\": %s", + tmp_pathspec, nonnull (strerror (errno))); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal (__FILE__, __LINE__, + "could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +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 (STREQ (str, pat)) + *str = '\0'; + } + return str; +} + +void +lt_debugprintf (const char *file, int line, const char *fmt, ...) +{ + va_list args; + if (lt_debug) + { + (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); + } +} + +static void +lt_error_core (int exit_status, const char *file, + int line, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *file, int line, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); + va_end (ap); +} + +static const char * +nonnull (const char *s) +{ + return s ? s : "(null)"; +} + +static const char * +nonempty (const char *s) +{ + return (s && !*s) ? "(empty)" : nonnull (s); +} + +void +lt_setenv (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_setenv) setting '%s' to '%s'\n", + nonnull (name), nonnull (value)); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + size_t len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + size_t orig_value_len = strlen (orig_value); + size_t add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + size_t len = strlen (new_value); + while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[--len] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +EOF + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac + + cat <<"EOF" +void lt_dump_script (FILE* f) +{ +EOF + func_emit_wrapper yes | + $SED -n -e ' +s/^\(.\{79\}\)\(..*\)/\1\ +\2/ +h +s/\([\\"]\)/\\\1/g +s/$/\\n/ +s/\([^\n]*\).*/ fputs ("\1", f);/p +g +D' + cat <<"EOF" +} +EOF +} +# end: func_emit_cwrapperexe_src + +# func_win32_import_lib_p ARG +# True if ARG is an import lib, as indicated by $file_magic_cmd +func_win32_import_lib_p () +{ + $debug_cmd + + case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in + *import*) : ;; + *) false ;; + esac +} + +# func_suncc_cstd_abi +# !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!! +# Several compiler flags select an ABI that is incompatible with the +# Cstd library. Avoid specifying it if any are in CXXFLAGS. +func_suncc_cstd_abi () +{ + $debug_cmd + + case " $compile_command " in + *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*) + suncc_use_cstd_abi=no + ;; + *) + suncc_use_cstd_abi=yes + ;; + esac +} + +# func_mode_link arg... +func_mode_link () +{ + $debug_cmd + + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # what 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 that 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= + new_inherited_linker_flags= + + avoid_version=no + bindir= + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + os2dllname= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=false + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module=$wl-single_module + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test yes != "$build_libtool_libs" \ + && func_fatal_configuration "cannot build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + 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 + func_quote_arg pretty,unquoted "$arg" + qarg=$func_quote_arg_unquoted_result + func_append libtool_args " $func_quote_arg_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + bindir) + bindir=$arg + prev= + continue + ;; + dlfiles|dlprefiles) + $preload || { + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=: + } + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test no = "$dlself"; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test dlprefiles = "$prev"; then + dlself=yes + elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test dlfiles = "$prev"; then + func_append dlfiles " $arg" + else + func_append dlprefiles " $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols=$arg + test -f "$arg" \ + || func_fatal_error "symbol file '$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex=$arg + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) func_append deplibs " $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir=$arg + prev= + continue + ;; + mllvm) + # Clang does not use LLVM to link, so we can simply discard any + # '-mllvm $arg' options when doing the link step. + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# func_append moreargs " $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test none = "$pic_object" && + test none = "$non_pic_object"; then + func_fatal_error "cannot find name of object for '$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir=$func_dirname_result + + if test none != "$pic_object"; then + # Prepend the subdirectory the object is found in. + pic_object=$xdir$pic_object + + if test dlfiles = "$prev"; then + if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then + func_append 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 dlprefiles = "$prev"; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg=$pic_object + fi + + # Non-PIC object. + if test none != "$non_pic_object"; then + # Prepend the subdirectory the object is found in. + non_pic_object=$xdir$non_pic_object + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test none = "$pic_object"; 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 + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir=$func_dirname_result + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "'$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file '$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + os2dllname) + os2dllname=$arg + prev= + continue + ;; + precious_regex) + precious_files_regex=$arg + prev= + continue + ;; + release) + release=-$arg + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test rpath = "$prev"; then + case "$rpath " in + *" $arg "*) ;; + *) func_append rpath " $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) func_append xrpath " $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds=$arg + prev= + continue + ;; + weak) + func_append weak_libs " $arg" + prev= + continue + ;; + xassembler) + func_append compiler_flags " -Xassembler $qarg" + prev= + func_append compile_command " -Xassembler $qarg" + func_append finalize_command " -Xassembler $qarg" + continue + ;; + xcclinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + 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 + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "'-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -bindir) + prev=bindir + 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 + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test X-export-symbols = "X$arg"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + 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*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname "-L" '' "$arg" + if test -z "$func_stripname_result"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between '-L' and '$1'" + else + func_fatal_error "need path for '-L' option" + fi + fi + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of '$dir'" + dir=$absdir + ;; + esac + case "$deplibs " in + *" -L$dir "* | *" $arg "*) + # Will only happen for absolute or sysroot arguments + ;; + *) + # Preserve sysroot, but never include relative directories + case $dir in + [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; + *) func_append deplibs " -L$dir" ;; + esac + func_append lib_search_path " $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) func_append dllsearchpath ":$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test X-lc = "X$arg" || test X-lm = "X$arg"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + # 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-lc = "X$arg" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig* | *-*-midnightbsd*) + # Do not include libc due to us having libc/libc_r. + test X-lc = "X$arg" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + func_append deplibs " System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test X-lc = "X$arg" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test X-lc = "X$arg" && continue + ;; + esac + elif test X-lc_r = "X$arg"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig* | *-*-midnightbsd*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + func_append deplibs " $arg" + continue + ;; + + -mllvm) + prev=mllvm + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot|--sysroot) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + # Solaris ld rejects as of 11.4. Refer to Oracle bug 22985199. + -pthread) + case $host in + *solaris2*) ;; + *) + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) func_append new_inherited_linker_flags " $arg" ;; + esac + ;; + esac + continue + ;; + -mt|-mthreads|-kthread|-Kthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) func_append new_inherited_linker_flags " $arg" ;; + esac + continue + ;; + + -multi_module) + single_module=$wl-multi_module + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "'-no-install' is ignored for $host" + func_warning "assuming '-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -os2dllname) + prev=os2dllname + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + =*) + func_stripname '=' '' "$dir" + dir=$lt_sysroot$func_stripname_result + ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + 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 + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs=$IFS; IFS=, + for flag in $args; do + IFS=$save_ifs + func_quote_arg pretty "$flag" + func_append arg " $func_quote_arg_result" + func_append compiler_flags " $func_quote_arg_result" + done + IFS=$save_ifs + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs=$IFS; IFS=, + for flag in $args; do + IFS=$save_ifs + func_quote_arg pretty "$flag" + func_append arg " $wl$func_quote_arg_result" + func_append compiler_flags " $wl$func_quote_arg_result" + func_append linker_flags " $func_quote_arg_result" + done + IFS=$save_ifs + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xassembler) + prev=xassembler + continue + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_arg pretty "$arg" + arg=$func_quote_arg_result + ;; + + # Flags to be passed through unchanged, with rationale: + # -64, -mips[0-9] enable 64-bit mode for the SGI compiler + # -r[0-9][0-9]* specify processor for the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler + # +DA*, +DD* enable 64-bit mode for the HP compiler + # -q* compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* architecture-specific flags for GCC + # -F/path path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* profiling flags for GCC + # -fstack-protector* stack protector flags for GCC + # @file GCC response files + # -tp=* Portland pgcc target processor selection + # --sysroot=* for sysroot support + # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization + # -specs=* GCC specs files + # -stdlib=* select c++ std lib with clang + # -fsanitize=* Clang/GCC memory and address sanitizer + # -fuse-ld=* Linker select flags for GCC + # -static-* direct GCC to link specific libraries statically + # -fcilkplus Cilk Plus language extension features for C/C++ + # -Wa,* Pass flags directly to the assembler + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ + -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \ + -specs=*|-fsanitize=*|-fuse-ld=*|-static-*|-fcilkplus|-Wa,*) + func_quote_arg pretty "$arg" + arg=$func_quote_arg_result + func_append compile_command " $arg" + func_append finalize_command " $arg" + func_append compiler_flags " $arg" + continue + ;; + + -Z*) + if test os2 = "`expr $host : '.*\(os2\)'`"; then + # OS/2 uses -Zxxx to specify OS/2-specific options + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case $arg in + -Zlinker | -Zstack) + prev=xcompiler + ;; + esac + continue + else + # Otherwise treat like 'Some other compiler flag' below + func_quote_arg pretty "$arg" + arg=$func_quote_arg_result + fi + ;; + + # Some other compiler flag. + -* | +*) + func_quote_arg pretty "$arg" + arg=$func_quote_arg_result + ;; + + *.$objext) + # A standard object. + func_append objs " $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test none = "$pic_object" && + test none = "$non_pic_object"; then + func_fatal_error "cannot find name of object for '$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir=$func_dirname_result + + test none = "$pic_object" || { + # Prepend the subdirectory the object is found in. + pic_object=$xdir$pic_object + + if test dlfiles = "$prev"; then + if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then + func_append 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 dlprefiles = "$prev"; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg=$pic_object + } + + # Non-PIC object. + if test none != "$non_pic_object"; then + # Prepend the subdirectory the object is found in. + non_pic_object=$xdir$non_pic_object + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test none = "$pic_object"; 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 + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir=$func_dirname_result + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "'$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + func_append deplibs " $arg" + func_append old_deplibs " $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + func_resolve_sysroot "$arg" + if test dlfiles = "$prev"; then + # This library was specified with -dlopen. + func_append dlfiles " $func_resolve_sysroot_result" + prev= + elif test dlprefiles = "$prev"; then + # The library was specified with -dlpreopen. + func_append dlprefiles " $func_resolve_sysroot_result" + prev= + else + func_append deplibs " $func_resolve_sysroot_result" + 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. + func_quote_arg pretty "$arg" + arg=$func_quote_arg_result + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the '$prevarg' option requires an argument" + + if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname=$func_basename_result + libobjs_save=$libobjs + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'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\" + + # Definition is injected by LT_CONFIG during libtool generation. + func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH" + + func_dirname "$output" "/" "" + output_objdir=$func_dirname_result$objdir + func_to_tool_file "$output_objdir/" + tool_output_objdir=$func_to_tool_file_result + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + 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 $opt_preserve_dup_deps; then + case "$libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append libs " $deplib" + done + + if test lib = "$linkmode"; 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 $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; + esac + func_append 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 + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can '-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=false + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test lib,link = "$linkmode,$pass"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs=$tmp_deplibs + fi + + if test lib,link = "$linkmode,$pass" || + test prog,scan = "$linkmode,$pass"; then + libs=$deplibs + deplibs= + fi + if test prog = "$linkmode"; then + case $pass in + dlopen) libs=$dlfiles ;; + dlpreopen) libs=$dlprefiles ;; + link) + libs="$deplibs %DEPLIBS%" + test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" + ;; + esac + fi + if test lib,dlpreopen = "$linkmode,$pass"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + func_resolve_sysroot "$lib" + case $lib in + *.la) func_source "$func_resolve_sysroot_result" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + func_basename "$deplib" + deplib_base=$func_basename_result + case " $weak_libs " in + *" $deplib_base "*) ;; + *) func_append deplibs " $deplib" ;; + esac + done + done + libs=$dlprefiles + fi + if test dlopen = "$pass"; then + # Collect dlpreopened libraries + save_deplibs=$deplibs + deplibs= + fi + + for deplib in $libs; do + lib= + found=false + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append compiler_flags " $deplib" + if test lib = "$linkmode"; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test lib != "$linkmode" && test prog != "$linkmode"; then + func_warning "'-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test lib = "$linkmode"; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; 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 .la = "$search_ext"; then + found=: + else + found=false + fi + break 2 + fi + done + done + if $found; then + # 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 yes = "$allow_libtool_libs_with_static_runtimes"; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll=$l + done + if test "X$ll" = "X$old_library"; then # only static version available + found=false + func_dirname "$lib" "" "." + ladir=$func_dirname_result + lib=$ladir/$old_library + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + else + # deplib doesn't seem to be a libtool library + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + ;; # -l + *.ltframework) + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test lib = "$linkmode"; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test conv = "$pass" && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + prog) + if test conv = "$pass"; then + deplibs="$deplib $deplibs" + continue + fi + if test scan = "$pass"; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + *) + func_warning "'-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test link = "$pass"; then + func_stripname '-R' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) + func_resolve_sysroot "$deplib" + lib=$func_resolve_sysroot_result + ;; + *.$libext) + if test conv = "$pass"; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=false + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=: + fi + ;; + pass_all) + valid_a_lib=: + ;; + esac + if $valid_a_lib; then + echo + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + else + 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 use here." + fi + ;; + esac + continue + ;; + prog) + if test link != "$pass"; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test conv = "$pass"; then + deplibs="$deplib $deplibs" + elif test prog = "$linkmode"; then + if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + func_append newdlprefiles " $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append newdlfiles " $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=: + continue + ;; + esac # case $deplib + + $found || test -f "$lib" \ + || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'" + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "'$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir=$func_dirname_result + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # 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 + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + if test lib,link = "$linkmode,$pass" || + test prog,scan = "$linkmode,$pass" || + { test prog != "$linkmode" && test lib != "$linkmode"; }; then + test -n "$dlopen" && func_append dlfiles " $dlopen" + test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" + fi + + if test conv = "$pass"; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for '$lib'" + fi + # It is a libtool convenience library, so add in its objects. + func_append convenience " $ladir/$objdir/$old_library" + func_append old_convenience " $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_preserve_dup_deps; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done + elif test prog != "$linkmode" && test lib != "$linkmode"; then + func_fatal_error "'$lib' is not a convenience library" + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + if test -n "$old_library" && + { test yes = "$prefer_static_libs" || + test built,no = "$prefer_static_libs,$installed"; }; then + linklib=$old_library + else + for l in $old_library $library_names; do + linklib=$l + done + fi + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for '$lib'" + fi + + # This library was specified with -dlopen. + if test dlopen = "$pass"; then + test -z "$libdir" \ + && func_fatal_error "cannot -dlopen a convenience library: '$lib'" + if test -z "$dlname" || + test yes != "$dlopen_support" || + test no = "$build_libtool_libs" + 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. + func_append dlprefiles " $lib $dependency_libs" + else + func_append 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 + func_warning "cannot determine absolute directory name of '$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir=$ladir + fi + ;; + esac + func_basename "$lib" + laname=$func_basename_result + + # Find the relevant object directory and library name. + if test yes = "$installed"; then + if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library '$lib' was moved." + dir=$ladir + absdir=$abs_ladir + libdir=$abs_ladir + else + dir=$lt_sysroot$libdir + absdir=$lt_sysroot$libdir + fi + test yes = "$hardcode_automatic" && 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 + func_append notinst_path " $abs_ladir" + else + dir=$ladir/$objdir + absdir=$abs_ladir/$objdir + # Remove this search path later + func_append notinst_path " $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test dlpreopen = "$pass"; then + if test -z "$libdir" && test prog = "$linkmode"; then + func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'" + fi + case $host in + # special handling for platforms with PE-DLLs. + *cygwin* | *mingw* | *cegcc* ) + # Linker will automatically link against shared library if both + # static and shared are present. Therefore, ensure we extract + # symbols from the import library if a shared library is present + # (otherwise, the dlopen module name will be incorrect). We do + # this by putting the import library name into $newdlprefiles. + # We recover the dlopen module name by 'saving' the la file + # name in a special purpose variable, and (later) extracting the + # dlname from the la file. + if test -n "$dlname"; then + func_tr_sh "$dir/$linklib" + eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" + func_append newdlprefiles " $dir/$linklib" + else + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + fi + ;; + * ) + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + func_append newdlprefiles " $dir/$dlname" + else + func_append newdlprefiles " $dir/$linklib" + fi + ;; + esac + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test lib = "$linkmode"; then + deplibs="$dir/$old_library $deplibs" + elif test prog,link = "$linkmode,$pass"; 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 prog = "$linkmode" && test link != "$pass"; then + func_append newlib_search_path " $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=false + if test no != "$link_all_deplibs" || test -z "$library_names" || + test no = "$build_libtool_libs"; then + linkalldeplibs=: + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + esac + # Need to link against all dependency_libs? + if $linkalldeplibs; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_preserve_dup_deps; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test prog,link = "$linkmode,$pass"; then + if test -n "$library_names" && + { { test no = "$prefer_static_libs" || + test built,yes = "$prefer_static_libs,$installed"; } || + 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 + *"$absdir:"*) ;; + *) func_append 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 "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if $alldeplibs && + { test pass_all = "$deplibs_check_method" || + { test yes = "$build_libtool_libs" && + 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 built = "$use_static_libs" && test yes = "$installed"; then + use_static_libs=no + fi + if test -n "$library_names" && + { test no = "$use_static_libs" || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc* | *os2*) + # No point in relinking DLLs because paths are not encoded + func_append notinst_deplibs " $lib" + need_relink=no + ;; + *) + if test no = "$installed"; then + func_append notinst_deplibs " $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule= + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule=$dlpremoduletest + break + fi + done + if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then + echo + if test prog = "$linkmode"; 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 lib = "$linkmode" && + test yes = "$hardcode_into_libs"; 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 "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname=$1 + 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* | *cegcc* | *os2*) + func_arith $current - $age + major=$func_arith_result + versuffix=-$major + ;; + esac + eval soname=\"$soname_spec\" + else + soname=$realname + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot=$soname + func_basename "$soroot" + soname=$func_basename_result + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from '$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for '$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + 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 prog = "$linkmode" || test relink != "$opt_mode"; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test no = "$hardcode_direct"; 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 (non-dlopened) module then we cannot + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null; then + if test "X$dlopenmodule" != "X$lib"; 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 + elif test -n "$old_library"; then + add=$dir/$old_library + fi + fi + esac + elif test no = "$hardcode_minus_L"; then + case $host in + *-*-sunos*) add_shlibpath=$dir ;; + esac + add_dir=-L$dir + add=-l$name + elif test no = "$hardcode_shlibpath_var"; then + add_shlibpath=$dir + add=-l$name + else + lib_linked=no + fi + ;; + relink) + if test yes = "$hardcode_direct" && + test no = "$hardcode_direct_absolute"; then + add=$dir/$linklib + elif test yes = "$hardcode_minus_L"; then + add_dir=-L$absdir + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add=-l$name + elif test yes = "$hardcode_shlibpath_var"; then + add_shlibpath=$dir + add=-l$name + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test yes != "$lib_linked"; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) func_append compile_shlibpath "$add_shlibpath:" ;; + esac + fi + if test prog = "$linkmode"; 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 yes != "$hardcode_direct" && + test yes != "$hardcode_minus_L" && + test yes = "$hardcode_shlibpath_var"; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + fi + fi + fi + + if test prog = "$linkmode" || test relink = "$opt_mode"; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test yes = "$hardcode_direct" && + test no = "$hardcode_direct_absolute"; then + add=$libdir/$linklib + elif test yes = "$hardcode_minus_L"; then + add_dir=-L$libdir + add=-l$name + elif test yes = "$hardcode_shlibpath_var"; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + add=-l$name + elif test yes = "$hardcode_automatic"; 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 + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add=-l$name + fi + + if test prog = "$linkmode"; 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 prog = "$linkmode"; 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 unsupported != "$hardcode_direct"; 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 yes = "$build_libtool_libs"; then + # Not a shared library + if test pass_all != "$deplibs_check_method"; 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 cannot 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 yes = "$module"; 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 no = "$build_old_libs"; 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 lib = "$linkmode"; then + if test -n "$dependency_libs" && + { test yes != "$hardcode_into_libs" || + test yes = "$build_old_libs" || + test yes = "$link_static"; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) func_append xrpath " $temp_xrpath";; + esac;; + *) func_append temp_deplibs " $libdir";; + esac + done + dependency_libs=$temp_deplibs + fi + + func_append newlib_search_path " $absdir" + # Link against this library + test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result";; + *) func_resolve_sysroot "$deplib" ;; + esac + if $opt_preserve_dup_deps; then + case "$tmp_libs " in + *" $func_resolve_sysroot_result "*) + func_append specialdeplibs " $func_resolve_sysroot_result" ;; + esac + fi + func_append tmp_libs " $func_resolve_sysroot_result" + done + + if test no != "$link_all_deplibs"; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path=$deplib ;; + *.la) + func_resolve_sysroot "$deplib" + deplib=$func_resolve_sysroot_result + func_dirname "$deplib" "" "." + dir=$func_dirname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of '$dir'" + absdir=$dir + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + 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 "$absdir/$objdir/$depdepl"; then + depdepl=$absdir/$objdir/$depdepl + darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`$OTOOL64 -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl" + func_append linker_flags " -dylib_file $darwin_install_name:$depdepl" + path= + fi + fi + ;; + *) + path=-L$absdir/$objdir + ;; + esac + else + eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "'$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "'$deplib' seems to be moved" + + path=-L$absdir + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test link = "$pass"; then + if test prog = "$linkmode"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs=$newdependency_libs + if test dlpreopen = "$pass"; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test dlopen != "$pass"; then + test conv = "$pass" || { + # 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 "*) ;; + *) func_append lib_search_path " $dir" ;; + esac + done + newlib_search_path= + } + + if test prog,link = "$linkmode,$pass"; then + vars="compile_deplibs finalize_deplibs" + else + vars=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 "*) ;; + *) func_append tmp_libs " $deplib" ;; + esac + ;; + *) func_append tmp_libs " $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + + # Add Sun CC postdeps if required: + test CXX = "$tagname" && { + case $host_os in + linux*) + case `$CC -V 2>&1 | $SED 5q` in + *Sun\ C*) # Sun C++ 5.9 + func_suncc_cstd_abi + + if test no != "$suncc_use_cstd_abi"; then + func_append postdeps ' -library=Cstd -library=Crun' + fi + ;; + esac + ;; + + solaris*) + func_cc_basename "$CC" + case $func_cc_basename_result in + CC* | sunCC*) + func_suncc_cstd_abi + + if test no != "$suncc_use_cstd_abi"; then + func_append postdeps ' -library=Cstd -library=Crun' + fi + ;; + esac + ;; + esac + } + + # 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 + func_append tmp_libs " $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test prog = "$linkmode"; then + dlfiles=$newdlfiles + fi + if test prog = "$linkmode" || test lib = "$linkmode"; then + dlprefiles=$newdlprefiles + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then + func_warning "'-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "'-l' and '-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "'-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "'-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "'-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "'-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "'-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs=$output + func_append objs "$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form 'libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test no = "$module" \ + && func_fatal_help "libtool library '$output' must begin with 'lib'" + + if test no != "$need_lib_prefix"; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test pass_all != "$deplibs_check_method"; then + func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs" + else + echo + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + func_append libobjs " $objs" + fi + fi + + test no = "$dlself" \ + || func_warning "'-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test 1 -lt "$#" \ + && func_warning "ignoring multiple '-rpath's for a libtool library" + + install_libdir=$1 + + oldlibs= + if test -z "$rpath"; then + if test yes = "$build_libtool_libs"; 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 + + test -n "$vinfo" && \ + func_warning "'-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "'-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs=$IFS; IFS=: + set dummy $vinfo 0 0 0 + shift + IFS=$save_ifs + + test -n "$7" && \ + func_fatal_help "too many parameters to '-version-info'" + + # 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=$1 + number_minor=$2 + number_revision=$3 + # + # 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 + # that has an extra 1 added just for fun + # + case $version_type in + # correct linux to gnu/linux during the next big refactor + darwin|freebsd-elf|linux|midnightbsd-elf|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age=$number_minor + revision=$number_revision + ;; + freebsd-aout|qnx|sunos) + current=$number_major + revision=$number_minor + age=0 + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age=$number_minor + revision=$number_minor + lt_irix_increment=no + ;; + *) + func_fatal_configuration "$modename: unknown library version type '$version_type'" + ;; + esac + ;; + no) + current=$1 + revision=$2 + age=$3 + ;; + 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]) ;; + *) + func_error "CURRENT '$current' must be a nonnegative integer" + func_fatal_error "'$vinfo' is not valid version information" + ;; + 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]) ;; + *) + func_error "REVISION '$revision' must be a nonnegative integer" + func_fatal_error "'$vinfo' is not valid version information" + ;; + 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]) ;; + *) + func_error "AGE '$age' must be a nonnegative integer" + func_fatal_error "'$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE '$age' is greater than the current interface number '$current'" + func_fatal_error "'$vinfo' is not valid version information" + 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 + func_arith $current - $age + major=.$func_arith_result + versuffix=$major.$age.$revision + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + # On Darwin other compilers + case $CC in + nagfor*) + verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" + ;; + *) + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + esac + ;; + + freebsd-aout) + major=.$current + versuffix=.$current.$revision + ;; + + freebsd-elf | midnightbsd-elf) + func_arith $current - $age + major=.$func_arith_result + versuffix=$major.$age.$revision + ;; + + irix | nonstopux) + if test no = "$lt_irix_increment"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + 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 0 -ne "$loop"; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring=$verstring_prefix$major.$iface:$verstring + done + + # Before this point, $major must not contain '.'. + major=.$major + versuffix=$major.$revision + ;; + + linux) # correct to gnu/linux during the next big refactor + func_arith $current - $age + major=.$func_arith_result + versuffix=$major.$age.$revision + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=.$current.$age.$revision + verstring=$current.$age.$revision + + # Add in all the interfaces that we are compatible with. + loop=$age + while test 0 -ne "$loop"; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring=$verstring:$iface.0 + done + + # Make executables depend on our current version. + func_append verstring ":$current.0" + ;; + + qnx) + major=.$current + versuffix=.$current + ;; + + sco) + major=.$current + versuffix=.$current + ;; + + sunos) + major=.$current + versuffix=.$current.$revision + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 file systems. + func_arith $current - $age + major=$func_arith_result + versuffix=-$major + ;; + + *) + func_fatal_configuration "unknown library version type '$version_type'" + ;; + 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 no = "$need_version"; then + versuffix= + else + versuffix=.0.0 + fi + fi + + # Remove version info from name if versioning should be avoided + if test yes,no = "$avoid_version,$need_version"; then + major= + versuffix= + verstring= + fi + + # Check to see if the archive will have undefined symbols. + if test yes = "$allow_undefined"; then + if test unsupported = "$allow_undefined_flag"; then + if test yes = "$build_old_libs"; then + func_warning "undefined symbols not allowed in $host shared libraries; building static only" + build_libtool_libs=no + else + func_fatal_error "can't build $host shared library unless -no-undefined is specified" + fi + fi + else + # Don't allow undefined symbols. + allow_undefined_flag=$no_undefined_flag + fi + + fi + + func_generate_dlsyms "$libname" "$libname" : + func_append libobjs " $symfileobj" + test " " = "$libobjs" && libobjs= + + if test relink != "$opt_mode"; 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 | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*) + if test -n "$precious_files_regex"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + func_append removelist " $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then + func_append oldlibs " $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` + # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` + # dependency_libs=`$ECHO "$dependency_libs " | $SED "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 + func_replace_sysroot "$libdir" + func_append temp_xrpath " -R$func_replace_sysroot_result" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; 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 "*) ;; + *) func_append 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 "*) ;; + *) func_append dlprefiles " $lib" ;; + esac + done + + if test yes = "$build_libtool_libs"; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + func_append deplibs " System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-midnightbsd*) + # 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 yes = "$build_libtool_need_lc"; then + func_append 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. + $opt_dry_run || $RM conftest.c + cat > conftest.c <<EOF + int main() { return 0; } +EOF + $opt_dry_run || $RM conftest + if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then + ldd_output=`ldd conftest` + for i in $deplibs; do + case $i in + -l*) + func_stripname -l '' "$i" + name=$func_stripname_result + if test yes = "$allow_libtool_libs_with_static_runtimes"; then + case " $predeps $postdeps " in + *" $i "*) + func_append 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; shift + deplib_match=$1 + if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then + func_append 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 + ;; + *) + func_append newdeplibs " $i" + ;; + esac + 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 + case $i in + -l*) + func_stripname -l '' "$i" + name=$func_stripname_result + $opt_dry_run || $RM conftest + if $LTCC $LTCFLAGS -o conftest conftest.c $i; then + ldd_output=`ldd conftest` + if test yes = "$allow_libtool_libs_with_static_runtimes"; then + case " $predeps $postdeps " in + *" $i "*) + func_append 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; shift + deplib_match=$1 + if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then + func_append 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 + ;; + *) + func_append newdeplibs " $i" + ;; + esac + done + fi + ;; + file_magic*) + set dummy $deplibs_check_method; shift + file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test yes = "$allow_libtool_libs_with_static_runtimes"; then + case " $predeps $postdeps " in + *" $a_deplib "*) + func_append newdeplibs " $a_deplib" + a_deplib= + ;; + esac + fi + if test -n "$a_deplib"; then + libname=`eval "\\$ECHO \"$libname_spec\""` + if test -n "$file_magic_glob"; then + libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob` + else + libnameglob=$libname + fi + test yes = "$want_nocaseglob" && nocaseglob=`shopt -p nocaseglob` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + if test yes = "$want_nocaseglob"; then + shopt -s nocaseglob + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + $nocaseglob + else + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + fi + 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 "$potlib" | $SED 's|[^/]*$||'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + func_append 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 + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test yes = "$allow_libtool_libs_with_static_runtimes"; then + case " $predeps $postdeps " in + *" $a_deplib "*) + func_append 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 + func_append 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 + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs= + tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` + if test yes = "$allow_libtool_libs_with_static_runtimes"; then + for i in $predeps $postdeps; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"` + done + fi + case $tmp_deplibs in + *[!\ \ ]*) + echo + if test none = "$deplibs_check_method"; 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 + ;; + esac + ;; + 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 with the System framework + newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + if test yes = "$droppeddeps"; then + if test yes = "$module"; 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 no = "$build_old_libs"; 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 no = "$allow_undefined"; 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 no = "$build_old_libs"; 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 + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + 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 " $deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append 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 yes = "$build_libtool_libs"; then + # Remove $wl instances when linking with ld. + # FIXME: should test the right _cmds variable. + case $archive_cmds in + *\$LD\ *) wl= ;; + esac + if test yes = "$hardcode_into_libs"; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath=$finalize_rpath + test relink = "$opt_mode" || rpath=$compile_rpath$rpath + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + func_replace_sysroot "$libdir" + libdir=$func_replace_sysroot_result + 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"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append dep_rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append 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 "dep_rpath=\"$hardcode_libdir_flag_spec\"" + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append 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 relink = "$opt_mode" || 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 + shift + realname=$1 + 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 + func_append linknames " $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols=$output_objdir/$libname.uexp + func_append delfiles " $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + func_dll_def_p "$export_symbols" || { + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols=$export_symbols + export_symbols= + always_export_symbols=yes + } + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for '$libname.la'" + export_symbols=$output_objdir/$libname.exp + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs=$IFS; IFS='~' + for cmd1 in $cmds; do + IFS=$save_ifs + # Take the normal branch if the nm_file_list_spec branch + # doesn't work or if tool conversion is not needed. + case $nm_file_list_spec~$to_tool_file_cmd in + *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) + try_normal_branch=yes + eval cmd=\"$cmd1\" + func_len " $cmd" + len=$func_len_result + ;; + *) + try_normal_branch=no + ;; + esac + if test yes = "$try_normal_branch" \ + && { test "$len" -lt "$max_cmd_len" \ + || test "$max_cmd_len" -le -1; } + then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + elif test -n "$nm_file_list_spec"; then + func_basename "$output" + output_la=$func_basename_result + save_libobjs=$libobjs + save_output=$output + output=$output_objdir/$output_la.nm + func_to_tool_file "$output" + libobjs=$nm_file_list_spec$func_to_tool_file_result + func_append delfiles " $output" + func_verbose "creating $NM input file list: $output" + for obj in $save_libobjs; do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > "$output" + eval cmd=\"$cmd1\" + func_show_eval "$cmd" 'exit $?' + output=$save_output + libobjs=$save_libobjs + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "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" && test : != "$skipped_export"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols=$export_symbols + test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test : != "$skipped_export" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for '$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands, which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + func_append tmp_deplibs " $test_deplib" + ;; + esac + done + deplibs=$tmp_deplibs + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test yes = "$compiler_needs_object" && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + func_append linker_flags " $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test relink = "$opt_mode"; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test yes = "$module" && 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 : != "$skipped_export" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # 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 + func_basename "$output" + output_la=$func_basename_result + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then + output=$output_objdir/$output_la.lnkscript + func_verbose "creating GNU ld script: $output" + echo 'INPUT (' > $output + for obj in $save_libobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + echo ')' >> $output + func_append delfiles " $output" + func_to_tool_file "$output" + output=$func_to_tool_file_result + elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then + output=$output_objdir/$output_la.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test yes = "$compiler_needs_object"; then + firstobj="$1 " + shift + fi + for obj + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + func_append delfiles " $output" + func_to_tool_file "$output" + output=$firstobj\"$file_list_spec$func_to_tool_file_result\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-$k.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test -z "$objlist" || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test 1 -eq "$k"; then + # The first file doesn't have a previous command to add. + reload_objs=$objlist + eval concat_cmds=\"$reload_cmds\" + else + # All subsequent reloadable object files will link in + # the last one created. + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-$k.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-$k.$objext + objlist=" $obj" + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + 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~ + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds$reload_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + func_append delfiles " $output" + + else + output= + fi + + ${skipped_export-false} && { + func_verbose "generating symbol list for '$libname.la'" + export_symbols=$output_objdir/$libname.exp + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + } + + test -n "$save_libobjs" && + func_verbose "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 + $opt_quiet || { + func_quote_arg expand,pretty "$cmd" + eval "func_echo $func_quote_arg_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test relink = "$opt_mode"; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS=$save_ifs + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + ${skipped_export-false} && { + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols=$export_symbols + test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for '$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands, which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + } + + 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\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test yes = "$module" && 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 + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs=$IFS; IFS='~' + for cmd in $cmds; do + IFS=$sp$nl + eval cmd=\"$cmd\" + IFS=$save_ifs + $opt_quiet || { + func_quote_arg expand,pretty "$cmd" + eval "func_echo $func_quote_arg_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test relink = "$opt_mode"; then + ( 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 relink = "$opt_mode"; then + $opt_dry_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 + func_show_eval '${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 + func_show_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 yes = "$module" || test yes = "$export_dynamic"; then + # On all known operating systems, these are identical. + dlname=$soname + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then + func_warning "'-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "'-l' and '-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "'-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "'-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "'-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "'-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object '$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj=$output + ;; + esac + + # Delete the old objects. + $opt_dry_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= + # if reload_cmds runs $LD directly, get rid of -Wl from + # whole_archive_flag_spec and hope we can get by with turning comma + # into space. + case $reload_cmds in + *\$LD[\ \$]*) wl= ;; + esac + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` + reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags + else + gentop=$output_objdir/${obj}x + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # If we're not building shared, we need to use non_pic_objs + test yes = "$build_libtool_libs" || libobjs=$non_pic_objects + + # Create the old-style object. + reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs + + output=$obj + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + test yes = "$build_libtool_libs" || { + if test -n "$gentop"; then + func_show_eval '${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" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + } + + if test -n "$pic_flag" || test default != "$pic_mode"; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output=$libobj + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "'-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "'-release' is ignored for programs" + + $preload \ + && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \ + && func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test CXX = "$tagname"; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + func_append compile_command " $wl-bind_at_load" + func_append finalize_command " $wl-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + 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 "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + compile_deplibs=$new_libs + + + func_append compile_command " $compile_deplibs" + func_append 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 "*) ;; + *) func_append 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"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) func_append dllsearchpath ":$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append 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"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) func_append 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 yes = "$build_old_libs"; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" false + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=: + case $host in + *cegcc* | *mingw32ce*) + # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. + wrappers_required=false + ;; + *cygwin* | *mingw* ) + test yes = "$build_libtool_libs" || wrappers_required=false + ;; + *) + if test no = "$need_relink" || test yes != "$build_libtool_libs"; then + wrappers_required=false + fi + ;; + esac + $wrappers_required || { + # Replace the output file specification. + compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + link_command=$compile_command$compile_rpath + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.$objext"; then + func_show_eval '$RM "$output_objdir/${outputname}S.$objext"' + fi + + exit $exit_status + } + + 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 + func_append 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 + func_append rpath "$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test yes = "$no_install"; 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 "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + exit $EXIT_SUCCESS + fi + + case $hardcode_action,$fast_install in + relink,*) + # Fast installation is not supported + link_command=$compile_var$compile_command$compile_rpath + relink_command=$finalize_var$finalize_command$finalize_rpath + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "'$output' will be relinked during installation" + ;; + *,yes) + link_command=$finalize_var$compile_command$finalize_rpath + relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` + ;; + *,no) + link_command=$compile_var$compile_command$compile_rpath + relink_command=$finalize_var$finalize_command$finalize_rpath + ;; + *,needless) + link_command=$finalize_var$compile_command$finalize_rpath + relink_command= + ;; + esac + + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output_objdir/$outputname" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Now create the wrapper script. + func_verbose "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}\" || $lt_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 + func_quote_arg pretty "$var_value" + relink_command="$var=$func_quote_arg_result; export $var; $relink_command" + fi + done + func_quote eval cd "`pwd`" + func_quote_arg pretty,unquoted "($func_quote_result; $relink_command)" + relink_command=$func_quote_arg_unquoted_result + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + 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 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host"; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + case $build_libtool_libs in + convenience) + oldobjs="$libobjs_save $symfileobj" + addlibs=$convenience + build_libtool_libs=no + ;; + module) + oldobjs=$libobjs_save + addlibs=$old_convenience + build_libtool_libs=no + ;; + *) + oldobjs="$old_deplibs $non_pic_objects" + $preload && test -f "$symfileobj" \ + && func_append oldobjs " $symfileobj" + addlibs=$old_convenience + ;; + esac + + if test -n "$addlibs"; then + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + + func_extract_archives $gentop $addlibs + func_append oldobjs " $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append oldobjs " $func_extract_archives_result" + fi + + # 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 + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + echo "copying selected object files to avoid basename conflicts..." + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase=$func_basename_result + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + func_append oldobjs " $gentop/$newobj" + ;; + *) func_append oldobjs " $obj" ;; + esac + done + fi + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + elif test -n "$archiver_list_spec"; then + func_verbose "using command file archive linking..." + for obj in $oldobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > $output_objdir/$libname.libcmd + func_to_tool_file "$output_objdir/$libname.libcmd" + oldobjs=" $archiver_list_spec$func_to_tool_file_result" + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$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 + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$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= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test -z "$oldobjs"; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test yes = "$build_old_libs" && old_library=$libname.$libext + func_verbose "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}\" || $lt_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 + func_quote_arg pretty,unquoted "$var_value" + relink_command="$var=$func_quote_arg_unquoted_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + func_quote eval cd "`pwd`" + relink_command="($func_quote_result; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + func_quote_arg pretty,unquoted "$relink_command" + relink_command=$func_quote_arg_unquoted_result + if test yes = "$hardcode_automatic"; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test yes = "$installed"; 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) + func_basename "$deplib" + name=$func_basename_result + func_resolve_sysroot "$deplib" + eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` + test -z "$libdir" && \ + func_fatal_error "'$deplib' is not a valid libtool archive" + func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" + ;; + -L*) + func_stripname -L '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -L$func_replace_sysroot_result" + ;; + -R*) + func_stripname -R '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -R$func_replace_sysroot_result" + ;; + *) func_append newdependency_libs " $deplib" ;; + esac + done + dependency_libs=$newdependency_libs + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name=$func_basename_result + eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "'$lib' is not a valid libtool archive" + func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" + ;; + *) func_append newdlfiles " $lib" ;; + esac + done + dlfiles=$newdlfiles + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name=$func_basename_result + eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "'$lib' is not a valid libtool archive" + func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" + ;; + esac + done + dlprefiles=$newdlprefiles + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlfiles " $abs" + done + dlfiles=$newdlfiles + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlprefiles " $abs" + done + dlprefiles=$newdlprefiles + fi + $RM $output + # place dlname in correct position for cygwin + # In fact, it would be nice if we could use this code for all target + # systems that can't hard-code library paths into their executables + # and that have no shared library path variable independent of PATH, + # but it turns out we can't easily determine that from inspecting + # libtool variables, so we have to hard-code the OSs to which it + # applies here; at the moment, that means platforms that use the PE + # object format with DLL files. See the long comment at the top of + # tests/bindir.at for full details. + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + # If a -bindir argument was supplied, place the dll there. + if test -n "$bindir"; then + func_relative_path "$install_libdir" "$bindir" + tdlname=$func_relative_path_result/$dlname + else + # Otherwise fall back on heuristic. + tdlname=../bin/$dlname + fi + ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE) $VERSION +# +# 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' + +# Linker flags that cannot go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_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 no,yes = "$installed,$need_relink"; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +if test link = "$opt_mode" || test relink = "$opt_mode"; then + func_mode_link ${1+"$@"} +fi + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $debug_cmd + + RM=$nonopt + files= + rmforce=false + 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) func_append RM " $arg"; rmforce=: ;; + -*) func_append RM " $arg" ;; + *) func_append files " $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + for file in $files; do + func_dirname "$file" "" "." + dir=$func_dirname_result + if test . = "$dir"; then + odir=$objdir + else + odir=$dir/$objdir + fi + func_basename "$file" + name=$func_basename_result + test uninstall = "$opt_mode" && odir=$dir + + # Remember odir for removal later, being careful to avoid duplicates + if test clean = "$opt_mode"; then + case " $rmdirs " in + *" $odir "*) ;; + *) func_append rmdirs " $odir" ;; + 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 $rmforce; then + continue + fi + + rmfiles=$file + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + func_append rmfiles " $odir/$n" + done + test -n "$old_library" && func_append rmfiles " $odir/$old_library" + + case $opt_mode in + clean) + case " $library_names " in + *" $dlname "*) ;; + *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; + esac + test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && test none != "$pic_object"; then + func_append rmfiles " $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && test none != "$non_pic_object"; then + func_append rmfiles " $dir/$non_pic_object" + fi + fi + ;; + + *) + if test clean = "$opt_mode"; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + func_append rmfiles " $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + func_append rmfiles " $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + func_append rmfiles " $odir/$name $odir/${name}S.$objext" + if test yes = "$fast_install" && test -n "$relink_command"; then + func_append rmfiles " $odir/lt-$name" + fi + if test "X$noexename" != "X$name"; then + func_append rmfiles " $odir/lt-$noexename.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + + # Try to remove the $objdir's in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then + func_mode_uninstall ${1+"$@"} +fi + +test -z "$opt_mode" && { + help=$generic_help + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode '$opt_mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# where 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 +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/mesh/README b/mesh/README deleted file mode 100644 index f36b97c2ba67214f676854daf764fdd616891652..0000000000000000000000000000000000000000 --- a/mesh/README +++ /dev/null @@ -1,95 +0,0 @@ -Bluetooth Mesh Daemon -********************* - -Copyright (C) 2019 Intel Corporation. All rights reserved. - -Compilation and installation -============================ - -In addition to main BlueZ requirements, MeshCtl needs the following: - - json-c library - -Configuration and options -========================= - - --enable-mesh - - Build mesh daemon and other Bluetooth Mesh based tools - -Current implementation of the mesh daemon requires exclusive access to -a Bluetooth controller. -The AutoEnable option in the installed main.conf should be set to "false". - -Storage -======= - -Default storage directory is /var/lib/bluetooth/mesh. - -The directory contains the provisioned nodes configurations. -Each node has its own subdirectory, named after node's Device UUID (32-digit -hexadecimal string) that is generated by the application that created a node. - -Each subdirectory contains the following files: - - node.json: - node configuration and is populated by the - daemon based on the configuration commands from a - provisioner/configuration client - - node.json.bak: - a backup that the last known good node configuration. - - seq_num: - File containing next sequence number to use - - seq_num.bak: - Backup of the sequence number. This may be larger than the - actual sequence number being used at runtime, to prevent re-use - of sequence numbers in the event of an unexpected restart. - - ./rpl/: - Directory to store the sequence numbers of remote nodes, as - required by Replay Protection List (RPL) parameters. - - xxxx: - Files named for remote Unicast addresses, and contain - last received iv_index + seq_num from each SRC address. - - ./dev_keys/: - Directory to store remote Device keys. This is only created/used - by Configuration Client (Network administration) nodes. - - xxxx: - Files named for remote Unicast addresses, and contains - 16 octet key. - - ./net_keys/: - Directory to store network subnet keys. This is only - created/used by Configuration Client (Network administration) - nodes. - - xxx: - Files named for subnet index, and contains key refresh - phase, and old/new versions of the key. - - ./app_keys/: - Directory to store application keys. This is only created/used - by Configuration Client (Network administration) nodes. - - xxx: - Files named for application index, and contains bound - subnet index, and old/new versions of the key. - -The node.json and node.json.bak are in JSON format. All other files are stored -in little endian binary format. - -Known Issues -============ - -Bluetooth Mesh makes heavy usage of AEAD-AES_CCM encryption, which is -implemented in the Linux kernel on most platforms. Some platforms, including -those with kernel versions including and prior to v4.8, did *not* correctly -implement the AEAD encryption routines. If Mesh is to be ported to such a -system, it will be the responsibility of the vendor to provide support for -AEAD-AES_CCM encryption by some other method. - -Support for the required AEAD routines can be determined by running the unit -tests provided with the ELL libraries used by Mesh. Specifically, the tests -found in .../ell/unit/test-cipher.c - -Information -=========== - -Mailing lists: - linux-bluetooth@vger.kernel.org - -For additional information about the project visit BlueZ web site: - http://www.bluez.org diff --git a/mesh/agent.c b/mesh/agent.c index 5058d0d8df0f3c7615828f5c1e48a148ab2b7daf..2f9697a3330c67b58a6963ab29053ffe15e27534 100644 --- a/mesh/agent.c +++ b/mesh/agent.c @@ -61,7 +61,7 @@ struct oob_info { uint16_t mask; }; -static struct prov_action cap_table[] = { +static const struct prov_action cap_table[] = { {"blink", 0x0001, 0x0000, 1}, {"beep", 0x0002, 0x0000, 1}, {"vibrate", 0x0004, 0x0000, 1}, @@ -73,7 +73,7 @@ static struct prov_action cap_table[] = { {"in-alpha", 0x0000, 0x0008, 8} }; -static struct oob_info oob_table[] = { +static const struct oob_info oob_table[] = { {"other", 0x0001}, {"uri", 0x0002}, {"machine-code-2d", 0x0004}, diff --git a/mesh/bluetooth-mesh.service.in b/mesh/bluetooth-mesh.service.in index c8afbf53e9c32a87f90d0836e010f0fc6a58db2f..899ef107b85bc8836367649337fe99ffe7fe4311 100644 --- a/mesh/bluetooth-mesh.service.in +++ b/mesh/bluetooth-mesh.service.in @@ -5,7 +5,7 @@ ConditionPathIsDirectory=/sys/class/bluetooth [Service] Type=dbus BusName=org.bluez.mesh -ExecStart=@pkglibexecdir@/bluetooth-meshd +ExecStart=@PKGLIBEXECDIR@/bluetooth-meshd NotifyAccess=main LimitNPROC=1 ProtectHome=true diff --git a/mesh/bluetooth-meshd.rst.in b/mesh/bluetooth-meshd.rst.in index 06cdb69da097e287cfbca150cbbe333c1303c3e2..761536711ca15a53749a806740b8f03aee8f0b6f 100644 --- a/mesh/bluetooth-meshd.rst.in +++ b/mesh/bluetooth-meshd.rst.in @@ -36,14 +36,17 @@ OPTIONS -i <type>, --io <type> Specifies I/O interface type: - *hci<index>* - Use generic HCI io on interface hci<index>, - or, if no idex is specified, the first available one. + *auto* - Use first available controller: via MGMT interface + if kernel supports it, otherwise, via raw HCI socket. + + *generic:[hci]<index>* - Use generic HCI io on interface + hci<index>. *unit:<fd_path>*- Specifies open file descriptor for daemon testing. - By default, if no type is specified, uses generic I/O - on the first available HCI interface. + By default, if no type is specified, uses auto I/O + on the first available controller. -c <file>, --config <file> Specifies an explicit config file path instead of relying on the diff --git a/mesh/cfgmod-server.c b/mesh/cfgmod-server.c index be90ef8c5888f56e7092b9b22e293836b2e1f9c3..f64566daf39eb1004caf25ddafb0878015f1bc83 100644 --- a/mesh/cfgmod-server.c +++ b/mesh/cfgmod-server.c @@ -30,8 +30,8 @@ (SET_ID(SIG_VENDOR, l_get_le16(pkt)))) /* Supported composition pages, sorted high to low */ -/* Only page 0 is currently supported */ static const uint8_t supported_pages[] = { + 128, 0 }; @@ -736,7 +736,7 @@ static uint16_t cfg_net_tx_msg(struct mesh_node *node, const uint8_t *pkt, static uint16_t get_composition(struct mesh_node *node, uint8_t page, uint8_t *buf) { - const uint8_t *comp; + const uint8_t *comp = NULL; uint16_t len = 0; size_t i; @@ -751,7 +751,7 @@ static uint16_t get_composition(struct mesh_node *node, uint8_t page, break; } - if (!len) + if (!len || !comp) return 0; *buf++ = page; diff --git a/mesh/crypto.c b/mesh/crypto.c index 668d16877981c99e99c6e80a643618e11d92469c..b712a26549ad7d00d9418862a6f135efd0281d62 100644 --- a/mesh/crypto.c +++ b/mesh/crypto.c @@ -94,13 +94,6 @@ bool mesh_crypto_aes_ccm_encrypt(const uint8_t nonce[13], const uint8_t key[16], result = l_aead_cipher_encrypt(cipher, msg, msg_len, aad, aad_len, nonce, 13, out_msg, msg_len + mic_size); - if (result && out_mic) { - if (mic_size == 4) - *(uint32_t *)out_mic = l_get_be32(out_msg + msg_len); - else - *(uint64_t *)out_mic = l_get_be64(out_msg + msg_len); - } - l_aead_cipher_free(cipher); return result; @@ -251,9 +244,9 @@ bool mesh_crypto_nkbk(const uint8_t n[16], uint8_t beacon_key[16]) return crypto_128(n, "nkbk", beacon_key); } -bool mesh_crypto_nkpk(const uint8_t n[16], uint8_t proxy_key[16]) +bool mesh_crypto_nkpk(const uint8_t n[16], uint8_t private_key[16]) { - return crypto_128(n, "nkpk", proxy_key); + return crypto_128(n, "nkpk", private_key); } bool mesh_crypto_k3(const uint8_t n[16], uint8_t out64[8]) @@ -1020,7 +1013,7 @@ static const uint8_t crypto_test_result[] = { 0x9a, 0x2a, 0xbf, 0x96 }; -bool mesh_crypto_check_avail() +bool mesh_crypto_check_avail(void) { void *cipher; bool result; diff --git a/mesh/crypto.h b/mesh/crypto.h index c31abbbbd1ca94831b57b58e1437945cfaa8b23a..55789886eb0eb8533d3932a6bcd88c4730d1de56 100644 --- a/mesh/crypto.h +++ b/mesh/crypto.h @@ -26,7 +26,7 @@ bool mesh_aes_ecb_one(const uint8_t key[16], const uint8_t plaintext[16], uint8_t encrypted[16]); bool mesh_crypto_nkik(const uint8_t network_key[16], uint8_t identity_key[16]); bool mesh_crypto_nkbk(const uint8_t network_key[16], uint8_t beacon_key[16]); -bool mesh_crypto_nkpk(const uint8_t network_key[16], uint8_t proxy_key[16]); +bool mesh_crypto_nkpk(const uint8_t network_key[16], uint8_t private_key[16]); bool mesh_crypto_identity(const uint8_t net_key[16], uint16_t addr, uint8_t id[16]); bool mesh_crypto_beacon_cmac(const uint8_t encryption_key[16], diff --git a/mesh/keyring.c b/mesh/keyring.c index 995a4b88fe91a506e2acad865df6f12ec6372b9c..1e1de3e54bfb1d7f13b629fbd57d00fff88b991e 100644 --- a/mesh/keyring.c +++ b/mesh/keyring.c @@ -30,9 +30,9 @@ #include "mesh/node.h" #include "mesh/keyring.h" -const char *dev_key_dir = "/dev_keys"; -const char *app_key_dir = "/app_keys"; -const char *net_key_dir = "/net_keys"; +static const char *dev_key_dir = "/dev_keys"; +static const char *app_key_dir = "/app_keys"; +static const char *net_key_dir = "/net_keys"; static int open_key_file(struct mesh_node *node, const char *key_dir, uint16_t idx, int flags) @@ -371,6 +371,28 @@ bool keyring_del_remote_dev_key(struct mesh_node *node, uint16_t unicast, return true; } +bool keyring_del_remote_dev_key_all(struct mesh_node *node, uint16_t unicast) +{ + uint8_t dev_key[16]; + uint8_t test_key[16]; + uint8_t cnt = 1; + + if (!keyring_get_remote_dev_key(node, unicast, dev_key)) + return false; + + while (keyring_get_remote_dev_key(node, unicast + cnt, test_key)) { + if (memcmp(dev_key, test_key, sizeof(dev_key))) + break; + + cnt++; + } + + if (cnt > 1) + return keyring_del_remote_dev_key(node, unicast + 1, cnt - 1); + + return true; +} + static DIR *open_key_dir(const char *node_path, const char *key_dir_name) { char dir_path[PATH_MAX]; diff --git a/mesh/keyring.h b/mesh/keyring.h index ecf62cbc10640ecf014e93009eb25725c6a03628..efc499ac267e3b46be52c9da1e4b57a29531c460 100644 --- a/mesh/keyring.h +++ b/mesh/keyring.h @@ -39,5 +39,6 @@ bool keyring_put_remote_dev_key(struct mesh_node *node, uint16_t unicast, uint8_t count, uint8_t dev_key[16]); bool keyring_del_remote_dev_key(struct mesh_node *node, uint16_t unicast, uint8_t count); +bool keyring_del_remote_dev_key_all(struct mesh_node *node, uint16_t unicast); bool keyring_build_export_keys_reply(struct mesh_node *node, struct l_dbus_message_builder *builder); diff --git a/mesh/main.c b/mesh/main.c index 3bca020a0a387bcab0ef334fc72c167e1948ba11..145bcfa98d8592fd861d2542972430ef6ca6516e 100644 --- a/mesh/main.c +++ b/mesh/main.c @@ -48,6 +48,12 @@ static const struct option main_options[] = { { } }; +static const char *io_usage = + "\t(auto | generic:[hci]<index> | unit:<fd_path>)\n" + "\t\tauto - Use first available controller (MGMT or raw HCI)\n" + "\t\tgeneric - Use raw HCI io on interface hci<index>\n" + "\t\tunit - Use test IO (for automatic testing only)\n"; + static void usage(void) { fprintf(stderr, @@ -55,18 +61,14 @@ static void usage(void) "\tbluetooth-meshd [options]\n"); fprintf(stderr, "Options:\n" - "\t--io <io> Use specified io (default: generic)\n" + "\t--io <io> Use specified io (default: auto)\n" "\t--config Daemon configuration directory\n" "\t--storage Mesh node(s) configuration directory\n" "\t--nodetach Run in foreground\n" "\t--debug Enable debug output\n" "\t--dbus-debug Enable D-Bus debugging\n" "\t--help Show %s information\n", __func__); - fprintf(stderr, - "io:\n" - "\t([hci]<index> | generic[:[hci]<index>] | unit:<fd_path>)\n" - "\t\tUse generic HCI io on interface hci<index>, or the first\n" - "\t\tavailable one\n"); + fprintf(stderr, "\n\t io: %s", io_usage); } static void do_debug(const char *str, void *user_data) @@ -157,21 +159,8 @@ static bool parse_io(const char *optarg, enum mesh_io_type *type, void **opts) *opts = index; optarg += strlen("auto"); - if (!*optarg) { - *index = MGMT_INDEX_NONE; - return true; - } - - if (*optarg != ':') - return false; - - optarg++; - - if (sscanf(optarg, "hci%d", index) == 1) - return true; - - if (sscanf(optarg, "%d", index) == 1) - return true; + *index = MGMT_INDEX_NONE; + return true; return false; } else if (strstr(optarg, "generic") == optarg) { @@ -181,12 +170,7 @@ static bool parse_io(const char *optarg, enum mesh_io_type *type, void **opts) *opts = index; optarg += strlen("generic"); - if (!*optarg) { - *index = MGMT_INDEX_NONE; - return true; - } - - if (*optarg != ':') + if (!*optarg || *optarg != ':') return false; optarg++; @@ -291,7 +275,7 @@ int main(int argc, char *argv[]) io = l_strdup_printf("auto"); if (!parse_io(io, &io_type, &io_opts)) { - l_error("Invalid io: %s", io); + l_error("Invalid io: %s\n%s", io, io_usage); status = EXIT_FAILURE; goto done; } diff --git a/mesh/manager.c b/mesh/manager.c index e66b1a45bd321f7ecb40fd8af1c064647e870f14..0c98721bf4b5d96f165bb7271e71e557a50c0988 100644 --- a/mesh/manager.c +++ b/mesh/manager.c @@ -21,75 +21,137 @@ #include "mesh/mesh.h" #include "mesh/mesh-io.h" #include "mesh/node.h" +#include "mesh/model.h" #include "mesh/net.h" #include "mesh/keyring.h" #include "mesh/agent.h" #include "mesh/provision.h" +#include "mesh/prov.h" +#include "mesh/remprv.h" #include "mesh/manager.h" -struct add_data{ +struct prov_remote_data { struct l_dbus_message *msg; struct mesh_agent *agent; struct mesh_node *node; uint32_t disc_watch; + uint16_t original; uint16_t primary; uint16_t net_idx; + uint8_t transport; uint8_t num_ele; uint8_t uuid[16]; }; -static int8_t scan_rssi; -static uint8_t scan_uuid[16]; -static struct mesh_node *scan_node; -static struct l_timeout *scan_timeout; -static struct add_data *add_pending; +struct scan_req { + struct mesh_node *node; + struct l_timeout *timeout; + uint16_t server; + uint16_t net_idx; + uint8_t uuid[16]; + int8_t rssi; + bool ext; +}; + +static struct l_queue *scans; +static struct prov_remote_data *prov_pending; static const uint8_t prvb[2] = {MESH_AD_TYPE_BEACON, 0x00}; +static bool by_scan(const void *a, const void *b) +{ + return a == b; +} + +static bool by_node(const void *a, const void *b) +{ + const struct scan_req *req = a; + const struct mesh_node *node = b; + + return req->node == node; +} + +static bool by_node_svr(const void *a, const void *b) +{ + const struct scan_req *req = a; + const struct scan_req *test = b; + + return req->node == test->node && req->server == test->server; +} + static void scan_cancel(struct l_timeout *timeout, void *user_data) { - struct mesh_node *node = user_data; + struct scan_req *req = user_data; struct mesh_io *io; struct mesh_net *net; + uint8_t msg[4]; + int n; l_debug(""); - if (scan_timeout) - l_timeout_remove(scan_timeout); + req = l_queue_remove_if(scans, by_scan, req); + + if (!req) + return; + + l_timeout_remove(req->timeout); + + if (req->server) { + n = mesh_model_opcode_set(OP_REM_PROV_SCAN_STOP, msg); + mesh_model_send(req->node, 0, req->server, APP_IDX_DEV_REMOTE, + req->net_idx, DEFAULT_TTL, + true, n, msg); + } else { + net = node_get_net(req->node); + io = mesh_net_get_io(net); + mesh_io_deregister_recv_cb(io, prvb, sizeof(prvb)); + } - net = node_get_net(node); - io = mesh_net_get_io(net); - mesh_io_deregister_recv_cb(io, prvb, sizeof(prvb)); - scan_node = NULL; - scan_timeout = NULL; + initiator_scan_unreg(req->node); + l_free(req); } -static void free_pending_add_call() +static void free_pending_add_call(void) { - if (!add_pending) + if (!prov_pending) return; - if (add_pending->disc_watch) + if (prov_pending->disc_watch) l_dbus_remove_watch(dbus_get_bus(), - add_pending->disc_watch); + prov_pending->disc_watch); - if (add_pending->msg) - l_dbus_message_unref(add_pending->msg); + if (prov_pending->msg) + l_dbus_message_unref(prov_pending->msg); - l_free(add_pending); - add_pending = NULL; + l_free(prov_pending); + prov_pending = NULL; } static void prov_disc_cb(struct l_dbus *bus, void *user_data) { - if (!add_pending) + if (!prov_pending) return; - initiator_cancel(add_pending); - add_pending->disc_watch = 0; + initiator_cancel(prov_pending); + prov_pending->disc_watch = 0; free_pending_add_call(); } +static void append_dict_entry_basic(struct l_dbus_message_builder *builder, + const char *key, const char *signature, + const void *data) +{ + if (!builder) + return; + + l_dbus_message_builder_enter_dict(builder, "sv"); + l_dbus_message_builder_append_basic(builder, 's', key); + l_dbus_message_builder_enter_variant(builder, signature); + l_dbus_message_builder_append_basic(builder, signature[0], data); + l_dbus_message_builder_leave_variant(builder); + l_dbus_message_builder_leave_dict(builder); +} + static void send_add_failed(const char *owner, const char *path, uint8_t status) { @@ -102,7 +164,7 @@ static void send_add_failed(const char *owner, const char *path, "AddNodeFailed"); builder = l_dbus_message_builder_new(msg); - dbus_append_byte_array(builder, add_pending->uuid, 16); + dbus_append_byte_array(builder, prov_pending->uuid, 16); l_dbus_message_builder_append_basic(builder, 's', mesh_prov_status_str(status)); l_dbus_message_builder_finalize(builder); @@ -115,14 +177,14 @@ static void send_add_failed(const char *owner, const char *path, static bool add_cmplt(void *user_data, uint8_t status, struct mesh_prov_node_info *info) { - struct add_data *pending = user_data; + struct prov_remote_data *pending = user_data; struct mesh_node *node = pending->node; struct l_dbus *dbus = dbus_get_bus(); struct l_dbus_message_builder *builder; struct l_dbus_message *msg; bool result; - if (pending != add_pending) + if (pending != prov_pending) return false; if (status != PROV_ERR_SUCCESS) { @@ -131,7 +193,12 @@ static bool add_cmplt(void *user_data, uint8_t status, return false; } - result = keyring_put_remote_dev_key(add_pending->node, info->unicast, + /* If Unicast address changing, delete old dev key */ + if (pending->transport == PB_NPPI_01) + keyring_del_remote_dev_key_all(pending->node, + pending->original); + + result = keyring_put_remote_dev_key(pending->node, info->unicast, info->num_ele, info->device_key); if (!result) { @@ -140,13 +207,29 @@ static bool add_cmplt(void *user_data, uint8_t status, return false; } - msg = l_dbus_message_new_method_call(dbus, node_get_owner(node), + if (pending->transport > PB_NPPI_02) + msg = l_dbus_message_new_method_call(dbus, node_get_owner(node), node_get_app_path(node), MESH_PROVISIONER_INTERFACE, "AddNodeComplete"); + else + msg = l_dbus_message_new_method_call(dbus, node_get_owner(node), + node_get_app_path(node), + MESH_PROVISIONER_INTERFACE, + "ReprovComplete"); builder = l_dbus_message_builder_new(msg); - dbus_append_byte_array(builder, add_pending->uuid, 16); + + if (pending->transport > PB_NPPI_02) + dbus_append_byte_array(builder, pending->uuid, 16); + else { + uint8_t nppi = (uint8_t) pending->transport; + + l_dbus_message_builder_append_basic(builder, 'q', + &pending->original); + l_dbus_message_builder_append_basic(builder, 'y', &nppi); + } + l_dbus_message_builder_append_basic(builder, 'q', &info->unicast); l_dbus_message_builder_append_basic(builder, 'y', &info->num_ele); l_dbus_message_builder_finalize(builder); @@ -161,47 +244,66 @@ static bool add_cmplt(void *user_data, uint8_t status, static void mgr_prov_data (struct l_dbus_message *reply, void *user_data) { - struct add_data *pending = user_data; + struct prov_remote_data *pending = user_data; uint16_t net_idx; uint16_t primary; - if (pending != add_pending) + if (pending != prov_pending) return; if (l_dbus_message_is_error(reply)) return; - if (!l_dbus_message_get_arguments(reply, "qq", &net_idx, &primary)) + if (pending->transport == PB_NPPI_01) { + /* If performing NPPI, we only get new primary unicast here */ + if (!l_dbus_message_get_arguments(reply, "q", &primary)) + return; + + net_idx = pending->net_idx; + + } else if (!l_dbus_message_get_arguments(reply, "qq", &net_idx, + &primary)) return; - add_pending->primary = primary; - add_pending->net_idx = net_idx; - initiator_prov_data(net_idx, primary, add_pending); + pending->primary = primary; + pending->net_idx = net_idx; + initiator_prov_data(net_idx, primary, pending); } static bool add_data_get(void *user_data, uint8_t num_ele) { - struct add_data *pending = user_data; + struct prov_remote_data *pending = user_data; struct l_dbus_message *msg; struct l_dbus *dbus; const char *app_path; const char *sender; - if (pending != add_pending) + if (pending != prov_pending) return false; dbus = dbus_get_bus(); - app_path = node_get_app_path(add_pending->node); - sender = node_get_owner(add_pending->node); + app_path = node_get_app_path(pending->node); + sender = node_get_owner(pending->node); - msg = l_dbus_message_new_method_call(dbus, sender, app_path, + if (pending->transport > PB_NPPI_02) { + msg = l_dbus_message_new_method_call(dbus, sender, app_path, MESH_PROVISIONER_INTERFACE, "RequestProvData"); - l_dbus_message_set_arguments(msg, "y", num_ele); - l_dbus_send_with_reply(dbus, msg, mgr_prov_data, add_pending, NULL); + l_dbus_message_set_arguments(msg, "y", num_ele); + } else if (pending->transport == PB_NPPI_01) { + msg = l_dbus_message_new_method_call(dbus, sender, app_path, + MESH_PROVISIONER_INTERFACE, + "RequestReprovData"); + + l_dbus_message_set_arguments(msg, "qy", pending->original, + num_ele); + } else + return false; - add_pending->num_ele = num_ele; + l_dbus_send_with_reply(dbus, msg, mgr_prov_data, pending, NULL); + + pending->num_ele = num_ele; return true; } @@ -213,15 +315,95 @@ static void add_start(void *user_data, int err) l_debug("Start callback"); if (err == MESH_ERROR_NONE) - reply = l_dbus_message_new_method_return(add_pending->msg); + reply = l_dbus_message_new_method_return(prov_pending->msg); else - reply = dbus_error(add_pending->msg, MESH_ERROR_FAILED, + reply = dbus_error(prov_pending->msg, MESH_ERROR_FAILED, "Failed to start provisioning initiator"); l_dbus_send(dbus_get_bus(), reply); - l_dbus_message_unref(add_pending->msg); + l_dbus_message_unref(prov_pending->msg); + + prov_pending->msg = NULL; +} + +static struct l_dbus_message *reprovision_call(struct l_dbus *dbus, + struct l_dbus_message *msg, + void *user_data) +{ + struct mesh_node *node = user_data; + struct l_dbus_message_iter options, var; + struct l_dbus_message *reply; + struct mesh_net *net = node_get_net(node); + const char *key; + uint16_t subidx; + uint16_t server = 0; + uint8_t nppi = 0; + + l_debug("Reprovision request"); + + if (!l_dbus_message_get_arguments(msg, "qa{sv}", &server, &options)) + return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); + + if (!IS_UNICAST(server)) + return dbus_error(msg, MESH_ERROR_INVALID_ARGS, "Bad Unicast"); + + /* Default to nodes primary subnet index */ + subidx = mesh_net_get_primary_idx(net); + + /* Get Provisioning Options */ + while (l_dbus_message_iter_next_entry(&options, &key, &var)) { + bool failed = true; + + if (!strcmp(key, "NPPI")) { + if (l_dbus_message_iter_get_variant(&var, "y", &nppi)) { + if (nppi <= 2) + failed = false; + } + } else if (!strcmp(key, "Subnet")) { + if (l_dbus_message_iter_get_variant(&var, "q", + &subidx)) { + if (subidx <= MAX_KEY_IDX) + failed = false; + } + } + + if (failed) + return dbus_error(msg, MESH_ERROR_INVALID_ARGS, + "Invalid options"); + } + + /* AddNode cancels all outstanding Scanning from node */ + manager_scan_cancel(node); - add_pending->msg = NULL; + /* Invoke Prov Initiator */ + prov_pending = l_new(struct prov_remote_data, 1); + + prov_pending->transport = nppi; + prov_pending->node = node; + prov_pending->original = server; + prov_pending->agent = node_get_agent(node); + + if (!node_is_provisioner(node) || (prov_pending->agent == NULL)) { + reply = dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, + "Missing Interfaces"); + goto fail; + } + + prov_pending->msg = l_dbus_message_ref(msg); + initiator_start(prov_pending->transport, server, subidx, NULL, 99, 60, + prov_pending->agent, add_start, + add_data_get, add_cmplt, node, + prov_pending); + + prov_pending->disc_watch = l_dbus_add_disconnect_watch(dbus, + node_get_owner(node), + prov_disc_cb, NULL, NULL); + + return NULL; +fail: + l_free(prov_pending); + prov_pending = NULL; + return reply; } static struct l_dbus_message *add_node_call(struct l_dbus *dbus, @@ -229,55 +411,101 @@ static struct l_dbus_message *add_node_call(struct l_dbus *dbus, void *user_data) { struct mesh_node *node = user_data; - struct l_dbus_message_iter iter_uuid, options; + struct l_dbus_message_iter iter_uuid, options, var; struct l_dbus_message *reply; + struct mesh_net *net = node_get_net(node); + const char *key; uint8_t *uuid; - uint32_t n = 22; + uint32_t n = 0; + uint16_t subidx; + uint16_t sec = 60; + uint16_t server = 0; l_debug("AddNode request"); if (!l_dbus_message_get_arguments(msg, "aya{sv}", &iter_uuid, &options)) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); - if (!l_dbus_message_iter_get_fixed_array(&iter_uuid, &uuid, &n) - || n != 16) + if (!l_dbus_message_iter_get_fixed_array(&iter_uuid, &uuid, &n) || + n != 16) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, "Bad device UUID"); - /* Allow AddNode to cancel Scanning if from the same node */ - if (scan_node) { - if (scan_node != node) - return dbus_error(msg, MESH_ERROR_BUSY, NULL); + /* Default to nodes primary subnet index */ + subidx = mesh_net_get_primary_idx(net); - scan_cancel(NULL, node); + /* Get Provisioning Options */ + while (l_dbus_message_iter_next_entry(&options, &key, &var)) { + bool failed = true; + + if (!strcmp(key, "Seconds")) { + if (l_dbus_message_iter_get_variant(&var, "q", &sec)) + failed = false; + } else if (!strcmp(key, "Server")) { + if (l_dbus_message_iter_get_variant(&var, "q", + &server)) { + if (server < 0x8000) + failed = false; + } + } else if (!strcmp(key, "Subnet")) { + if (l_dbus_message_iter_get_variant(&var, "q", + &subidx)) { + if (subidx <= MAX_KEY_IDX) + failed = false; + } + } + + if (failed) + return dbus_error(msg, MESH_ERROR_INVALID_ARGS, + "Invalid options"); } + /* Device Key update/Composition update requires remote server */ + if (!n && !server) + return dbus_error(msg, MESH_ERROR_INVALID_ARGS, + "Invalid options"); + + /* If no server specified, use local */ + if (!server) + server = node_get_primary(node); + + /* AddNode cancels all outstanding Scanning from node */ + manager_scan_cancel(node); + /* Invoke Prov Initiator */ - add_pending = l_new(struct add_data, 1); - memcpy(add_pending->uuid, uuid, 16); - add_pending->node = node; - add_pending->agent = node_get_agent(node); + prov_pending = l_new(struct prov_remote_data, 1); + + if (n) + memcpy(prov_pending->uuid, uuid, 16); + else + uuid = NULL; - if (!node_is_provisioner(node) || (add_pending->agent == NULL)) { + prov_pending->transport = PB_ADV; + prov_pending->node = node; + prov_pending->agent = node_get_agent(node); + + if (!node_is_provisioner(node) || (prov_pending->agent == NULL)) { l_debug("Provisioner: %d", node_is_provisioner(node)); - l_debug("Agent: %p", add_pending->agent); + l_debug("Agent: %p", prov_pending->agent); reply = dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, "Missing Interfaces"); goto fail; } - add_pending->msg = l_dbus_message_ref(msg); - initiator_start(PB_ADV, uuid, 99, 60, add_pending->agent, add_start, - add_data_get, add_cmplt, node, add_pending); + prov_pending->msg = l_dbus_message_ref(msg); + initiator_start(PB_ADV, server, subidx, uuid, 99, sec, + prov_pending->agent, add_start, + add_data_get, add_cmplt, node, + prov_pending); - add_pending->disc_watch = l_dbus_add_disconnect_watch(dbus, + prov_pending->disc_watch = l_dbus_add_disconnect_watch(dbus, node_get_owner(node), prov_disc_cb, NULL, NULL); return NULL; fail: - l_free(add_pending); - add_pending = NULL; + l_free(prov_pending); + prov_pending = NULL; return reply; } @@ -337,38 +565,50 @@ static struct l_dbus_message *delete_node_call(struct l_dbus *dbus, return l_dbus_message_new_method_return(msg); } -static void prov_beacon_recv(void *user_data, struct mesh_io_recv_info *info, +static void manager_scan_result(void *user_data, uint16_t server, bool ext, const uint8_t *data, uint16_t len) { - struct mesh_node *node = user_data; + struct scan_req node_svr = { + .node = user_data, + .server = server, + }; + struct scan_req *req; struct l_dbus_message_builder *builder; struct l_dbus_message *msg; struct l_dbus *dbus; int16_t rssi; - if (scan_node != node || len < sizeof(scan_uuid) + 2 || data[1] != 0x00) + l_debug("scan_result %4.4x %p", server, user_data); + req = l_queue_find(scans, by_node_svr, &node_svr); + if (!req) { + l_debug("No scan_result req"); return; + } - if (!memcmp(data + 2, scan_uuid, sizeof(scan_uuid))) { - if (info->rssi <= scan_rssi) + /* Filter repeats with weaker signal */ + if (!memcmp(data + 1, req->uuid, sizeof(req->uuid))) { + if (!ext && ((int8_t) data[0] <= req->rssi)) { + l_debug("Already Seen"); return; + } } - memcpy(scan_uuid, data + 2, sizeof(scan_uuid)); - scan_rssi = info->rssi; - rssi = info->rssi; + if (!ext && ((int8_t) data[0] > req->rssi)) + req->rssi = (int8_t) data[0]; + rssi = req->rssi; + memcpy(req->uuid, data + 1, sizeof(req->uuid)); dbus = dbus_get_bus(); - msg = l_dbus_message_new_method_call(dbus, node_get_owner(node), - node_get_app_path(node), + msg = l_dbus_message_new_method_call(dbus, node_get_owner(req->node), + node_get_app_path(req->node), MESH_PROVISIONER_INTERFACE, "ScanResult"); builder = l_dbus_message_builder_new(msg); l_dbus_message_builder_append_basic(builder, 'n', &rssi); - dbus_append_byte_array(builder, data + 2, len -2); + dbus_append_byte_array(builder, data + 1, len - 1); l_dbus_message_builder_enter_array(builder, "{sv}"); - /* TODO: populate with options when defined */ + append_dict_entry_basic(builder, "Server", "q", &server); l_dbus_message_builder_leave_array(builder); l_dbus_message_builder_finalize(builder); l_dbus_message_builder_destroy(builder); @@ -380,27 +620,71 @@ static struct l_dbus_message *start_scan_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { - struct mesh_node *node = user_data; - uint16_t duration = 0; - struct mesh_io *io; + struct scan_req new_req = { + .node = user_data, + .server = 0, + .timeout = NULL, + .ext = false, + }; + struct scan_req *req; struct mesh_net *net; + uint8_t *uuid, *ext = NULL; + uint8_t scan_req[21]; + int n; + uint32_t ext_len; + uint32_t flen = 0; + uint16_t sec = 60; const char *key; struct l_dbus_message_iter options, var; const char *sender = l_dbus_message_get_sender(msg); - if (strcmp(sender, node_get_owner(node))) + if (strcmp(sender, node_get_owner(new_req.node))) return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); if (!l_dbus_message_get_arguments(msg, "a{sv}", &options)) return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL); + if (!node_is_provisioner(new_req.node)) + return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); + + net = node_get_net(new_req.node); + new_req.net_idx = mesh_net_get_primary_idx(net); + memset(new_req.uuid, 0, sizeof(new_req.uuid)); + while (l_dbus_message_iter_next_entry(&options, &key, &var)) { bool failed = true; if (!strcmp(key, "Seconds")) { - if (l_dbus_message_iter_get_variant(&var, "q", - &duration)) { + if (l_dbus_message_iter_get_variant(&var, "q", &sec)) failed = false; + } else if (!strcmp(key, "Subnet")) { + if (l_dbus_message_iter_get_variant(&var, "q", + &new_req.net_idx)) { + if (new_req.net_idx <= MAX_KEY_IDX) + failed = false; + } + } else if (!strcmp(key, "Server")) { + if (l_dbus_message_iter_get_variant(&var, "q", + &new_req.server)) { + if (new_req.server < 0x8000) + failed = false; + } + } else if (!strcmp(key, "Filter")) { + if (l_dbus_message_iter_get_variant(&var, "ay", &var)) { + if (l_dbus_message_iter_get_fixed_array(&var, + &uuid, &flen)) { + if (flen == 16) { + memcpy(new_req.uuid, uuid, + flen); + failed = false; + } + } + } + } else if (!strcmp(key, "Extended")) { + if (l_dbus_message_iter_get_variant(&var, "ay", &var)) { + if (l_dbus_message_iter_get_fixed_array(&var, + &ext, &ext_len)) + failed = false; } } @@ -409,27 +693,51 @@ static struct l_dbus_message *start_scan_call(struct l_dbus *dbus, "Invalid options"); } - if (scan_node && scan_node != node) - return dbus_error(msg, MESH_ERROR_BUSY, NULL); + if (!scans) + scans = l_queue_new(); - if (!node_is_provisioner(node)) - return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); + if (new_req.server) { + if (!sec || sec > 60) + return dbus_error(msg, MESH_ERROR_INVALID_ARGS, + "Invalid options"); + } else { + new_req.server = node_get_primary(new_req.node); + if (!sec || sec > 60) + sec = 60; + } + + req = l_queue_remove_if(scans, by_node_svr, &new_req); + + if (!req) + req = l_new(struct scan_req, 1); + + if (req->timeout) { + l_timeout_remove(req->timeout); + req->timeout = NULL; + } + + *req = new_req; + req->rssi = -128; + + if (sec) + req->timeout = l_timeout_create(sec, scan_cancel, req, NULL); - if (scan_timeout) - l_timeout_remove(scan_timeout); - memset(scan_uuid, 0, sizeof(scan_uuid)); - scan_rssi = -128; - scan_timeout = NULL; - net = node_get_net(node); - io = mesh_net_get_io(net); - scan_node = node; - mesh_io_register_recv_cb(io, prvb, sizeof(prvb), - prov_beacon_recv, node); + n = mesh_model_opcode_set(OP_REM_PROV_SCAN_START, scan_req); + scan_req[n++] = 5; + scan_req[n++] = sec; + if (flen) { + memcpy(scan_req + n, req->uuid, flen); + n += flen; + } + + mesh_model_send(req->node, 0, req->server, APP_IDX_DEV_REMOTE, + req->net_idx, DEFAULT_TTL, + true, n, scan_req); - if (duration) - scan_timeout = l_timeout_create(duration, scan_cancel, - node, NULL); + initiator_scan_reg(manager_scan_result, req->node); + + l_queue_push_tail(scans, req); return l_dbus_message_new_method_return(msg); } @@ -444,12 +752,7 @@ static struct l_dbus_message *cancel_scan_call(struct l_dbus *dbus, if (strcmp(sender, node_get_owner(node)) || !node_is_provisioner(node)) return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL); - if (scan_node) { - if (scan_node != node) - return dbus_error(msg, MESH_ERROR_BUSY, NULL); - - scan_cancel(NULL, node); - } + manager_scan_cancel(node); return l_dbus_message_new_method_return(msg); } @@ -814,6 +1117,8 @@ static void setup_management_interface(struct l_dbus_interface *iface) "aya{sv}", "uuid", "options"); l_dbus_interface_method(iface, "ImportRemoteNode", 0, import_node_call, "", "qyay", "primary", "count", "dev_key"); + l_dbus_interface_method(iface, "Reprovision", 0, reprovision_call, + "", "qa{sv}", "unicast", "options"); l_dbus_interface_method(iface, "DeleteRemoteNode", 0, delete_node_call, "", "qy", "primary", "count"); l_dbus_interface_method(iface, "UnprovisionedScan", 0, start_scan_call, @@ -849,7 +1154,7 @@ bool manager_dbus_init(struct l_dbus *bus) if (!l_dbus_register_interface(bus, MESH_MANAGEMENT_INTERFACE, setup_management_interface, NULL, false)) { - l_info("Unable to register %s interface", + l_debug("Unable to register %s interface", MESH_MANAGEMENT_INTERFACE); return false; } @@ -859,8 +1164,8 @@ bool manager_dbus_init(struct l_dbus *bus) void manager_scan_cancel(struct mesh_node *node) { - if (scan_node != node) - return; + struct scan_req *req; - scan_cancel(NULL, node); + while ((req = l_queue_find(scans, by_node, node))) + scan_cancel(NULL, req); } diff --git a/mesh/mesh-config-json.c b/mesh/mesh-config-json.c index 7f46c8582c5ce0f81a901662d9eee10c5881bbf2..5372130d7f8a3493dc2a205e43d3febc04821067 100644 --- a/mesh/mesh-config-json.c +++ b/mesh/mesh-config-json.c @@ -58,6 +58,33 @@ static const char *cfgnode_name = "/node.json"; static const char *bak_ext = ".bak"; static const char *tmp_ext = ".tmp"; +/* JSON key words */ +static const char *unicastAddress = "unicastAddress"; +static const char *deviceCan = "deviceCan"; +static const char *deviceKey = "deviceKey"; +static const char *defaultTTL = "defaultTTL"; +static const char *sequenceNumber = "sequenceNumber"; +static const char *netKeys = "netKeys"; +static const char *appKeys = "appKeys"; +static const char *elements = "elements"; +static const char *models = "models"; +static const char *modelId = "modelId"; +static const char *address = "address"; +static const char *bind = "bind"; +static const char *publish = "publish"; +static const char *subscribe = "subscribe"; +static const char *boundNetKey = "boundNetKey"; +static const char *keyRefresh = "keyRefresh"; +static const char *subEnabled = "subEnabled"; +static const char *pubEnabled = "pubEnabled"; +static const char *retransmit = "retransmit"; + +/* Common JSON values */ +static const char *enabled = "enabled"; +static const char *disabled = "disabled"; +static const char *unsupported = "unsupported"; + + static bool save_config(json_object *jnode, const char *fname) { FILE *outfile; @@ -134,14 +161,14 @@ static int get_element_index(json_object *jnode, uint16_t ele_addr) uint16_t addr, num_ele; char *str; - if (!json_object_object_get_ex(jnode, "unicastAddress", &jvalue)) + if (!json_object_object_get_ex(jnode, unicastAddress, &jvalue)) return -1; str = (char *)json_object_get_string(jvalue); if (sscanf(str, "%04hx", &addr) != 1) return -1; - if (!json_object_object_get_ex(jnode, "elements", &jelements)) + if (!json_object_object_get_ex(jnode, elements, &jelements)) return -1; num_ele = json_object_array_length(jelements); @@ -160,14 +187,14 @@ static json_object *get_element_model(json_object *jnode, int ele_idx, size_t len; char buf[9]; - if (!json_object_object_get_ex(jnode, "elements", &jelements)) + if (!json_object_object_get_ex(jnode, elements, &jelements)) return NULL; jelement = json_object_array_get_idx(jelements, ele_idx); if (!jelement) return NULL; - if (!json_object_object_get_ex(jelement, "models", &jmodels)) + if (!json_object_object_get_ex(jelement, models, &jmodels)) return NULL; num_mods = json_object_array_length(jmodels); @@ -189,7 +216,7 @@ static json_object *get_element_model(json_object *jnode, int ele_idx, char *str; jmodel = json_object_array_get_idx(jmodels, i); - if (!json_object_object_get_ex(jmodel, "modelId", &jvalue)) + if (!json_object_object_get_ex(jmodel, modelId, &jvalue)) return NULL; str = (char *)json_object_get_string(jvalue); @@ -298,7 +325,7 @@ static bool read_unicast_address(json_object *jobj, uint16_t *unicast) json_object *jvalue; char *str; - if (!json_object_object_get_ex(jobj, "unicastAddress", &jvalue)) + if (!json_object_object_get_ex(jobj, unicastAddress, &jvalue)) return false; str = (char *)json_object_get_string(jvalue); @@ -314,7 +341,7 @@ static bool read_default_ttl(json_object *jobj, uint8_t *ttl) int val; /* defaultTTL is optional */ - if (!json_object_object_get_ex(jobj, "defaultTTL", &jvalue)) + if (!json_object_object_get_ex(jobj, defaultTTL, &jvalue)) return true; val = json_object_get_int(jvalue); @@ -336,7 +363,7 @@ static bool read_seq_number(json_object *jobj, uint32_t *seq_number) int val; /* sequenceNumber is optional */ - if (!json_object_object_get_ex(jobj, "sequenceNumber", &jvalue)) + if (!json_object_object_get_ex(jobj, sequenceNumber, &jvalue)) return true; val = json_object_get_int(jvalue); @@ -396,7 +423,25 @@ static bool read_device_key(json_object *jobj, uint8_t key_buf[16]) if (!key_buf) return false; - if (!json_object_object_get_ex(jobj, "deviceKey", &jvalue)) + if (!json_object_object_get_ex(jobj, deviceKey, &jvalue)) + return false; + + str = (char *)json_object_get_string(jvalue); + if (!str2hex(str, strlen(str), key_buf, 16)) + return false; + + return true; +} + +static bool read_candidate(json_object *jobj, uint8_t key_buf[16]) +{ + json_object *jvalue; + char *str; + + if (!key_buf) + return false; + + if (!json_object_object_get_ex(jobj, deviceCan, &jvalue)) return false; str = (char *)json_object_get_string(jvalue); @@ -460,7 +505,7 @@ static bool read_app_keys(json_object *jobj, struct mesh_config_node *node) int len; int i; - if (!json_object_object_get_ex(jobj, "appKeys", &jarray)) + if (!json_object_object_get_ex(jobj, appKeys, &jarray)) return true; if (json_object_get_type(jarray) != json_type_array) @@ -484,7 +529,7 @@ static bool read_app_keys(json_object *jobj, struct mesh_config_node *node) if (!get_key_index(jtemp, "index", &appkey->app_idx)) goto fail; - if (!get_key_index(jtemp, "boundNetKey", &appkey->net_idx)) + if (!get_key_index(jtemp, boundNetKey, &appkey->net_idx)) goto fail; if (!json_object_object_get_ex(jtemp, "key", &jvalue)) @@ -516,7 +561,7 @@ static bool read_net_keys(json_object *jobj, struct mesh_config_node *node) int i; /* At least one NetKey must be present for a provisioned node */ - if (!json_object_object_get_ex(jobj, "netKeys", &jarray)) + if (!json_object_object_get_ex(jobj, netKeys, &jarray)) return false; if (json_object_get_type(jarray) != json_type_array) @@ -547,7 +592,7 @@ static bool read_net_keys(json_object *jobj, struct mesh_config_node *node) if (!str2hex(str, strlen(str), netkey->new_key, 16)) goto fail; - if (!json_object_object_get_ex(jtemp, "keyRefresh", &jvalue)) + if (!json_object_object_get_ex(jtemp, keyRefresh, &jvalue)) netkey->phase = KEY_REFRESH_PHASE_NONE; else netkey->phase = (uint8_t) json_object_get_int(jvalue); @@ -598,7 +643,7 @@ bool mesh_config_net_key_add(struct mesh_config *cfg, uint16_t idx, jnode = cfg->jnode; l_debug("netKey %4.4x", idx); - json_object_object_get_ex(jnode, "netKeys", &jarray); + json_object_object_get_ex(jnode, netKeys, &jarray); if (jarray) jentry = get_key_object(jarray, idx); @@ -616,14 +661,14 @@ bool mesh_config_net_key_add(struct mesh_config *cfg, uint16_t idx, if (!add_key_value(jentry, "key", key)) goto fail; - json_object_object_add(jentry, "keyRefresh", + json_object_object_add(jentry, keyRefresh, json_object_new_int(KEY_REFRESH_PHASE_NONE)); if (!jarray) { jarray = json_object_new_array(); if (!jarray) goto fail; - json_object_object_add(jnode, "netKeys", jarray); + json_object_object_add(jnode, netKeys, jarray); } json_object_array_add(jarray, jentry); @@ -648,7 +693,7 @@ bool mesh_config_net_key_update(struct mesh_config *cfg, uint16_t idx, jnode = cfg->jnode; - if (!json_object_object_get_ex(jnode, "netKeys", &jarray)) + if (!json_object_object_get_ex(jnode, netKeys, &jarray)) return false; jentry = get_key_object(jarray, idx); @@ -667,7 +712,7 @@ bool mesh_config_net_key_update(struct mesh_config *cfg, uint16_t idx, if (!add_key_value(jentry, "key", key)) return false; - json_object_object_add(jentry, "keyRefresh", + json_object_object_add(jentry, keyRefresh, json_object_new_int(KEY_REFRESH_PHASE_ONE)); return save_config(jnode, cfg->node_dir_path); @@ -682,20 +727,55 @@ bool mesh_config_net_key_del(struct mesh_config *cfg, uint16_t idx) jnode = cfg->jnode; - if (!json_object_object_get_ex(jnode, "netKeys", &jarray)) + if (!json_object_object_get_ex(jnode, netKeys, &jarray)) return true; jarray_key_del(jarray, idx); if (!json_object_array_length(jarray)) - json_object_object_del(jnode, "netKeys"); + json_object_object_del(jnode, netKeys); return save_config(jnode, cfg->node_dir_path); } bool mesh_config_write_device_key(struct mesh_config *cfg, uint8_t *key) { - if (!cfg || !add_key_value(cfg->jnode, "deviceKey", key)) + if (!cfg || !add_key_value(cfg->jnode, deviceKey, key)) + return false; + + return save_config(cfg->jnode, cfg->node_dir_path); +} + +bool mesh_config_write_candidate(struct mesh_config *cfg, uint8_t *key) +{ + if (!cfg || !add_key_value(cfg->jnode, deviceCan, key)) + return false; + + return save_config(cfg->jnode, cfg->node_dir_path); +} + +bool mesh_config_read_candidate(struct mesh_config *cfg, uint8_t *key) +{ + if (!cfg) + return false; + + return read_candidate(cfg->jnode, key); +} + +bool mesh_config_finalize_candidate(struct mesh_config *cfg) +{ + uint8_t key[16]; + + if (!cfg) + return false; + + if (!read_candidate(cfg->jnode, key)) + return false; + + json_object_object_del(cfg->jnode, deviceCan); + json_object_object_del(cfg->jnode, deviceKey); + + if (!add_key_value(cfg->jnode, deviceKey, key)) return false; return save_config(cfg->jnode, cfg->node_dir_path); @@ -719,7 +799,7 @@ bool mesh_config_app_key_add(struct mesh_config *cfg, uint16_t net_idx, jnode = cfg->jnode; - json_object_object_get_ex(jnode, "appKeys", &jarray); + json_object_object_get_ex(jnode, appKeys, &jarray); if (jarray) jentry = get_key_object(jarray, app_idx); @@ -734,7 +814,7 @@ bool mesh_config_app_key_add(struct mesh_config *cfg, uint16_t net_idx, if (!write_int(jentry, "index", app_idx)) goto fail; - if (!write_int(jentry, "boundNetKey", net_idx)) + if (!write_int(jentry, boundNetKey, net_idx)) goto fail; if (!add_key_value(jentry, "key", key)) @@ -744,7 +824,7 @@ bool mesh_config_app_key_add(struct mesh_config *cfg, uint16_t net_idx, jarray = json_object_new_array(); if (!jarray) goto fail; - json_object_object_add(jnode, "appKeys", jarray); + json_object_object_add(jnode, appKeys, jarray); } json_object_array_add(jarray, jentry); @@ -770,7 +850,7 @@ bool mesh_config_app_key_update(struct mesh_config *cfg, uint16_t app_idx, jnode = cfg->jnode; - if (!json_object_object_get_ex(jnode, "appKeys", &jarray)) + if (!json_object_object_get_ex(jnode, appKeys, &jarray)) return false; /* The key entry should exist if the key is updated */ @@ -804,13 +884,13 @@ bool mesh_config_app_key_del(struct mesh_config *cfg, uint16_t net_idx, jnode = cfg->jnode; - if (!json_object_object_get_ex(jnode, "appKeys", &jarray)) + if (!json_object_object_get_ex(jnode, appKeys, &jarray)) return true; jarray_key_del(jarray, idx); if (!json_object_array_length(jarray)) - json_object_object_del(jnode, "appKeys"); + json_object_object_del(jnode, appKeys); return save_config(jnode, cfg->node_dir_path); } @@ -840,7 +920,7 @@ bool mesh_config_model_binding_add(struct mesh_config *cfg, uint16_t ele_addr, if (!jmodel) return false; - json_object_object_get_ex(jmodel, "bind", &jarray); + json_object_object_get_ex(jmodel, bind, &jarray); if (jarray && jarray_has_string(jarray, buf, 4)) return true; @@ -854,7 +934,7 @@ bool mesh_config_model_binding_add(struct mesh_config *cfg, uint16_t ele_addr, json_object_put(jstring); return false; } - json_object_object_add(jmodel, "bind", jarray); + json_object_object_add(jmodel, bind, jarray); } json_object_array_add(jarray, jstring); @@ -887,13 +967,13 @@ bool mesh_config_model_binding_del(struct mesh_config *cfg, uint16_t ele_addr, if (!jmodel) return false; - if (!json_object_object_get_ex(jmodel, "bind", &jarray)) + if (!json_object_object_get_ex(jmodel, bind, &jarray)) return true; jarray_string_del(jarray, buf, 4); if (!json_object_array_length(jarray)) - json_object_object_del(jmodel, "bind"); + json_object_object_del(jmodel, bind); return save_config(jnode, cfg->node_dir_path); } @@ -963,7 +1043,7 @@ static struct mesh_config_pub *parse_model_publication(json_object *jpub) int len, value; char *str; - if (!json_object_object_get_ex(jpub, "address", &jvalue)) + if (!json_object_object_get_ex(jpub, address, &jvalue)) return NULL; str = (char *)json_object_get_string(jvalue); @@ -998,9 +1078,10 @@ static struct mesh_config_pub *parse_model_publication(json_object *jpub) if (!get_int(jpub, "credentials", &value)) goto fail; + pub->credential = (uint8_t) value; - if (!json_object_object_get_ex(jpub, "retransmit", &jvalue)) + if (!json_object_object_get_ex(jpub, retransmit, &jvalue)) goto fail; if (!get_int(jvalue, "count", &value)) @@ -1093,7 +1174,7 @@ static bool parse_models(json_object *jmodels, struct mesh_config_element *ele) l_queue_push_tail(ele->models, mod); - if (!json_object_object_get_ex(jmodel, "modelId", &jvalue)) + if (!json_object_object_get_ex(jmodel, modelId, &jvalue)) goto fail; str = (char *)json_object_get_string(jvalue); @@ -1112,29 +1193,32 @@ static bool parse_models(json_object *jmodels, struct mesh_config_element *ele) mod->id = id; - if (json_object_object_get_ex(jmodel, "bind", &jarray)) { + if (len == 8) + mod->vendor = true; + + if (json_object_object_get_ex(jmodel, bind, &jarray)) { if (json_object_get_type(jarray) != json_type_array || !parse_bindings(jarray, mod)) goto fail; } - if (json_object_object_get_ex(jmodel, "pubEnabled", &jvalue)) + if (json_object_object_get_ex(jmodel, pubEnabled, &jvalue)) mod->pub_enabled = json_object_get_boolean(jvalue); else mod->pub_enabled = true; - if (json_object_object_get_ex(jmodel, "subEnabled", &jvalue)) + if (json_object_object_get_ex(jmodel, subEnabled, &jvalue)) mod->sub_enabled = json_object_get_boolean(jvalue); else mod->sub_enabled = true; - if (json_object_object_get_ex(jmodel, "publish", &jvalue)) { + if (json_object_object_get_ex(jmodel, publish, &jvalue)) { mod->pub = parse_model_publication(jvalue); if (!mod->pub) goto fail; } - if (json_object_object_get_ex(jmodel, "subscribe", &jarray)) { + if (json_object_object_get_ex(jmodel, subscribe, &jarray)) { if (!parse_model_subscriptions(jarray, mod)) goto fail; } @@ -1187,7 +1271,7 @@ static bool parse_elements(json_object *jelems, struct mesh_config_node *node) if (sscanf(str, "%04hx", &(ele->location)) != 1) goto fail; - if (json_object_object_get_ex(jelement, "models", &jmodels)) { + if (json_object_object_get_ex(jelement, models, &jmodels)) { if (json_object_get_type(jmodels) != json_type_array || !parse_models(jmodels, ele)) goto fail; @@ -1211,13 +1295,13 @@ static int get_mode(json_object *jvalue) if (!str) return 0xffffffff; - if (!strncasecmp(str, "disabled", strlen("disabled"))) + if (!strncasecmp(str, disabled, strlen(disabled))) return MESH_MODE_DISABLED; - if (!strncasecmp(str, "enabled", strlen("enabled"))) + if (!strncasecmp(str, enabled, strlen(enabled))) return MESH_MODE_ENABLED; - if (!strncasecmp(str, "unsupported", strlen("unsupported"))) + if (!strncasecmp(str, unsupported, strlen(unsupported))) return MESH_MODE_UNSUPPORTED; return 0xffffffff; @@ -1253,6 +1337,19 @@ static void parse_features(json_object *jconfig, struct mesh_config_node *node) node->modes.beacon = mode; } + if (json_object_object_get_ex(jconfig, "mpb", &jvalue)) { + mode = get_mode(jvalue); + if (mode <= MESH_MODE_UNSUPPORTED) + node->modes.mpb = mode; + + if (node->modes.mpb == MESH_MODE_ENABLED) { + if (json_object_object_get_ex(jconfig, "mpbPeriod", + &jvalue)) + node->modes.mpb_period = + json_object_get_int(jvalue); + } + } + if (!json_object_object_get_ex(jconfig, "relay", &jrelay)) return; @@ -1323,7 +1420,7 @@ static bool read_net_transmit(json_object *jobj, struct mesh_config_node *node) uint16_t interval; uint8_t cnt; - if (!json_object_object_get_ex(jobj, "retransmit", &jrtx)) + if (!json_object_object_get_ex(jobj, retransmit, &jrtx)) return true; if (!json_object_object_get_ex(jrtx, "count", &jvalue)) @@ -1386,7 +1483,7 @@ static bool read_node(json_object *jnode, struct mesh_config_node *node) } /* Check for required "elements" property */ - if (!json_object_object_get_ex(jnode, "elements", &jvalue)) + if (!json_object_object_get_ex(jnode, elements, &jvalue)) return false; if (!read_net_transmit(jnode, node)) { @@ -1460,11 +1557,11 @@ static const char *mode_to_string(int mode) { switch (mode) { case MESH_MODE_DISABLED: - return "disabled"; + return disabled; case MESH_MODE_ENABLED: - return "enabled"; + return enabled; default: - return "unsupported"; + return unsupported; } } @@ -1492,6 +1589,18 @@ bool mesh_config_write_mode(struct mesh_config *cfg, const char *keyword, return save_config(cfg->jnode, cfg->node_dir_path); } +bool mesh_config_write_mode_ex(struct mesh_config *cfg, const char *keyword, + int value, bool save) +{ + if (!cfg) + return false; + + if (save) + return mesh_config_write_mode(cfg, keyword, value); + else + return write_mode(cfg->jnode, keyword, value); +} + static bool write_relay_mode(json_object *jobj, uint8_t mode, uint8_t count, uint16_t interval) { @@ -1522,7 +1631,7 @@ fail: bool mesh_config_write_unicast(struct mesh_config *cfg, uint16_t unicast) { - if (!cfg || !write_uint16_hex(cfg->jnode, "unicastAddress", unicast)) + if (!cfg || !write_uint16_hex(cfg->jnode, unicastAddress, unicast)) return false; return save_config(cfg->jnode, cfg->node_dir_path); @@ -1538,6 +1647,21 @@ bool mesh_config_write_relay_mode(struct mesh_config *cfg, uint8_t mode, return save_config(cfg->jnode, cfg->node_dir_path); } +bool mesh_config_write_mpb(struct mesh_config *cfg, uint8_t mode, + uint8_t period) +{ + + if (!cfg || !write_mode(cfg->jnode, "mpb", mode)) + return false; + + if (mode) { + if (!write_int(cfg->jnode, "mpbPeriod", period)) + return false; + } + + return save_config(cfg->jnode, cfg->node_dir_path); +} + bool mesh_config_write_net_transmit(struct mesh_config *cfg, uint8_t cnt, uint16_t interval) { @@ -1558,8 +1682,8 @@ bool mesh_config_write_net_transmit(struct mesh_config *cfg, uint8_t cnt, if (!write_int(jrtx, "interval", interval)) goto fail; - json_object_object_del(jnode, "retransmit"); - json_object_object_add(jnode, "retransmit", jrtx); + json_object_object_del(jnode, retransmit); + json_object_object_add(jnode, retransmit, jrtx); return save_config(cfg->jnode, cfg->node_dir_path); @@ -1599,8 +1723,8 @@ static void add_model(void *a, void *b) if (!jmodel) return; - result = (mod->vendor) ? write_uint32_hex(jmodel, "modelId", mod->id) : - write_uint16_hex(jmodel, "modelId", (uint16_t) mod->id); + result = (mod->vendor) ? write_uint32_hex(jmodel, modelId, mod->id) : + write_uint16_hex(jmodel, modelId, (uint16_t) mod->id); if (!result) { json_object_put(jmodel); @@ -1608,10 +1732,10 @@ static void add_model(void *a, void *b) } jval = json_object_new_boolean(mod->sub_enabled); - json_object_object_add(jmodel, "subEnabled", jval); + json_object_object_add(jmodel, subEnabled, jval); jval = json_object_new_boolean(mod->pub_enabled); - json_object_object_add(jmodel, "pubEnabled", jval); + json_object_object_add(jmodel, pubEnabled, jval); json_object_array_add(jmodels, jmodel); } @@ -1662,12 +1786,20 @@ static struct mesh_config *create_config(const char *cfg_path, if (!write_mode(jnode, "beacon", modes->beacon)) return NULL; + if (!write_mode(jnode, "mpb", modes->mpb)) + return NULL; + + if (modes->mpb) { + if (!write_int(jnode, "mpbPeriod", modes->mpb_period)) + return NULL; + } + /* Sequence number */ - json_object_object_add(jnode, "sequenceNumber", + json_object_object_add(jnode, sequenceNumber, json_object_new_int(node->seq_number)); /* Default TTL */ - json_object_object_add(jnode, "defaultTTL", + json_object_object_add(jnode, defaultTTL, json_object_new_int(node->ttl)); /* Elements */ @@ -1702,11 +1834,11 @@ static struct mesh_config *create_config(const char *cfg_path, if (!jmodels) goto fail; - json_object_object_add(jelement, "models", jmodels); + json_object_object_add(jelement, models, jmodels); l_queue_foreach(ele->models, add_model, jmodels); } - json_object_object_add(jnode, "elements", jelems); + json_object_object_add(jnode, elements, jelems); cfg = l_new(struct mesh_config, 1); @@ -1724,6 +1856,55 @@ fail: return NULL; } +void mesh_config_reset(struct mesh_config *cfg, struct mesh_config_node *node) +{ + json_object *jelems; + const struct l_queue_entry *entry; + + if (!cfg || !cfg->jnode) + return; + + /* TODO: Recreate Element Array */ + jelems = json_object_new_array(); + if (!jelems) + return; + + entry = l_queue_get_entries(node->elements); + + for (; entry; entry = entry->next) { + struct mesh_config_element *ele = entry->data; + json_object *jelement, *jmodels; + + jelement = json_object_new_object(); + + if (!jelement) { + json_object_put(jelems); + return; + } + + write_int(jelement, "elementIndex", ele->index); + write_uint16_hex(jelement, "location", ele->location); + json_object_array_add(jelems, jelement); + + /* Models */ + if (l_queue_isempty(ele->models)) + continue; + + jmodels = json_object_new_array(); + if (!jmodels) { + json_object_put(jelems); + return; + } + + json_object_object_add(jelement, models, jmodels); + l_queue_foreach(ele->models, add_model, jmodels); + } + + /* Replace element array */ + json_object_object_del(cfg->jnode, elements); + json_object_object_add(cfg->jnode, elements, jelems); +} + struct mesh_config *mesh_config_create(const char *cfgdir_name, const uint8_t uuid[16], struct mesh_config_node *db_node) { @@ -1768,7 +1949,7 @@ static void finish_key_refresh(json_object *jobj, uint16_t net_idx) int i, len; /* Clean up all the bound appkeys */ - if (!json_object_object_get_ex(jobj, "appKeys", &jarray)) + if (!json_object_object_get_ex(jobj, appKeys, &jarray)) return; len = json_object_array_length(jarray); @@ -1779,7 +1960,7 @@ static void finish_key_refresh(json_object *jobj, uint16_t net_idx) jentry = json_object_array_get_idx(jarray, i); - if (!get_key_index(jentry, "boundNetKey", &idx)) + if (!get_key_index(jentry, boundNetKey, &idx)) continue; if (idx != net_idx) @@ -1803,14 +1984,14 @@ bool mesh_config_net_key_set_phase(struct mesh_config *cfg, uint16_t idx, jnode = cfg->jnode; - if (json_object_object_get_ex(jnode, "netKeys", &jarray)) + if (json_object_object_get_ex(jnode, netKeys, &jarray)) jentry = get_key_object(jarray, idx); if (!jentry) return false; - json_object_object_del(jentry, "keyRefresh"); - json_object_object_add(jentry, "keyRefresh", + json_object_object_del(jentry, keyRefresh); + json_object_object_add(jentry, keyRefresh, json_object_new_int(phase)); if (phase == KEY_REFRESH_PHASE_NONE) { @@ -1842,16 +2023,16 @@ bool mesh_config_model_pub_add(struct mesh_config *cfg, uint16_t ele_addr, if (!jmodel) return false; - json_object_object_del(jmodel, "publish"); + json_object_object_del(jmodel, publish); jpub = json_object_new_object(); if (!jpub) return false; if (pub->virt) - res = add_key_value(jpub, "address", pub->virt_addr); + res = add_key_value(jpub, address, pub->virt_addr); else - res = write_uint16_hex(jpub, "address", pub->addr); + res = write_uint16_hex(jpub, address, pub->addr); if (!res) goto fail; @@ -1878,8 +2059,8 @@ bool mesh_config_model_pub_add(struct mesh_config *cfg, uint16_t ele_addr, if (!write_int(jrtx, "interval", pub->interval)) goto fail; - json_object_object_add(jpub, "retransmit", jrtx); - json_object_object_add(jmodel, "publish", jpub); + json_object_object_add(jpub, retransmit, jrtx); + json_object_object_add(jmodel, publish, jpub); return save_config(jnode, cfg->node_dir_path); @@ -1911,23 +2092,23 @@ bool mesh_config_model_pub_del(struct mesh_config *cfg, uint16_t addr, uint32_t mod_id, bool vendor) { if (!cfg || !delete_model_property(cfg->jnode, addr, mod_id, vendor, - "publish")) + publish)) return false; return save_config(cfg->jnode, cfg->node_dir_path); } -static void del_page(json_object *jarray, uint8_t page) +static bool del_page(json_object *jarray, uint8_t page) { char buf[3]; int i, len, ret; if (!jarray) - return; + return false; ret = snprintf(buf, 3, "%2.2x", page); if (ret < 0) - return; + return false; len = json_object_array_length(jarray); @@ -1938,10 +2119,29 @@ static void del_page(json_object *jarray, uint8_t page) jentry = json_object_array_get_idx(jarray, i); str = (char *)json_object_get_string(jentry); - /* Delete matching page(s) */ - if (!memcmp(str, buf, 2)) + /* Delete matching page */ + if (!memcmp(str, buf, 2)) { json_object_array_del_idx(jarray, i, 1); + break; + } } + + return true; +} + +void mesh_config_comp_page_del(struct mesh_config *cfg, uint8_t page) +{ + json_object *jnode, *jarray = NULL; + + if (!cfg) + return; + + jnode = cfg->jnode; + + json_object_object_get_ex(jnode, "pages", &jarray); + + if (del_page(jarray, page)) + save_config(jnode, cfg->node_dir_path); } bool mesh_config_comp_page_add(struct mesh_config *cfg, uint8_t page, @@ -1984,56 +2184,6 @@ bool mesh_config_comp_page_add(struct mesh_config *cfg, uint8_t page, return save_config(jnode, cfg->node_dir_path); } -bool mesh_config_comp_page_mv(struct mesh_config *cfg, uint8_t old, uint8_t nw) -{ - json_object *jnode, *jarray = NULL; - uint8_t *data; - char *str; - char old_buf[3]; - int i, len, ret, dlen = 0; - bool status = true; - - if (!cfg || old == nw) - return false; - - ret = snprintf(old_buf, 3, "%2.2x", old); - if (ret < 0) - return false; - - jnode = cfg->jnode; - - json_object_object_get_ex(jnode, "pages", &jarray); - - if (!jarray) - return false; - - data = l_malloc(MAX_MSG_LEN); - - len = json_object_array_length(jarray); - - for (i = 0; i < len; i++) { - json_object *jentry; - - jentry = json_object_array_get_idx(jarray, i); - str = (char *)json_object_get_string(jentry); - - /* Delete matching page(s) but save data*/ - if (!memcmp(str, old_buf, 2)) { - dlen = strlen(str + 2); - str2hex(str + 2, dlen, data, MAX_MSG_LEN); - dlen /= 2; - json_object_array_del_idx(jarray, i, 1); - } - } - - if (dlen) - status = mesh_config_comp_page_add(cfg, nw, data, dlen); - - l_free(data); - - return status; -} - bool mesh_config_model_sub_add(struct mesh_config *cfg, uint16_t ele_addr, uint32_t mod_id, bool vendor, struct mesh_config_sub *sub) @@ -2064,7 +2214,7 @@ bool mesh_config_model_sub_add(struct mesh_config *cfg, uint16_t ele_addr, len = 32; } - json_object_object_get_ex(jmodel, "subscribe", &jarray); + json_object_object_get_ex(jmodel, subscribe, &jarray); if (jarray && jarray_has_string(jarray, buf, len)) return true; @@ -2078,7 +2228,7 @@ bool mesh_config_model_sub_add(struct mesh_config *cfg, uint16_t ele_addr, json_object_put(jstring); return false; } - json_object_object_add(jmodel, "subscribe", jarray); + json_object_object_add(jmodel, subscribe, jarray); } json_object_array_add(jarray, jstring); @@ -2107,7 +2257,7 @@ bool mesh_config_model_sub_del(struct mesh_config *cfg, uint16_t ele_addr, if (!jmodel) return false; - if (!json_object_object_get_ex(jmodel, "subscribe", &jarray)) + if (!json_object_object_get_ex(jmodel, subscribe, &jarray)) return true; if (!sub->virt) { @@ -2122,7 +2272,7 @@ bool mesh_config_model_sub_del(struct mesh_config *cfg, uint16_t ele_addr, jarray_string_del(jarray, buf, len); if (!json_object_array_length(jarray)) - json_object_object_del(jmodel, "subscribe"); + json_object_object_del(jmodel, subscribe); return save_config(jnode, cfg->node_dir_path); } @@ -2131,7 +2281,7 @@ bool mesh_config_model_sub_del_all(struct mesh_config *cfg, uint16_t addr, uint32_t mod_id, bool vendor) { if (!cfg || !delete_model_property(cfg->jnode, addr, mod_id, vendor, - "subscribe")) + subscribe)) return false; return save_config(cfg->jnode, cfg->node_dir_path); @@ -2161,7 +2311,7 @@ bool mesh_config_model_pub_enable(struct mesh_config *cfg, uint16_t ele_addr, json_object_object_add(jmodel, "pubDisabled", jval); if (!enable) - json_object_object_del(jmodel, "publish"); + json_object_object_del(jmodel, publish); return save_config(cfg->jnode, cfg->node_dir_path); } @@ -2184,13 +2334,13 @@ bool mesh_config_model_sub_enable(struct mesh_config *cfg, uint16_t ele_addr, if (!jmodel) return false; - json_object_object_del(jmodel, "subEnabled"); + json_object_object_del(jmodel, subEnabled); jval = json_object_new_boolean(enable); - json_object_object_add(jmodel, "subEnabled", jval); + json_object_object_add(jmodel, subEnabled, jval); if (!enable) - json_object_object_del(jmodel, "subscribe"); + json_object_object_del(jmodel, subscribe); return save_config(cfg->jnode, cfg->node_dir_path); } @@ -2205,14 +2355,14 @@ bool mesh_config_write_seq_number(struct mesh_config *cfg, uint32_t seq, return false; if (!cache) { - if (!write_int(cfg->jnode, "sequenceNumber", seq)) + if (!write_int(cfg->jnode, sequenceNumber, seq)) return false; return mesh_config_save(cfg, true, NULL, NULL); } /* If resetting seq to Zero, make sure cached value reset as well */ - if (seq && get_int(cfg->jnode, "sequenceNumber", &value)) + if (seq && get_int(cfg->jnode, sequenceNumber, &value)) cached = (uint32_t)value; /* @@ -2262,8 +2412,8 @@ bool mesh_config_write_seq_number(struct mesh_config *cfg, uint32_t seq, l_debug("Seq Cache: %d -> %d", seq, cached); - if (!write_int(cfg->jnode, "sequenceNumber", cached)) - return false; + if (!write_int(cfg->jnode, sequenceNumber, cached)) + return false; return mesh_config_save(cfg, false, NULL, NULL); } @@ -2273,7 +2423,7 @@ bool mesh_config_write_seq_number(struct mesh_config *cfg, uint32_t seq, bool mesh_config_write_ttl(struct mesh_config *cfg, uint8_t ttl) { - if (!cfg || !write_int(cfg->jnode, "defaultTTL", ttl)) + if (!cfg || !write_int(cfg->jnode, defaultTTL, ttl)) return false; return save_config(cfg->jnode, cfg->node_dir_path); @@ -2544,7 +2694,8 @@ bool mesh_config_load_nodes(const char *cfgdir_name, mesh_config_node_func_t cb, void mesh_config_destroy_nvm(struct mesh_config *cfg) { - char *node_dir, *node_name; + char *node_dir; + const char *node_name; char uuid[33]; if (!cfg) @@ -2556,7 +2707,7 @@ void mesh_config_destroy_nvm(struct mesh_config *cfg) if (!hex2str(cfg->uuid, 16, uuid, sizeof(uuid))) return; - node_name = basename(node_dir); + node_name = mesh_basename(node_dir); /* Make sure path name of node follows expected guidelines */ if (strcmp(node_name, uuid)) diff --git a/mesh/mesh-config.h b/mesh/mesh-config.h index 420775829e8e761ace9363fc320014a27a1647d0..3cb20b85d5c337bfaf756e1e710d97f4f78e0da4 100644 --- a/mesh/mesh-config.h +++ b/mesh/mesh-config.h @@ -60,6 +60,8 @@ struct mesh_config_modes { uint8_t friend; uint8_t proxy; uint8_t beacon; + uint8_t mpb; + uint8_t mpb_period; }; struct mesh_config_netkey { @@ -119,6 +121,7 @@ void mesh_config_release(struct mesh_config *cfg); void mesh_config_destroy_nvm(struct mesh_config *cfg); bool mesh_config_save(struct mesh_config *cfg, bool no_wait, mesh_config_status_func_t cb, void *user_data); +void mesh_config_reset(struct mesh_config *cfg, struct mesh_config_node *node); struct mesh_config *mesh_config_create(const char *cfgdir_name, const uint8_t uuid[16], struct mesh_config_node *node); @@ -126,6 +129,9 @@ struct mesh_config *mesh_config_create(const char *cfgdir_name, bool mesh_config_write_net_transmit(struct mesh_config *cfg, uint8_t cnt, uint16_t interval); bool mesh_config_write_device_key(struct mesh_config *cfg, uint8_t *key); +bool mesh_config_write_candidate(struct mesh_config *cfg, uint8_t *key); +bool mesh_config_read_candidate(struct mesh_config *cfg, uint8_t *key); +bool mesh_config_finalize_candidate(struct mesh_config *cfg); bool mesh_config_write_token(struct mesh_config *cfg, uint8_t *token); bool mesh_config_write_network_key(struct mesh_config *cfg, uint16_t idx, uint8_t *key, uint8_t *new_key, int phase); @@ -136,12 +142,16 @@ bool mesh_config_write_seq_number(struct mesh_config *cfg, uint32_t seq, bool mesh_config_write_unicast(struct mesh_config *cfg, uint16_t unicast); bool mesh_config_write_relay_mode(struct mesh_config *cfg, uint8_t mode, uint8_t count, uint16_t interval); +bool mesh_config_write_mpb(struct mesh_config *cfg, uint8_t mode, + uint8_t period); bool mesh_config_write_ttl(struct mesh_config *cfg, uint8_t ttl); bool mesh_config_write_mode(struct mesh_config *cfg, const char *keyword, int value); +bool mesh_config_write_mode_ex(struct mesh_config *cfg, const char *keyword, + int value, bool save); bool mesh_config_comp_page_add(struct mesh_config *cfg, uint8_t page, uint8_t *data, uint16_t size); -bool mesh_config_comp_page_mv(struct mesh_config *cfg, uint8_t old, uint8_t nw); +void mesh_config_comp_page_del(struct mesh_config *cfg, uint8_t page); bool mesh_config_model_binding_add(struct mesh_config *cfg, uint16_t ele_addr, uint32_t mod_id, bool vendor, uint16_t app_idx); diff --git a/mesh/mesh-io-api.h b/mesh/mesh-io-api.h index 21c505cd0d8712798472d94b70d4ed6a17d6af75..ae51cbc55ab90846409a76a0901bcea2c3b963b0 100644 --- a/mesh/mesh-io-api.h +++ b/mesh/mesh-io-api.h @@ -34,6 +34,13 @@ struct mesh_io_api { mesh_io_tx_cancel_t cancel; }; +struct mesh_io_reg { + mesh_io_recv_func_t cb; + void *user_data; + uint8_t len; + uint8_t filter[]; +}; + struct mesh_io { int index; int favored_index; diff --git a/mesh/mesh-io-generic.c b/mesh/mesh-io-generic.c index 827128ec8796788fe3501a34afbdc8356ae8936f..13a863b48158b996ff7d1847ea47366b2ec95f3a 100644 --- a/mesh/mesh-io-generic.c +++ b/mesh/mesh-io-generic.c @@ -33,7 +33,6 @@ struct mesh_io_private { struct mesh_io *io; struct bt_hci *hci; struct l_timeout *tx_timeout; - struct l_queue *rx_regs; struct l_queue *tx_pkts; struct tx_pkt *tx; uint16_t interval; @@ -41,13 +40,6 @@ struct mesh_io_private { bool active; }; -struct pvt_rx_reg { - mesh_io_recv_func_t cb; - void *user_data; - uint8_t len; - uint8_t filter[0]; -}; - struct process_data { struct mesh_io_private *pvt; const uint8_t *data; @@ -87,7 +79,7 @@ static uint32_t instant_remaining_ms(uint32_t instant) static void process_rx_callbacks(void *v_reg, void *v_rx) { - struct pvt_rx_reg *rx_reg = v_reg; + struct mesh_io_reg *rx_reg = v_reg; struct process_data *rx = v_rx; if (!memcmp(rx->data, rx_reg->filter, rx_reg->len)) @@ -108,7 +100,7 @@ static void process_rx(struct mesh_io_private *pvt, int8_t rssi, .info.rssi = rssi, }; - l_queue_foreach(pvt->rx_regs, process_rx_callbacks, &rx); + l_queue_foreach(pvt->io->rx_regs, process_rx_callbacks, &rx); } static void event_adv_report(struct mesh_io *io, const void *buf, uint8_t size) @@ -354,7 +346,7 @@ static bool find_by_pattern(const void *a, const void *b) static bool find_active(const void *a, const void *b) { - const struct pvt_rx_reg *rx_reg = a; + const struct mesh_io_reg *rx_reg = a; /* Mesh specific AD types do *not* require active scanning, * so do not turn on Active Scanning on their account. @@ -370,10 +362,10 @@ static void restart_scan(struct mesh_io_private *pvt) { struct bt_hci_cmd_le_set_scan_enable cmd; - if (l_queue_isempty(pvt->rx_regs)) + if (l_queue_isempty(pvt->io->rx_regs)) return; - pvt->active = l_queue_find(pvt->rx_regs, find_active, NULL); + pvt->active = l_queue_find(pvt->io->rx_regs, find_active, NULL); cmd.enable = 0x00; /* Disable scanning */ cmd.filter_dup = 0x00; /* Report duplicates */ bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_ENABLE, @@ -388,6 +380,9 @@ static void hci_init(void *user_data) if (io->pvt->hci) bt_hci_unref(io->pvt->hci); + /* Clear controller HCI list to suppress mgmt interface warnings */ + mesh_mgmt_clear(); + io->pvt->hci = bt_hci_new_user_channel(io->index); if (!io->pvt->hci) { l_error("Failed to start mesh io (hci %u): %s", io->index, @@ -417,7 +412,6 @@ static bool dev_init(struct mesh_io *io, void *opts, void *user_data) io->pvt = l_new(struct mesh_io_private, 1); - io->pvt->rx_regs = l_queue_new(); io->pvt->tx_pkts = l_queue_new(); io->pvt->io = io; @@ -436,7 +430,6 @@ static bool dev_destroy(struct mesh_io *io) bt_hci_unref(pvt->hci); l_timeout_remove(pvt->tx_timeout); - l_queue_destroy(pvt->rx_regs, l_free); l_queue_remove_if(pvt->tx_pkts, simple_match, pvt->tx); l_queue_destroy(pvt->tx_pkts, l_free); l_free(pvt->tx); @@ -726,7 +719,7 @@ static bool send_tx(struct mesh_io *io, struct mesh_io_send_info *info, l_queue_push_tail(pvt->tx_pkts, tx); } - /* If not already sending, schedule the tx worker */ + /* If not already sending, schedule the tx worker */ if (!pvt->tx) { l_timeout_remove(pvt->tx_timeout); pvt->tx_timeout = NULL; @@ -780,46 +773,18 @@ static bool tx_cancel(struct mesh_io *io, const uint8_t *data, uint8_t len) return true; } -static bool find_by_filter(const void *a, const void *b) -{ - const struct pvt_rx_reg *rx_reg_old = a; - const struct pvt_rx_reg *rx_reg = b; - - if (rx_reg_old->len != rx_reg->len) - return false; - - return !memcmp(rx_reg_old->filter, rx_reg->filter, rx_reg->len); -} - static bool recv_register(struct mesh_io *io, const uint8_t *filter, uint8_t len, mesh_io_recv_func_t cb, void *user_data) { struct bt_hci_cmd_le_set_scan_enable cmd; struct mesh_io_private *pvt = io->pvt; - struct pvt_rx_reg *rx_reg, *rx_reg_old; bool already_scanning; bool active = false; - if (!cb || !filter || !len) - return false; - - rx_reg = l_malloc(sizeof(*rx_reg) + len); - - memcpy(rx_reg->filter, filter, len); - rx_reg->len = len; - rx_reg->cb = cb; - rx_reg->user_data = user_data; - - rx_reg_old = l_queue_remove_if(pvt->rx_regs, find_by_filter, rx_reg); - - l_free(rx_reg_old); - - already_scanning = !l_queue_isempty(pvt->rx_regs); - - l_queue_push_head(pvt->rx_regs, rx_reg); + already_scanning = l_queue_length(io->rx_regs) > 1; /* Look for any AD types requiring Active Scanning */ - if (l_queue_find(pvt->rx_regs, find_active, NULL)) + if (l_queue_find(io->rx_regs, find_active, NULL)) active = true; if (!already_scanning || pvt->active != active) { @@ -839,25 +804,13 @@ static bool recv_deregister(struct mesh_io *io, const uint8_t *filter, { struct bt_hci_cmd_le_set_scan_enable cmd = {0, 0}; struct mesh_io_private *pvt = io->pvt; - struct pvt_rx_reg *rx_reg, *rx_reg_tmp; bool active = false; - rx_reg_tmp = l_malloc(sizeof(*rx_reg_tmp) + len); - memcpy(&rx_reg_tmp->filter, filter, len); - rx_reg_tmp->len = len; - - rx_reg = l_queue_remove_if(pvt->rx_regs, find_by_filter, rx_reg_tmp); - - if (rx_reg) - l_free(rx_reg); - - l_free(rx_reg_tmp); - /* Look for any AD types requiring Active Scanning */ - if (l_queue_find(pvt->rx_regs, find_active, NULL)) + if (l_queue_find(io->rx_regs, find_active, NULL)) active = true; - if (l_queue_isempty(pvt->rx_regs)) { + if (l_queue_isempty(io->rx_regs)) { bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_ENABLE, &cmd, sizeof(cmd), NULL, NULL, NULL); diff --git a/mesh/mesh-io-mgmt.c b/mesh/mesh-io-mgmt.c index 9ae1af05a17bf6a6b0e9d177bc65b2154e20fde6..5f0eb206b3b2a1bf1ca35b7e5267447ee0a4d438 100644 --- a/mesh/mesh-io-mgmt.c +++ b/mesh/mesh-io-mgmt.c @@ -35,8 +35,8 @@ struct mesh_io_private { struct mesh_io *io; void *user_data; struct l_timeout *tx_timeout; + struct l_timeout *dup_timeout; struct l_queue *dup_filters; - struct l_queue *rx_regs; struct l_queue *tx_pkts; struct tx_pkt *tx; unsigned int tx_id; @@ -48,13 +48,6 @@ struct mesh_io_private { bool active; }; -struct pvt_rx_reg { - mesh_io_recv_func_t cb; - void *user_data; - uint8_t len; - uint8_t filter[0]; -}; - struct process_data { struct mesh_io_private *pvt; const uint8_t *data; @@ -82,6 +75,8 @@ struct dup_filter { uint8_t addr[6]; } __packed; +static const uint8_t zero_addr[] = {0, 0, 0, 0, 0, 0}; + static struct mesh_io_private *pvt; static uint32_t get_instant(void) @@ -110,6 +105,14 @@ static bool find_by_addr(const void *a, const void *b) return !memcmp(filter->addr, b, 6); } +static bool find_by_adv(const void *a, const void *b) +{ + const struct dup_filter *filter = a; + uint64_t data = l_get_be64(b); + + return !memcmp(filter->addr, zero_addr, 6) && filter->data == data; +} + static void filter_timeout(struct l_timeout *timeout, void *user_data) { struct dup_filter *filter; @@ -136,6 +139,7 @@ static void filter_timeout(struct l_timeout *timeout, void *user_data) done: l_timeout_remove(timeout); + pvt->dup_timeout = NULL; } /* Ignore consequtive duplicate advertisements within timeout period */ @@ -146,7 +150,22 @@ static bool filter_dups(const uint8_t *addr, const uint8_t *adv, uint32_t instant_delta; uint64_t data = l_get_be64(adv); - filter = l_queue_remove_if(pvt->dup_filters, find_by_addr, addr); + if (!addr) + addr = zero_addr; + + if (adv[1] == MESH_AD_TYPE_PROVISION) { + filter = l_queue_find(pvt->dup_filters, find_by_adv, adv); + + if (!filter && addr != zero_addr) + return false; + + l_queue_remove(pvt->dup_filters, filter); + + } else { + filter = l_queue_remove_if(pvt->dup_filters, find_by_addr, + addr); + } + if (!filter) { filter = l_new(struct dup_filter, 1); memcpy(filter->addr, addr, 6); @@ -154,7 +173,8 @@ static bool filter_dups(const uint8_t *addr, const uint8_t *adv, /* Start filter expiration timer */ if (!l_queue_length(pvt->dup_filters)) - l_timeout_create(1, filter_timeout, NULL, NULL); + pvt->dup_timeout = l_timeout_create(1, filter_timeout, NULL, + NULL); l_queue_push_head(pvt->dup_filters, filter); instant_delta = instant - filter->instant; @@ -170,14 +190,14 @@ static bool filter_dups(const uint8_t *addr, const uint8_t *adv, static void process_rx_callbacks(void *v_reg, void *v_rx) { - struct pvt_rx_reg *rx_reg = v_reg; + struct mesh_io_reg *rx_reg = v_reg; struct process_data *rx = v_rx; if (!memcmp(rx->data, rx_reg->filter, rx_reg->len)) rx_reg->cb(rx_reg->user_data, &rx->info, rx->data, rx->len); } -static void process_rx(struct mesh_io_private *pvt, int8_t rssi, +static void process_rx(uint16_t index, struct mesh_io_private *pvt, int8_t rssi, uint32_t instant, const uint8_t *addr, const uint8_t *data, uint8_t len) { @@ -191,21 +211,25 @@ static void process_rx(struct mesh_io_private *pvt, int8_t rssi, .info.rssi = rssi, }; + /* Accept all traffic except beacons from any controller */ + if (index != pvt->send_idx && data[0] == MESH_AD_TYPE_BEACON) + return; + print_packet("RX", data, len); - l_queue_foreach(pvt->rx_regs, process_rx_callbacks, &rx); + l_queue_foreach(pvt->io->rx_regs, process_rx_callbacks, &rx); } static void send_cmplt(uint16_t index, uint16_t length, const void *param, void *user_data) { - print_packet("Mesh Send Complete", param, length); + /* print_packet("Mesh Send Complete", param, length); */ } static void event_device_found(uint16_t index, uint16_t length, const void *param, void *user_data) { const struct mgmt_ev_mesh_device_found *ev = param; - struct mesh_io *io = user_data; + struct mesh_io_private *pvt = user_data; const uint8_t *adv; const uint8_t *addr; uint32_t instant; @@ -236,9 +260,10 @@ static void event_device_found(uint16_t index, uint16_t length, if (len > adv_len) break; - if (adv[1] >= 0x29 && adv[1] <= 0x2B) - process_rx(io->pvt, ev->rssi, instant, addr, adv + 1, - adv[0]); + if (adv[1] >= MESH_AD_TYPE_PROVISION && + adv[1] <= MESH_AD_TYPE_BEACON) + process_rx(index, pvt, ev->rssi, instant, addr, + adv + 1, adv[0]); adv += field_len + 1; } @@ -270,7 +295,7 @@ static bool find_by_pattern(const void *a, const void *b) static bool find_active(const void *a, const void *b) { - const struct pvt_rx_reg *rx_reg = a; + const struct mesh_io_reg *rx_reg = a; /* Mesh specific AD types do *not* require active scanning, * so do not turn on Active Scanning on their account. @@ -320,6 +345,12 @@ static void ctl_up(uint8_t status, uint16_t length, mesh->num_ad_types = sizeof(mesh_ad_types); memcpy(mesh->ad_types, mesh_ad_types, sizeof(mesh_ad_types)); + pvt->rx_id = mesh_mgmt_register(MGMT_EV_MESH_DEVICE_FOUND, + MGMT_INDEX_NONE, event_device_found, pvt, + NULL); + pvt->tx_id = mesh_mgmt_register(MGMT_EV_MESH_PACKET_CMPLT, + index, send_cmplt, pvt, NULL); + mesh_mgmt_send(MGMT_OP_SET_MESH_RECEIVER, index, len, mesh, mesh_up, L_UINT_TO_PTR(index), NULL); l_debug("done %d mesh startup", index); @@ -407,13 +438,7 @@ static bool dev_init(struct mesh_io *io, void *opts, void *user_data) mesh_mgmt_send(MGMT_OP_READ_INFO, index, 0, NULL, read_info_cb, L_UINT_TO_PTR(index), NULL); - pvt->rx_id = mesh_mgmt_register(MGMT_EV_MESH_DEVICE_FOUND, - MGMT_INDEX_NONE, event_device_found, io, NULL); - pvt->tx_id = mesh_mgmt_register(MGMT_EV_MESH_PACKET_CMPLT, - MGMT_INDEX_NONE, send_cmplt, io, NULL); - pvt->dup_filters = l_queue_new(); - pvt->rx_regs = l_queue_new(); pvt->tx_pkts = l_queue_new(); pvt->io = io; @@ -422,14 +447,6 @@ static bool dev_init(struct mesh_io *io, void *opts, void *user_data) return true; } -static void free_rx_reg(void *user_data) -{ - struct pvt_rx_reg *rx_reg = user_data; - - l_free(rx_reg); -} - - static bool dev_destroy(struct mesh_io *io) { unsigned char param[] = { 0x00 }; @@ -443,8 +460,8 @@ static bool dev_destroy(struct mesh_io *io) mesh_mgmt_unregister(pvt->rx_id); mesh_mgmt_unregister(pvt->tx_id); l_timeout_remove(pvt->tx_timeout); + l_timeout_remove(pvt->dup_timeout); l_queue_destroy(pvt->dup_filters, l_free); - l_queue_destroy(pvt->rx_regs, free_rx_reg); l_queue_destroy(pvt->tx_pkts, l_free); io->pvt = NULL; l_free(pvt); @@ -475,7 +492,7 @@ static void send_cancel(struct mesh_io_private *pvt) if (pvt->handle) { remove.handle = pvt->handle; - l_debug("Cancel TX"); + /* l_debug("Cancel TX"); */ mesh_mgmt_send(MGMT_OP_MESH_SEND_CANCEL, pvt->send_idx, sizeof(remove), &remove, NULL, NULL, NULL); @@ -522,9 +539,14 @@ static void send_pkt(struct mesh_io_private *pvt, struct tx_pkt *tx, send->adv_data_len = tx->len + 1; send->adv_data[0] = tx->len; memcpy(send->adv_data + 1, tx->pkt, tx->len); + + /* Filter looped back Provision packets */ + if (tx->pkt[0] == MESH_AD_TYPE_PROVISION) + filter_dups(NULL, send->adv_data, get_instant()); + mesh_mgmt_send(MGMT_OP_MESH_SEND, index, len, send, send_queued, tx, NULL); - print_packet("Mesh Send Start", tx->pkt, tx->len); + /* print_packet("Mesh Send Start", tx->pkt, tx->len); */ pvt->tx = tx; } @@ -711,37 +733,16 @@ static bool tx_cancel(struct mesh_io *io, const uint8_t *data, uint8_t len) return true; } -static bool find_by_filter(const void *a, const void *b) -{ - const struct pvt_rx_reg *rx_reg = a; - const uint8_t *filter = b; - - return !memcmp(rx_reg->filter, filter, rx_reg->len); -} - static bool recv_register(struct mesh_io *io, const uint8_t *filter, uint8_t len, mesh_io_recv_func_t cb, void *user_data) { - struct pvt_rx_reg *rx_reg; bool active = false; - if (!cb || !filter || !len || io->pvt != pvt) + if (io->pvt != pvt) return false; - rx_reg = l_queue_remove_if(pvt->rx_regs, find_by_filter, filter); - - free_rx_reg(rx_reg); - rx_reg = l_malloc(sizeof(*rx_reg) + len); - - memcpy(rx_reg->filter, filter, len); - rx_reg->len = len; - rx_reg->cb = cb; - rx_reg->user_data = user_data; - - l_queue_push_head(pvt->rx_regs, rx_reg); - /* Look for any AD types requiring Active Scanning */ - if (l_queue_find(pvt->rx_regs, find_active, NULL)) + if (l_queue_find(io->rx_regs, find_active, NULL)) active = true; if (pvt->active != active) { @@ -755,18 +756,13 @@ static bool recv_register(struct mesh_io *io, const uint8_t *filter, static bool recv_deregister(struct mesh_io *io, const uint8_t *filter, uint8_t len) { - struct pvt_rx_reg *rx_reg; bool active = false; if (io->pvt != pvt) return false; - rx_reg = l_queue_remove_if(pvt->rx_regs, find_by_filter, filter); - - free_rx_reg(rx_reg); - /* Look for any AD types requiring Active Scanning */ - if (l_queue_find(pvt->rx_regs, find_active, NULL)) + if (l_queue_find(io->rx_regs, find_active, NULL)) active = true; if (active != pvt->active) { diff --git a/mesh/mesh-io-unit.c b/mesh/mesh-io-unit.c index f4f6198036ebba9277f1a8fd92f9db8220d7bc14..a9fa53308eb166b278dbecaaeb4703132cc937cf 100644 --- a/mesh/mesh-io-unit.c +++ b/mesh/mesh-io-unit.c @@ -485,39 +485,9 @@ static bool tx_cancel(struct mesh_io *io, const uint8_t *data, uint8_t len) return true; } -static bool find_by_filter(const void *a, const void *b) -{ - const struct pvt_rx_reg *rx_reg_old = a; - const struct pvt_rx_reg *rx_reg = b; - - if (rx_reg_old->len != rx_reg->len) - return false; - - return !memcmp(rx_reg_old->filter, rx_reg->filter, rx_reg->len); -} - static bool recv_register(struct mesh_io *io, const uint8_t *filter, uint8_t len, mesh_io_recv_func_t cb, void *user_data) { - struct mesh_io_private *pvt = io->pvt; - struct pvt_rx_reg *rx_reg, *rx_reg_old; - - if (!cb || !filter || !len) - return false; - - rx_reg = l_malloc(sizeof(*rx_reg) + len); - - memcpy(rx_reg->filter, filter, len); - rx_reg->len = len; - rx_reg->cb = cb; - rx_reg->user_data = user_data; - - rx_reg_old = l_queue_remove_if(pvt->rx_regs, find_by_filter, rx_reg); - - l_free(rx_reg_old); - - l_queue_push_head(pvt->rx_regs, rx_reg); - return true; } diff --git a/mesh/mesh-io.c b/mesh/mesh-io.c index 233f4b32875245e3e3f77532336f00b6bc95575c..b953bf4cff81c3c6bd2cc3602c354316d6a015a2 100644 --- a/mesh/mesh-io.c +++ b/mesh/mesh-io.c @@ -28,12 +28,10 @@ #include "mesh/mesh-io-generic.h" #include "mesh/mesh-io-unit.h" -struct mesh_io_reg { - mesh_io_recv_func_t cb; - void *user_data; - uint8_t len; - uint8_t filter[]; -} packed; +struct loop_data { + uint16_t len; + uint8_t data[]; +}; /* List of Supported Mesh-IO Types */ static const struct mesh_io_table table[] = { @@ -42,7 +40,10 @@ static const struct mesh_io_table table[] = { {MESH_IO_TYPE_UNIT_TEST, &mesh_io_unit}, }; +static const uint8_t unprv_filter[] = { MESH_AD_TYPE_BEACON, 0 }; + static struct mesh_io *default_io; +static struct l_timeout *loop_adv_to; static const struct mesh_io_api *io_api(enum mesh_io_type type) { @@ -71,12 +72,20 @@ static void ctl_alert(int index, bool up, bool pwr, bool mesh, void *user_data) enum mesh_io_type type = L_PTR_TO_UINT(user_data); const struct mesh_io_api *api = NULL; - l_warn("up:%d pwr: %d mesh: %d", up, pwr, mesh); + l_warn("index %u up:%d pwr: %d mesh: %d", index, up, pwr, mesh); /* If specific IO controller requested, honor it */ - if (default_io->favored_index != MGMT_INDEX_NONE && - default_io->favored_index != index) - return; + if (default_io->favored_index != MGMT_INDEX_NONE) { + if (default_io->favored_index != index) + return; + + if (!up | pwr) { + l_warn("HCI%u failed to start generic IO %s", + index, pwr ? ": already powered on" : ""); + if (default_io->ready) + default_io->ready(default_io->user_data, false); + } + } if (!up && default_io->index == index) { /* Our controller has disappeared */ @@ -96,7 +105,6 @@ static void ctl_alert(int index, bool up, bool pwr, bool mesh, void *user_data) if (mesh && type != MESH_IO_TYPE_GENERIC) api = io_api(MESH_IO_TYPE_MGMT); - else if (!pwr) api = io_api(MESH_IO_TYPE_GENERIC); @@ -104,7 +112,6 @@ static void ctl_alert(int index, bool up, bool pwr, bool mesh, void *user_data) default_io->index = index; default_io->api = api; api->init(default_io, &index, default_io->user_data); - l_queue_foreach(default_io->rx_regs, refresh_rx, default_io); } } @@ -122,6 +129,23 @@ static void free_io(struct mesh_io *io) } } +static struct mesh_io_reg *find_by_filter(struct l_queue *rx_regs, + const uint8_t *filter, uint8_t len) +{ + const struct l_queue_entry *entry; + + entry = l_queue_get_entries(rx_regs); + + for (; entry; entry = entry->next) { + struct mesh_io_reg *rx_reg = entry->data; + + if (rx_reg->len == len && !memcmp(rx_reg->filter, filter, len)) + return rx_reg; + } + + return NULL; +} + struct mesh_io *mesh_io_new(enum mesh_io_type type, void *opts, mesh_io_ready_func_t cb, void *user_data) { @@ -183,14 +207,23 @@ bool mesh_io_register_recv_cb(struct mesh_io *io, const uint8_t *filter, { struct mesh_io_reg *rx_reg; - if (io != default_io) + if (io == NULL) + io = default_io; + + if (io != default_io || !cb || !filter || !len) return false; + rx_reg = find_by_filter(io->rx_regs, filter, len); + + l_free(rx_reg); + l_queue_remove(io->rx_regs, rx_reg); + rx_reg = l_malloc(sizeof(struct mesh_io_reg) + len); rx_reg->cb = cb; rx_reg->len = len; rx_reg->user_data = user_data; memcpy(rx_reg->filter, filter, len); + l_queue_push_head(io->rx_regs, rx_reg); if (io && io->api && io->api->reg) @@ -199,14 +232,6 @@ bool mesh_io_register_recv_cb(struct mesh_io *io, const uint8_t *filter, return false; } -static bool by_filter(const void *a, const void *b) -{ - const struct mesh_io_reg *rx_reg = a; - const uint8_t *filter = b; - - return rx_reg->filter[0] == filter[0]; -} - bool mesh_io_deregister_recv_cb(struct mesh_io *io, const uint8_t *filter, uint8_t len) { @@ -215,7 +240,9 @@ bool mesh_io_deregister_recv_cb(struct mesh_io *io, const uint8_t *filter, if (io != default_io) return false; - rx_reg = l_queue_remove_if(io->rx_regs, by_filter, filter); + rx_reg = find_by_filter(io->rx_regs, filter, len); + + l_queue_remove(io->rx_regs, rx_reg); l_free(rx_reg); if (io && io->api && io->api->dereg) @@ -224,6 +251,38 @@ bool mesh_io_deregister_recv_cb(struct mesh_io *io, const uint8_t *filter, return false; } +static void loop_foreach(void *data, void *user_data) +{ + struct mesh_io_reg *rx_reg = data; + struct loop_data *rx = user_data; + + if (!memcmp(rx_reg->filter, unprv_filter, sizeof(unprv_filter))) + rx_reg->cb(rx_reg->user_data, NULL, rx->data, rx->len); +} + +static void loop_rx(struct l_timeout *timeout, void *user_data) +{ + struct loop_data *rx = user_data; + + l_queue_foreach(default_io->rx_regs, loop_foreach, rx); + l_timeout_modify_ms(loop_adv_to, 500); +} + +static void loop_destroy(void *user_data) +{ + l_free(user_data); +} + +static void loop_unprv_beacon(const uint8_t *data, uint16_t len) +{ + struct loop_data *pkt = l_malloc(len + sizeof(struct loop_data)); + + memcpy(pkt->data, data, len); + pkt->len = len; + l_timeout_remove(loop_adv_to); + loop_adv_to = l_timeout_create_ms(500, loop_rx, pkt, loop_destroy); +} + bool mesh_io_send(struct mesh_io *io, struct mesh_io_send_info *info, const uint8_t *data, uint16_t len) { @@ -233,6 +292,10 @@ bool mesh_io_send(struct mesh_io *io, struct mesh_io_send_info *info, if (!io) io = default_io; + /* Loop unprovisioned beacons for local clients */ + if (!memcmp(data, unprv_filter, sizeof(unprv_filter))) + loop_unprv_beacon(data, len); + if (io && io->api && io->api->send) return io->api->send(io, info, data, len); @@ -248,6 +311,11 @@ bool mesh_io_send_cancel(struct mesh_io *io, const uint8_t *pattern, if (!io) io = default_io; + if (loop_adv_to && len >= 2 && !memcmp(pattern, unprv_filter, 2)) { + l_timeout_remove(loop_adv_to); + loop_adv_to = NULL; + } + if (io && io->api && io->api->cancel) return io->api->cancel(io, pattern, len); diff --git a/mesh/mesh-io.h b/mesh/mesh-io.h index 9dd946cdf0e04ebab0ca0aaa600d448b7f4d0912..f7711e78635e866204c326c73937ab0947978642 100644 --- a/mesh/mesh-io.h +++ b/mesh/mesh-io.h @@ -8,8 +8,6 @@ * */ -struct mesh_io; - #define MESH_IO_TX_COUNT_UNLIMITED 0 enum mesh_io_type { diff --git a/mesh/mesh-mgmt.c b/mesh/mesh-mgmt.c index d37aeb5acd4a43767c0650332d5acf69a633fcb6..fd21a168ab27088901bd6396ed00bcf55be85aa1 100644 --- a/mesh/mesh-mgmt.c +++ b/mesh/mesh-mgmt.c @@ -271,3 +271,8 @@ bool mesh_mgmt_unregister(unsigned int id) { return mgmt_unregister(mgmt_mesh, id); } + +void mesh_mgmt_clear(void) +{ + l_queue_clear(ctl_list, l_free); +} diff --git a/mesh/mesh-mgmt.h b/mesh/mesh-mgmt.h index a3cd72fafaa85ed2569bb89ce6e1a371132b9400..5702822971415ec2736745f835b91a4be511ce2e 100644 --- a/mesh/mesh-mgmt.h +++ b/mesh/mesh-mgmt.h @@ -22,3 +22,4 @@ unsigned int mesh_mgmt_register(uint16_t event, uint16_t index, void *user_data, mgmt_destroy_func_t destroy); bool mesh_mgmt_unregister(unsigned int id); void mesh_mgmt_destroy(void); +void mesh_mgmt_clear(void); diff --git a/mesh/model.c b/mesh/model.c index d48e6ef120cbad7cf35cb588dc71b9c526351168..4ccafa17edd432c3e4bb0769a2025ed4d769c879 100644 --- a/mesh/model.c +++ b/mesh/model.c @@ -24,6 +24,9 @@ #include "mesh/net.h" #include "mesh/appkey.h" #include "mesh/cfgmod.h" +#include "mesh/prov.h" +#include "mesh/remprv.h" +#include "mesh/prv-beacon.h" #include "mesh/error.h" #include "mesh/dbus.h" #include "mesh/util.h" @@ -76,6 +79,12 @@ static bool is_internal(uint32_t id) if (id == CONFIG_SRV_MODEL || id == CONFIG_CLI_MODEL) return true; + if (id == REM_PROV_SRV_MODEL || id == REM_PROV_CLI_MODEL) + return true; + + if (id == PRV_BEACON_SRV_MODEL || id == PRV_BEACON_CLI_MODEL) + return true; + return false; } @@ -457,13 +466,25 @@ static int dev_packet_decrypt(struct mesh_node *node, const uint8_t *data, dst, key_aid, seq, iv_idx, out, key)) return APP_IDX_DEV_LOCAL; - if (!keyring_get_remote_dev_key(node, src, dev_key)) + key = dev_key; + + if (keyring_get_remote_dev_key(node, src, dev_key)) { + if (mesh_crypto_payload_decrypt(NULL, 0, data, size, szmict, + src, dst, key_aid, seq, iv_idx, out, key)) + return APP_IDX_DEV_REMOTE; + } + + /* See if there is a local Device Key Candidate as last resort */ + if (!node_get_device_key_candidate(node, dev_key)) return -1; - key = dev_key; - if (mesh_crypto_payload_decrypt(NULL, 0, data, size, szmict, src, - dst, key_aid, seq, iv_idx, out, key)) - return APP_IDX_DEV_REMOTE; + if (mesh_crypto_payload_decrypt(NULL, 0, data, size, szmict, + src, dst, key_aid, seq, iv_idx, out, key)) { + + /* If candidate dev_key worked, it is considered finalized */ + node_finalize_candidate(node); + return APP_IDX_DEV_LOCAL; + } return -1; } @@ -630,6 +651,9 @@ static int update_binding(struct mesh_node *node, uint16_t addr, uint32_t id, if (id == CONFIG_SRV_MODEL || id == CONFIG_CLI_MODEL) return MESH_STATUS_INVALID_MODEL; + if (id == PRV_BEACON_SRV_MODEL || id == PRV_BEACON_CLI_MODEL) + return MESH_STATUS_INVALID_MODEL; + if (!appkey_have_key(node_get_net(node), app_idx)) return MESH_STATUS_INVALID_APPKEY; @@ -1638,7 +1662,8 @@ static struct mesh_model *model_setup(struct mesh_net *net, uint8_t ele_idx, SET_ID(SIG_VENDOR, db_mod->id)); /* Implicitly bind config server model to device key */ - if (db_mod->id == CONFIG_SRV_MODEL) { + if (db_mod->id == CONFIG_SRV_MODEL || + db_mod->id == PRV_BEACON_SRV_MODEL) { if (ele_idx != PRIMARY_ELE_IDX) { l_free(mod); diff --git a/mesh/net-keys.c b/mesh/net-keys.c index ee7bbf0c0591764be48ac107e6aa899ebd557049..57a9df04a2a7c9499ec1d72bf3d13a0ec54478e4 100644 --- a/mesh/net-keys.c +++ b/mesh/net-keys.c @@ -21,39 +21,55 @@ #include "mesh/net.h" #include "mesh/net-keys.h" -#define BEACON_TYPE_SNB 0x01 -#define KEY_REFRESH 0x01 -#define IV_INDEX_UPDATE 0x02 - #define BEACON_INTERVAL_MIN 10 #define BEACON_INTERVAL_MAX 600 -struct net_beacon { +/* This allows daemon to skip decryption on recently seen beacons */ +#define BEACON_CACHE_MAX 10 + +struct beacon_rx { + uint8_t data[28]; + uint32_t id; + uint32_t ivi; + bool kr; + bool ivu; +}; + +struct beacon_observe { struct l_timeout *timeout; uint32_t ts; - uint16_t observe_period; - uint16_t observed; + uint16_t period; + uint16_t seen; uint16_t expected; bool half_period; - uint8_t beacon[23]; }; struct net_key { uint32_t id; - struct net_beacon snb; + struct l_timeout *mpb_to; + uint8_t *mpb; + uint8_t *snb; + struct beacon_observe observe; + uint32_t ivi; uint16_t ref_cnt; - uint16_t beacon_enables; + uint16_t mpb_enables; + uint16_t snb_enables; + uint8_t mpb_refresh; uint8_t friend_key; uint8_t nid; uint8_t flooding[16]; - uint8_t encrypt[16]; - uint8_t privacy[16]; - uint8_t beacon[16]; - uint8_t network[8]; + uint8_t enc_key[16]; + uint8_t prv_key[16]; + uint8_t snb_key[16]; + uint8_t pvt_key[16]; + uint8_t net_id[8]; + bool kr; + bool ivu; }; -static struct l_queue *keys = NULL; -static uint32_t last_flooding_id = 0; +static struct l_queue *beacons; +static struct l_queue *keys; +static uint32_t last_flooding_id; /* To avoid re-decrypting same packet for multiple nodes, cache and check */ static uint8_t cache_pkt[29]; @@ -81,9 +97,9 @@ static bool match_id(const void *a, const void *b) static bool match_network(const void *a, const void *b) { const struct net_key *key = a; - const uint8_t *network = b; + const uint8_t *net_id = b; - return memcmp(key->network, network, sizeof(key->network)) == 0; + return memcmp(key->net_id, net_id, sizeof(key->net_id)) == 0; } /* Key added from Provisioning, NetKey Add or NetKey update */ @@ -101,19 +117,27 @@ uint32_t net_key_add(const uint8_t flooding[16]) if (!keys) keys = l_queue_new(); + if (!beacons) + beacons = l_queue_new(); + key = l_new(struct net_key, 1); memcpy(key->flooding, flooding, 16); key->ref_cnt++; - result = mesh_crypto_k2(flooding, p, sizeof(p), &key->nid, key->encrypt, - key->privacy); + key->mpb_refresh = NET_MPB_REFRESH_DEFAULT; + result = mesh_crypto_k2(flooding, p, sizeof(p), &key->nid, key->enc_key, + key->prv_key); if (!result) goto fail; - result = mesh_crypto_k3(flooding, key->network); + result = mesh_crypto_k3(flooding, key->net_id); if (!result) goto fail; - result = mesh_crypto_nkbk(flooding, key->beacon); + result = mesh_crypto_nkbk(flooding, key->snb_key); + if (!result) + goto fail; + + result = mesh_crypto_nkpk(flooding, key->pvt_key); if (!result) goto fail; @@ -146,7 +170,7 @@ uint32_t net_key_frnd_add(uint32_t flooding_id, uint16_t lpn, uint16_t frnd, l_put_be16(fn_cnt, p + 7); result = mesh_crypto_k2(key->flooding, p, sizeof(p), &frnd_key->nid, - frnd_key->encrypt, frnd_key->privacy); + frnd_key->enc_key, frnd_key->prv_key); if (!result) { l_free(frnd_key); @@ -167,7 +191,7 @@ void net_key_unref(uint32_t id) if (key && key->ref_cnt) { if (--key->ref_cnt == 0) { - l_timeout_remove(key->snb.timeout); + l_timeout_remove(key->observe.timeout); l_queue_remove(keys, key); l_free(key); } @@ -206,7 +230,7 @@ static void decrypt_net_pkt(void *a, void *b) result = mesh_crypto_packet_decode(cache_pkt, cache_len, false, cache_plain, cache_iv_index, - key->encrypt, key->privacy); + key->enc_key, key->prv_key); if (result) { cache_id = key->id; @@ -254,8 +278,8 @@ bool net_key_encrypt(uint32_t id, uint32_t iv_index, uint8_t *pkt, size_t len) if (!key) return false; - result = mesh_crypto_packet_encode(pkt, len, iv_index, key->encrypt, - key->privacy); + result = mesh_crypto_packet_encode(pkt, len, iv_index, key->enc_key, + key->prv_key); if (!result) return false; @@ -265,9 +289,9 @@ bool net_key_encrypt(uint32_t id, uint32_t iv_index, uint8_t *pkt, size_t len) return result; } -uint32_t net_key_network_id(const uint8_t network[8]) +uint32_t net_key_network_id(const uint8_t net_id[8]) { - struct net_key *key = l_queue_find(keys, match_network, network); + struct net_key *key = l_queue_find(keys, match_network, net_id); if (!key) return 0; @@ -275,6 +299,55 @@ uint32_t net_key_network_id(const uint8_t network[8]) return key->id; } +struct auth_check { + const uint8_t *data; + uint32_t id; + uint32_t ivi; + bool ivu; + bool kr; +}; + +static void check_auth(void *a, void *b) +{ + struct net_key *key = a; + struct auth_check *auth = b; + uint8_t out[5]; + + + /* Stop checking if already found */ + if (auth->id) + return; + + if (mesh_crypto_aes_ccm_decrypt(auth->data + 1, key->pvt_key, NULL, 0, + auth->data + 14, 13, + out, NULL, 8)) { + auth->id = key->id; + auth->ivi = l_get_be32(out + 1); + auth->ivu = !!(out[0] & 0x02); + auth->kr = !!(out[0] & 0x01); + } +} + +static uint32_t private_beacon_check(const void *beacon, uint32_t *ivi, + bool *ivu, bool *kr) +{ + struct auth_check auth = { + .data = beacon, + .id = 0, + }; + + auth.id = 0; + l_queue_foreach(keys, check_auth, &auth); + + if (auth.id) { + *ivi = auth.ivi; + *ivu = auth.ivu; + *kr = auth.kr; + } + + return auth.id; +} + bool net_key_snb_check(uint32_t id, uint32_t iv_index, bool kr, bool ivu, uint64_t cmac) { @@ -285,7 +358,7 @@ bool net_key_snb_check(uint32_t id, uint32_t iv_index, bool kr, bool ivu, return false; /* Any behavioral changes must pass CMAC test */ - if (!mesh_crypto_beacon_cmac(key->beacon, key->network, iv_index, kr, + if (!mesh_crypto_beacon_cmac(key->snb_key, key->net_id, iv_index, kr, ivu, &cmac_check)) { l_error("mesh_crypto_beacon_cmac failed"); return false; @@ -300,39 +373,142 @@ bool net_key_snb_check(uint32_t id, uint32_t iv_index, bool kr, bool ivu, return true; } -bool net_key_snb_compose(uint32_t id, uint32_t iv_index, bool kr, bool ivu, - uint8_t *snb) +static bool mpb_compose(struct net_key *key, uint32_t ivi, bool kr, bool ivu) +{ + uint8_t b_data[5 + 8]; + uint8_t random[13]; + + if (!key) + return false; + + b_data[0] = 0; + l_put_be32(ivi, b_data + 1); + + if (kr) + b_data[0] |= KEY_REFRESH; + + if (ivu) + b_data[0] |= IV_INDEX_UPDATE; + + l_getrandom(random, sizeof(random)); + if (!mesh_crypto_aes_ccm_encrypt(random, key->pvt_key, NULL, 0, + b_data, 5, b_data, NULL, 8)) + return false; + + key->mpb[0] = MESH_AD_TYPE_BEACON; + key->mpb[1] = BEACON_TYPE_MPB; + memcpy(key->mpb + 2, random, 13); + memcpy(key->mpb + 15, b_data, 13); + + return true; +} + +static bool snb_compose(struct net_key *key, uint32_t ivi, bool kr, bool ivu) { - struct net_key *key = l_queue_find(keys, match_id, L_UINT_TO_PTR(id)); uint64_t cmac; if (!key) return false; /* Any behavioral changes must pass CMAC test */ - if (!mesh_crypto_beacon_cmac(key->beacon, key->network, iv_index, kr, + if (!mesh_crypto_beacon_cmac(key->snb_key, key->net_id, ivi, kr, ivu, &cmac)) { l_error("mesh_crypto_beacon_cmac failed"); return false; } - snb[0] = MESH_AD_TYPE_BEACON; - snb[1] = BEACON_TYPE_SNB; - snb[2] = 0; + key->snb[0] = MESH_AD_TYPE_BEACON; + key->snb[1] = BEACON_TYPE_SNB; + key->snb[2] = 0; if (kr) - snb[2] |= KEY_REFRESH; + key->snb[2] |= KEY_REFRESH; if (ivu) - snb[2] |= IV_INDEX_UPDATE; + key->snb[2] |= IV_INDEX_UPDATE; - memcpy(snb + 3, key->network, 8); - l_put_be32(iv_index, snb + 11); - l_put_be64(cmac, snb + 15); + memcpy(key->snb + 3, key->net_id, 8); + l_put_be32(ivi, key->snb + 11); + l_put_be64(cmac, key->snb + 15); return true; } +static bool match_beacon(const void *a, const void *b) +{ + const struct beacon_rx *cached = a; + const uint8_t *incoming = b; + + if (incoming[0] == BEACON_TYPE_MPB) + return !memcmp(cached->data, incoming, 27); + + if (incoming[0] == BEACON_TYPE_SNB) + return !memcmp(cached->data, incoming, 22); + + return false; +} + +uint32_t net_key_beacon(const uint8_t *data, uint16_t len, uint32_t *ivi, + bool *ivu, bool *kr) +{ + struct net_key *key; + struct beacon_rx *beacon; + uint32_t b_id, b_ivi; + bool b_ivu, b_kr; + + if (data[1] == BEACON_TYPE_SNB && len != 23) + return 0; + + if (data[1] == BEACON_TYPE_MPB && len != 28) + return 0; + + beacon = l_queue_remove_if(beacons, match_beacon, data + 1); + + if (beacon) + goto accept; + + /* Validate beacon data */ + if (data[1] == BEACON_TYPE_SNB) { + key = l_queue_find(keys, match_network, data + 3); + + if (!key) + return 0; + + b_id = key->id; + b_ivu = !!(data[2] & 0x02); + b_kr = !!(data[2] & 0x01); + b_ivi = l_get_be32(data + 11); + + if (!net_key_snb_check(b_id, b_ivi, b_kr, b_ivu, + l_get_be64(data + 15))) + return 0; + + } else if (data[1] == BEACON_TYPE_MPB) { + b_id = private_beacon_check(data + 1, &b_ivi, &b_ivu, &b_kr); + + if (!b_id) + return 0; + + } else + return 0; + + beacon = l_new(struct beacon_rx, 1); + memcpy(beacon->data, data + 1, len - 1); + beacon->id = b_id; + beacon->ivi = b_ivi; + beacon->ivu = b_ivu; + beacon->kr = b_kr; + +accept: + *ivi = beacon->ivi; + *ivu = beacon->ivu; + *kr = beacon->kr; + + l_queue_push_head(beacons, beacon); + + return beacon->id; +} + static void send_network_beacon(struct net_key *key) { struct mesh_io_send_info info = { @@ -343,10 +519,26 @@ static void send_network_beacon(struct net_key *key) .u.gen.max_delay = DEFAULT_MAX_DELAY }; - mesh_io_send(NULL, &info, key->snb.beacon, sizeof(key->snb.beacon)); + if (key->mpb_enables) { + /* If Interval steps == 0, refresh key every time */ + if (!key->mpb_refresh || !key->mpb || !key->mpb[0]) + net_key_beacon_refresh(key->id, key->ivi, key->kr, + key->ivu, true); + + mesh_io_send(NULL, &info, key->mpb, 28); + } + + if (key->snb_enables) { + if (!key->snb || !key->snb[0]) { + net_key_beacon_refresh(key->id, key->ivi, key->kr, + key->ivu, true); + } + + mesh_io_send(NULL, &info, key->snb, 23); + } } -static void snb_timeout(struct l_timeout *timeout, void *user_data) +static void beacon_timeout(struct l_timeout *timeout, void *user_data) { struct net_key *key = user_data; uint32_t interval, scale_factor; @@ -355,29 +547,29 @@ static void snb_timeout(struct l_timeout *timeout, void *user_data) send_network_beacon(key); /* Count our own beacons towards the vicinity total */ - key->snb.observed++; + key->observe.seen++; - if (!key->snb.half_period) { + if (!key->observe.half_period) { l_debug("beacon %d for %d nodes, period %d, obs %d, exp %d", - key->id, - key->beacon_enables, - key->snb.observe_period, - key->snb.observed, - key->snb.expected); + key->id, + key->snb_enables + key->mpb_enables, + key->observe.period, + key->observe.seen, + key->observe.expected); - interval = (key->snb.observe_period * key->snb.observed) - / key->snb.expected; + interval = (key->observe.period * key->observe.seen) + / key->observe.expected; /* Limit Increases and Decreases by 10 seconds Up and * 20 seconds down each step, to avoid going nearly silent * in highly populated environments. */ - if (interval - 10 > key->snb.observe_period) - interval = key->snb.observe_period + 10; - else if (interval + 20 < key->snb.observe_period) - interval = key->snb.observe_period - 20; + if (interval - 10 > key->observe.period) + interval = key->observe.period + 10; + else if (interval + 20 < key->observe.period) + interval = key->observe.period - 20; /* Beaconing must be no *slower* than once every 10 minutes, * and no *faster* than once every 10 seconds, per spec. @@ -388,26 +580,26 @@ static void snb_timeout(struct l_timeout *timeout, void *user_data) else if (interval > BEACON_INTERVAL_MAX * 2) interval = BEACON_INTERVAL_MAX * 2; - key->snb.observe_period = interval; - key->snb.observed = 0; + key->observe.period = interval; + key->observe.seen = 0; /* To prevent "over slowing" of the beaconing frequency, * require more significant "over observing" the slower * our own beaconing frequency. */ - key->snb.expected = interval / 10; + key->observe.expected = interval / 10; scale_factor = interval / 60; - key->snb.expected += scale_factor * 3; + key->observe.expected += scale_factor * 3; } - interval = key->snb.observe_period / 2; - key->snb.half_period = !key->snb.half_period; + interval = key->observe.period / 2; + key->observe.half_period = !key->observe.half_period; - if (key->beacon_enables) + if (key->mpb_enables || key->snb_enables) l_timeout_modify(timeout, interval); else { l_timeout_remove(timeout); - key->snb.timeout = NULL; + key->observe.timeout = NULL; } } @@ -416,8 +608,8 @@ void net_key_beacon_seen(uint32_t id) struct net_key *key = l_queue_find(keys, match_id, L_UINT_TO_PTR(id)); if (key) { - key->snb.observed++; - key->snb.ts = get_timestamp_secs(); + key->observe.seen++; + key->observe.ts = get_timestamp_secs(); } } @@ -426,12 +618,87 @@ uint32_t net_key_beacon_last_seen(uint32_t id) struct net_key *key = l_queue_find(keys, match_id, L_UINT_TO_PTR(id)); if (key) - return key->snb.ts; + return key->observe.ts; return 0; } -void net_key_beacon_enable(uint32_t id) +bool net_key_beacon_refresh(uint32_t id, uint32_t ivi, bool kr, bool ivu, + bool force) +{ + struct net_key *key = l_queue_find(keys, match_id, L_UINT_TO_PTR(id)); + bool refresh = force; + uint32_t rand_ms; + + if (!key) + return false; + + if (key->snb_enables && !key->snb) { + key->snb = l_new(uint8_t, 23); + refresh = true; + } + + if (key->mpb_enables && !key->mpb) { + key->mpb = l_new(uint8_t, 28); + refresh = true; + } + + if (key->ivi != ivi || key->ivu != ivu || key->kr != kr) + refresh = true; + + if (!refresh) + return true; + + if (key->mpb) { + if (!mpb_compose(key, ivi, kr, ivu)) + return false; + + print_packet("Set MPB to", key->mpb, 28); + } + + if (key->snb) { + if (!snb_compose(key, ivi, kr, ivu)) + return false; + + print_packet("Set SNB to", key->snb, 23); + } + + l_debug("Set Beacon: IVI: %8.8x, IVU: %d, KR: %d", ivi, ivu, kr); + + key->ivi = ivi; + key->ivu = ivu; + key->kr = kr; + + /* Propagate changes to all local nodes */ + net_local_beacon(id, ivi, ivu, kr); + + /* Send one new SNB soon, after all nodes have seen it */ + l_getrandom(&rand_ms, sizeof(rand_ms)); + rand_ms %= 1000; + key->observe.expected++; + + if (key->observe.timeout) + l_timeout_modify_ms(key->observe.timeout, 500 + rand_ms); + else + key->observe.timeout = l_timeout_create_ms(500 + rand_ms, + beacon_timeout, key, NULL); + + return true; +} + +static void mpb_timeout(struct l_timeout *timeout, void *user_data) +{ + struct net_key *key = user_data; + + if (key->mpb_refresh) { + l_debug("Refresh in %d seconds", key->mpb_refresh * 10); + l_timeout_modify(timeout, key->mpb_refresh * 10); + } + + net_key_beacon_refresh(key->id, key->ivi, key->kr, key->ivu, true); +} + +void net_key_beacon_enable(uint32_t id, bool mpb, uint8_t refresh_count) { struct net_key *key = l_queue_find(keys, match_id, L_UINT_TO_PTR(id)); bool enabled; @@ -440,8 +707,19 @@ void net_key_beacon_enable(uint32_t id) if (!key) return; - enabled = !!key->beacon_enables; - key->beacon_enables++; + enabled = !!key->snb_enables || !!key->mpb_enables; + + if (mpb) { + key->mpb_enables++; + key->mpb_refresh = refresh_count; + l_timeout_remove(key->mpb_to); + if (refresh_count) + key->mpb_to = l_timeout_create(refresh_count * 10, + mpb_timeout, key, NULL); + else + key->mpb_to = NULL; + } else + key->snb_enables++; /* If already Enabled, do nothing */ if (enabled) @@ -453,70 +731,68 @@ void net_key_beacon_enable(uint32_t id) rand_ms++; /* Enable Periodic Beaconing on this key */ - key->snb.observe_period = BEACON_INTERVAL_MIN * 2; - key->snb.expected = 2; - key->snb.observed = 0; - key->snb.half_period = true; - l_timeout_remove(key->snb.timeout); - key->snb.timeout = l_timeout_create_ms(rand_ms, snb_timeout, key, NULL); + key->observe.period = BEACON_INTERVAL_MIN * 2; + key->observe.expected = 2; + key->observe.seen = 0; + key->observe.half_period = true; + l_timeout_remove(key->observe.timeout); + key->observe.timeout = l_timeout_create_ms(rand_ms, beacon_timeout, + key, NULL); } -bool net_key_beacon_refresh(uint32_t id, uint32_t iv_index, bool kr, bool ivu) +void net_key_beacon_disable(uint32_t id, bool mpb) { struct net_key *key = l_queue_find(keys, match_id, L_UINT_TO_PTR(id)); - uint8_t beacon[23]; - uint32_t rand_ms; if (!key) - return false; + return; - if (!net_key_snb_compose(id, iv_index, kr, ivu, beacon)) - return false; + if (mpb) { + if (!key->mpb_enables) + return; - if (memcmp(key->snb.beacon, beacon, sizeof(beacon))) - memcpy(key->snb.beacon, beacon, sizeof(beacon)); - else - return false; + key->mpb_enables--; - l_debug("Setting SNB: IVI: %8.8x, IVU: %d, KR: %d", iv_index, ivu, kr); - print_packet("Set SNB Beacon to", beacon, sizeof(beacon)); + if (!key->mpb_enables) { + l_free(key->mpb); + key->mpb = NULL; + l_timeout_remove(key->mpb_to); + key->mpb_to = NULL; + } + } else { + if (!key->snb_enables) + return; - /* Propagate changes to all local nodes */ - net_local_beacon(id, beacon); + key->snb_enables--; - /* Send one new SNB soon, after all nodes have seen it */ - l_getrandom(&rand_ms, sizeof(rand_ms)); - rand_ms %= 1000; - key->snb.expected++; + if (!key->snb_enables) { + l_free(key->snb); + key->snb = NULL; + } + } - if (key->snb.timeout) - l_timeout_modify_ms(key->snb.timeout, 500 + rand_ms); - else - key->snb.timeout = l_timeout_create_ms(500 + rand_ms, - snb_timeout, key, NULL); + if (key->snb_enables || key->mpb_enables) + return; - return true; + /* Disable periodic Beaconing on this key */ + l_timeout_remove(key->observe.timeout); + key->observe.timeout = NULL; } -void net_key_beacon_disable(uint32_t id) +static void free_key(void *data) { - struct net_key *key = l_queue_find(keys, match_id, L_UINT_TO_PTR(id)); - - if (!key || !key->beacon_enables) - return; - - key->beacon_enables--; + struct net_key *key = data; - if (key->beacon_enables) - return; - - /* Disable periodic Beaconing on this key */ - l_timeout_remove(key->snb.timeout); - key->snb.timeout = NULL; + l_timeout_remove(key->mpb_to); + l_free(key->snb); + l_free(key->mpb); + l_free(key); } void net_key_cleanup(void) { - l_queue_destroy(keys, l_free); + l_queue_destroy(keys, free_key); keys = NULL; + l_queue_destroy(beacons, l_free); + beacons = NULL; } diff --git a/mesh/net-keys.h b/mesh/net-keys.h index 420618f710637fbfae19e000c9ef07edd652070e..e73812481ddbcf9439c9718598e601e515ef50a7 100644 --- a/mesh/net-keys.h +++ b/mesh/net-keys.h @@ -9,8 +9,10 @@ */ #define BEACON_TYPE_SNB 0x01 +#define BEACON_TYPE_MPB 0x02 #define KEY_REFRESH 0x01 #define IV_INDEX_UPDATE 0x02 +#define NET_MPB_REFRESH_DEFAULT 60 void net_key_cleanup(void); bool net_key_confirm(uint32_t id, const uint8_t flooding[16]); @@ -23,12 +25,15 @@ uint32_t net_key_decrypt(uint32_t iv_index, const uint8_t *pkt, size_t len, uint8_t **plain, size_t *plain_len); bool net_key_encrypt(uint32_t id, uint32_t iv_index, uint8_t *pkt, size_t len); uint32_t net_key_network_id(const uint8_t network[8]); +uint32_t net_key_beacon(const uint8_t *data, uint16_t len, uint32_t *ivi, + bool *ivu, bool *kr); bool net_key_snb_check(uint32_t id, uint32_t iv_index, bool kr, bool ivu, uint64_t cmac); bool net_key_snb_compose(uint32_t id, uint32_t iv_index, bool kr, bool ivu, uint8_t *snb); void net_key_beacon_seen(uint32_t id); -void net_key_beacon_enable(uint32_t id); -bool net_key_beacon_refresh(uint32_t id, uint32_t iv_index, bool kr, bool ivu); -void net_key_beacon_disable(uint32_t id); +bool net_key_beacon_refresh(uint32_t id, uint32_t iv_index, bool kr, bool ivu, + bool force); +void net_key_beacon_enable(uint32_t id, bool mpb, uint8_t refresh_count); +void net_key_beacon_disable(uint32_t id, bool mpb); uint32_t net_key_beacon_last_seen(uint32_t id); diff --git a/mesh/net.c b/mesh/net.c index 1d27289bf74706aa8e8d9769112521a19d7a274a..05ca48326fc538ed685671d0ccc5327255baf84b 100644 --- a/mesh/net.c +++ b/mesh/net.c @@ -102,7 +102,8 @@ struct mesh_net { unsigned int sar_id_next; bool friend_enable; - bool beacon_enable; + bool snb_enable; + bool mpb_enable; bool proxy_enable; bool friend_seq; struct l_timeout *iv_update_timeout; @@ -119,6 +120,7 @@ struct mesh_net { uint8_t chan; /* Channel of recent Rx */ uint8_t default_ttl; uint8_t tid; + uint8_t mpb_period; struct { bool enable; @@ -217,6 +219,7 @@ struct net_beacon_data { bool ivu; bool kr; bool processed; + bool local; }; static struct l_queue *fast_cache; @@ -526,6 +529,13 @@ static void mesh_sar_free(void *data) static void subnet_free(void *data) { struct mesh_subnet *subnet = data; + struct mesh_net *net = subnet->net; + + if (net->snb_enable) + net_key_beacon_disable(subnet->net_key_tx, false); + + if (net->mpb_enable) + net_key_beacon_disable(subnet->net_key_tx, true); net_key_unref(subnet->net_key_cur); net_key_unref(subnet->net_key_upd); @@ -545,15 +555,27 @@ static struct mesh_subnet *subnet_new(struct mesh_net *net, uint16_t idx) return subnet; } -static void enable_beacon(void *a, void *b) +static void enable_snb(void *a, void *b) +{ + struct mesh_subnet *subnet = a; + struct mesh_net *net = b; + + if (net->snb_enable) + net_key_beacon_enable(subnet->net_key_tx, false, 0); + else + net_key_beacon_disable(subnet->net_key_tx, false); +} + +static void enable_mpb(void *a, void *b) { struct mesh_subnet *subnet = a; struct mesh_net *net = b; - if (net->beacon_enable) - net_key_beacon_enable(subnet->net_key_tx); + if (net->mpb_enable) + net_key_beacon_enable(subnet->net_key_tx, true, + net->mpb_period); else - net_key_beacon_disable(subnet->net_key_tx); + net_key_beacon_disable(subnet->net_key_tx, true); } static void enqueue_update(void *a, void *b); @@ -602,7 +624,8 @@ static void refresh_beacon(void *a, void *b) struct mesh_net *net = b; net_key_beacon_refresh(subnet->net_key_tx, net->iv_index, - !!(subnet->kr_phase == KEY_REFRESH_PHASE_TWO), net->iv_update); + !!(subnet->kr_phase == KEY_REFRESH_PHASE_TWO), net->iv_update, + false); } struct mesh_net *mesh_net_new(struct mesh_node *node) @@ -826,7 +849,7 @@ int mesh_net_del_key(struct mesh_net *net, uint16_t idx) if (idx == net->hb_pub.net_idx) net->hb_pub.dst = UNASSIGNED_ADDRESS; - /* TODO: cancel beacon_enable on this subnet */ + /* TODO: cancel snb_enable on this subnet */ l_queue_remove(net->subnets, subnet); subnet_free(subnet); @@ -853,10 +876,14 @@ static struct mesh_subnet *add_key(struct mesh_net *net, uint16_t idx, } net_key_beacon_refresh(subnet->net_key_tx, net->iv_index, - false, net->iv_update); + false, net->iv_update, false); - if (net->beacon_enable) - net_key_beacon_enable(subnet->net_key_tx); + if (net->snb_enable) + net_key_beacon_enable(subnet->net_key_tx, false, 0); + + if (net->mpb_enable) + net_key_beacon_enable(subnet->net_key_tx, true, + net->mpb_period); l_queue_push_tail(net->subnets, subnet); @@ -2598,6 +2625,13 @@ static int key_refresh_phase_two(struct mesh_net *net, uint16_t idx) if (subnet->kr_phase == KEY_REFRESH_PHASE_TWO) return MESH_STATUS_SUCCESS; + /* Stop beaconing on old key */ + if (net->snb_enable) + net_key_beacon_disable(subnet->net_key_tx, false); + + if (net->mpb_enable) + net_key_beacon_disable(subnet->net_key_tx, true); + subnet->key_refresh = 1; subnet->net_key_tx = subnet->net_key_upd; /* @@ -2605,6 +2639,15 @@ static int key_refresh_phase_two(struct mesh_net *net, uint16_t idx) * it hears beacons from all the nodes */ subnet->kr_phase = KEY_REFRESH_PHASE_TWO; + + /* Start beaconing on new key */ + if (net->snb_enable) + net_key_beacon_enable(subnet->net_key_tx, false, 0); + + if (net->mpb_enable) + net_key_beacon_enable(subnet->net_key_tx, true, + net->mpb_period); + refresh_beacon(subnet, net); queue_friend_update(net); @@ -2794,83 +2837,111 @@ static void process_beacon(void *net_ptr, void *user_data) beacon_data->processed = true; /* - * Ignore the beacon if it doesn't change anything, unless we're - * doing IV Recovery + * Ignore local beacons and beacons that don't change anything, + * unless we're doing IV Recovery */ - if (net->iv_upd_state == IV_UPD_INIT || ivi != net->iv_index || + if (!beacon_data->local) { + if (net->iv_upd_state == IV_UPD_INIT || ivi != net->iv_index || ivu != net->iv_update) - updated |= update_iv_ivu_state(net, ivi, ivu); + updated |= update_iv_ivu_state(net, ivi, ivu); - if (kr != local_kr || beacon_data->net_key_id != subnet->net_key_cur) - updated |= update_kr_state(subnet, kr, beacon_data->net_key_id); + if (kr != local_kr) + updated |= update_kr_state(subnet, kr, + beacon_data->net_key_id); - if (updated) - net_key_beacon_refresh(subnet->net_key_tx, net->iv_index, + + if (updated) + net_key_beacon_refresh(beacon_data->net_key_id, + net->iv_index, !!(subnet->kr_phase == KEY_REFRESH_PHASE_TWO), - net->iv_update); + net->iv_update, false); + } } static void beacon_recv(void *user_data, struct mesh_io_recv_info *info, const uint8_t *data, uint16_t len) { struct net_beacon_data beacon_data = { + .local = false, .processed = false, }; - if (len != 23 || data[1] != 0x01) - return; + beacon_data.net_key_id = net_key_beacon(data, len, &beacon_data.ivi, + &beacon_data.ivu, &beacon_data.kr); - /* Ignore Network IDs unknown to this daemon */ - beacon_data.net_key_id = net_key_network_id(data + 3); if (!beacon_data.net_key_id) return; - /* Get data bits from beacon */ - beacon_data.ivu = !!(data[2] & 0x02); - beacon_data.kr = !!(data[2] & 0x01); - beacon_data.ivi = l_get_be32(data + 11); - - /* Validate beacon before accepting */ - if (!net_key_snb_check(beacon_data.net_key_id, beacon_data.ivi, - beacon_data.kr, beacon_data.ivu, - l_get_be64(data + 15))) { - l_error("mesh_crypto_beacon verify failed"); - return; - } - l_queue_foreach(nets, process_beacon, &beacon_data); if (beacon_data.processed) net_key_beacon_seen(beacon_data.net_key_id); } -void net_local_beacon(uint32_t net_key_id, uint8_t *beacon) +void net_local_beacon(uint32_t net_key_id, uint32_t ivi, bool ivu, bool kr) { struct net_beacon_data beacon_data = { + .local = true, + .processed = false, .net_key_id = net_key_id, - .ivu = !!(beacon[2] & 0x02), - .kr = !!(beacon[2] & 0x01), - .ivi = l_get_be32(beacon + 11), + .ivu = ivu, + .kr = kr, + .ivi = ivi, }; /* Deliver locally generated beacons to all nodes */ l_queue_foreach(nets, process_beacon, &beacon_data); } -bool mesh_net_set_beacon_mode(struct mesh_net *net, bool enable) +bool mesh_net_set_snb_mode(struct mesh_net *net, bool enable) +{ + if (!net) + return false; + + if (net->snb_enable == enable) + return true; + + net->snb_enable = enable; + + if (enable) + l_queue_foreach(net->subnets, refresh_beacon, net); + + l_queue_foreach(net->subnets, enable_snb, net); + queue_friend_update(net); + + return true; +} + +bool mesh_net_set_mpb_mode(struct mesh_net *net, bool enable, uint8_t period, + bool initialize) { + uint8_t old_period; + bool old_enable; + if (!net) return false; - if (net->beacon_enable == enable) + old_enable = net->mpb_enable; + old_period = net->mpb_period; + + if (enable) + net->mpb_period = period; + + if (old_enable == enable && old_period == net->mpb_period) return true; - net->beacon_enable = enable; + if (enable && !initialize) { + /* If enable with different period, disable and re-enable */ + net->mpb_enable = false; + l_queue_foreach(net->subnets, enable_mpb, net); + } + + net->mpb_enable = enable; if (enable) l_queue_foreach(net->subnets, refresh_beacon, net); - l_queue_foreach(net->subnets, enable_beacon, net); + l_queue_foreach(net->subnets, enable_mpb, net); queue_friend_update(net); return true; @@ -2908,17 +2979,25 @@ bool mesh_net_set_key(struct mesh_net *net, uint16_t idx, const uint8_t *key, subnet->key_refresh = 1; subnet->net_key_tx = subnet->net_key_upd; - if (net->beacon_enable) { + if (net->snb_enable) { + /* Switch beaconing key */ + net_key_beacon_disable(subnet->net_key_cur, false); + net_key_beacon_enable(subnet->net_key_upd, false, 0); + } + + if (net->mpb_enable) { /* Switch beaconing key */ - net_key_beacon_disable(subnet->net_key_cur); - net_key_beacon_enable(subnet->net_key_upd); + net_key_beacon_disable(subnet->net_key_cur, true); + net_key_beacon_enable(subnet->net_key_upd, true, + net->mpb_period); } } subnet->kr_phase = phase; net_key_beacon_refresh(subnet->net_key_tx, net->iv_index, - !!(subnet->kr_phase == KEY_REFRESH_PHASE_TWO), net->iv_update); + !!(subnet->kr_phase == KEY_REFRESH_PHASE_TWO), net->iv_update, + false); return true; @@ -2933,8 +3012,9 @@ bool mesh_net_attach(struct mesh_net *net, struct mesh_io *io) first = l_queue_isempty(nets); if (first) { - uint8_t snb[] = {MESH_AD_TYPE_BEACON, 0x01}; - uint8_t pkt[] = {MESH_AD_TYPE_NETWORK}; + const uint8_t snb[] = {MESH_AD_TYPE_BEACON, 1}; + const uint8_t mpb[] = {MESH_AD_TYPE_BEACON, 2}; + const uint8_t pkt[] = {MESH_AD_TYPE_NETWORK}; if (!nets) nets = l_queue_new(); @@ -2944,6 +3024,8 @@ bool mesh_net_attach(struct mesh_net *net, struct mesh_io *io) mesh_io_register_recv_cb(io, snb, sizeof(snb), beacon_recv, NULL); + mesh_io_register_recv_cb(io, mpb, sizeof(mpb), + beacon_recv, NULL); mesh_io_register_recv_cb(io, pkt, sizeof(pkt), net_msg_recv, NULL); } @@ -2960,8 +3042,9 @@ bool mesh_net_attach(struct mesh_net *net, struct mesh_io *io) struct mesh_io *mesh_net_detach(struct mesh_net *net) { - uint8_t snb[] = {MESH_AD_TYPE_BEACON, 0x01}; - uint8_t pkt[] = {MESH_AD_TYPE_NETWORK}; + const uint8_t snb[] = {MESH_AD_TYPE_BEACON, 1}; + const uint8_t mpb[] = {MESH_AD_TYPE_BEACON, 2}; + const uint8_t pkt[] = {MESH_AD_TYPE_NETWORK}; struct mesh_io *io; uint8_t type = 0; @@ -2975,6 +3058,7 @@ struct mesh_io *mesh_net_detach(struct mesh_net *net) /* Only deregister io if this is the last network detached.*/ if (l_queue_length(nets) < 2) { mesh_io_deregister_recv_cb(io, snb, sizeof(snb)); + mesh_io_deregister_recv_cb(io, mpb, sizeof(mpb)); mesh_io_deregister_recv_cb(io, pkt, sizeof(pkt)); } diff --git a/mesh/net.h b/mesh/net.h index 0bacbbbbf18b4fcc46ff8ebe519f60424f883775..d385ba16efddf57633d5949baa0838c886bbd3aa 100644 --- a/mesh/net.h +++ b/mesh/net.h @@ -236,8 +236,10 @@ void mesh_net_set_frnd_seq(struct mesh_net *net, bool seq); uint16_t mesh_net_get_address(struct mesh_net *net); bool mesh_net_register_unicast(struct mesh_net *net, uint16_t unicast, uint8_t num_ele); -void net_local_beacon(uint32_t net_key_id, uint8_t *beacon); -bool mesh_net_set_beacon_mode(struct mesh_net *net, bool enable); +void net_local_beacon(uint32_t key_id, uint32_t ivi, bool ivu, bool kr); +bool mesh_net_set_snb_mode(struct mesh_net *net, bool enable); +bool mesh_net_set_mpb_mode(struct mesh_net *net, bool enabla, uint8_t period, + bool init); bool mesh_net_set_proxy_mode(struct mesh_net *net, bool enable); bool mesh_net_set_relay_mode(struct mesh_net *net, bool enable, uint8_t cnt, uint8_t interval); diff --git a/mesh/node.c b/mesh/node.c index cf4ed140e2fe4b72c28b83920d16d9465767d14d..93537c5ba4cc7549a8e11b9035f9c1d4a7d0ed32 100644 --- a/mesh/node.c +++ b/mesh/node.c @@ -27,9 +27,12 @@ #include "mesh/appkey.h" #include "mesh/mesh-config.h" #include "mesh/provision.h" +#include "mesh/prov.h" #include "mesh/keyring.h" #include "mesh/model.h" #include "mesh/cfgmod.h" +#include "mesh/remprv.h" +#include "mesh/prv-beacon.h" #include "mesh/util.h" #include "mesh/error.h" #include "mesh/dbus.h" @@ -98,6 +101,8 @@ struct mesh_node { uint8_t proxy; uint8_t friend; uint8_t beacon; + uint8_t mpb; + uint8_t mpb_period; }; struct node_import { @@ -204,6 +209,8 @@ static void set_defaults(struct mesh_node *node) { node->lpn = MESH_MODE_UNSUPPORTED; node->proxy = MESH_MODE_UNSUPPORTED; + node->mpb = MESH_MODE_DISABLED; + node->mpb_period = NET_MPB_REFRESH_DEFAULT; node->friend = (mesh_friendship_supported()) ? MESH_MODE_DISABLED : MESH_MODE_UNSUPPORTED; node->beacon = (mesh_beacon_enabled()) ? MESH_MODE_ENABLED : @@ -340,6 +347,7 @@ static bool add_elements_from_storage(struct mesh_node *node, struct mesh_config_node *db_node) { const struct l_queue_entry *entry; + struct node_element *ele; entry = l_queue_get_entries(db_node->elements); @@ -347,6 +355,20 @@ static bool add_elements_from_storage(struct mesh_node *node, if (!add_element_from_storage(node, entry->data)) return false; + ele = l_queue_find(node->elements, match_element_idx, + L_UINT_TO_PTR(PRIMARY_ELE_IDX)); + if (!ele) + return false; + + /* Add configuration server model on the primary element */ + mesh_model_add(node, ele->models, CONFIG_SRV_MODEL, NULL); + + /* Add remote provisioning models on the primary element */ + mesh_model_add(node, ele->models, REM_PROV_SRV_MODEL, NULL); + + if (node->provisioner) + mesh_model_add(node, ele->models, REM_PROV_CLI_MODEL, NULL); + return true; } @@ -392,7 +414,7 @@ static bool init_storage_dir(struct mesh_node *node) return rpl_init(node->storage_dir); } -static void update_net_settings(struct mesh_node *node) +static void init_net_settings(struct mesh_node *node) { struct mesh_net *net = node->net; @@ -403,7 +425,9 @@ static void update_net_settings(struct mesh_node *node) mesh_net_set_relay_mode(net, node->relay.mode == MESH_MODE_ENABLED, node->relay.cnt, node->relay.interval); - mesh_net_set_beacon_mode(net, node->beacon == MESH_MODE_ENABLED); + mesh_net_set_snb_mode(net, node->beacon == MESH_MODE_ENABLED); + mesh_net_set_mpb_mode(net, node->mpb == MESH_MODE_ENABLED, + node->mpb_period, true); } static bool init_from_storage(struct mesh_config_node *db_node, @@ -431,6 +455,8 @@ static bool init_from_storage(struct mesh_config_node *db_node, node->relay.cnt = db_node->modes.relay.cnt; node->relay.interval = db_node->modes.relay.interval; node->beacon = db_node->modes.beacon; + node->mpb = db_node->modes.mpb; + node->mpb_period = db_node->modes.mpb_period; l_debug("relay %2.2x, proxy %2.2x, lpn %2.2x, friend %2.2x", node->relay.mode, node->proxy, node->lpn, node->friend); @@ -484,11 +510,18 @@ static bool init_from_storage(struct mesh_config_node *db_node, mesh_net_set_seq_num(node->net, node->seq_number); mesh_net_set_default_ttl(node->net, node->ttl); - update_net_settings(node); + init_net_settings(node); /* Initialize configuration server model */ cfgmod_server_init(node, PRIMARY_ELE_IDX); + /* Initialize remote provisioning models */ + remote_prov_server_init(node, PRIMARY_ELE_IDX); + remote_prov_client_init(node, PRIMARY_ELE_IDX); + + /* Initialize Private Beacon server model */ + prv_beacon_server_init(node, PRIMARY_ELE_IDX); + node->cfg = cfg; return true; @@ -550,12 +583,78 @@ uint16_t node_get_primary(struct mesh_node *node) return node->primary; } +bool node_refresh(struct mesh_node *node, bool hard, void *prov_info) +{ + struct mesh_prov_node_info *info = prov_info; + bool res = true; + + if (!node || !info) + return false; + + if (!IS_UNICAST(info->unicast)) + return false; + + /* Changing Unicast addresses requires a hard node reset */ + if (!hard && info->unicast != node->primary) + return false; + + /* + * Hard refresh results in immediate use of new Device Key. + * Soft refresh saves new device key as Candidate until we + * successfully receive new incoming message on that key. + */ + if (hard) { + if (!mesh_config_write_device_key(node->cfg, info->device_key)) + return false; + + memcpy(node->dev_key, info->device_key, sizeof(node->dev_key)); + + } else if (!mesh_config_write_candidate(node->cfg, info->device_key)) + return false; + + /* Replace Primary Unicast address if it has changed */ + if (node->primary != info->unicast) { + res = mesh_config_write_unicast(node->cfg, info->unicast); + if (res) { + node->primary = info->unicast; + node->num_ele = info->num_ele; + mesh_net_register_unicast(node->net, node->primary, + node->num_ele); + } + } + + /* Replace Page 0 with Page 128 if it exists */ + if (res) { + if (node_replace_comp(node, 0, 128)) + return true; + } + + return res; +} + const uint8_t *node_get_device_key(struct mesh_node *node) { if (!node) return NULL; - else - return node->dev_key; + + return node->dev_key; +} + +bool node_get_device_key_candidate(struct mesh_node *node, uint8_t *key) +{ + if (!node) + return false; + + return mesh_config_read_candidate(node->cfg, key); +} + +void node_finalize_candidate(struct mesh_node *node) +{ + if (!node) + return; + + if (mesh_config_read_candidate(node->cfg, node->dev_key)) + mesh_config_finalize_candidate(node->cfg); } void node_set_token(struct mesh_node *node, uint8_t token[8]) @@ -744,7 +843,7 @@ bool node_beacon_mode_set(struct mesh_node *node, bool enable) if (res) { node->beacon = beacon; - mesh_net_set_beacon_mode(node->net, enable); + mesh_net_set_snb_mode(node->net, enable); } return res; @@ -758,6 +857,36 @@ uint8_t node_beacon_mode_get(struct mesh_node *node) return node->beacon; } +bool node_mpb_mode_set(struct mesh_node *node, bool enable, uint8_t period) +{ + bool res; + uint8_t beacon; + + if (!node) + return false; + + beacon = enable ? MESH_MODE_ENABLED : MESH_MODE_DISABLED; + res = mesh_config_write_mpb(node->cfg, beacon, period); + + if (res) { + node->mpb = beacon; + node->mpb_period = period; + mesh_net_set_mpb_mode(node->net, enable, period, false); + } + + return res; +} + +uint8_t node_mpb_mode_get(struct mesh_node *node, uint8_t *period) +{ + if (!node) + return MESH_MODE_DISABLED; + + *period = node->mpb_period; + + return node->mpb; +} + bool node_friend_mode_set(struct mesh_node *node, bool enable) { bool res; @@ -785,7 +914,7 @@ uint8_t node_friend_mode_get(struct mesh_node *node) return node->friend; } -static uint16_t generate_node_comp(struct mesh_node *node, uint8_t *buf, +static uint16_t node_generate_comp(struct mesh_node *node, uint8_t *buf, uint16_t sz) { uint16_t n, features, num_ele = 0; @@ -870,6 +999,8 @@ static void convert_node_to_storage(struct mesh_node *node, db_node->modes.relay.cnt = node->relay.cnt; db_node->modes.relay.interval = node->relay.interval; db_node->modes.beacon = node->beacon; + db_node->modes.mpb = node->mpb; + db_node->modes.mpb_period = node->mpb_period; db_node->ttl = node->ttl; db_node->seq_number = node->seq_number; @@ -895,6 +1026,21 @@ static void convert_node_to_storage(struct mesh_node *node, } +static void free_db_storage(struct mesh_config_node *db_node) +{ + const struct l_queue_entry *entry; + + /* Free temporarily allocated resources */ + entry = l_queue_get_entries(db_node->elements); + for (; entry; entry = entry->next) { + struct mesh_config_element *db_ele = entry->data; + + l_queue_destroy(db_ele->models, l_free); + } + + l_queue_destroy(db_node->elements, l_free); +} + static bool create_node_config(struct mesh_node *node, const uint8_t uuid[16]) { struct mesh_config_node db_node; @@ -922,7 +1068,22 @@ static bool create_node_config(struct mesh_node *node, const uint8_t uuid[16]) return node->cfg != NULL; } -static bool set_node_comp(struct mesh_node *node, uint8_t page_num, +static void node_del_comp(struct mesh_node *node, uint8_t page_num) +{ + struct mesh_config_comp_page *page; + + if (!node) + return; + + page = l_queue_remove_if(node->pages, match_page, + L_UINT_TO_PTR(page_num)); + + l_free(page); + + mesh_config_comp_page_del(node->cfg, page_num); +} + +static bool node_set_comp(struct mesh_node *node, uint8_t page_num, const uint8_t *data, uint16_t len) { struct mesh_config_comp_page *page; @@ -944,16 +1105,6 @@ static bool set_node_comp(struct mesh_node *node, uint8_t page_num, return mesh_config_comp_page_add(node->cfg, page_num, page->data, len); } -static bool create_node_comp(struct mesh_node *node) -{ - uint16_t len; - uint8_t comp[MAX_MSG_LEN - 2]; - - len = generate_node_comp(node, comp, sizeof(comp)); - - return set_node_comp(node, 0, comp, len); -} - const uint8_t *node_get_comp(struct mesh_node *node, uint8_t page_num, uint16_t *len) { @@ -975,6 +1126,7 @@ const uint8_t *node_get_comp(struct mesh_node *node, uint8_t page_num, bool node_replace_comp(struct mesh_node *node, uint8_t retire, uint8_t with) { struct mesh_config_comp_page *old_page, *keep; + bool status; if (!node) return false; @@ -989,9 +1141,13 @@ bool node_replace_comp(struct mesh_node *node, uint8_t retire, uint8_t with) l_free(old_page); keep->page_num = retire; - mesh_config_comp_page_mv(node->cfg, with, retire); + status = mesh_config_comp_page_add(node->cfg, keep->page_num, + keep->data, keep->len); - return true; + if (with != retire) + mesh_config_comp_page_del(node->cfg, with); + + return status; } static void attach_io(void *a, void *b) @@ -1067,9 +1223,16 @@ static bool get_sig_models_from_properties(struct mesh_node *node, while (l_dbus_message_iter_next_entry(&mods, &m_id, &var)) { uint32_t id = SET_ID(SIG_VENDOR, m_id); - /* Allow Config Server Model only on the primary element */ - if (ele->idx != PRIMARY_ELE_IDX && id == CONFIG_SRV_MODEL) - return false; + /* + * Allow Config Server & Private Beacon Models only on + * the primary element + */ + if (ele->idx != PRIMARY_ELE_IDX) { + if (id == CONFIG_SRV_MODEL) + return false; + if (id == PRV_BEACON_SRV_MODEL) + return false; + } if (!mesh_model_add(node, ele->models, id, &var)) return false; @@ -1170,8 +1333,14 @@ static bool get_element_properties(struct mesh_node *node, const char *path, * daemon. If the model is present in the application properties, * the operation below will be a "no-op". */ - if (ele->idx == PRIMARY_ELE_IDX) + if (ele->idx == PRIMARY_ELE_IDX) { mesh_model_add(node, ele->models, CONFIG_SRV_MODEL, NULL); + mesh_model_add(node, ele->models, PRV_BEACON_SRV_MODEL, NULL); + mesh_model_add(node, ele->models, REM_PROV_SRV_MODEL, NULL); + if (node->provisioner) + mesh_model_add(node, ele->models, REM_PROV_CLI_MODEL, + NULL); + } return true; fail: @@ -1232,6 +1401,15 @@ static bool get_app_properties(struct mesh_node *node, const char *path, return true; } +static void save_pages(void *data, void *user_data) +{ + struct mesh_config_comp_page *page = data; + struct mesh_node *node = user_data; + + mesh_config_comp_page_add(node->cfg, page->page_num, page->data, + page->len); +} + static bool add_local_node(struct mesh_node *node, uint16_t unicast, bool kr, bool ivu, uint32_t iv_idx, uint8_t dev_key[16], uint16_t net_key_idx, uint8_t net_key[16]) @@ -1275,10 +1453,17 @@ static bool add_local_node(struct mesh_node *node, uint16_t unicast, bool kr, return false; } - update_net_settings(node); + l_queue_foreach(node->pages, save_pages, node); - /* Initialize configuration server model */ + init_net_settings(node); + + /* Initialize internal server models */ cfgmod_server_init(node, PRIMARY_ELE_IDX); + remote_prov_server_init(node, PRIMARY_ELE_IDX); + remote_prov_client_init(node, PRIMARY_ELE_IDX); + + /* Initialize Private Beacon server model */ + prv_beacon_server_init(node, PRIMARY_ELE_IDX); node->busy = true; @@ -1326,39 +1511,59 @@ static void update_model_options(struct mesh_node *node, static bool check_req_node(struct managed_obj_request *req) { + struct mesh_node *node; const int offset = 8; uint16_t node_len, len; uint8_t comp[MAX_MSG_LEN - 2]; const uint8_t *node_comp; - len = generate_node_comp(req->node, comp, sizeof(comp)); + if (req->type != REQUEST_TYPE_ATTACH) { + node = req->node; - if (len < MIN_COMP_SIZE) - return false; + if (!create_node_config(node, node->uuid)) + return false; + } else + node = req->attach; - node_comp = node_get_comp(req->attach, 0, &node_len); + node_comp = node_get_comp(node, 0, &node_len); + len = node_generate_comp(req->node, comp, sizeof(comp)); - /* If no page 0 exists, create it and accept */ - if (!node_len || !node_comp) - return set_node_comp(req->attach, 0, comp, len); + /* If no page 0 exists, then current composition as valid */ + if (req->type != REQUEST_TYPE_ATTACH || !node_len) + goto page_zero_valid; - /* Test Element/Model part of composition and reject if changed */ + /* + * If composition has materially changed, save new composition + * in page 128 until next NPPI procedure. But we do allow + * for CID, PID, VID and/or CRPL to freely change without + * requiring a NPPI procedure. + */ if (node_len != len || memcmp(&node_comp[offset], &comp[offset], node_len - offset)) - return false; + return node_set_comp(node, 128, comp, len); - /* If comp has changed, but not Element/Models, resave and accept */ - else if (memcmp(node_comp, comp, node_len)) - return set_node_comp(req->attach, 0, comp, len); +page_zero_valid: + /* If page 0 represents current App, ensure page 128 doesn't exist */ + node_del_comp(node, 128); - /* Nothing has changed */ - return true; + if (len == node_len && !memcmp(node_comp, comp, len)) + return true; + + return node_set_comp(node, 0, comp, len); +} + +static bool is_zero(const void *a, const void *b) +{ + const struct node_element *element = a; + + return !element->idx; } static bool attach_req_node(struct mesh_node *attach, struct mesh_node *node) { const struct l_queue_entry *attach_entry; const struct l_queue_entry *node_entry; + bool comp_changed = false; attach->obj_path = node->obj_path; node->obj_path = NULL; @@ -1368,6 +1573,34 @@ static bool attach_req_node(struct mesh_node *attach, struct mesh_node *node) return false; } + if (attach->num_ele != node->num_ele) { + struct mesh_config_node db_node; + struct node_element *old_ele, *new_ele; + + convert_node_to_storage(node, &db_node); + + /* + * If composition has materially changed, we need to discard + * everything we knew about elements in the old application, + * and start from what they are telling us now. + */ + old_ele = l_queue_remove_if(attach->elements, is_zero, NULL); + new_ele = l_queue_remove_if(node->elements, is_zero, NULL); + element_free(new_ele); + + l_queue_destroy(attach->elements, element_free); + attach->elements = node->elements; + attach->num_ele = node->num_ele; + + /* Restore primary elements */ + l_queue_push_head(attach->elements, old_ele); + + comp_changed = true; + + mesh_config_reset(attach->cfg, &db_node); + free_db_storage(&db_node); + } + attach_entry = l_queue_get_entries(attach->elements); node_entry = l_queue_get_entries(node->elements); @@ -1384,6 +1617,10 @@ static bool attach_req_node(struct mesh_node *attach, struct mesh_node *node) attach_entry = attach_entry->next; node_entry = node_entry->next; + + /* Only need the Primary element during Composition change */ + if (comp_changed) + break; } mesh_agent_remove(attach->agent); @@ -1399,8 +1636,12 @@ static bool attach_req_node(struct mesh_node *attach, struct mesh_node *node) node->owner = NULL; update_composition(node, attach); + update_model_options(node, attach); + if (comp_changed) + node->elements = NULL; + node_remove(node); return true; @@ -1499,16 +1740,7 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data) node->num_ele = num_ele; - if (req->type != REQUEST_TYPE_ATTACH) { - /* Generate node configuration for a brand new node */ - if (!create_node_config(node, node->uuid)) - goto fail; - - /* Create node composition */ - if (!create_node_comp(node)) - goto fail; - } else if (!check_req_node(req)) - /* Check the integrity of the node composition */ + if (!check_req_node(req)) goto fail; switch (req->type) { diff --git a/mesh/node.h b/mesh/node.h index 2e3d89812f91a1724044e54d93245888b1e6e9db..4f31c5056dfd849db2d291e14f843928d17e68fe 100644 --- a/mesh/node.h +++ b/mesh/node.h @@ -38,6 +38,8 @@ uint16_t node_get_primary_net_idx(struct mesh_node *node); void node_set_token(struct mesh_node *node, uint8_t token[8]); const uint8_t *node_get_token(struct mesh_node *node); const uint8_t *node_get_device_key(struct mesh_node *node); +bool node_get_device_key_candidate(struct mesh_node *node, uint8_t *key); +void node_finalize_candidate(struct mesh_node *node); void node_set_num_elements(struct mesh_node *node, uint8_t num_ele); uint8_t node_get_num_elements(struct mesh_node *node); uint8_t node_default_ttl_get(struct mesh_node *node); @@ -61,6 +63,8 @@ uint8_t node_relay_mode_get(struct mesh_node *node, uint8_t *cnt, bool node_proxy_mode_set(struct mesh_node *node, bool enable); uint8_t node_proxy_mode_get(struct mesh_node *node); bool node_beacon_mode_set(struct mesh_node *node, bool enable); +bool node_mpb_mode_set(struct mesh_node *node, bool enable, uint8_t period); +uint8_t node_mpb_mode_get(struct mesh_node *node, uint8_t *period); uint8_t node_beacon_mode_get(struct mesh_node *node); bool node_friend_mode_set(struct mesh_node *node, bool enable); uint8_t node_friend_mode_get(struct mesh_node *node); @@ -89,3 +93,4 @@ const char *node_get_storage_dir(struct mesh_node *node); bool node_load_from_storage(const char *storage_dir); void node_finalize_new_node(struct mesh_node *node, struct mesh_io *io); void node_property_changed(struct mesh_node *node, const char *property); +bool node_refresh(struct mesh_node *node, bool hard, void *prov_info); diff --git a/mesh/pb-adv.c b/mesh/pb-adv.c index 180b162580f370e01fe20ebf6a9d4ef4ba3d2028..7a1dd87dc21066e4b9e7bad02cfe1989902ac7ff 100644 --- a/mesh/pb-adv.c +++ b/mesh/pb-adv.c @@ -166,7 +166,7 @@ static void send_adv_segs(struct pb_adv_session *session, const uint8_t *data, consumed = init_size; for (i = 1; i <= max_seg; i++) { - uint8_t seg_size; /* Amount of payload data being sent */ + size_t seg_size; /* Amount of payload data being sent */ if (size - consumed > PB_ADV_MTU - 1) seg_size = PB_ADV_MTU - 1; @@ -219,7 +219,7 @@ static void tx_timeout(struct l_timeout *timeout, void *user_data) cb(user_data, 1); } -static void pb_adv_tx(void *user_data, void *data, uint16_t len) +static void pb_adv_tx(void *user_data, const void *data, uint16_t len) { struct pb_adv_session *session = user_data; @@ -478,7 +478,7 @@ static void pb_adv_packet(void *user_data, const uint8_t *pkt, uint16_t len) bool pb_adv_reg(bool initiator, mesh_prov_open_func_t open_cb, mesh_prov_close_func_t close_cb, mesh_prov_receive_func_t rx_cb, mesh_prov_ack_func_t ack_cb, - uint8_t uuid[16], void *user_data) + const uint8_t *uuid, void *user_data) { struct pb_adv_session *session, *old_session; diff --git a/mesh/pb-adv.h b/mesh/pb-adv.h index 5b1e03dae8838082062cf928c6be7fe363336b33..e33ba8e35e948a9a2723c0544cadcfb428a5cc40 100644 --- a/mesh/pb-adv.h +++ b/mesh/pb-adv.h @@ -11,5 +11,5 @@ bool pb_adv_reg(bool initiator, mesh_prov_open_func_t open_cb, mesh_prov_close_func_t close_cb, mesh_prov_receive_func_t rx_cb, mesh_prov_ack_func_t ack_cb, - uint8_t uuid[16], void *user_data); + const uint8_t *uuid, void *user_data); void pb_adv_unreg(void *user_data); diff --git a/mesh/prov-acceptor.c b/mesh/prov-acceptor.c index bf8c573da37a184ad24496ed8b467530acf243ff..fd9d4cd5d209ed3bc0f90a3f5bf5ba1680b4e765 100644 --- a/mesh/prov-acceptor.c +++ b/mesh/prov-acceptor.c @@ -22,6 +22,7 @@ #include "mesh/net.h" #include "mesh/prov.h" #include "mesh/provision.h" +#include "mesh/remprv.h" #include "mesh/pb-adv.h" #include "mesh/mesh.h" #include "mesh/agent.h" @@ -169,9 +170,6 @@ static void acp_prov_open(void *user_data, prov_trans_tx_t trans_tx, prov->transport != transport) return; - if (transport != PB_ADV) - return; - prov->trans_tx = trans_tx; prov->transport = transport; prov->trans_data = trans_data; @@ -425,9 +423,10 @@ static bool prov_start_check(struct prov_start *start, return true; } -static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len) +static void acp_prov_rx(void *user_data, const void *dptr, uint16_t len) { struct mesh_prov_acceptor *rx_prov = user_data; + const uint8_t *data = dptr; struct mesh_prov_node_info *info; struct prov_fail_msg fail; uint8_t type = *data++; @@ -654,14 +653,19 @@ static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len) info->flags = prov->rand_auth_workspace[18]; info->iv_index = l_get_be32(prov->rand_auth_workspace + 19); info->unicast = l_get_be16(prov->rand_auth_workspace + 23); + info->num_ele = prov->conf_inputs.caps.num_ele; + + /* Send prov complete */ + prov->rand_auth_workspace[0] = PROV_COMPLETE; + prov->trans_tx(prov->trans_data, + prov->rand_auth_workspace, 1); result = prov->cmplt(prov->caller_data, PROV_ERR_SUCCESS, info); prov->cmplt = NULL; l_free(info); if (result) { - prov->rand_auth_workspace[0] = PROV_COMPLETE; - prov_send(prov, prov->rand_auth_workspace, 1); + l_debug("PROV_COMPLETE"); goto cleanup; } else { fail.reason = PROV_ERR_UNEXPECTED_ERR; @@ -721,7 +725,7 @@ static void acp_prov_ack(void *user_data, uint8_t msg_num) /* This starts unprovisioned device beacon */ -bool acceptor_start(uint8_t num_ele, uint8_t uuid[16], +bool acceptor_start(uint8_t num_ele, uint8_t *uuid, uint16_t algorithms, uint32_t timeout, struct mesh_agent *agent, mesh_prov_acceptor_complete_func_t complete_cb, @@ -733,8 +737,10 @@ bool acceptor_start(uint8_t num_ele, uint8_t uuid[16], uint8_t len = sizeof(beacon) - sizeof(uint32_t); bool result; - /* Invoked from Join() method in mesh-api.txt, to join a - * remote mesh network. + /* + * Invoked from Join() method in mesh-api.txt, to join a + * remote mesh network. May also be invoked with a NULL + * uuid to perform a Device Key Refresh procedure. */ if (prov) @@ -752,37 +758,50 @@ bool acceptor_start(uint8_t num_ele, uint8_t uuid[16], caps = mesh_agent_get_caps(agent); - /* TODO: Should we sanity check values here or elsewhere? */ prov->conf_inputs.caps.num_ele = num_ele; - prov->conf_inputs.caps.pub_type = caps->pub_type; - prov->conf_inputs.caps.static_type = caps->static_type; - prov->conf_inputs.caps.output_size = caps->output_size; - prov->conf_inputs.caps.input_size = caps->input_size; - - /* Store UINT16 values in Over-the-Air order, in packed structure - * for crypto inputs - */ l_put_be16(algorithms, &prov->conf_inputs.caps.algorithms); - l_put_be16(caps->output_action, &prov->conf_inputs.caps.output_action); - l_put_be16(caps->input_action, &prov->conf_inputs.caps.input_action); - - /* Compose Unprovisioned Beacon */ - memcpy(beacon + 2, uuid, 16); - l_put_be16(caps->oob_info, beacon + 18); - if (caps->oob_info & OOB_INFO_URI_HASH){ - l_put_be32(caps->uri_hash, beacon + 20); - len += sizeof(uint32_t); + + if (caps) { + /* TODO: Should we sanity check values here or elsewhere? */ + prov->conf_inputs.caps.pub_type = caps->pub_type; + prov->conf_inputs.caps.static_type = caps->static_type; + prov->conf_inputs.caps.output_size = caps->output_size; + prov->conf_inputs.caps.input_size = caps->input_size; + + /* Store UINT16 values in Over-the-Air order, in packed + * structure for crypto inputs + */ + l_put_be16(caps->output_action, + &prov->conf_inputs.caps.output_action); + l_put_be16(caps->input_action, + &prov->conf_inputs.caps.input_action); + + /* Populate Caps fields of beacon */ + l_put_be16(caps->oob_info, beacon + 18); + if (caps->oob_info & OOB_INFO_URI_HASH) { + l_put_be32(caps->uri_hash, beacon + 20); + len += sizeof(uint32_t); + } } - /* Infinitely Beacon until Canceled, or Provisioning Starts */ - result = mesh_send_pkt(0, 500, beacon, len); + if (uuid) { + /* Compose Unprovisioned Beacon */ + memcpy(beacon + 2, uuid, 16); + + /* Infinitely Beacon until Canceled, or Provisioning Starts */ + result = mesh_send_pkt(0, 500, beacon, len); - if (!result) - goto error_fail; + if (!result) + goto error_fail; - /* Always register for PB-ADV */ - result = pb_adv_reg(false, acp_prov_open, acp_prov_close, acp_prov_rx, - acp_prov_ack, uuid, prov); + /* Always register for PB-ADV */ + result = pb_adv_reg(false, acp_prov_open, acp_prov_close, + acp_prov_rx, acp_prov_ack, uuid, prov); + } else { + /* Run Device Key Refresh Procedure */ + result = register_nppi_acceptor(acp_prov_open, acp_prov_close, + acp_prov_rx, acp_prov_ack, prov); + } if (result) return true; diff --git a/mesh/prov-initiator.c b/mesh/prov-initiator.c index c6257752397886000cc4c47d31ab03534bd84d21..e353d23865ef5a422d2bf6e569d01b5cedb73009 100644 --- a/mesh/prov-initiator.c +++ b/mesh/prov-initiator.c @@ -21,10 +21,12 @@ #include "mesh/crypto.h" #include "mesh/net.h" #include "mesh/node.h" +#include "mesh/model.h" #include "mesh/keyring.h" #include "mesh/prov.h" #include "mesh/provision.h" #include "mesh/pb-adv.h" +#include "mesh/remprv.h" #include "mesh/mesh.h" #include "mesh/agent.h" #include "mesh/error.h" @@ -82,12 +84,16 @@ struct mesh_prov_initiator { struct l_timeout *timeout; uint32_t to_secs; enum int_state state; - enum trans_type transport; uint16_t net_idx; + uint16_t svr_idx; uint16_t unicast; + uint16_t server; + uint8_t transport; uint8_t material; uint8_t expected; int8_t previous; + uint8_t out_num; + uint8_t rpr_state; struct conf_input conf_inputs; uint8_t calc_key[16]; uint8_t salt[16]; @@ -100,14 +106,23 @@ struct mesh_prov_initiator { uint8_t uuid[16]; }; +struct scan_req { + mesh_prov_initiator_scan_result_t scan_result; + struct mesh_node *node; + int count; +}; + static struct mesh_prov_initiator *prov = NULL; +static struct l_queue *scans; static void initiator_free(void) { - if (prov) + if (prov) { l_timeout_remove(prov->timeout); - mesh_send_cancel(&pkt_filter, sizeof(pkt_filter)); + if (!prov->server) + mesh_send_cancel(&pkt_filter, sizeof(pkt_filter)); + } pb_adv_unreg(prov); @@ -119,6 +134,15 @@ static void int_prov_close(void *user_data, uint8_t reason) { struct mesh_prov_initiator *prov = user_data; struct mesh_prov_node_info info; + uint8_t msg[4]; + int n; + + if (prov->server) { + n = mesh_model_opcode_set(OP_REM_PROV_LINK_CLOSE, msg); + msg[n++] = reason == PROV_ERR_SUCCESS ? 0x00 : 0x02; + mesh_model_send(prov->node, 0, prov->server, APP_IDX_DEV_REMOTE, + prov->svr_idx, DEFAULT_TTL, true, n, msg); + } if (reason != PROV_ERR_SUCCESS) { prov->complete_cb(prov->caller_data, reason, NULL); @@ -626,9 +650,10 @@ static void int_prov_start_auth(const struct mesh_agent_prov_caps *prov_caps, } } -static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len) +static void int_prov_rx(void *user_data, const void *dptr, uint16_t len) { struct mesh_prov_initiator *rx_prov = user_data; + const uint8_t *data = dptr; uint8_t *out; uint8_t type = *data++; uint8_t fail_code[2]; @@ -648,10 +673,15 @@ static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len) goto failure; } - if (type >= L_ARRAY_SIZE(expected_pdu_size) || - len != expected_pdu_size[type]) { + if (type >= L_ARRAY_SIZE(expected_pdu_size)) { + l_error("Invalid PDU type %2.2x", type); + fail_code[1] = PROV_ERR_INVALID_FORMAT; + goto failure; + } + + if (len != expected_pdu_size[type]) { l_error("Expected PDU size %d, Got %d (type: %2.2x)", - len, expected_pdu_size[type], type); + expected_pdu_size[type], len, type); fail_code[1] = PROV_ERR_INVALID_FORMAT; goto failure; } @@ -773,7 +803,12 @@ static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len) goto failure; } - if (!prov->data_req_cb(prov->caller_data, + if (prov->transport == PB_NPPI_00 || + prov->transport == PB_NPPI_02) { + /* No App data needed */ + initiator_prov_data(prov->svr_idx, prov->server, + prov->caller_data); + } else if (!prov->data_req_cb(prov->caller_data, prov->conf_inputs.caps.num_ele)) { l_error("Provisioning Failed-Data Get"); fail_code[1] = PROV_ERR_CANT_ASSIGN_ADDR; @@ -851,6 +886,8 @@ static void int_prov_ack(void *user_data, uint8_t msg_num) static void initiator_open_cb(void *user_data, int err) { + uint8_t msg[20]; + int n; bool result; if (!prov) @@ -859,18 +896,30 @@ static void initiator_open_cb(void *user_data, int err) if (err != MESH_ERROR_NONE) goto fail; - /* Always register for PB-ADV */ - result = pb_adv_reg(true, int_prov_open, int_prov_close, int_prov_rx, - int_prov_ack, prov->uuid, prov); + if (prov->server) { + n = mesh_model_opcode_set(OP_REM_PROV_LINK_OPEN, msg); + + if (prov->transport <= PB_NPPI_02) { + msg[n++] = prov->transport; + } else { + memcpy(msg + n, prov->uuid, 16); + n += 16; + } + + result = mesh_model_send(prov->node, 0, prov->server, + APP_IDX_DEV_REMOTE, prov->svr_idx, + DEFAULT_TTL, true, n, msg); + } else { + /* Always register for PB-ADV */ + result = pb_adv_reg(true, int_prov_open, int_prov_close, + int_prov_rx, int_prov_ack, prov->uuid, prov); + } if (!result) { err = MESH_ERROR_FAILED; goto fail; } - if (!prov) - return; - prov->start_cb(prov->caller_data, MESH_ERROR_NONE); return; fail: @@ -878,10 +927,20 @@ fail: initiator_free(); } -bool initiator_start(enum trans_type transport, - uint8_t uuid[16], - uint16_t max_ele, - uint32_t timeout, /* in seconds from mesh.conf */ +static void initiate_to(struct l_timeout *timeout, void *user_data) +{ + struct mesh_prov_initiator *rx_prov = user_data; + + if (rx_prov != prov) { + l_timeout_remove(timeout); + return; + } + + int_prov_close(user_data, PROV_ERR_TIMEOUT); +} + +bool initiator_start(uint8_t transport, uint16_t server, uint16_t svr_idx, + uint8_t uuid[16], uint16_t max_ele, uint32_t timeout, struct mesh_agent *agent, mesh_prov_initiator_start_func_t start_cb, mesh_prov_initiator_data_req_func_t data_req_cb, @@ -904,6 +963,10 @@ bool initiator_start(enum trans_type transport, prov->data_req_cb = data_req_cb; prov->caller_data = caller_data; prov->previous = -1; + prov->server = server; + prov->svr_idx = svr_idx; + prov->transport = transport; + prov->timeout = l_timeout_create(timeout, initiate_to, prov, NULL); memcpy(prov->uuid, uuid, 16); mesh_agent_refresh(prov->agent, initiator_open_cb, prov); @@ -915,3 +978,182 @@ void initiator_cancel(void *user_data) { initiator_free(); } + +static void rpr_tx(void *user_data, const void *data, uint16_t len) +{ + struct mesh_prov_initiator *prov = user_data; + uint8_t msg[72]; + int n; + + n = mesh_model_opcode_set(OP_REM_PROV_PDU_SEND, msg); + msg[n++] = ++prov->out_num; + memcpy(msg + n, data, len); + l_debug("Send OB %2.2x, with packet type %d", msg[n], prov->out_num); + n += len; + + prov->rpr_state = PB_REMOTE_STATE_OB_PKT_TX; + mesh_model_send(prov->node, 0, prov->server, APP_IDX_DEV_REMOTE, + prov->svr_idx, DEFAULT_TTL, true, n, msg); +} + +static bool match_req_node(const void *a, const void *b) +{ + const struct scan_req *req = a; + const struct mesh_node *node = b; + + return req->node == node; +} + +static bool remprv_cli_pkt(uint16_t src, uint16_t unicast, uint16_t app_idx, + uint16_t net_idx, const uint8_t *data, + uint16_t size, const void *user_data) +{ + struct mesh_node *node = (struct mesh_node *) user_data; + const uint8_t *pkt = data; + struct scan_req *req; + uint32_t opcode; + uint16_t n; + + if (mesh_model_opcode_get(pkt, size, &opcode, &n)) { + size -= n; + pkt += n; + } else + return false; + + if (opcode < OP_REM_PROV_SCAN_CAP_GET || + opcode > OP_REM_PROV_PDU_REPORT) + return false; + + if (app_idx != APP_IDX_DEV_REMOTE && app_idx != APP_IDX_DEV_LOCAL) + return true; + + /* Local Dev key only allowed for Loop-backs */ + if (app_idx == APP_IDX_DEV_LOCAL && unicast != src) + return true; + + if (prov && (prov->server != src || prov->node != node)) + return true; + + n = 0; + + switch (opcode) { + default: + return false; + + /* Provisioning Opcodes */ + case OP_REM_PROV_LINK_STATUS: + if (size != 2 || !prov) + break; + + if (pkt[0] == PB_REM_ERR_SUCCESS) + prov->rpr_state = pkt[1]; + + break; + + case OP_REM_PROV_LINK_REPORT: + if (size != 2 || !prov) + return true; + + if (pkt[0] != PB_REM_ERR_SUCCESS) { + if (pkt[0] == PB_REM_ERR_CLOSED_BY_DEVICE || + pkt[0] == PB_REM_ERR_CLOSED_BY_SERVER) + int_prov_close(prov, pkt[1]); + + break; + } + + + if (prov->rpr_state == PB_REMOTE_STATE_LINK_OPENING) + int_prov_open(prov, rpr_tx, prov, prov->transport); + else if (prov->rpr_state == PB_REMOTE_STATE_LINK_CLOSING) { + prov->rpr_state = PB_REMOTE_STATE_IDLE; + int_prov_close(prov, pkt[1]); + break; + } + + prov->rpr_state = pkt[1]; + + break; + + case OP_REM_PROV_PDU_REPORT: + int_prov_rx(prov, pkt + 1, size - 1); + break; + + case OP_REM_PROV_PDU_OB_REPORT: + if (size != 1 || !prov) + break; + + l_debug("Got Ack for OB %d", pkt[0]); + if (prov->rpr_state == PB_REMOTE_STATE_OB_PKT_TX && + pkt[0] == prov->out_num) + int_prov_ack(prov, pkt[0]); + + break; + + /* Scan Opcodes */ + case OP_REM_PROV_SCAN_CAP_STATUS: + case OP_REM_PROV_SCAN_STATUS: + break; + + case OP_REM_PROV_SCAN_REPORT: + case OP_REM_PROV_EXT_SCAN_REPORT: + req = l_queue_find(scans, match_req_node, node); + if (req) { + req->scan_result(node, src, + opcode == OP_REM_PROV_EXT_SCAN_REPORT, + pkt, size); + } + } + + return true; +} + +void initiator_scan_reg(mesh_prov_initiator_scan_result_t scan_result, + void *user_data) +{ + struct scan_req *req; + + if (!scans) + scans = l_queue_new(); + + req = l_queue_find(scans, match_req_node, user_data); + if (!req) { + req = l_new(struct scan_req, 1); + l_queue_push_head(scans, req); + } + + req->scan_result = scan_result; + req->node = user_data; + req->count++; +} + +void initiator_scan_unreg(void *user_data) +{ + struct scan_req *req; + + req = l_queue_find(scans, match_req_node, user_data); + if (req) { + req->count--; + if (!req->count) { + l_queue_remove(scans, req); + l_free(req); + } + } +} + +static void remprv_cli_unregister(void *user_data) +{ +} + +static const struct mesh_model_ops ops = { + .unregister = remprv_cli_unregister, + .recv = remprv_cli_pkt, + .bind = NULL, + .sub = NULL, + .pub = NULL +}; + +void remote_prov_client_init(struct mesh_node *node, uint8_t ele_idx) +{ + mesh_model_register(node, ele_idx, REM_PROV_CLI_MODEL, &ops, node); +} diff --git a/mesh/prov.h b/mesh/prov.h index 99e864c503a9f62c74502812a086da4e08863d48..e86668fe40b8db7a9fdcf2a73884a339eebabb2c 100644 --- a/mesh/prov.h +++ b/mesh/prov.h @@ -39,14 +39,14 @@ enum mesh_prov_mode { struct mesh_prov; -typedef void (*prov_trans_tx_t)(void *trans_data, void *data, uint16_t len); +typedef void (*prov_trans_tx_t)(void *tx_data, const void *data, uint16_t len); typedef void (*mesh_prov_open_func_t)(void *user_data, prov_trans_tx_t trans_tx, void *trans_data, uint8_t trans_type); typedef void (*mesh_prov_close_func_t)(void *user_data, uint8_t reason); typedef void (*mesh_prov_send_func_t)(bool success, struct mesh_prov *prov); typedef void (*mesh_prov_ack_func_t)(void *user_data, uint8_t msg_num); -typedef void (*mesh_prov_receive_func_t)(void *user_data, const uint8_t *data, +typedef void (*mesh_prov_receive_func_t)(void *user_data, const void *data, uint16_t size); diff --git a/mesh/provision.h b/mesh/provision.h index 1634c4d4079335388024742a7d5ef14ef11b69fe..cfeb6debab5365d31a47b9e8da81ba94d1d90453 100644 --- a/mesh/provision.h +++ b/mesh/provision.h @@ -70,10 +70,11 @@ struct mesh_agent; #define OOB_INFO_URI_HASH 0x0002 /* PB_REMOTE not supported from unprovisioned state */ -enum trans_type { - PB_ADV = 0, - PB_GATT, -}; +#define PB_NPPI_00 0x00 +#define PB_NPPI_01 0x01 +#define PB_NPPI_02 0x02 +#define PB_ADV 0x03 /* Internal only, and may be reassigned */ +#define PB_GATT 0x04 /* Internal only, and may be reassigned */ #define PROV_FLAG_KR 0x01 #define PROV_FLAG_IVU 0x02 @@ -101,15 +102,21 @@ typedef bool (*mesh_prov_initiator_complete_func_t)(void *user_data, uint8_t status, struct mesh_prov_node_info *info); +typedef void (*mesh_prov_initiator_scan_result_t)(void *user_data, + uint16_t server, bool extended, + const uint8_t *data, uint16_t len); + /* This starts unprovisioned device beacon */ -bool acceptor_start(uint8_t num_ele, uint8_t uuid[16], +bool acceptor_start(uint8_t num_ele, uint8_t *uuid, uint16_t algorithms, uint32_t timeout, struct mesh_agent *agent, mesh_prov_acceptor_complete_func_t complete_cb, void *caller_data); void acceptor_cancel(void *user_data); -bool initiator_start(enum trans_type transport, +bool initiator_start(uint8_t transport, + uint16_t server, + uint16_t svr_idx, uint8_t uuid[16], uint16_t max_ele, uint32_t timeout, /* in seconds from mesh.conf */ @@ -120,3 +127,7 @@ bool initiator_start(enum trans_type transport, void *node, void *caller_data); void initiator_prov_data(uint16_t net_idx, uint16_t primary, void *caller_data); void initiator_cancel(void *caller_data); + +void initiator_scan_reg(mesh_prov_initiator_scan_result_t scan_result, + void *user_data); +void initiator_scan_unreg(void *caller_data); diff --git a/mesh/prv-beacon.h b/mesh/prv-beacon.h new file mode 100644 index 0000000000000000000000000000000000000000..1e69e7fdadf62960b5cddce90ccf933b0b0dbfb4 --- /dev/null +++ b/mesh/prv-beacon.h @@ -0,0 +1,36 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ + +struct mesh_node; + +#define PRV_BEACON_SRV_MODEL SET_ID(SIG_VENDOR, 0x0008) +#define PRV_BEACON_CLI_MODEL SET_ID(SIG_VENDOR, 0x0009) + +/* Private Beacon opcodes */ +#define OP_PRIVATE_BEACON_GET 0x8060 +#define OP_PRIVATE_BEACON_SET 0x8061 +#define OP_PRIVATE_BEACON_STATUS 0x8062 +#define OP_PRIVATE_GATT_PROXY_GET 0x8063 +#define OP_PRIVATE_GATT_PROXY_SET 0x8064 +#define OP_PRIVATE_GATT_PROXY_STATUS 0x8065 +#define OP_PRIVATE_NODE_ID_GET 0x8066 +#define OP_PRIVATE_NODE_ID_SET 0x8067 +#define OP_PRIVATE_NODE_ID_STATUS 0x8068 + +void prv_beacon_server_init(struct mesh_node *node, uint8_t ele_idx); diff --git a/mesh/prvbeac-server.c b/mesh/prvbeac-server.c new file mode 100644 index 0000000000000000000000000000000000000000..dd0e4cbf449e3648074ede8a985f8b0940535579 --- /dev/null +++ b/mesh/prvbeac-server.c @@ -0,0 +1,128 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/time.h> +#include <ell/ell.h> + +#include "mesh/mesh-defs.h" +#include "mesh/node.h" +#include "mesh/net.h" +#include "mesh/appkey.h" +#include "mesh/model.h" +#include "mesh/mesh-config.h" +#include "mesh/prv-beacon.h" + +#define NOT_SUPPORTED 0x02 + +static bool prvbec_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx, + uint16_t net_idx, const uint8_t *data, + uint16_t size, const void *user_data) +{ + struct mesh_node *node = (struct mesh_node *) user_data; + const uint8_t *pkt = data; + uint32_t opcode; + uint8_t msg[5]; + uint16_t n; + uint8_t period; + + if (app_idx != APP_IDX_DEV_LOCAL) + return false; + + if (mesh_model_opcode_get(pkt, size, &opcode, &n)) { + size -= n; + pkt += n; + } else + return false; + + l_debug("PRV-BEAC-SRV-opcode 0x%x size %u idx %3.3x", opcode, size, + net_idx); + + n = 0; + + switch (opcode) { + default: + return false; + + case OP_PRIVATE_BEACON_SET: + if (size == 1) + node_mpb_mode_get(node, &period); + else if (size == 2) + period = pkt[1]; + else + return true; + + if (pkt[0] > 1) + return true; + + node_mpb_mode_set(node, !!pkt[0], period); + + /* fall through */ + + case OP_PRIVATE_BEACON_GET: + n = mesh_model_opcode_set(OP_PRIVATE_BEACON_STATUS, msg); + + msg[n++] = node_mpb_mode_get(node, &period); + msg[n++] = period; + + l_debug("Get/Set Private Beacon (%d)", msg[n-2]); + break; + + case OP_PRIVATE_GATT_PROXY_SET: + /* fall through */ + case OP_PRIVATE_GATT_PROXY_GET: + n = mesh_model_opcode_set(OP_PRIVATE_GATT_PROXY_STATUS, msg); + msg[n++] = NOT_SUPPORTED; + break; + + case OP_PRIVATE_NODE_ID_SET: + /* fall through */ + case OP_PRIVATE_NODE_ID_GET: + n = mesh_model_opcode_set(OP_PRIVATE_NODE_ID_STATUS, msg); + msg[n++] = NOT_SUPPORTED; + break; + } + + if (n) + mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, + DEFAULT_TTL, false, n, msg); + + return true; +} + +static void prvbec_srv_unregister(void *user_data) +{ +} + +static const struct mesh_model_ops ops = { + .unregister = prvbec_srv_unregister, + .recv = prvbec_srv_pkt, + .bind = NULL, + .sub = NULL, + .pub = NULL +}; + +void prv_beacon_server_init(struct mesh_node *node, uint8_t ele_idx) +{ + l_debug("%2.2x", ele_idx); + mesh_model_register(node, ele_idx, PRV_BEACON_SRV_MODEL, &ops, node); +} diff --git a/mesh/remprv-server.c b/mesh/remprv-server.c new file mode 100644 index 0000000000000000000000000000000000000000..927dbab0e361d11fd4ccbb6a83670943406c52dc --- /dev/null +++ b/mesh/remprv-server.c @@ -0,0 +1,919 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/time.h> +#include <ell/ell.h> + +#include "src/shared/ad.h" + +#include "mesh/mesh-defs.h" +#include "mesh/mesh-io.h" +#include "mesh/util.h" +#include "mesh/node.h" +#include "mesh/net.h" +#include "mesh/appkey.h" +#include "mesh/model.h" +#include "mesh/prov.h" +#include "mesh/provision.h" +#include "mesh/pb-adv.h" +#include "mesh/remprv.h" + +#define EXT_LIST_SIZE 60 + +#define RPR_DEV_KEY 0x00 +#define RPR_ADDR 0x01 +#define RPR_COMP 0x02 +#define RPR_ADV 0xFF /* Internal use only*/ + +struct rem_scan_data { + struct mesh_node *node; + struct l_timeout *timeout; + uint8_t *list; + uint16_t client; + uint16_t oob_info; + uint16_t net_idx; + uint8_t state; + uint8_t scanned_limit; + uint8_t addr[6]; + uint8_t uuid[16]; + uint8_t to_secs; + uint8_t rxed_ads; + uint8_t ext_cnt; + bool fltr; + uint8_t ext[0]; +}; + +static struct rem_scan_data *rpb_scan; + +struct rem_prov_data { + struct mesh_node *node; + struct l_timeout *timeout; + void *trans_data; + uint16_t client; + uint16_t net_idx; + uint8_t svr_pdu_num; + uint8_t cli_pdu_num; + uint8_t state; + uint8_t nppi_proc; + union { + struct { + mesh_prov_open_func_t open_cb; + mesh_prov_close_func_t close_cb; + mesh_prov_receive_func_t rx_cb; + mesh_prov_ack_func_t ack_cb; + struct mesh_prov_node_info info; + } nppi; + struct { + uint8_t uuid[17]; + prov_trans_tx_t tx; + } adv; + } u; +}; + +static struct rem_prov_data *rpb_prov; + +static const uint8_t prvb[2] = {BT_AD_MESH_BEACON, 0x00}; +static const uint8_t pkt_filter = BT_AD_MESH_PROV; +static const char *name = "Test Name"; + +static const uint8_t zero[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +static void srv_open(void *user_data, prov_trans_tx_t adv_tx, + void *trans_data, uint8_t nppi_proc) +{ + struct rem_prov_data *prov = user_data; + uint8_t msg[5]; + int n; + + if (prov != rpb_prov || prov->state != PB_REMOTE_STATE_LINK_OPENING) + return; + + l_debug("Remote Link open confirmed"); + prov->u.adv.tx = adv_tx; + prov->trans_data = trans_data; + prov->state = PB_REMOTE_STATE_LINK_ACTIVE; + + n = mesh_model_opcode_set(OP_REM_PROV_LINK_REPORT, msg); + msg[n++] = PB_REM_ERR_SUCCESS; + msg[n++] = prov->state; + + mesh_model_send(prov->node, 0, prov->client, APP_IDX_DEV_LOCAL, + prov->net_idx, DEFAULT_TTL, true, n, msg); +} + +static void srv_rx(void *user_data, const void *dptr, uint16_t len) +{ + struct rem_prov_data *prov = user_data; + const uint8_t *data = dptr; + uint8_t msg[69]; + int n; + + if (prov != rpb_prov || prov->state < PB_REMOTE_STATE_LINK_ACTIVE || + len > 65) + return; + + l_debug("Remote PB IB-PDU"); + + prov->svr_pdu_num++; + n = mesh_model_opcode_set(OP_REM_PROV_PDU_REPORT, msg); + msg[n++] = prov->svr_pdu_num; + memcpy(msg + n, data, len); + n += len; + + mesh_model_send(prov->node, 0, prov->client, APP_IDX_DEV_LOCAL, + prov->net_idx, DEFAULT_TTL, true, n, msg); +} + +static void srv_ack(void *user_data, uint8_t msg_num) +{ + struct rem_prov_data *prov = user_data; + uint8_t msg[4]; + int n; + + if (prov != rpb_prov || prov->state != PB_REMOTE_STATE_OB_PKT_TX) + return; + + l_debug("Remote PB ACK"); + + prov->state = PB_REMOTE_STATE_LINK_ACTIVE; + n = mesh_model_opcode_set(OP_REM_PROV_PDU_OB_REPORT, msg); + msg[n++] = prov->cli_pdu_num; + + mesh_model_send(prov->node, 0, prov->client, APP_IDX_DEV_LOCAL, + prov->net_idx, DEFAULT_TTL, true, n, msg); +} + +static void srv_close(void *user_data, uint8_t reason) +{ + struct rem_prov_data *prov = user_data; + uint8_t msg[4]; + int n; + + if (prov != rpb_prov || prov->state < PB_REMOTE_STATE_LINK_ACTIVE) + return; + + l_debug("Remote PB Close"); + + prov->state = PB_REMOTE_STATE_LINK_CLOSING; + n = mesh_model_opcode_set(OP_REM_PROV_LINK_REPORT, msg); + msg[n++] = prov->state; + msg[n++] = reason; + + mesh_model_send(prov->node, 0, prov->client, APP_IDX_DEV_LOCAL, + prov->net_idx, DEFAULT_TTL, true, n, msg); +} + +static void send_prov_status(struct rem_prov_data *prov, uint8_t status) +{ + uint16_t n; + uint8_t msg[5]; + bool segmented = prov->state == PB_REMOTE_STATE_LINK_CLOSING ? + true : false; + + n = mesh_model_opcode_set(OP_REM_PROV_LINK_STATUS, msg); + msg[n++] = status; + msg[n++] = prov->state; + + l_info("RPB-Link Status(%d): dst %4.4x", prov->state, prov->client); + + mesh_model_send(prov->node, 0, prov->client, APP_IDX_DEV_LOCAL, + prov->net_idx, DEFAULT_TTL, segmented, n, msg); +} + +static void remprv_prov_cancel(struct l_timeout *timeout, + void *user_data) +{ + struct rem_prov_data *prov = user_data; + + if (prov != rpb_prov) + return; + + l_timeout_remove(prov->timeout); + l_free(prov); + rpb_prov = NULL; +} + +static void deregister_ext_ad_type(uint8_t ad_type) +{ + uint8_t short_ad; + + switch (ad_type) { + case BT_AD_MESH_BEACON: + case BT_AD_MESH_DATA: + case BT_AD_MESH_PROV: + case BT_AD_UUID16_SOME: + case BT_AD_UUID32_SOME: + case BT_AD_UUID128_SOME: + case BT_AD_NAME_SHORT: + return; + + case BT_AD_UUID16_ALL: + case BT_AD_UUID32_ALL: + case BT_AD_UUID128_ALL: + case BT_AD_NAME_COMPLETE: + /* Automatically get short versions */ + short_ad = ad_type - 1; + mesh_io_deregister_recv_cb(NULL, &short_ad, 1); + + /* fall through */ + default: + mesh_io_deregister_recv_cb(NULL, &ad_type, 1); + break; + } +} + +static void remprv_scan_cancel(struct l_timeout *timeout, + void *user_data) +{ + struct rem_scan_data *scan = user_data; + uint8_t msg[22 + EXT_LIST_SIZE]; + uint16_t i, n; + + if (!scan || scan != rpb_scan) + return; + + for (n = 0; n < scan->ext_cnt; n++) + deregister_ext_ad_type(scan->ext[n]); + + if (scan->timeout == timeout) { + /* Return Extended Results */ + if (scan->ext_cnt) { + /* Return Extended Result */ + n = mesh_model_opcode_set( + OP_REM_PROV_EXT_SCAN_REPORT, msg); + msg[n++] = PB_REM_ERR_SUCCESS; + memcpy(msg + n, scan->uuid, 16); + n += 16; + + if (scan->oob_info) { + l_put_le16(0, msg + n); + n += 2; + } + + i = 0; + while (scan->list[i]) { + msg[n++] = scan->list[i]; + memcpy(msg + n, &scan->list[i + 1], + scan->list[i]); + n += scan->list[i]; + i += scan->list[i] + 1; + } + } + } + + l_timeout_remove(scan->timeout); + l_free(scan->list); + l_free(scan); + rpb_scan = NULL; +} + +static void scan_pkt(void *user_data, struct mesh_io_recv_info *info, + const uint8_t *data, uint16_t len) +{ + struct rem_scan_data *scan = user_data; + uint8_t msg[22 + EXT_LIST_SIZE]; + uint8_t addr[6]; + uint16_t i, n; + int8_t rssi; + uint8_t filled = 0; + bool report = false; + + if (scan != rpb_scan) + return; + + if (info) { + rssi = info->rssi; + memcpy(addr, info->addr, 6); + } else { + rssi = 0; + memset(addr, 0, 6); + } + + if (scan->ext_cnt) + goto extended_scan; + + /* RX Unprovisioned Beacon */ + if (data[0] != BT_AD_MESH_BEACON || data[1] || + (len != 18 && len != 20 && len != 24)) + return; + + data += 2; + len -= 2; + + for (n = 0; !report && n < scan->scanned_limit; n++) { + if (!memcmp(&scan->list[n * 17 + 1], data, 16)) { + + /* Repeat UUID, check RSSI */ + if ((int8_t) scan->list[n * 17] < rssi) { + report = true; + scan->list[n * 17] = (uint8_t) rssi; + } + + } else if (!memcmp(&scan->list[n * 17 + 1], zero, 16)) { + + /* Found Empty slot */ + report = true; + scan->list[n * 17] = (uint8_t) rssi; + memcpy(&scan->list[n * 17 + 1], data, 16); + } + + filled++; + } + + if (!report) + return; + + n = mesh_model_opcode_set(OP_REM_PROV_SCAN_REPORT, msg); + msg[n++] = (uint8_t) rssi; + memcpy(msg + n, data, len); + n += len; + + /* Always return oob_info, even if it wasn't in beacon */ + if (len == 16) { + l_put_le16(0, msg + n); + n += 2; + } + + goto send_report; + +extended_scan: + if (data[0] == BT_AD_MESH_BEACON && !data[1]) { + if (len != 18 && len != 20 && len != 24) + return; + + /* Check UUID */ + if (memcmp(data + 2, scan->uuid, 16)) + return; + + /* Zero AD list if prior data RXed from different bd_addr */ + if (memcmp(scan->addr, addr, 6)) { + scan->list[0] = 0; + scan->rxed_ads = 0; + } + + memcpy(scan->addr, addr, 6); + scan->fltr = true; + + if (len >= 20) + scan->oob_info = l_get_le16(data + 18); + + if (scan->rxed_ads != scan->ext_cnt) + return; + + + } else if (data[0] != BT_AD_MESH_BEACON) { + if (!scan->fltr || !memcmp(scan->addr, addr, 6)) { + i = 0; + while (scan->list[i]) { + /* check if seen */ + if (scan->list[i + 1] == data[0]) + return; + + i += scan->list[i] + 1; + } + + /* Overflow Protection */ + if (i + len + 1 > EXT_LIST_SIZE) + return; + + scan->list[i] = len; + scan->list[i + len + 1] = 0; + memcpy(scan->list + i + 1, data, len); + scan->rxed_ads++; + } + + if (scan->rxed_ads != scan->ext_cnt) + return; + + } else + return; + + n = mesh_model_opcode_set(OP_REM_PROV_EXT_SCAN_REPORT, msg); + msg[n++] = PB_REM_ERR_SUCCESS; + memcpy(msg + n, scan->uuid, 16); + n += 16; + l_put_le16(scan->oob_info, msg + n); + n += 2; + + i = 0; + while (scan->list[i]) { + msg[n++] = scan->list[i]; + memcpy(msg + n, &scan->list[i + 1], scan->list[i]); + n += scan->list[i]; + i += scan->list[i]; + } + +send_report: + print_packet("App Tx", msg, n); + mesh_model_send(scan->node, 0, scan->client, APP_IDX_DEV_LOCAL, + scan->net_idx, DEFAULT_TTL, true, n, msg); + + /* Clean-up if we are done reporting*/ + if (filled == scan->scanned_limit || scan->ext_cnt) + remprv_scan_cancel(NULL, scan); +} + +static bool register_ext_ad_type(uint8_t ad_type, struct rem_scan_data *scan) +{ + uint8_t short_ad; + + switch (ad_type) { + case BT_AD_MESH_PROV: + case BT_AD_UUID16_SOME: + case BT_AD_UUID32_SOME: + case BT_AD_UUID128_SOME: + case BT_AD_NAME_SHORT: + /* Illegal Requests */ + return false; + + case BT_AD_UUID16_ALL: + case BT_AD_UUID32_ALL: + case BT_AD_UUID128_ALL: + case BT_AD_NAME_COMPLETE: + /* Automatically get short versions */ + short_ad = ad_type - 1; + mesh_io_register_recv_cb(NULL, &short_ad, 1, scan_pkt, scan); + + /* fall through */ + default: + mesh_io_register_recv_cb(NULL, &ad_type, 1, scan_pkt, scan); + + /* fall through */ + + case BT_AD_MESH_BEACON: + /* Ignored/auto request */ + break; + } + + return true; +} + +static void link_active(void *user_data) +{ + struct rem_prov_data *prov = user_data; + uint8_t msg[5]; + int n; + + if (prov != rpb_prov || prov->state != PB_REMOTE_STATE_LINK_OPENING) + return; + + l_debug("Remote Link open confirmed"); + prov->state = PB_REMOTE_STATE_LINK_ACTIVE; + + n = mesh_model_opcode_set(OP_REM_PROV_LINK_REPORT, msg); + msg[n++] = PB_REM_ERR_SUCCESS; + msg[n++] = PB_REMOTE_STATE_LINK_ACTIVE; + + mesh_model_send(prov->node, 0, prov->client, APP_IDX_DEV_LOCAL, + prov->net_idx, DEFAULT_TTL, true, n, msg); +} + +bool register_nppi_acceptor(mesh_prov_open_func_t open_cb, + mesh_prov_close_func_t close_cb, + mesh_prov_receive_func_t rx_cb, + mesh_prov_ack_func_t ack_cb, + void *user_data) +{ + struct rem_prov_data *prov = rpb_prov; + + if (!prov || prov->nppi_proc == RPR_ADV) + return false; + + prov->u.nppi.open_cb = open_cb; + prov->u.nppi.close_cb = close_cb; + prov->u.nppi.rx_cb = rx_cb; + prov->u.nppi.ack_cb = ack_cb; + prov->trans_data = user_data; + + open_cb(user_data, srv_rx, prov, prov->nppi_proc); + + l_idle_oneshot(link_active, prov, NULL); + + return true; +} + +static bool nppi_cmplt(void *user_data, uint8_t status, + struct mesh_prov_node_info *info) +{ + struct rem_prov_data *prov = user_data; + + if (prov != rpb_prov) + return false; + + /* Save new info to apply on Link Close */ + prov->u.nppi.info = *info; + return true; +} + +static bool start_dev_key_refresh(struct mesh_node *node, uint8_t nppi_proc, + struct rem_prov_data *prov) +{ + uint8_t num_ele = node_get_num_elements(node); + + prov->nppi_proc = nppi_proc; + return acceptor_start(num_ele, NULL, 0x0001, 60, NULL, nppi_cmplt, + prov); +} + +static bool remprv_srv_pkt(uint16_t src, uint16_t unicast, uint16_t app_idx, + uint16_t net_idx, const uint8_t *data, + uint16_t size, const void *user_data) +{ + struct rem_prov_data *prov = rpb_prov; + struct rem_scan_data *scan = rpb_scan; + struct mesh_node *node = (struct mesh_node *) user_data; + const uint8_t *pkt = data; + bool segmented = false; + uint32_t opcode; + uint8_t msg[69]; + uint8_t old_state, status; + uint16_t n; + + if (app_idx != APP_IDX_DEV_LOCAL) + return false; + + if (mesh_model_opcode_get(pkt, size, &opcode, &n)) { + size -= n; + pkt += n; + } else + return false; + + n = 0; + + switch (opcode) { + default: + return false; + + case OP_REM_PROV_SCAN_CAP_GET: + if (size != 0) + return true; + + /* Compose Scan Info Status */ + n = mesh_model_opcode_set(OP_REM_PROV_SCAN_CAP_STATUS, msg); + msg[n++] = PB_REMOTE_MAX_SCAN_QUEUE_SIZE; + msg[n++] = 1; /* Active Scanning Supported */ + break; + + case OP_REM_PROV_EXT_SCAN_START: + if (!size || !pkt[0]) + return true; + + /* Size check the message */ + if (pkt[0] + 18 == size) { + /* Range check the Timeout */ + if (!pkt[size - 1] || pkt[size - 1] > 5) + return true; + } else if (pkt[0] + 1 != size) + return true; + + /* Get local device extended info */ + if (pkt[0] + 18 != size) { + n = mesh_model_opcode_set( + OP_REM_PROV_EXT_SCAN_REPORT, msg); + msg[n++] = PB_REM_ERR_SUCCESS; + memcpy(msg + n, node_uuid_get(node), 16); + n += 16; + l_put_le16(0, msg + n); + n += 2; + size--; + pkt++; + + while (size--) { + if (*pkt++ == BT_AD_NAME_COMPLETE) { + msg[n] = strlen(name) + 1; + if (msg[n] > sizeof(msg) - n - 1) + msg[n] = sizeof(msg) - n - 1; + n++; + msg[n++] = BT_AD_NAME_COMPLETE; + memcpy(&msg[n], name, msg[n - 2] - 1); + n += msg[n - 2] - 1; + goto send_pkt; + } + } + + /* Send internal report */ + l_debug("Send internal extended info %d", n); + goto send_pkt; + } + + status = PB_REM_ERR_SUCCESS; + if (scan) { + if (scan->client != src || scan->node != node || + scan->ext_cnt != pkt[0]) + status = PB_REM_ERR_SCANNING_CANNOT_START; + else if (memcmp(scan->ext, pkt + 1, pkt[0])) + status = PB_REM_ERR_SCANNING_CANNOT_START; + else if (memcmp(scan->uuid, pkt + 2, 16)) + status = PB_REM_ERR_SCANNING_CANNOT_START; + } + + if (status != PB_REM_ERR_SUCCESS) { + n = mesh_model_opcode_set(OP_REM_PROV_EXT_SCAN_REPORT, + msg); + msg[n++] = status; + memset(msg + n, 0, 16); + n += 16; + segmented = true; + break; + } + + /* Ignore extended requests while already scanning */ + if (scan) + return true; + + scan = (void *) l_new(uint8_t, + sizeof(struct rem_scan_data) + pkt[0]); + + /* Validate and register Extended AD types */ + for (n = 0; n < pkt[0]; n++) { + if (!register_ext_ad_type(pkt[1 + n], scan)) { + /* Invalid AD type detected -- Undo */ + while (n--) + deregister_ext_ad_type(pkt[1 + n]); + + l_free(scan); + return true; + } + } + + rpb_scan = scan; + scan->client = src; + scan->net_idx = net_idx; + memcpy(scan->uuid, pkt + size - 17, 16); + scan->ext_cnt = pkt[0]; + memcpy(scan->ext, pkt + 1, pkt[0]); + scan->list = l_malloc(EXT_LIST_SIZE); + scan->list[0] = 0; + + mesh_io_register_recv_cb(NULL, prvb, sizeof(prvb), + scan_pkt, scan); + + scan->timeout = l_timeout_create(pkt[size-1], + remprv_scan_cancel, scan, NULL); + return true; + + case OP_REM_PROV_SCAN_START: + if (size != 2 && size != 18) + return true; + + /* Reject Timeout of Zero */ + if (!pkt[1]) + return true; + + status = PB_REM_ERR_SUCCESS; + if (scan) { + if (scan->ext_cnt || scan->client != src || + scan->node != node) + status = PB_REM_ERR_SCANNING_CANNOT_START; + else if (!!(scan->fltr) != !!(size != 18)) + status = PB_REM_ERR_SCANNING_CANNOT_START; + else if (scan->fltr && memcmp(scan->uuid, pkt + 2, 16)) + status = PB_REM_ERR_SCANNING_CANNOT_START; + } + + if (status != PB_REM_ERR_SUCCESS) { + n = mesh_model_opcode_set(OP_REM_PROV_SCAN_STATUS, msg); + msg[n++] = status; + msg[n++] = scan ? scan->state : 0; + msg[n++] = scan ? scan->scanned_limit : + PB_REMOTE_MAX_SCAN_QUEUE_SIZE; + msg[n++] = scan ? scan->to_secs : 0; + break; + } + + if (!scan) + scan = l_new(struct rem_scan_data, 1); + + rpb_scan = scan; + + if (size == 18) { + memcpy(scan->uuid, pkt + 2, 16); + scan->fltr = true; + scan->state = 0x02; /* Limited */ + } else { + memset(scan->uuid, 0, 16); + scan->fltr = false; + scan->state = 0x01; /* Unlimited */ + } + + scan->client = src; + scan->net_idx = net_idx; + scan->node = node; + + if (!scan->list) + scan->list = l_new(uint8_t, + 23 * PB_REMOTE_MAX_SCAN_QUEUE_SIZE); + + mesh_io_register_recv_cb(NULL, prvb, 2, scan_pkt, scan); + + scan->to_secs = pkt[1]; + + if (pkt[0]) + scan->scanned_limit = pkt[0]; + else + scan->scanned_limit = PB_REMOTE_MAX_SCAN_QUEUE_SIZE; + + scan->timeout = l_timeout_create(pkt[1], + remprv_scan_cancel, scan, NULL); + + /* fall through */ + + case OP_REM_PROV_SCAN_GET: + /* Compose Scan Status */ + n = mesh_model_opcode_set(OP_REM_PROV_SCAN_STATUS, msg); + msg[n++] = PB_REM_ERR_SUCCESS; + msg[n++] = scan ? scan->state : 0; + msg[n++] = scan ? scan->scanned_limit : + PB_REMOTE_MAX_SCAN_QUEUE_SIZE; + msg[n++] = scan ? scan->to_secs : 0; + break; + + case OP_REM_PROV_SCAN_STOP: + if (size != 0 || !scan) + return true; + + remprv_scan_cancel(NULL, scan); + return true; + + case OP_REM_PROV_LINK_GET: + if (size != 0 || !prov) + return true; + + send_prov_status(prov, PB_REM_ERR_SUCCESS); + return true; + + case OP_REM_PROV_LINK_OPEN: + /* Sanity check args */ + if (size != 16 && size != 17 && size != 1) + return true; + + if (size == 17 && (pkt[16] == 0 || pkt[16] > 0x3c)) + return true; + + if (size == 1 && pkt[0] > 0x02) + return true; + + if (prov) { + if (prov->client != src || prov->node != node || + (size == 1 && prov->nppi_proc != pkt[0]) || + (size >= 16 && (prov->nppi_proc != RPR_ADV || + memcmp(prov->u.adv.uuid, pkt, 16)))) { + + /* Send Reject (in progress) */ + send_prov_status(prov, PB_REM_ERR_CANNOT_OPEN); + n = mesh_model_opcode_set( + OP_REM_PROV_LINK_STATUS, msg); + msg[n++] = PB_REM_ERR_CANNOT_OPEN; + msg[n++] = PB_REMOTE_STATE_LINK_ACTIVE; + break; + } + + /* Send redundant Success */ + send_prov_status(prov, PB_REM_ERR_SUCCESS); + return true; + } + + if (scan && scan->client != src && scan->node != node) { + n = mesh_model_opcode_set(OP_REM_PROV_LINK_STATUS, msg); + msg[n++] = PB_REM_ERR_CANNOT_OPEN; + msg[n++] = PB_REMOTE_STATE_LINK_ACTIVE; + break; + } + + print_packet("Remote Prov Link Open", pkt, size); + + remprv_scan_cancel(NULL, scan); + + rpb_prov = prov = l_new(struct rem_prov_data, 1); + prov->client = src; + prov->net_idx = net_idx; + prov->node = node; + prov->state = PB_REMOTE_STATE_LINK_OPENING; + + if (size == 1) { + status = start_dev_key_refresh(node, pkt[0], prov); + + } else { + if (size == 17) + prov->timeout = l_timeout_create(pkt[16], + remprv_prov_cancel, prov, NULL); + + + prov->nppi_proc = RPR_ADV; + memcpy(prov->u.adv.uuid, pkt, 16); + status = pb_adv_reg(true, srv_open, srv_close, srv_rx, + srv_ack, pkt, prov); + } + + if (status) + send_prov_status(prov, PB_REM_ERR_SUCCESS); + else { + n = mesh_model_opcode_set(OP_REM_PROV_LINK_STATUS, msg); + msg[n++] = PB_REM_ERR_CANNOT_OPEN; + msg[n++] = PB_REMOTE_STATE_IDLE; + remprv_prov_cancel(NULL, prov); + } + + return true; + + case OP_REM_PROV_LINK_CLOSE: + if (size != 1) + return true; + + if (!prov || prov->node != node || prov->client != src) + return true; + + old_state = prov->state; + prov->state = PB_REMOTE_STATE_LINK_CLOSING; + mesh_io_send_cancel(NULL, &pkt_filter, sizeof(pkt_filter)); + send_prov_status(prov, PB_REM_ERR_SUCCESS); + if (pkt[0] == 0x02 && + old_state >= PB_REMOTE_STATE_LINK_ACTIVE) { + msg[0] = PROV_FAILED; + msg[1] = PROV_ERR_CANT_ASSIGN_ADDR; + if (prov->nppi_proc == RPR_ADV) + prov->u.adv.tx(prov->trans_data, msg, 2); + else + prov->u.nppi.rx_cb(prov->trans_data, msg, 2); + } + + if (prov->nppi_proc == RPR_ADV) + pb_adv_unreg(prov); + + else if (prov->nppi_proc <= RPR_COMP) { + /* Hard or Soft refresh of local node, based on NPPI */ + node_refresh(prov->node, (prov->nppi_proc == RPR_ADDR), + &prov->u.nppi.info); + } + + remprv_prov_cancel(NULL, prov); + + return true; + + case OP_REM_PROV_PDU_SEND: + if (!prov || prov->node != node || prov->client != src) + return true; + + if (size < 2) + return true; + + + prov->cli_pdu_num = *pkt++; + size--; + prov->state = PB_REMOTE_STATE_OB_PKT_TX; + + if (prov->nppi_proc == RPR_ADV) + prov->u.adv.tx(prov->trans_data, pkt, size); + else { + srv_ack(prov, prov->cli_pdu_num); + prov->u.nppi.rx_cb(prov->trans_data, pkt, size); + } + + return true; + } + +send_pkt: + l_info("PB-SVR: src %4.4x dst %4.4x", unicast, src); + print_packet("App Tx", msg, n); + mesh_model_send(node, 0, src, APP_IDX_DEV_LOCAL, + net_idx, DEFAULT_TTL, segmented, n, msg); + + return true; +} + +static void remprv_srv_unregister(void *user_data) +{ +} + +static const struct mesh_model_ops ops = { + .unregister = remprv_srv_unregister, + .recv = remprv_srv_pkt, + .bind = NULL, + .sub = NULL, + .pub = NULL +}; + +void remote_prov_server_init(struct mesh_node *node, uint8_t ele_idx) +{ + mesh_model_register(node, ele_idx, REM_PROV_SRV_MODEL, &ops, node); +} diff --git a/mesh/remprv.h b/mesh/remprv.h new file mode 100644 index 0000000000000000000000000000000000000000..ab7e32b2ddf21e906f065bed68e64db91a8117f7 --- /dev/null +++ b/mesh/remprv.h @@ -0,0 +1,78 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ + +#define REM_PROV_SRV_MODEL SET_ID(SIG_VENDOR, 0x0004) +#define REM_PROV_CLI_MODEL SET_ID(SIG_VENDOR, 0x0005) + +#define PB_REMOTE_MAX_SCAN_QUEUE_SIZE 5 + +#define PB_REMOTE_STATE_IDLE 0x00 +#define PB_REMOTE_STATE_LINK_OPENING 0x01 +#define PB_REMOTE_STATE_LINK_ACTIVE 0x02 +#define PB_REMOTE_STATE_OB_PKT_TX 0x03 +#define PB_REMOTE_STATE_LINK_CLOSING 0x04 + +#define PB_REMOTE_TYPE_LOCAL 0x01 +#define PB_REMOTE_TYPE_ADV 0x02 +#define PB_REMOTE_TYPE_GATT 0x04 + +#define PB_REMOTE_SCAN_TYPE_NONE 0x00 +#define PB_REMOTE_SCAN_TYPE_UNLIMITED 0x01 +#define PB_REMOTE_SCAN_TYPE_LIMITED 0x02 +#define PB_REMOTE_SCAN_TYPE_DETAILED 0x03 + +/* Remote Provisioning Opcode List */ +#define OP_REM_PROV_SCAN_CAP_GET 0x804F +#define OP_REM_PROV_SCAN_CAP_STATUS 0x8050 +#define OP_REM_PROV_SCAN_GET 0x8051 +#define OP_REM_PROV_SCAN_START 0x8052 +#define OP_REM_PROV_SCAN_STOP 0x8053 +#define OP_REM_PROV_SCAN_STATUS 0x8054 +#define OP_REM_PROV_SCAN_REPORT 0x8055 +#define OP_REM_PROV_EXT_SCAN_START 0x8056 +#define OP_REM_PROV_EXT_SCAN_REPORT 0x8057 +#define OP_REM_PROV_LINK_GET 0x8058 +#define OP_REM_PROV_LINK_OPEN 0x8059 +#define OP_REM_PROV_LINK_CLOSE 0x805A +#define OP_REM_PROV_LINK_STATUS 0x805B +#define OP_REM_PROV_LINK_REPORT 0x805C +#define OP_REM_PROV_PDU_SEND 0x805D +#define OP_REM_PROV_PDU_OB_REPORT 0x805E +#define OP_REM_PROV_PDU_REPORT 0x805F + +/* Remote Provisioning Errors */ +#define PB_REM_ERR_SUCCESS 0x00 +#define PB_REM_ERR_SCANNING_CANNOT_START 0x01 +#define PB_REM_ERR_INVALID_STATE 0x02 +#define PB_REM_ERR_LIMITED_RESOURCES 0x03 +#define PB_REM_ERR_CANNOT_OPEN 0x04 +#define PB_REM_ERR_OPEN_FAILED 0x05 +#define PB_REM_ERR_CLOSED_BY_DEVICE 0x06 +#define PB_REM_ERR_CLOSED_BY_SERVER 0x07 +#define PB_REM_ERR_CLOSED_BY_CLIENT 0x08 +#define PB_REM_ERR_CLOSED_CANNOT_RX_PDU 0x09 +#define PB_REM_ERR_CLOSED_CANNOT_TX_PDU 0x0A + +void remote_prov_server_init(struct mesh_node *node, uint8_t ele_idx); +void remote_prov_client_init(struct mesh_node *node, uint8_t ele_idx); +bool register_nppi_acceptor(mesh_prov_open_func_t open_cb, + mesh_prov_close_func_t close_cb, + mesh_prov_receive_func_t rx_cb, + mesh_prov_ack_func_t ack_cb, + void *user_data); diff --git a/mesh/rpl.c b/mesh/rpl.c index 1213ee66e745fe0a3e47a26f4fe88139e3077e43..69533bf431b441b73c099699afea5d67b564e2ab 100644 --- a/mesh/rpl.c +++ b/mesh/rpl.c @@ -31,7 +31,7 @@ #include "mesh/util.h" #include "mesh/rpl.h" -const char *rpl_dir = "/rpl"; +static const char *rpl_dir = "/rpl"; bool rpl_put_entry(struct mesh_node *node, uint16_t src, uint32_t iv_index, uint32_t seq) @@ -146,7 +146,7 @@ static void get_entries(const char *iv_path, struct l_queue *rpl_list) if (!dir) return; - iv_txt = basename(iv_path); + iv_txt = mesh_basename(iv_path); if (sscanf(iv_txt, "%08x", &iv_index) != 1) { closedir(dir); return; diff --git a/mesh/util.c b/mesh/util.c index 82b57f642f477efe5ca88f61cbae50b015b68bba..73f13aab7d64d397bcab0ffa3276f41d7e03c0ec 100644 --- a/mesh/util.c +++ b/mesh/util.c @@ -161,3 +161,13 @@ void enable_debug(void) debug_enabled = true; l_debug_enable("*"); } + +#if !HAVE_DECL_BASENAME +#include <string.h> +const char *mesh_basename(const char *path) +{ + const char *base = strrchr(path, '/'); + + return base ? base + 1 : path; +} +#endif diff --git a/mesh/util.h b/mesh/util.h index 085ec333097d18aa7350145b9340ebeae1ac0d9a..bb417dc40f16e544a58d75d57ab3040761363887 100644 --- a/mesh/util.h +++ b/mesh/util.h @@ -16,3 +16,8 @@ void print_packet(const char *label, const void *data, uint16_t size); int create_dir(const char *dir_name); void del_path(const char *path); void enable_debug(void); +#if !HAVE_DECL_BASENAME +const char *mesh_basename(const char *path); +#else +#define mesh_basename basename +#endif diff --git a/missing b/missing new file mode 100755 index 0000000000000000000000000000000000000000..1fe1611f18514b7174f3529145b56cdc51d48c7c --- /dev/null +++ b/missing @@ -0,0 +1,215 @@ +#! /bin/sh +# Common wrapper for a few potentially missing GNU programs. + +scriptversion=2018-03-07.03; # UTC + +# Copyright (C) 1996-2021 Free Software Foundation, Inc. +# Originally written 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, see <https://www.gnu.org/licenses/>. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try '$0 --help' for more information" + exit 1 +fi + +case $1 in + + --is-lightweight) + # Used by our autoconf macros to check whether the available missing + # script is modern enough. + exit 0 + ;; + + --run) + # Back-compat with the calling convention used by older automake. + shift + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due +to PROGRAM being missing or too old. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal autoconf autoheader autom4te automake makeinfo + bison yacc flex lex help2man + +Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and +'g' are ignored when checking the name. + +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 + +# Run the given program, remember its exit status. +"$@"; st=$? + +# If it succeeded, we are done. +test $st -eq 0 && exit 0 + +# Also exit now if we it failed (or wasn't found), and '--version' was +# passed; such an option is passed most likely to detect whether the +# program is present and works. +case $2 in --version|--help) exit $st;; esac + +# Exit code 63 means version mismatch. This often happens when the user +# tries to use an ancient version of a tool on a file that requires a +# minimum version. +if test $st -eq 63; then + msg="probably too old" +elif test $st -eq 127; then + # Program was missing. + msg="missing on your system" +else + # Program was found and executed, but failed. Give up. + exit $st +fi + +perl_URL=https://www.perl.org/ +flex_URL=https://github.com/westes/flex +gnu_software_URL=https://www.gnu.org/software + +program_details () +{ + case $1 in + aclocal|automake) + echo "The '$1' program is part of the GNU Automake package:" + echo "<$gnu_software_URL/automake>" + echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" + echo "<$gnu_software_URL/autoconf>" + echo "<$gnu_software_URL/m4/>" + echo "<$perl_URL>" + ;; + autoconf|autom4te|autoheader) + echo "The '$1' program is part of the GNU Autoconf package:" + echo "<$gnu_software_URL/autoconf/>" + echo "It also requires GNU m4 and Perl in order to run:" + echo "<$gnu_software_URL/m4/>" + echo "<$perl_URL>" + ;; + esac +} + +give_advice () +{ + # Normalize program name to check for. + normalized_program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + + printf '%s\n' "'$1' is $msg." + + configure_deps="'configure.ac' or m4 files included by 'configure.ac'" + case $normalized_program in + autoconf*) + echo "You should only need it if you modified 'configure.ac'," + echo "or m4 files included by it." + program_details 'autoconf' + ;; + autoheader*) + echo "You should only need it if you modified 'acconfig.h' or" + echo "$configure_deps." + program_details 'autoheader' + ;; + automake*) + echo "You should only need it if you modified 'Makefile.am' or" + echo "$configure_deps." + program_details 'automake' + ;; + aclocal*) + echo "You should only need it if you modified 'acinclude.m4' or" + echo "$configure_deps." + program_details 'aclocal' + ;; + autom4te*) + echo "You might have modified some maintainer files that require" + echo "the 'autom4te' program to be rebuilt." + program_details 'autom4te' + ;; + bison*|yacc*) + echo "You should only need it if you modified a '.y' file." + echo "You may want to install the GNU Bison package:" + echo "<$gnu_software_URL/bison/>" + ;; + lex*|flex*) + echo "You should only need it if you modified a '.l' file." + echo "You may want to install the Fast Lexical Analyzer package:" + echo "<$flex_URL>" + ;; + help2man*) + echo "You should only need it if you modified a dependency" \ + "of a man page." + echo "You may want to install the GNU Help2man package:" + echo "<$gnu_software_URL/help2man/>" + ;; + makeinfo*) + echo "You should only need it if you modified a '.texi' file, or" + echo "any other file indirectly affecting the aspect of the manual." + echo "You might want to install the Texinfo package:" + echo "<$gnu_software_URL/texinfo/>" + echo "The spurious makeinfo call might also be the consequence of" + echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" + echo "want to install GNU make:" + echo "<$gnu_software_URL/make/>" + ;; + *) + echo "You might have modified some files without having the proper" + echo "tools for further handling them. Check the 'README' file, it" + echo "often tells you about the needed prerequisites for installing" + echo "this package. You may also peek at any GNU archive site, in" + echo "case some other package contains this missing '$1' program." + ;; + esac +} + +give_advice "$1" | sed -e '1s/^/WARNING: /' \ + -e '2,$s/^/ /' >&2 + +# Propagate the correct exit status (expected to be 127 for a program +# not found, 63 for a program that failed due to version mismatch). +exit $st + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/monitor/a2dp.c b/monitor/a2dp.c index f6e99ab264698525a5ba7d6d11740752b6189c18..ae88f565ed4ff5822566b5509762c74804425d88 100644 --- a/monitor/a2dp.c +++ b/monitor/a2dp.c @@ -47,6 +47,8 @@ #define APTX_HD_CODEC_ID 0x0024 #define LDAC_VENDOR_ID 0x0000012d #define LDAC_CODEC_ID 0x00aa +#define OPUS_G_VENDOR_ID 0x000000e0 +#define OPUS_G_CODEC_ID 0x0001 struct bit_desc { uint8_t bit_num; @@ -201,6 +203,24 @@ static const struct bit_desc faststream_source_frequency_table[] = { { } }; +static const struct bit_desc opus_g_frequency_table[] = { + { 7, "48000" }, + { } +}; + +static const struct bit_desc opus_g_duration_table[] = { + { 3, "10 ms" }, + { 4, "20 ms" }, + { } +}; + +static const struct bit_desc opus_g_channels_table[] = { + { 0, "Mono" }, + { 1, "Stereo" }, + { 2, "Dual Mono" }, + { } +}; + static void print_value_bits(uint8_t indent, uint32_t value, const struct bit_desc *table) { @@ -244,6 +264,7 @@ static bool codec_vendor_aptx_ll_cfg(uint8_t losc, struct l2cap_frame *frame); static bool codec_vendor_aptx_hd_cap(uint8_t losc, struct l2cap_frame *frame); static bool codec_vendor_aptx_hd_cfg(uint8_t losc, struct l2cap_frame *frame); static bool codec_vendor_ldac(uint8_t losc, struct l2cap_frame *frame); +static bool codec_vendor_opus_g(uint8_t losc, struct l2cap_frame *frame); static const struct vndcodec vndcodecs[] = { { APTX_VENDOR_ID, APTX_CODEC_ID, "aptX", @@ -256,6 +277,8 @@ static const struct vndcodec vndcodecs[] = { codec_vendor_aptx_hd_cap, codec_vendor_aptx_hd_cfg }, { LDAC_VENDOR_ID, LDAC_CODEC_ID, "LDAC", codec_vendor_ldac, codec_vendor_ldac }, + { OPUS_G_VENDOR_ID, OPUS_G_CODEC_ID, "Opus (Google)", + codec_vendor_opus_g, codec_vendor_opus_g }, { } }; @@ -685,6 +708,31 @@ static bool codec_vendor_ldac(uint8_t losc, struct l2cap_frame *frame) return true; } +static bool codec_vendor_opus_g(uint8_t losc, struct l2cap_frame *frame) +{ + uint8_t cap = 0; + + if (losc != 1) + return false; + + l2cap_frame_get_u8(frame, &cap); + + print_field("%*cFrequency: 0x%02x", BASE_INDENT + 2, ' ', cap & 0x80); + print_value_bits(BASE_INDENT + 2, cap, opus_g_frequency_table); + + print_field("%*cFrame Duration: 0x%02x", BASE_INDENT + 2, ' ', + cap & 0x18); + print_value_bits(BASE_INDENT + 2, cap, opus_g_duration_table); + + print_field("%*cChannel Mode: 0x%02x", BASE_INDENT + 2, ' ', + cap & 0x07); + print_value_bits(BASE_INDENT + 2, cap, opus_g_channels_table); + + print_field("%*cReserved: 0x%02x", BASE_INDENT + 2, ' ', cap & 0x60); + + return true; +} + static bool codec_vendor_cap(uint8_t losc, struct l2cap_frame *frame) { uint32_t vendor_id = 0; diff --git a/monitor/analyze.c b/monitor/analyze.c index a20ba98b0be40bb3ef8fbd291b06dd67712def76..3cc482cd9227270253f69dee0e3520205735a6a2 100644 --- a/monitor/analyze.c +++ b/monitor/analyze.c @@ -17,6 +17,7 @@ #include <stdio.h> #include <string.h> #include <sys/time.h> +#include <unistd.h> #include "lib/bluetooth.h" @@ -28,6 +29,9 @@ #include "monitor/packet.h" #include "monitor/analyze.h" +#define TIMEVAL_MSEC(_tv) \ + (long long)((_tv)->tv_sec * 1000 + (_tv)->tv_usec / 1000) + struct hci_dev { uint16_t index; uint8_t type; @@ -55,45 +59,121 @@ struct hci_dev { #define CONN_LE_ACL 0x04 #define CONN_LE_ISO 0x05 +struct hci_stats { + size_t bytes; + size_t num; + size_t num_comp; + struct packet_latency latency; + struct queue *plot; + uint16_t min; + uint16_t max; +}; + struct hci_conn { uint16_t handle; + uint16_t link; uint8_t type; uint8_t bdaddr[6]; bool setup_seen; bool terminated; - unsigned long rx_num; - unsigned long tx_num; - unsigned long tx_num_comp; - size_t tx_bytes; struct queue *tx_queue; - struct timeval tx_lat_min; - struct timeval tx_lat_max; - struct timeval tx_lat_med; - uint16_t tx_pkt_min; - uint16_t tx_pkt_max; - uint16_t tx_pkt_med; + struct timeval last_rx; struct queue *chan_list; + struct hci_stats rx; + struct hci_stats tx; +}; + +struct hci_conn_tx { + struct timeval tv; + struct l2cap_chan *chan; +}; + +struct plot { + long long x_msec; + size_t y_count; }; struct l2cap_chan { uint16_t cid; uint16_t psm; bool out; - unsigned long num; + struct timeval last_rx; + struct hci_stats rx; + struct hci_stats tx; }; static struct queue *dev_list; +static void tmp_write(void *data, void *user_data) +{ + struct plot *plot = data; + FILE *tmp = user_data; + + fprintf(tmp, "%lld %zu\n", plot->x_msec, plot->y_count); +} + +static void plot_draw(struct queue *queue, const char *tittle) +{ + FILE *gplot; + + if (queue_length(queue) < 2) + return; + + gplot = popen("gnuplot", "w"); + if (!gplot) + return; + + fprintf(gplot, "$data << EOD\n"); + queue_foreach(queue, tmp_write, gplot); + fprintf(gplot, "EOD\n"); + + fprintf(gplot, "set terminal dumb enhanced ansi\n"); + fprintf(gplot, "set xlabel 'Latency (ms)'\n"); + fprintf(gplot, "set tics out nomirror\n"); + fprintf(gplot, "set log y\n"); + fprintf(gplot, "set yrange [0.5:*]\n"); + fprintf(gplot, "plot $data using 1:2 t '%s' w impulses\n", tittle); + fflush(gplot); + + pclose(gplot); +} + +static void print_stats(struct hci_stats *stats, const char *label) +{ + if (!stats->num) + return; + + print_field("%s packets: %zu/%zu", label, stats->num, stats->num_comp); + print_field("%s Latency: %lld-%lld msec (~%lld msec)", label, + TV_MSEC(stats->latency.min), + TV_MSEC(stats->latency.max), + TV_MSEC(stats->latency.med)); + print_field("%s size: %u-%u octets (~%zd octets)", label, + stats->min, stats->max, stats->bytes / stats->num); + + if (TV_MSEC(stats->latency.total)) + print_field("%s speed: ~%lld Kb/s", label, + stats->bytes * 8 / TV_MSEC(stats->latency.total)); + + plot_draw(stats->plot, label); +} + static void chan_destroy(void *data) { struct l2cap_chan *chan = data; - printf(" Found %s L2CAP channel with CID %u\n", + if (!chan->rx.num && !chan->tx.num) + goto done; + + printf(" Found %s L2CAP channel with CID %u\n", chan->out ? "TX" : "RX", chan->cid); if (chan->psm) - printf(" PSM %u\n", chan->psm); - printf(" %lu packets\n", chan->num); + print_field("PSM %u", chan->psm); + print_stats(&chan->rx, "RX"); + print_stats(&chan->tx, "TX"); + +done: free(chan); } @@ -106,6 +186,8 @@ static struct l2cap_chan *chan_alloc(struct hci_conn *conn, uint16_t cid, chan->cid = cid; chan->out = out; + chan->rx.plot = queue_new(); + chan->tx.plot = queue_new(); return chan; } @@ -161,32 +243,16 @@ static void conn_destroy(void *data) break; } - if (conn->tx_num > 0) - conn->tx_pkt_med = conn->tx_bytes / conn->tx_num; - printf(" Found %s connection with handle %u\n", str, conn->handle); /* TODO: Store address type */ packet_print_addr("Address", conn->bdaddr, 0x00); if (!conn->setup_seen) print_field("Connection setup missing"); - print_field("%lu RX packets", conn->rx_num); - print_field("%lu TX packets", conn->tx_num); - print_field("%lu TX completed packets", conn->tx_num_comp); - print_field("%lld msec min latency", - (long long) - (conn->tx_lat_min.tv_sec * 1000 + - conn->tx_lat_min.tv_usec / 1000)); - print_field("%lld msec max latency", - (long long) - (conn->tx_lat_max.tv_sec * 1000 + - conn->tx_lat_max.tv_usec / 1000)); - print_field("%lld msec median latency", - (long long) - (conn->tx_lat_med.tv_sec * 1000 + - conn->tx_lat_med.tv_usec / 1000)); - print_field("%u octets TX min packet size", conn->tx_pkt_min); - print_field("%u octets TX max packet size", conn->tx_pkt_max); - print_field("%u octets TX median packet size", conn->tx_pkt_med); + print_stats(&conn->rx, "RX"); + print_stats(&conn->tx, "TX"); + + queue_destroy(conn->rx.plot, free); + queue_destroy(conn->tx.plot, free); queue_destroy(conn->chan_list, chan_destroy); queue_destroy(conn->tx_queue, free); @@ -203,6 +269,8 @@ static struct hci_conn *conn_alloc(struct hci_dev *dev, uint16_t handle, conn->handle = handle; conn->type = type; conn->tx_queue = queue_new(); + conn->tx.plot = queue_new(); + conn->rx.plot = queue_new(); conn->chan_list = queue_new(); @@ -223,6 +291,20 @@ static struct hci_conn *conn_lookup(struct hci_dev *dev, uint16_t handle) UINT_TO_PTR(handle)); } +static bool link_match_handle(const void *a, const void *b) +{ + const struct hci_conn *conn = a; + uint16_t handle = PTR_TO_UINT(b); + + return (conn->link == handle && !conn->terminated); +} + +static struct hci_conn *link_lookup(struct hci_dev *dev, uint16_t handle) +{ + return queue_find(dev->conn_list, link_match_handle, + UINT_TO_PTR(handle)); +} + static struct hci_conn *conn_lookup_type(struct hci_dev *dev, uint16_t handle, uint8_t type) { @@ -230,7 +312,7 @@ static struct hci_conn *conn_lookup_type(struct hci_dev *dev, uint16_t handle, conn = queue_find(dev->conn_list, conn_match_handle, UINT_TO_PTR(handle)); - if (!conn || conn->type != type) { + if (!conn || (type && conn->type != type)) { conn = conn_alloc(dev, handle, type); queue_push_tail(dev->conn_list, conn); } @@ -447,6 +529,70 @@ static void evt_cmd_complete(struct hci_dev *dev, struct timeval *tv, } } +static bool match_plot_latency(const void *data, const void *user_data) +{ + const struct plot *plot = data; + const struct timeval *latency = user_data; + + return TIMEVAL_MSEC(latency) == plot->x_msec; +} + +static void plot_add(struct queue *queue, struct timeval *latency, + uint16_t count) +{ + struct plot *plot; + + /* Use LRU ordering */ + plot = queue_remove_if(queue, match_plot_latency, latency); + if (plot) { + plot->y_count += count; + queue_push_head(queue, plot); + return; + } + + plot = new0(struct plot, 1); + plot->x_msec = TIMEVAL_MSEC(latency); + plot->y_count = count; + + queue_push_tail(queue, plot); +} + +static void evt_le_conn_complete(struct hci_dev *dev, struct timeval *tv, + struct iovec *iov) +{ + const struct bt_hci_evt_le_conn_complete *evt; + struct hci_conn *conn; + + evt = util_iov_pull_mem(iov, sizeof(*evt)); + if (!evt || evt->status) + return; + + conn = conn_lookup_type(dev, le16_to_cpu(evt->handle), CONN_LE_ACL); + if (!conn) + return; + + memcpy(conn->bdaddr, evt->peer_addr, 6); + conn->setup_seen = true; +} + +static void evt_le_enh_conn_complete(struct hci_dev *dev, struct timeval *tv, + struct iovec *iov) +{ + const struct bt_hci_evt_le_enhanced_conn_complete *evt; + struct hci_conn *conn; + + evt = util_iov_pull_mem(iov, sizeof(*evt)); + if (!evt || evt->status) + return; + + conn = conn_lookup_type(dev, le16_to_cpu(evt->handle), CONN_LE_ACL); + if (!conn) + return; + + memcpy(conn->bdaddr, evt->peer_addr, 6); + conn->setup_seen = true; +} + static void evt_num_completed_packets(struct hci_dev *dev, struct timeval *tv, const void *data, uint16_t size) { @@ -461,7 +607,8 @@ static void evt_num_completed_packets(struct hci_dev *dev, struct timeval *tv, uint16_t count = get_le16(data + 2); struct hci_conn *conn; struct timeval res; - struct timeval *last_tx; + struct hci_conn_tx *last_tx; + int j; data += 4; size -= 4; @@ -470,48 +617,165 @@ static void evt_num_completed_packets(struct hci_dev *dev, struct timeval *tv, if (!conn) continue; - conn->tx_num_comp += count; + conn->tx.num_comp += count; - last_tx = queue_pop_head(conn->tx_queue); - if (last_tx) { - timersub(tv, last_tx, &res); + for (j = 0; j < count; j++) { + last_tx = queue_pop_head(conn->tx_queue); + if (last_tx) { + struct l2cap_chan *chan = last_tx->chan; - if ((!timerisset(&conn->tx_lat_min) || - timercmp(&res, &conn->tx_lat_min, <)) && - res.tv_sec >= 0 && res.tv_usec >= 0) - conn->tx_lat_min = res; + timersub(tv, &last_tx->tv, &res); - if (!timerisset(&conn->tx_lat_max) || - timercmp(&res, &conn->tx_lat_max, >)) - conn->tx_lat_max = res; + packet_latency_add(&conn->tx.latency, &res); + plot_add(conn->tx.plot, &res, 1); - if (timerisset(&conn->tx_lat_med)) { - struct timeval tmp; + if (chan) { + chan->tx.num_comp += count; + packet_latency_add(&chan->tx.latency, + &res); + plot_add(chan->tx.plot, &res, 1); + } - timeradd(&conn->tx_lat_med, &res, &tmp); + free(last_tx); + } + } + } +} - tmp.tv_sec /= 2; - tmp.tv_usec /= 2; - if (tmp.tv_sec % 2) { - tmp.tv_usec += 500000; - if (tmp.tv_usec >= 1000000) { - tmp.tv_sec++; - tmp.tv_usec -= 1000000; - } - } +static void evt_sync_conn_complete(struct hci_dev *dev, struct timeval *tv, + const void *data, uint16_t size) +{ + const struct bt_hci_evt_sync_conn_complete *evt = data; + struct hci_conn *conn; - conn->tx_lat_med = tmp; - } else - conn->tx_lat_med = res; + if (evt->status) + return; - free(last_tx); - } + conn = conn_lookup_type(dev, le16_to_cpu(evt->handle), evt->link_type); + if (!conn) + return; + + memcpy(conn->bdaddr, evt->bdaddr, 6); + conn->setup_seen = true; +} + +static void evt_le_cis_established(struct hci_dev *dev, struct timeval *tv, + struct iovec *iov) +{ + const struct bt_hci_evt_le_cis_established *evt; + struct hci_conn *conn, *link; + + evt = util_iov_pull_mem(iov, sizeof(*evt)); + if (!evt || evt->status) + return; + + conn = conn_lookup_type(dev, le16_to_cpu(evt->conn_handle), + CONN_LE_ISO); + if (!conn) + return; + + conn->setup_seen = true; + + link = link_lookup(dev, conn->handle); + if (link) + memcpy(conn->bdaddr, link->bdaddr, 6); +} + +static void evt_le_cis_req(struct hci_dev *dev, struct timeval *tv, + struct iovec *iov) +{ + const struct bt_hci_evt_le_cis_req *evt; + struct hci_conn *conn; + + evt = util_iov_pull_mem(iov, sizeof(*evt)); + if (!evt) + return; + + conn = conn_lookup(dev, le16_to_cpu(evt->acl_handle)); + if (!conn) + return; + + conn->link = le16_to_cpu(evt->cis_handle); +} + +static void evt_le_big_complete(struct hci_dev *dev, struct timeval *tv, + struct iovec *iov) +{ + const struct bt_hci_evt_le_big_complete *evt; + int i; + + evt = util_iov_pull_mem(iov, sizeof(*evt)); + if (!evt || evt->status) + return; + + for (i = 0; i < evt->num_bis; i++) { + struct hci_conn *conn; + uint16_t handle; + + if (!util_iov_pull_le16(iov, &handle)) + return; + + conn = conn_lookup_type(dev, handle, CONN_LE_ISO); + if (conn) + conn->setup_seen = true; + } +} + +static void evt_le_big_sync_established(struct hci_dev *dev, struct timeval *tv, + struct iovec *iov) +{ + const struct bt_hci_evt_le_big_sync_estabilished *evt; + int i; + + evt = util_iov_pull_mem(iov, sizeof(*evt)); + if (!evt || evt->status) + return; + + for (i = 0; i < evt->num_bis; i++) { + struct hci_conn *conn; + uint16_t handle; + + if (!util_iov_pull_le16(iov, &handle)) + return; + + conn = conn_lookup_type(dev, handle, CONN_LE_ISO); + if (conn) + conn->setup_seen = true; } } static void evt_le_meta_event(struct hci_dev *dev, struct timeval *tv, const void *data, uint16_t size) { + struct iovec iov = { + .iov_base = (void *)data, + .iov_len = size, + }; + uint8_t subevt; + + if (!util_iov_pull_u8(&iov, &subevt)) + return; + + switch (subevt) { + case BT_HCI_EVT_LE_CONN_COMPLETE: + evt_le_conn_complete(dev, tv, &iov); + break; + case BT_HCI_EVT_LE_ENHANCED_CONN_COMPLETE: + evt_le_enh_conn_complete(dev, tv, &iov); + break; + case BT_HCI_EVT_LE_CIS_ESTABLISHED: + evt_le_cis_established(dev, tv, &iov); + break; + case BT_HCI_EVT_LE_CIS_REQ: + evt_le_cis_req(dev, tv, &iov); + break; + case BT_HCI_EVT_LE_BIG_COMPLETE: + evt_le_big_complete(dev, tv, &iov); + break; + case BT_HCI_EVT_LE_BIG_SYNC_ESTABILISHED: + evt_le_big_sync_established(dev, tv, &iov); + break; + } } static void event_pkt(struct timeval *tv, uint16_t index, @@ -543,19 +807,79 @@ static void event_pkt(struct timeval *tv, uint16_t index, case BT_HCI_EVT_NUM_COMPLETED_PACKETS: evt_num_completed_packets(dev, tv, data, size); break; + case BT_HCI_EVT_SYNC_CONN_COMPLETE: + evt_sync_conn_complete(dev, tv, data, size); + break; case BT_HCI_EVT_LE_META_EVENT: evt_le_meta_event(dev, tv, data, size); break; } } +static void stats_add(struct hci_stats *stats, uint16_t size) +{ + stats->num++; + stats->bytes += size; + + if (!stats->min || size < stats->min) + stats->min = size; + if (!stats->max || size > stats->max) + stats->max = size; +} + +static void conn_pkt_tx(struct hci_conn *conn, struct timeval *tv, + uint16_t size, struct l2cap_chan *chan) +{ + struct hci_conn_tx *last_tx; + + last_tx = new0(struct hci_conn_tx, 1); + memcpy(last_tx, tv, sizeof(*tv)); + last_tx->chan = chan; + queue_push_tail(conn->tx_queue, last_tx); + + stats_add(&conn->tx, size); + + if (chan) + stats_add(&chan->tx, size); +} + +static void conn_pkt_rx(struct hci_conn *conn, struct timeval *tv, + uint16_t size, struct l2cap_chan *chan) +{ + struct timeval res; + + if (timerisset(&conn->last_rx)) { + timersub(tv, &conn->last_rx, &res); + packet_latency_add(&conn->rx.latency, &res); + plot_add(conn->rx.plot, &res, 1); + } + + conn->last_rx = *tv; + + stats_add(&conn->rx, size); + conn->rx.num_comp++; + + if (chan) { + if (timerisset(&chan->last_rx)) { + timersub(tv, &chan->last_rx, &res); + packet_latency_add(&chan->rx.latency, &res); + plot_add(chan->rx.plot, &res, 1); + } + + chan->last_rx = *tv; + + stats_add(&chan->rx, size); + chan->rx.num_comp++; + } +} + static void acl_pkt(struct timeval *tv, uint16_t index, bool out, const void *data, uint16_t size) { const struct bt_hci_acl_hdr *hdr = data; struct hci_dev *dev; struct hci_conn *conn; - struct l2cap_chan *chan; + struct l2cap_chan *chan = NULL; uint16_t cid; data += sizeof(*hdr); @@ -568,8 +892,7 @@ static void acl_pkt(struct timeval *tv, uint16_t index, bool out, dev->num_hci++; dev->num_acl++; - conn = conn_lookup_type(dev, le16_to_cpu(hdr->handle) & 0x0fff, - CONN_BR_ACL); + conn = conn_lookup_type(dev, le16_to_cpu(hdr->handle) & 0x0fff, 0x00); if (!conn) return; @@ -578,35 +901,24 @@ static void acl_pkt(struct timeval *tv, uint16_t index, bool out, case 0x02: cid = get_le16(data + 2); chan = chan_lookup(conn, cid, out); - if (chan) - chan->num++; if (cid == 1) l2cap_sig(conn, out, data + 4, size - 4); break; } if (out) { - struct timeval *last_tx; - - conn->tx_num++; - last_tx = new0(struct timeval, 1); - memcpy(last_tx, tv, sizeof(*tv)); - queue_push_tail(conn->tx_queue, last_tx); - conn->tx_bytes += size; - - if (!conn->tx_pkt_min || size < conn->tx_pkt_min) - conn->tx_pkt_min = size; - if (!conn->tx_pkt_max || size > conn->tx_pkt_max) - conn->tx_pkt_max = size; + conn_pkt_tx(conn, tv, size, chan); } else { - conn->rx_num++; + conn_pkt_rx(conn, tv, size, chan); } } -static void sco_pkt(struct timeval *tv, uint16_t index, +static void sco_pkt(struct timeval *tv, uint16_t index, bool out, const void *data, uint16_t size) { + const struct bt_hci_acl_hdr *hdr = data; struct hci_dev *dev; + struct hci_conn *conn; dev = dev_lookup(index); if (!dev) @@ -614,6 +926,17 @@ static void sco_pkt(struct timeval *tv, uint16_t index, dev->num_hci++; dev->num_sco++; + + conn = conn_lookup_type(dev, le16_to_cpu(hdr->handle) & 0x0fff, + CONN_BR_SCO); + if (!conn) + return; + + if (out) { + conn_pkt_tx(conn, tv, size - sizeof(*hdr), NULL); + } else { + conn_pkt_rx(conn, tv, size - sizeof(*hdr), NULL); + } } static void info_index(struct timeval *tv, uint16_t index, @@ -677,9 +1000,11 @@ static void ctrl_msg(struct timeval *tv, uint16_t index, dev->ctrl_msg++; } -static void iso_pkt(struct timeval *tv, uint16_t index, +static void iso_pkt(struct timeval *tv, uint16_t index, bool out, const void *data, uint16_t size) { + const struct bt_hci_iso_hdr *hdr = data; + struct hci_conn *conn; struct hci_dev *dev; dev = dev_lookup(index); @@ -688,6 +1013,17 @@ static void iso_pkt(struct timeval *tv, uint16_t index, dev->num_hci++; dev->num_iso++; + + conn = conn_lookup_type(dev, le16_to_cpu(hdr->handle) & 0x0fff, + CONN_LE_ISO); + if (!conn) + return; + + if (out) { + conn_pkt_tx(conn, tv, size - sizeof(*hdr), NULL); + } else { + conn_pkt_rx(conn, tv, size - sizeof(*hdr), NULL); + } } static void unknown_opcode(struct timeval *tv, uint16_t index, @@ -755,8 +1091,10 @@ void analyze_trace(const char *path) acl_pkt(&tv, index, false, buf, pktlen); break; case BTSNOOP_OPCODE_SCO_TX_PKT: + sco_pkt(&tv, index, true, buf, pktlen); + break; case BTSNOOP_OPCODE_SCO_RX_PKT: - sco_pkt(&tv, index, buf, pktlen); + sco_pkt(&tv, index, false, buf, pktlen); break; case BTSNOOP_OPCODE_OPEN_INDEX: case BTSNOOP_OPCODE_CLOSE_INDEX: @@ -780,8 +1118,10 @@ void analyze_trace(const char *path) ctrl_msg(&tv, index, buf, pktlen); break; case BTSNOOP_OPCODE_ISO_TX_PKT: + iso_pkt(&tv, index, true, buf, pktlen); + break; case BTSNOOP_OPCODE_ISO_RX_PKT: - iso_pkt(&tv, index, buf, pktlen); + iso_pkt(&tv, index, false, buf, pktlen); break; default: unknown_opcode(&tv, index, buf, pktlen); diff --git a/monitor/att.c b/monitor/att.c index efd840d519612c9b47f1230b868a63c7d8c3004c..3f41c2bd096fcd0372ad06928308b4e9cdc27da5 100644 --- a/monitor/att.c +++ b/monitor/att.c @@ -5,6 +5,7 @@ * * Copyright (C) 2011-2014 Intel Corporation * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org> + * Copyright 2023 NXP * * */ @@ -21,7 +22,7 @@ #include <inttypes.h> #include <stdbool.h> #include <errno.h> -#include <linux/limits.h> +#include <limits.h> #include <sys/stat.h> #include <glib.h> @@ -42,12 +43,15 @@ #include "display.h" #include "l2cap.h" #include "att.h" +#include "keys.h" struct att_read { + struct att_conn_data *conn; struct gatt_db_attribute *attr; bool in; uint16_t chan; void (*func)(const struct l2cap_frame *frame); + struct iovec *iov; }; struct att_conn_data { @@ -56,6 +60,7 @@ struct att_conn_data { struct gatt_db *rdb; struct timespec rdb_mtim; struct queue *reads; + uint16_t mtu; }; static void print_uuid(const char *label, const void *data, uint16_t size) @@ -106,27 +111,127 @@ static bool match_read_frame(const void *data, const void *match_data) return read->chan == frame->chan; } -static void print_data_list(const char *label, uint8_t length, - const struct l2cap_frame *frame) +static struct att_read *att_get_read(const struct l2cap_frame *frame) { struct packet_conn_data *conn; struct att_conn_data *data; + + conn = packet_get_conn_data(frame->handle); + if (!conn) + return NULL; + + data = conn->data; + if (!data) + return NULL; + + return queue_remove_if(data->reads, match_read_frame, (void *)frame); +} + +static void print_value(struct gatt_db_attribute *attr) +{ + uint16_t handle; + struct gatt_db_attribute *val; + const bt_uuid_t *uuid; + bt_uuid_t chrc = { + .type = BT_UUID16, + .value.u16 = 0x2803, + }; + char label[27]; + + uuid = gatt_db_attribute_get_type(attr); + if (!uuid) + return; + + /* Skip in case of characteristic declaration since it already prints + * the value handle and properties. + */ + if (!bt_uuid_cmp(uuid, &chrc)) + return; + + val = gatt_db_attribute_get_value(attr); + if (!val || val == attr) + return; + + uuid = gatt_db_attribute_get_type(val); + if (!uuid) + return; + + handle = gatt_db_attribute_get_handle(val); + if (!handle) + return; + + switch (uuid->type) { + case BT_UUID16: + sprintf(label, "Value Handle: 0x%4.4x Type", handle); + print_field("%s: %s (0x%4.4x)", label, + bt_uuid16_to_str(uuid->value.u16), + uuid->value.u16); + return; + case BT_UUID128: + sprintf(label, "Value Handle: 0x%4.4x Type", handle); + print_uuid(label, &uuid->value.u128, 16); + return; + case BT_UUID_UNSPEC: + case BT_UUID32: + break; + } +} + +static void print_attribute(struct gatt_db_attribute *attr) +{ + uint16_t handle; + const bt_uuid_t *uuid; + char label[21]; + + handle = gatt_db_attribute_get_handle(attr); + if (!handle) + goto done; + + uuid = gatt_db_attribute_get_type(attr); + if (!uuid) + goto done; + + switch (uuid->type) { + case BT_UUID16: + sprintf(label, "Handle: 0x%4.4x Type", handle); + print_field("%s: %s (0x%4.4x)", label, + bt_uuid16_to_str(uuid->value.u16), + uuid->value.u16); + print_value(attr); + return; + case BT_UUID128: + sprintf(label, "Handle: 0x%4.4x Type", handle); + print_uuid(label, &uuid->value.u128, 16); + print_value(attr); + return; + case BT_UUID_UNSPEC: + case BT_UUID32: + break; + } + +done: + print_field("Handle: 0x%4.4x", handle); +} + +static void att_read_free(struct att_read *read) +{ + if (!read) + return; + + util_iov_free(read->iov, 1); + free(read); +} + +static void print_data_list(const char *label, uint8_t length, + const struct l2cap_frame *frame) +{ struct att_read *read; uint8_t count; if (length == 0) return; - conn = packet_get_conn_data(frame->handle); - if (conn) { - data = conn->data; - if (data) - read = queue_remove_if(data->reads, match_read_frame, - (void *)frame); - else - read = NULL; - } else - read = NULL; + read = att_get_read(frame); count = frame->size / length; @@ -138,7 +243,7 @@ static void print_data_list(const char *label, uint8_t length, print_hex_field("Value", frame->data, length - 2); - if (read) { + if (read && read->func) { struct l2cap_frame f; l2cap_frame_clone_size(&f, frame, length - 2); @@ -151,7 +256,7 @@ static void print_data_list(const char *label, uint8_t length, } packet_hexdump(frame->data, frame->size); - free(read); + att_read_free(read); } static void print_attribute_info(uint16_t type, const void *data, uint16_t len) @@ -271,6 +376,13 @@ static void att_error_response(const struct l2cap_frame *frame) pdu->request); print_field("Handle: 0x%4.4x", le16_to_cpu(pdu->handle)); print_field("Error: %s (0x%2.2x)", str, pdu->error); + + /* Read/Read By Type/Read By Group Type may create a read object which + * needs to be dequeued and freed in case the operation fails. + */ + if (pdu->request == 0x08 || pdu->request == 0x0a || + pdu->request == 0x10) + att_read_free(att_get_read(frame)); } static const struct bitfield_data chrc_prop_table[] = { @@ -285,10 +397,203 @@ static const struct bitfield_data chrc_prop_table[] = { { } }; +static void att_conn_data_free(void *data) +{ + struct att_conn_data *att_data = data; + + gatt_db_unref(att_data->rdb); + gatt_db_unref(att_data->ldb); + queue_destroy(att_data->reads, free); + free(att_data); +} + +static struct att_conn_data *att_get_conn_data(struct packet_conn_data *conn) +{ + struct att_conn_data *data; + + if (!conn) + return NULL; + + data = conn->data; + + if (data) + return data; + + data = new0(struct att_conn_data, 1); + data->rdb = gatt_db_new(); + data->ldb = gatt_db_new(); + conn->data = data; + conn->destroy = att_conn_data_free; + + return data; +} + +static void gatt_load_db(struct gatt_db *db, const char *filename, + struct timespec *mtim) +{ + struct stat st; + + if (lstat(filename, &st)) + return; + + if (!gatt_db_isempty(db)) { + /* Check if file has been modified since last time */ + if (st.st_mtim.tv_sec == mtim->tv_sec && + st.st_mtim.tv_nsec == mtim->tv_nsec) + return; + /* Clear db before reloading */ + gatt_db_clear(db); + } + + *mtim = st.st_mtim; + + btd_settings_gatt_db_load(db, filename); +} + +static void load_gatt_db(struct packet_conn_data *conn) +{ + struct att_conn_data *data = att_get_conn_data(conn); + char filename[PATH_MAX]; + char local[18]; + char peer[18]; + uint8_t id[6], id_type; + + ba2str((bdaddr_t *)conn->src, local); + + if (keys_resolve_identity(conn->dst, id, &id_type)) + ba2str((bdaddr_t *)id, peer); + else + ba2str((bdaddr_t *)conn->dst, peer); + + create_filename(filename, PATH_MAX, "/%s/attributes", local); + gatt_load_db(data->ldb, filename, &data->ldb_mtim); + + create_filename(filename, PATH_MAX, "/%s/cache/%s", local, peer); + gatt_load_db(data->rdb, filename, &data->rdb_mtim); +} + +static struct gatt_db *get_db(const struct l2cap_frame *frame, bool rsp) +{ + struct packet_conn_data *conn; + struct att_conn_data *data; + struct gatt_db *db; + + conn = packet_get_conn_data(frame->handle); + if (!conn) + return NULL; + + /* Try loading local and remote gatt_db if not loaded yet */ + load_gatt_db(conn); + + data = conn->data; + if (!data) + return NULL; + + if (frame->in) { + if (rsp) + db = data->rdb; + else + db = data->ldb; + } else { + if (rsp) + db = data->ldb; + else + db = data->rdb; + } + + return db; +} + +static struct gatt_db_attribute *insert_chrc(const struct l2cap_frame *frame, + uint16_t handle, + uint16_t value_handle, + bt_uuid_t *uuid, uint8_t prop, + bool rsp) +{ + struct gatt_db *db; + + db = get_db(frame, rsp); + if (!db) + return NULL; + + return gatt_db_insert_characteristic(db, handle, value_handle, uuid, 0, + prop, NULL, NULL, NULL); +} + +static int bt_uuid_from_data(bt_uuid_t *uuid, const void *data, uint16_t size) +{ + uint128_t u128; + + if (!uuid) + return -EINVAL; + + switch (size) { + case 2: + return bt_uuid16_create(uuid, get_le16(data)); + case 4: + return bt_uuid32_create(uuid, get_le32(data)); + case 16: + memcpy(u128.data, data, sizeof(u128.data)); + return bt_uuid128_create(uuid, u128); + } + + return -EINVAL; +} + +static bool svc_read(const struct l2cap_frame *frame, uint16_t *start, + uint16_t *end, bt_uuid_t *uuid) +{ + if (!l2cap_frame_get_le16((void *)frame, start)) + return false; + + if (!l2cap_frame_get_le16((void *)frame, end)) + return false; + + return !bt_uuid_from_data(uuid, frame->data, frame->size); +} + +static struct gatt_db_attribute *insert_svc(const struct l2cap_frame *frame, + uint16_t handle, + bt_uuid_t *uuid, bool primary, + bool rsp, uint16_t num_handles) +{ + struct gatt_db *db; + + db = get_db(frame, rsp); + if (!db) + return NULL; + + return gatt_db_insert_service(db, handle, uuid, primary, num_handles); +} + +static void pri_svc_read(const struct l2cap_frame *frame) +{ + uint16_t start, end; + bt_uuid_t uuid; + + if (!svc_read(frame, &start, &end, &uuid)) + return; + + insert_svc(frame, start, &uuid, true, true, end - start + 1); +} + +static void sec_svc_read(const struct l2cap_frame *frame) +{ + uint16_t start, end; + bt_uuid_t uuid; + + if (!svc_read(frame, &start, &end, &uuid)) + return; + + insert_svc(frame, start, &uuid, true, false, end - start + 1); +} + static void print_chrc(const struct l2cap_frame *frame) { uint8_t prop; uint8_t mask; + uint16_t handle; + bt_uuid_t uuid; if (!l2cap_frame_get_u8((void *)frame, &prop)) { print_text(COLOR_ERROR, "Property: invalid size"); @@ -302,10 +607,16 @@ static void print_chrc(const struct l2cap_frame *frame) print_text(COLOR_WHITE_BG, " Unknown fields (0x%2.2x)", mask); - if (!l2cap_frame_print_le16((void *)frame, " Value Handle")) + if (!l2cap_frame_get_le16((void *)frame, &handle)) { + print_text(COLOR_ERROR, " Value Handle: invalid size"); return; + } + print_field(" Value Handle: 0x%4.4x", handle); print_uuid(" Value UUID", frame->data, frame->size); + bt_uuid_from_data(&uuid, frame->data, frame->size); + + insert_chrc(frame, handle - 1, handle, &uuid, prop, true); } static void chrc_read(const struct l2cap_frame *frame) @@ -377,12 +688,20 @@ static bool print_ase_codec(const struct l2cap_frame *frame) return true; } -static bool print_ase_lv(const struct l2cap_frame *frame, const char *label, - struct packet_ltv_decoder *decoder, size_t decoder_len) +static void print_ltv(const char *str, void *user_data) { - struct bt_hci_lv_data *lv; + const char *label = user_data; - lv = l2cap_frame_pull((void *)frame, frame, sizeof(*lv)); + print_field("%s: %s", label, str); +} + +static bool print_ase_lv(const struct l2cap_frame *frame, const char *label, + const struct util_ltv_debugger *decoder, + size_t decoder_len) +{ + struct bt_hci_lv_data *lv; + + lv = l2cap_frame_pull((void *)frame, frame, sizeof(*lv)); if (!lv) { print_text(COLOR_ERROR, "%s: invalid size", label); return false; @@ -393,13 +712,15 @@ static bool print_ase_lv(const struct l2cap_frame *frame, const char *label, return false; } - packet_print_ltv(label, lv->data, lv->len, decoder, decoder_len); + util_debug_ltv(lv->data, lv->len, decoder, decoder_len, print_ltv, + (void *) label); return true; } static bool print_ase_cc(const struct l2cap_frame *frame, const char *label, - struct packet_ltv_decoder *decoder, size_t decoder_len) + const struct util_ltv_debugger *decoder, + size_t decoder_len) { return print_ase_lv(frame, label, decoder, decoder_len); } @@ -446,7 +767,8 @@ done: print_hex_field(" Data", frame->data, frame->size); } -static void ase_decode_preferred_context(const uint8_t *data, uint8_t len) +static void ase_debug_preferred_context(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) { struct l2cap_frame frame; @@ -455,7 +777,8 @@ static void ase_decode_preferred_context(const uint8_t *data, uint8_t len) print_context(&frame, " Preferred Context"); } -static void ase_decode_context(const uint8_t *data, uint8_t len) +static void ase_debug_context(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) { struct l2cap_frame frame; @@ -464,7 +787,8 @@ static void ase_decode_context(const uint8_t *data, uint8_t len) print_context(&frame, " Context"); } -static void ase_decode_program_info(const uint8_t *data, uint8_t len) +static void ase_debug_program_info(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) { struct l2cap_frame frame; const char *str; @@ -484,7 +808,8 @@ done: print_hex_field(" Data", frame.data, frame.size); } -static void ase_decode_language(const uint8_t *data, uint8_t len) +static void ase_debug_language(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) { struct l2cap_frame frame; uint32_t value; @@ -503,16 +828,17 @@ done: print_hex_field(" Data", frame.data, frame.size); } -struct packet_ltv_decoder ase_metadata_table[] = { - LTV_DEC(0x01, ase_decode_preferred_context), - LTV_DEC(0x02, ase_decode_context), - LTV_DEC(0x03, ase_decode_program_info), - LTV_DEC(0x04, ase_decode_language) +static const struct util_ltv_debugger ase_metadata_table[] = { + UTIL_LTV_DEBUG(0x01, ase_debug_preferred_context), + UTIL_LTV_DEBUG(0x02, ase_debug_context), + UTIL_LTV_DEBUG(0x03, ase_debug_program_info), + UTIL_LTV_DEBUG(0x04, ase_debug_language) }; static bool print_ase_metadata(const struct l2cap_frame *frame) { - return print_ase_lv(frame, " Metadata", NULL, 0); + return print_ase_lv(frame, " Metadata", ase_metadata_table, + ARRAY_SIZE(ase_metadata_table)); } static const struct bitfield_data pac_freq_table[] = { @@ -535,7 +861,8 @@ static const struct bitfield_data pac_freq_table[] = { { } }; -static void pac_decode_freq(const uint8_t *data, uint8_t len) +static void pac_decode_freq(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) { struct l2cap_frame frame; uint16_t value; @@ -572,7 +899,8 @@ static const struct bitfield_data pac_duration_table[] = { { } }; -static void pac_decode_duration(const uint8_t *data, uint8_t len) +static void pac_decode_duration(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) { struct l2cap_frame frame; uint8_t value; @@ -609,7 +937,8 @@ static const struct bitfield_data pac_channel_table[] = { { } }; -static void pac_decode_channels(const uint8_t *data, uint8_t len) +static void pac_decode_channels(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) { struct l2cap_frame frame; uint8_t value; @@ -634,7 +963,8 @@ done: print_hex_field(" Data", frame.data, frame.size); } -static void pac_decode_frame_length(const uint8_t *data, uint8_t len) +static void pac_decode_frame_length(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) { struct l2cap_frame frame; uint16_t min, max; @@ -659,7 +989,8 @@ done: print_hex_field(" Data", frame.data, frame.size); } -static void pac_decode_sdu(const uint8_t *data, uint8_t len) +static void pac_decode_sdu(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) { struct l2cap_frame frame; uint8_t value; @@ -678,12 +1009,12 @@ done: print_hex_field(" Data", frame.data, frame.size); } -struct packet_ltv_decoder pac_cap_table[] = { - LTV_DEC(0x01, pac_decode_freq), - LTV_DEC(0x02, pac_decode_duration), - LTV_DEC(0x03, pac_decode_channels), - LTV_DEC(0x04, pac_decode_frame_length), - LTV_DEC(0x05, pac_decode_sdu) +static const struct util_ltv_debugger pac_cap_table[] = { + UTIL_LTV_DEBUG(0x01, pac_decode_freq), + UTIL_LTV_DEBUG(0x02, pac_decode_duration), + UTIL_LTV_DEBUG(0x03, pac_decode_channels), + UTIL_LTV_DEBUG(0x04, pac_decode_frame_length), + UTIL_LTV_DEBUG(0x05, pac_decode_sdu) }; static void print_pac(const struct l2cap_frame *frame) @@ -819,7 +1150,8 @@ static bool print_ase_pd(const struct l2cap_frame *frame, const char *label) return true; } -static void ase_decode_freq(const uint8_t *data, uint8_t len) +static void ase_debug_freq(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) { struct l2cap_frame frame; uint8_t value; @@ -845,31 +1177,31 @@ static void ase_decode_freq(const uint8_t *data, uint8_t len) print_field(" Sampling Frequency: 22.05 Khz (0x04)"); break; case 0x05: - print_field(" Sampling Frequency: 24 Khz (0x04)"); + print_field(" Sampling Frequency: 24 Khz (0x05)"); break; case 0x06: - print_field(" Sampling Frequency: 32 Khz (0x04)"); + print_field(" Sampling Frequency: 32 Khz (0x06)"); break; case 0x07: - print_field(" Sampling Frequency: 44.1 Khz (0x04)"); + print_field(" Sampling Frequency: 44.1 Khz (0x07)"); break; case 0x08: - print_field(" Sampling Frequency: 48 Khz (0x04)"); + print_field(" Sampling Frequency: 48 Khz (0x08)"); break; case 0x09: - print_field(" Sampling Frequency: 88.2 Khz (0x04)"); + print_field(" Sampling Frequency: 88.2 Khz (0x09)"); break; case 0x0a: - print_field(" Sampling Frequency: 96 Khz (0x04)"); + print_field(" Sampling Frequency: 96 Khz (0x0a)"); break; case 0x0b: - print_field(" Sampling Frequency: 176.4 Khz (0x04)"); + print_field(" Sampling Frequency: 176.4 Khz (0x0b)"); break; case 0x0c: - print_field(" Sampling Frequency: 192 Khz (0x04)"); + print_field(" Sampling Frequency: 192 Khz (0x0c)"); break; case 0x0d: - print_field(" Sampling Frequency: 384 Khz (0x04)"); + print_field(" Sampling Frequency: 384 Khz (0x0d)"); break; default: print_field(" Sampling Frequency: RFU (0x%2.2x)", value); @@ -881,7 +1213,8 @@ done: print_hex_field(" Data", frame.data, frame.size); } -static void ase_decode_duration(const uint8_t *data, uint8_t len) +static void ase_debug_duration(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) { struct l2cap_frame frame; uint8_t value; @@ -968,7 +1301,8 @@ done: print_hex_field(" Data", frame->data, frame->size); } -static void ase_decode_location(const uint8_t *data, uint8_t len) +static void ase_debug_location(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) { struct l2cap_frame frame; @@ -977,7 +1311,8 @@ static void ase_decode_location(const uint8_t *data, uint8_t len) print_location(&frame); } -static void ase_decode_frame_length(const uint8_t *data, uint8_t len) +static void ase_debug_frame_length(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) { struct l2cap_frame frame; uint16_t value; @@ -996,7 +1331,8 @@ done: print_hex_field(" Data", frame.data, frame.size); } -static void ase_decode_blocks(const uint8_t *data, uint8_t len) +static void ase_debug_blocks(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) { struct l2cap_frame frame; uint8_t value; @@ -1015,12 +1351,12 @@ done: print_hex_field(" Data", frame.data, frame.size); } -struct packet_ltv_decoder ase_cc_table[] = { - LTV_DEC(0x01, ase_decode_freq), - LTV_DEC(0x02, ase_decode_duration), - LTV_DEC(0x03, ase_decode_location), - LTV_DEC(0x04, ase_decode_frame_length), - LTV_DEC(0x05, ase_decode_blocks) +static const struct util_ltv_debugger ase_cc_table[] = { + UTIL_LTV_DEBUG(0x01, ase_debug_freq), + UTIL_LTV_DEBUG(0x02, ase_debug_duration), + UTIL_LTV_DEBUG(0x03, ase_debug_location), + UTIL_LTV_DEBUG(0x04, ase_debug_frame_length), + UTIL_LTV_DEBUG(0x05, ase_debug_blocks) }; static void print_ase_config(const struct l2cap_frame *frame) @@ -1389,7 +1725,7 @@ static bool ase_release_cmd(const struct l2cap_frame *frame) .func = _func, \ } -struct ase_cmd { +static const struct ase_cmd { const char *desc; bool (*func)(const struct l2cap_frame *frame); } ase_cmd_table[] = { @@ -1411,7 +1747,7 @@ struct ase_cmd { ASE_CMD(0x08, "Release", ase_release_cmd), }; -static struct ase_cmd *ase_get_cmd(uint8_t op) +static const struct ase_cmd *ase_get_cmd(uint8_t op) { if (op > ARRAY_SIZE(ase_cmd_table)) return NULL; @@ -1422,7 +1758,7 @@ static struct ase_cmd *ase_get_cmd(uint8_t op) static void print_ase_cmd(const struct l2cap_frame *frame) { uint8_t op, num, i; - struct ase_cmd *cmd; + const struct ase_cmd *cmd; if (!l2cap_frame_get_u8((void *)frame, &op)) { print_text(COLOR_ERROR, "opcode: invalid size"); @@ -1590,7 +1926,7 @@ static bool print_ase_cp_rsp_reason(const struct l2cap_frame *frame) static void print_ase_cp_rsp(const struct l2cap_frame *frame) { uint8_t op, num, i; - struct ase_cmd *cmd; + const struct ase_cmd *cmd; if (!l2cap_frame_get_u8((void *)frame, &op)) { print_text(COLOR_ERROR, " opcode: invalid size"); @@ -1688,6 +2024,85 @@ static void pac_context_notify(const struct l2cap_frame *frame) print_pac_context(frame); } +static void csip_rank_read(const struct l2cap_frame *frame) +{ + uint8_t rank; + + if (!l2cap_frame_get_u8((void *)frame, &rank)) { + print_text(COLOR_ERROR, "Rank: invalid size"); + goto done; + } + + print_field(" Rank: 0x%02x", rank); + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void csip_lock_read(const struct l2cap_frame *frame) +{ + uint8_t lock; + + if (!l2cap_frame_get_u8((void *)frame, &lock)) { + print_text(COLOR_ERROR, "Lock: invalid size"); + goto done; + } + + switch (lock) { + case 0x01: + print_field(" Unlocked (0x%02x)", lock); + break; + case 0x02: + print_field(" Locked (0x%02x)", lock); + break; + default: + print_field(" RFU (0x%02x)", lock); + break; + } + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void print_csip_size(const struct l2cap_frame *frame) +{ + uint8_t size; + + if (!l2cap_frame_get_u8((void *)frame, &size)) { + print_text(COLOR_ERROR, "Size: invalid size"); + goto done; + } + print_field(" Size: 0x%02x", size); + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void csip_size_read(const struct l2cap_frame *frame) +{ + print_csip_size(frame); +} + +static void csip_size_notify(const struct l2cap_frame *frame) +{ + print_csip_size(frame); +} + +static void csip_sirk_read(const struct l2cap_frame *frame) +{ + if (frame->size) + print_hex_field(" SIRK", frame->data, frame->size); +} + +static void csip_sirk_notify(const struct l2cap_frame *frame) +{ + if (frame->size) + print_hex_field(" SIRK", frame->data, frame->size); +} + static void print_vcs_state(const struct l2cap_frame *frame) { uint8_t vol_set, mute, chng_ctr; @@ -1761,7 +2176,7 @@ static bool vcs_absolute_cmd(const struct l2cap_frame *frame) .func = _func, \ } -struct vcs_cmd { +static const struct vcs_cmd { const char *desc; bool (*func)(const struct l2cap_frame *frame); } vcs_cmd_table[] = { @@ -1781,7 +2196,7 @@ struct vcs_cmd { VCS_CMD(0x06, "Mute", vcs_config_cmd), }; -static struct vcs_cmd *vcs_get_cmd(uint8_t op) +static const struct vcs_cmd *vcs_get_cmd(uint8_t op) { if (op > ARRAY_SIZE(vcs_cmd_table)) return NULL; @@ -1792,7 +2207,7 @@ static struct vcs_cmd *vcs_get_cmd(uint8_t op) static void print_vcs_cmd(const struct l2cap_frame *frame) { uint8_t op; - struct vcs_cmd *cmd; + const struct vcs_cmd *cmd; if (!l2cap_frame_get_u8((void *)frame, &op)) { print_text(COLOR_ERROR, "opcode: invalid size"); @@ -1876,6 +2291,8 @@ static void print_mp_name(const struct l2cap_frame *frame) name = name2utf8((uint8_t *)frame->data, frame->size); print_field(" Media Player Name: %s", name); + + g_free(name); } static void mp_name_read(const struct l2cap_frame *frame) @@ -1905,6 +2322,8 @@ static void print_track_title(const struct l2cap_frame *frame) name = name2utf8((uint8_t *)frame->data, frame->size); print_field(" Track Title: %s", name); + + g_free(name); } static void track_title_read(const struct l2cap_frame *frame) @@ -2031,227 +2450,889 @@ static void seeking_speed_notify(const struct l2cap_frame *frame) print_seeking_speed(frame); } -static const char *play_order_str(uint8_t order) +static void print_bearer_name(const struct l2cap_frame *frame) { - switch (order) { + char *name; + + name = name2utf8((uint8_t *)frame->data, frame->size); + + print_field(" Bearer Name: %s", name); + + g_free(name); +} + +static void bearer_name_read(const struct l2cap_frame *frame) +{ + print_bearer_name(frame); +} + +static void bearer_name_notify(const struct l2cap_frame *frame) +{ + print_bearer_name(frame); +} + +static void bearer_uci_read(const struct l2cap_frame *frame) +{ + char *name; + + name = name2utf8((uint8_t *)frame->data, frame->size); + + print_field(" Bearer Uci Name: %s", name); + + g_free(name); +} + +static void print_technology_name(const struct l2cap_frame *frame) +{ + int8_t tech_id; + const char *str; + + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&tech_id)) { + print_text(COLOR_ERROR, " Technology id:: invalid size"); + goto done; + } + + switch (tech_id) { case 0x01: - return "Single once"; + str = "3G"; + break; case 0x02: - return "Single repeat"; + str = "4G"; + break; case 0x03: - return "In order once"; + str = "LTE"; + break; case 0x04: - return "In order repeat"; + str = "WiFi"; + break; case 0x05: - return "Oldest once"; + str = "5G"; + break; case 0x06: - return "Oldest repeat"; + str = "GSM"; + break; case 0x07: - return "Newest once"; + str = "CDMA"; + break; case 0x08: - return "Newest repeat"; + str = "2G"; + break; case 0x09: - return "Shuffle once"; - case 0x0A: - return "Shuffle repeat"; + str = "WCDMA"; + break; default: - return "RFU"; - } -} - -static void print_playing_order(const struct l2cap_frame *frame) -{ - int8_t playing_order; - - if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&playing_order)) { - print_text(COLOR_ERROR, " Playing Order: invalid size"); - goto done; + str = "Reserved"; + break; } - print_field(" Playing Order: %s", play_order_str(playing_order)); + print_field("Technology: %s (0x%2.2x)", str, tech_id); done: if (frame->size) print_hex_field(" Data", frame->data, frame->size); } -static void playing_order_read(const struct l2cap_frame *frame) +static void bearer_technology_read(const struct l2cap_frame *frame) { - print_playing_order(frame); + print_technology_name(frame); } -static void playing_order_write(const struct l2cap_frame *frame) +static void bearer_technology_notify(const struct l2cap_frame *frame) { - print_playing_order(frame); + print_technology_name(frame); } -static void playing_order_notify(const struct l2cap_frame *frame) +static void print_uri_scheme_list(const struct l2cap_frame *frame) { - print_playing_order(frame); + char *name; + + name = name2utf8((uint8_t *)frame->data, frame->size); + + print_field(" Uri scheme Name: %s", name); + + g_free(name); } -static const struct bitfield_data playing_orders_table[] = { - { 0, "Single once (0x0001)" }, - { 1, "Single repeat (0x0002)" }, - { 2, "In order once (0x0004)" }, - { 3, "In Order Repeat (0x0008)" }, - { 4, "Oldest once (0x0010)" }, - { 5, "Oldest repeat (0x0020)" }, - { 6, "Newest once (0x0040)" }, - { 7, "Newest repeat (0x0080)" }, - { 8, "Shuffle once (0x0100)" }, - { 9, "Shuffle repeat (0x0200)" }, - { 10, "RFU (0x0400)" }, - { 11, "RFU (0x0800)" }, - { 12, "RFU (0x1000)" }, - { 13, "RFU (0x2000)" }, - { 14, "RFU (0x4000)" }, - { 15, "RFU (0x8000)" }, - { } -}; +static void bearer_uri_schemes_list_read(const struct l2cap_frame *frame) +{ + print_uri_scheme_list(frame); +} -static void print_playing_orders_supported(const struct l2cap_frame *frame) +static void print_signal_strength(const struct l2cap_frame *frame) { - uint16_t supported_orders; - uint16_t mask; + uint8_t signal_strength; - if (!l2cap_frame_get_le16((void *)frame, &supported_orders)) { - print_text(COLOR_ERROR, - " Supported Playing Orders: invalid size"); + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&signal_strength)) { + print_text(COLOR_ERROR, " signal_strength:: invalid size"); goto done; } - print_field(" Supported Playing Orders: 0x%4.4x", - supported_orders); + print_field(" signal_strength: %x", signal_strength); - mask = print_bitfield(8, supported_orders, playing_orders_table); - if (mask) - print_text(COLOR_WHITE_BG, " Unknown fields (0x%4.4x)", - mask); + if (signal_strength == 0) + print_field(" No Service"); + else if (signal_strength == 0x64) + print_field(" Maximum signal strength"); + else if ((signal_strength > 0) && (signal_strength < 0x64)) + print_field(" Implementation specific"); + else if (signal_strength == 0xFF) + print_field(" Signal strength is unavailable"); + else + print_field(" RFU"); done: if (frame->size) - print_hex_field(" Data", frame->data, frame->size); + print_hex_field(" Data", frame->data, frame->size); } -static void playing_orders_supported_read(const struct l2cap_frame *frame) +static void bearer_signal_strength_read(const struct l2cap_frame *frame) { - print_playing_orders_supported(frame); + print_signal_strength(frame); } -static const char *media_state_str(uint8_t state) +static void bearer_signal_strength_notify(const struct l2cap_frame *frame) { - switch (state) { - case 0x00: - return "Inactive"; - case 0x01: - return "Playing"; - case 0x02: - return "Paused"; - case 0x03: - return "Seeking"; - default: - return "RFU"; - } + print_signal_strength(frame); } -static void print_media_state(const struct l2cap_frame *frame) +static void +print_signal_strength_rep_intrvl(const struct l2cap_frame *frame) { - int8_t state; + int8_t reporting_intrvl; - if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&state)) { - print_text(COLOR_ERROR, " Media State: invalid size"); + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&reporting_intrvl)) { + print_text(COLOR_ERROR, "Reporting_interval:: invalid size"); goto done; } - print_field(" Media State: %s", media_state_str(state)); + print_field(" Reporting_interval: 0x%x", reporting_intrvl); done: if (frame->size) print_hex_field(" Data", frame->data, frame->size); } -static void media_state_read(const struct l2cap_frame *frame) +static void +bearer_signal_strength_rep_intrvl_read(const struct l2cap_frame *frame) { - print_media_state(frame); + print_signal_strength_rep_intrvl(frame); } -static void media_state_notify(const struct l2cap_frame *frame) +static void +bearer_signal_strength_rep_intrvl_write(const struct l2cap_frame *frame) { - print_media_state(frame); + print_signal_strength_rep_intrvl(frame); } -struct media_cp_opcode { - uint8_t opcode; - const char *opcode_str; -} media_cp_opcode_table[] = { - {0x01, "Play"}, - {0x02, "Pause"}, - {0x03, "Fast Rewind"}, - {0x04, "Fast Forward"}, - {0x05, "Stop"}, - {0x10, "Move Relative"}, - {0x20, "Previous Segment"}, - {0x21, "Next Segment"}, - {0x22, "First Segment"}, - {0x23, "Last Segment"}, - {0x24, "Goto Segment"}, - {0x30, "Previous Track"}, - {0x31, "Next Track"}, - {0x32, "First Track"}, - {0x33, "Last Track"}, - {0x34, "Goto Track"}, - {0x40, "Previous Group"}, - {0x41, "Next Group"}, - {0x42, "First Group"}, - {0x43, "Last Group"}, - {0x44, "Goto Group"}, -}; - -static const char *cp_opcode_str(uint8_t opcode) +static void print_call_list(const struct l2cap_frame *frame) { - size_t i; + uint8_t list_item_length; + uint8_t call_index; + uint8_t call_state; + uint8_t call_flag; + char *call_uri; - for (i = 0; i < ARRAY_SIZE(media_cp_opcode_table); i++) { - const char *str = media_cp_opcode_table[i].opcode_str; + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&list_item_length)) { + print_text(COLOR_ERROR, " list_item_length:: invalid size"); + goto done; + } - if (opcode == media_cp_opcode_table[i].opcode) - return str; + print_field(" list_item_length: 0x%x", list_item_length); + + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&call_index)) { + print_text(COLOR_ERROR, " call_index:: invalid size"); + goto done; } - return "RFU"; -} + print_field(" call_index: 0x%x", call_index); -static void print_media_cp(const struct l2cap_frame *frame) -{ - int8_t opcode; + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&call_state)) { + print_text(COLOR_ERROR, " call_state:: invalid size"); + goto done; + } - if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&opcode)) { - print_text(COLOR_ERROR, " Media Control Point: invalid size"); + print_field(" call_state: 0x%x", call_state); + + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&call_flag)) { + print_text(COLOR_ERROR, " call_flag:: invalid size"); goto done; } - print_field(" Media Control Point: %s", cp_opcode_str(opcode)); + print_field(" call_flag: 0x%x", call_flag); + + call_uri = name2utf8((uint8_t *)frame->data, frame->size); + + print_field(" call_uri: %s", call_uri); + + g_free(call_uri); done: if (frame->size) - print_hex_field(" Data", frame->data, frame->size); + print_hex_field(" call_list Data", frame->data, frame->size); } -static void media_cp_write(const struct l2cap_frame *frame) +static void bearer_current_call_list_read(const struct l2cap_frame *frame) { - print_media_cp(frame); + print_call_list(frame); } -static void media_cp_notify(const struct l2cap_frame *frame) +static void bearer_current_call_list_notify(const struct l2cap_frame *frame) { - print_media_cp(frame); + print_call_list(frame); } -static const struct bitfield_data supported_opcodes_table[] = { - {0, "Play (0x00000001)" }, - {1, "Pause (0x00000002)" }, - {2, "Fast Rewind (0x00000004)" }, +static void print_ccid(const struct l2cap_frame *frame) +{ + int8_t ccid; + + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&ccid)) { + print_text(COLOR_ERROR, " ccid:: invalid size"); + goto done; + } + + print_field(" ccid: %x", ccid); + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void call_content_control_id_read(const struct l2cap_frame *frame) +{ + print_ccid(frame); +} + +static void print_status_flag(const struct l2cap_frame *frame) +{ + int16_t flag; + + if (!l2cap_frame_get_le16((void *)frame, (uint16_t *)&flag)) { + print_text(COLOR_ERROR, " status flag:: invalid size"); + goto done; + } + + print_field(" status flag:"); + + if (flag & 0x1) + print_field(" Inband Ringtone Enabled:"); + else + print_field(" Inband Ringtone Disabled:"); + + if (flag & 0x2) + print_field(" Server in silent Mode"); + else + print_field(" Server Not in silent Mode"); + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void status_flag_read(const struct l2cap_frame *frame) +{ + print_status_flag(frame); +} + +static void status_flag_notify(const struct l2cap_frame *frame) +{ + print_status_flag(frame); +} + +static void print_target_uri(const struct l2cap_frame *frame) +{ + char *name; + uint8_t call_idx; + + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&call_idx)) { + print_text(COLOR_ERROR, " call_idx:: invalid size"); + goto done; + } + + print_field(" call_idx: %x", call_idx); + + name = name2utf8((uint8_t *)frame->data, frame->size); + + print_field(" Uri: %s", name); + + g_free(name); + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void incom_target_bearer_uri_read(const struct l2cap_frame *frame) +{ + print_target_uri(frame); +} + +static void incom_target_bearer_uri_notify(const struct l2cap_frame *frame) +{ + print_target_uri(frame); +} + +static void print_call_state(const struct l2cap_frame *frame) +{ + uint8_t call_Index; + uint8_t call_state; + uint8_t call_flag; + + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&call_Index)) { + print_text(COLOR_ERROR, " call_Index:: invalid index"); + goto done; + } + + print_field(" call_Index: 0x%2.2x", call_Index); + + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&call_state)) { + print_text(COLOR_ERROR, " call_state:: invalid state"); + goto done; + } + + print_field(" call_state: 0x%2.2x", call_state); + + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&call_flag)) { + print_text(COLOR_ERROR, " call_flag:: invalid flag"); + goto done; + } + + print_field(" call_flag: 0x%2.2x", call_flag); + +done: + if (frame->size) + print_hex_field(" call_state Data", frame->data, frame->size); +} + +static void call_state_read(const struct l2cap_frame *frame) +{ + print_call_state(frame); +} + +static void call_state_notify(const struct l2cap_frame *frame) +{ + print_call_state(frame); +} + +static void print_call_cp(const struct l2cap_frame *frame) +{ + uint8_t opcode; + uint8_t parameter; + const char *str; + char *name; + + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&opcode)) { + print_text(COLOR_ERROR, " opcode:: invalid size"); + goto done; + } + + print_field(" opcode: 0x%2.2x", opcode); + + switch (opcode) { + case 0x00: + str = "Accept"; + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)¶meter)) { + print_text(COLOR_ERROR, " parameter:: invalid size"); + goto done; + } + print_field(" Operation: %s (0x%2.2x)", str, parameter); + break; + case 0x01: + str = "Terminate"; + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)¶meter)) { + print_text(COLOR_ERROR, " parameter:: invalid size"); + goto done; + } + print_field(" Operation: %s (0x%2.2x)", str, parameter); + break; + case 0x02: + str = "Local Hold"; + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)¶meter)) { + print_text(COLOR_ERROR, " parameter:: invalid size"); + goto done; + } + print_field(" Operation: %s (0x%2.2x)", str, parameter); + break; + case 0x03: + str = "Local Retrieve"; + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)¶meter)) { + print_text(COLOR_ERROR, " parameter:: invalid size"); + goto done; + } + print_field(" Operation: %s (0x%2.2x)", str, parameter); + break; + case 0x04: + str = "Originate"; + name = name2utf8((uint8_t *)frame->data, frame->size); + print_field(" Operation: %s Uri: %s", str, name); + g_free(name); + break; + case 0x05: + str = "Join"; + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)¶meter)) { + print_text(COLOR_ERROR, " parameter:: invalid size"); + goto done; + } + print_field(" Operation: %s (0x%2.2x)", str, parameter); + break; + default: + str = "RFU"; + print_field(" Operation: %s", str); + break; + } + +done: + if (frame->size) + print_hex_field("call_cp Data", frame->data, frame->size); +} + +static void print_call_cp_notification(const struct l2cap_frame *frame) +{ + uint8_t opcode; + uint8_t result_code; + const char *str; + + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&opcode)) { + print_text(COLOR_ERROR, " result_code:: invalid opcode"); + goto done; + } + + print_field(" opcode: 0x%2.2x", opcode); + + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&result_code)) { + print_text(COLOR_ERROR, " result_code:: invalid result_code"); + goto done; + } + + print_field(" result_code: 0x%2.2x", result_code); + + switch (result_code) { + case 0x00: + str = "SUCCESS"; + break; + case 0x01: + str = "OPCODE NOT SUPPORTED"; + break; + case 0x02: + str = "OPERATION NOT POSSIBLE"; + break; + case 0x03: + str = "INVALID CALL INDEX"; + break; + case 0x04: + str = "STATE MISMATCH"; + break; + case 0x05: + str = "LACK OF RESOURCES"; + break; + case 0x06: + str = "INVALID OUTGOING URI"; + break; + default: + str = "RFU"; + break; + } + + print_field(" Status: %s", str); + +done: + if (frame->size) + print_hex_field(" call_cp Data", frame->data, frame->size); +} + +static void call_cp_write(const struct l2cap_frame *frame) +{ + print_call_cp(frame); +} + +static void call_cp_notify(const struct l2cap_frame *frame) +{ + print_call_cp_notification(frame); +} + +static void print_call_cp_opt(const struct l2cap_frame *frame) +{ + uint16_t operation; + + if (!l2cap_frame_get_le16((void *)frame, (uint16_t *)&operation)) { + print_text(COLOR_ERROR, " status operation:: invalid size"); + goto done; + } + + print_field(" operation: 0x%2x", operation); + + if (operation & 0x1) { + print_field(" Local Hold and Local Retrieve " + "Call Control Point Opcodes supported"); + } else { + print_field(" Local Hold and Local Retrieve " + "Call Control Point Opcodes not supported"); + } + + if (operation & 0x2) + print_field(" Join Call Control Point Opcode supported"); + else + print_field(" Join Call Control Point Opcode not supported"); + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void call_cp_opt_opcodes_read(const struct l2cap_frame *frame) +{ + print_call_cp_opt(frame); +} + +static void print_term_reason(const struct l2cap_frame *frame) +{ + uint8_t call_id, reason; + + if (!l2cap_frame_get_u8((void *)frame, &call_id)) { + print_text(COLOR_ERROR, "Call Index: invalid size"); + goto done; + } + print_field(" call Index: %u", call_id); + + if (!l2cap_frame_get_u8((void *)frame, &reason)) { + print_text(COLOR_ERROR, "Reason: invalid size"); + goto done; + } + + print_field(" Reason:"); + + switch (reason) { + case 0x00: + print_field(" Improper URI"); + break; + case 0x01: + print_field(" Call Failed"); + break; + case 0x02: + print_field(" Remote party ended the call"); + break; + case 0x03: + print_field(" Server ended the call"); + break; + case 0x04: + print_field(" Line was Busy"); + break; + case 0x05: + print_field(" Network Congestion"); + break; + case 0x06: + print_field(" Client terminated the call"); + break; + case 0x07: + print_field(" No service"); + break; + case 0x08: + print_field(" No answer"); + break; + case 0x09: + print_field(" Unspecified"); + break; + default: + print_field(" RFU"); + break; + } + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void call_termination_reason_notify(const struct l2cap_frame *frame) +{ + print_term_reason(frame); +} + +static void print_incom_call(const struct l2cap_frame *frame) +{ + char *name; + uint8_t call_id; + + if (!l2cap_frame_get_u8((void *)frame, &call_id)) { + print_text(COLOR_ERROR, "Call Index: invalid size"); + goto done; + } + + print_field(" Call Index: %u", call_id); + + name = name2utf8((uint8_t *)frame->data, frame->size); + + print_field(" call_string: %s", name); + + g_free(name); + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void incoming_call_read(const struct l2cap_frame *frame) +{ + print_incom_call(frame); +} + +static void incoming_call_notify(const struct l2cap_frame *frame) +{ + print_incom_call(frame); +} + +static void print_call_friendly_name(const struct l2cap_frame *frame) +{ + char *name; + uint8_t call_id; + + if (!l2cap_frame_get_u8((void *)frame, &call_id)) { + print_text(COLOR_ERROR, "Call Index: invalid size"); + goto done; + } + + print_field(" Call Index: %u", call_id); + + name = name2utf8((uint8_t *)frame->data, frame->size); + + print_field(" Friendly Name: %s", name); + + g_free(name); + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void call_friendly_name_read(const struct l2cap_frame *frame) +{ + print_call_friendly_name(frame); +} + +static void call_friendly_name_notify(const struct l2cap_frame *frame) +{ + print_call_friendly_name(frame); +} + +static const char *play_order_str(uint8_t order) +{ + switch (order) { + case 0x01: + return "Single once"; + case 0x02: + return "Single repeat"; + case 0x03: + return "In order once"; + case 0x04: + return "In order repeat"; + case 0x05: + return "Oldest once"; + case 0x06: + return "Oldest repeat"; + case 0x07: + return "Newest once"; + case 0x08: + return "Newest repeat"; + case 0x09: + return "Shuffle once"; + case 0x0A: + return "Shuffle repeat"; + default: + return "RFU"; + } +} + +static void print_playing_order(const struct l2cap_frame *frame) +{ + int8_t playing_order; + + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&playing_order)) { + print_text(COLOR_ERROR, " Playing Order: invalid size"); + goto done; + } + + print_field(" Playing Order: %s", play_order_str(playing_order)); + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void playing_order_read(const struct l2cap_frame *frame) +{ + print_playing_order(frame); +} + +static void playing_order_write(const struct l2cap_frame *frame) +{ + print_playing_order(frame); +} + +static void playing_order_notify(const struct l2cap_frame *frame) +{ + print_playing_order(frame); +} + +static const struct bitfield_data playing_orders_table[] = { + { 0, "Single once (0x0001)" }, + { 1, "Single repeat (0x0002)" }, + { 2, "In order once (0x0004)" }, + { 3, "In Order Repeat (0x0008)" }, + { 4, "Oldest once (0x0010)" }, + { 5, "Oldest repeat (0x0020)" }, + { 6, "Newest once (0x0040)" }, + { 7, "Newest repeat (0x0080)" }, + { 8, "Shuffle once (0x0100)" }, + { 9, "Shuffle repeat (0x0200)" }, + { 10, "RFU (0x0400)" }, + { 11, "RFU (0x0800)" }, + { 12, "RFU (0x1000)" }, + { 13, "RFU (0x2000)" }, + { 14, "RFU (0x4000)" }, + { 15, "RFU (0x8000)" }, + { } +}; + +static void print_playing_orders_supported(const struct l2cap_frame *frame) +{ + uint16_t supported_orders; + uint16_t mask; + + if (!l2cap_frame_get_le16((void *)frame, &supported_orders)) { + print_text(COLOR_ERROR, + " Supported Playing Orders: invalid size"); + goto done; + } + + print_field(" Supported Playing Orders: 0x%4.4x", + supported_orders); + + mask = print_bitfield(8, supported_orders, playing_orders_table); + if (mask) + print_text(COLOR_WHITE_BG, " Unknown fields (0x%4.4x)", + mask); + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void playing_orders_supported_read(const struct l2cap_frame *frame) +{ + print_playing_orders_supported(frame); +} + +static const char *media_state_str(uint8_t state) +{ + switch (state) { + case 0x00: + return "Inactive"; + case 0x01: + return "Playing"; + case 0x02: + return "Paused"; + case 0x03: + return "Seeking"; + default: + return "RFU"; + } +} + +static void print_media_state(const struct l2cap_frame *frame) +{ + int8_t state; + + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&state)) { + print_text(COLOR_ERROR, " Media State: invalid size"); + goto done; + } + + print_field(" Media State: %s", media_state_str(state)); + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void media_state_read(const struct l2cap_frame *frame) +{ + print_media_state(frame); +} + +static void media_state_notify(const struct l2cap_frame *frame) +{ + print_media_state(frame); +} + +static const struct media_cp_opcode { + uint8_t opcode; + const char *opcode_str; +} media_cp_opcode_table[] = { + {0x01, "Play"}, + {0x02, "Pause"}, + {0x03, "Fast Rewind"}, + {0x04, "Fast Forward"}, + {0x05, "Stop"}, + {0x10, "Move Relative"}, + {0x20, "Previous Segment"}, + {0x21, "Next Segment"}, + {0x22, "First Segment"}, + {0x23, "Last Segment"}, + {0x24, "Goto Segment"}, + {0x30, "Previous Track"}, + {0x31, "Next Track"}, + {0x32, "First Track"}, + {0x33, "Last Track"}, + {0x34, "Goto Track"}, + {0x40, "Previous Group"}, + {0x41, "Next Group"}, + {0x42, "First Group"}, + {0x43, "Last Group"}, + {0x44, "Goto Group"}, +}; + +static const char *cp_opcode_str(uint8_t opcode) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(media_cp_opcode_table); i++) { + const char *str = media_cp_opcode_table[i].opcode_str; + + if (opcode == media_cp_opcode_table[i].opcode) + return str; + } + + return "RFU"; +} + +static void print_media_cp(const struct l2cap_frame *frame) +{ + int8_t opcode; + + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&opcode)) { + print_text(COLOR_ERROR, " Media Control Point: invalid size"); + goto done; + } + + print_field(" Media Control Point: %s", cp_opcode_str(opcode)); + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void media_cp_write(const struct l2cap_frame *frame) +{ + print_media_cp(frame); +} + +static void media_cp_notify(const struct l2cap_frame *frame) +{ + print_media_cp(frame); +} + +static const struct bitfield_data supported_opcodes_table[] = { + {0, "Play (0x00000001)" }, + {1, "Pause (0x00000002)" }, + {2, "Fast Rewind (0x00000004)" }, {3, "Fast Forward (0x00000008)" }, {4, "Stop (0x00000010)" }, {5, "Move Relative (0x00000020)" }, @@ -2284,59 +3365,652 @@ static const struct bitfield_data supported_opcodes_table[] = { { } }; -static void print_media_cp_op_supported(const struct l2cap_frame *frame) +static void print_media_cp_op_supported(const struct l2cap_frame *frame) +{ + uint32_t supported_opcodes; + uint32_t mask; + + if (!l2cap_frame_get_le32((void *)frame, &supported_opcodes)) { + print_text(COLOR_ERROR, " value: invalid size"); + goto done; + } + + print_field(" Supported Opcodes: 0x%8.8x", supported_opcodes); + + mask = print_bitfield(8, supported_opcodes, supported_opcodes_table); + if (mask) + print_text(COLOR_WHITE_BG, " Unknown fields (0x%4.4x)", + mask); + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void media_cp_op_supported_read(const struct l2cap_frame *frame) +{ + print_media_cp_op_supported(frame); +} + +static void media_cp_op_supported_notify(const struct l2cap_frame *frame) +{ + print_media_cp_op_supported(frame); +} + +static void print_content_control_id(const struct l2cap_frame *frame) +{ + int8_t ccid; + + if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&ccid)) { + print_text(COLOR_ERROR, " Content Control ID: invalid size"); + goto done; + } + + print_field(" Content Control ID: 0x%2.2x", ccid); + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void content_control_id_read(const struct l2cap_frame *frame) +{ + print_content_control_id(frame); +} + +static const struct pa_sync_state_decoder { + uint8_t code; + const char *value; +} pa_sync_state_decoders[] = { + { 0x00, "Not synchronized to PA" }, + { 0x01, "SyncInfo Request" }, + { 0x02, "Synchronized to PA" }, + { 0x03, "Failed to synchronize to PA" }, + { 0x04, "No PAST" }, +}; + +static const struct cp_pa_sync_state_decoder { + uint8_t code; + const char *value; +} cp_pa_sync_state_decoders[] = { + { 0x00, "Do not synchronize to PA" }, + { 0x01, "Synchronize to PA - PAST available" }, + { 0x02, "Synchronize to PA - PAST not available" }, +}; + +static const struct big_enc_decoder { + uint8_t code; + const char *value; +} big_enc_decoders[] = { + { 0x00, "Not encrypted" }, + { 0x01, "Broadcast_Code required" }, + { 0x02, "Decrypting" }, + { 0x03, "Bad_Code (incorrect encryption key)" }, +}; + +static bool print_subgroup_lv(const struct l2cap_frame *frame, + const char *label, + const struct util_ltv_debugger *debugger, + size_t debugger_len) +{ + struct bt_hci_lv_data *lv; + + lv = l2cap_frame_pull((void *)frame, frame, sizeof(*lv)); + if (!lv) { + print_text(COLOR_ERROR, "%s: invalid size", label); + return false; + } + + if (!l2cap_frame_pull((void *)frame, frame, lv->len)) { + print_text(COLOR_ERROR, "%s: invalid size", label); + return false; + } + + util_debug_ltv(lv->data, lv->len, debugger, debugger_len, + print_ltv, (void *)label); + + return true; +} + +static bool print_subgroup_metadata(const char *label, + const struct l2cap_frame *frame) +{ + return print_subgroup_lv(frame, label, NULL, 0); +} + +static void print_bcast_recv_state(const struct l2cap_frame *frame) +{ + uint8_t i; + uint8_t id; + uint8_t addr_type; + uint8_t *addr; + uint8_t sid; + uint32_t bid; + uint8_t pa_sync_state; + uint8_t enc; + uint8_t *bad_code; + uint8_t num_subgroups = 0; + uint32_t bis_sync_state; + + if (frame->size == 0) { + print_field(" Empty characteristic"); + goto done; + } + + if (!l2cap_frame_get_u8((void *)frame, &id)) { + print_text(COLOR_ERROR, "Source_ID: invalid size"); + goto done; + } + + print_field(" Source_ID: %u", id); + + if (!l2cap_frame_get_u8((void *)frame, &addr_type)) { + print_text(COLOR_ERROR, "Source_Address_Type: invalid size"); + goto done; + } + + print_field(" Source_Address_Type: %u", addr_type); + + addr = l2cap_frame_pull((void *)frame, frame, sizeof(bdaddr_t)); + if (!addr) { + print_text(COLOR_ERROR, "Source_Address: invalid size"); + goto done; + } + + print_field(" Source_Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", + addr[5], addr[4], + addr[3], addr[2], + addr[1], addr[0]); + + if (!l2cap_frame_get_u8((void *)frame, &sid)) { + print_text(COLOR_ERROR, "Source_Adv_SID: invalid size"); + goto done; + } + + print_field(" Source_Adv_SID: %u", sid); + + if (!l2cap_frame_get_le24((void *)frame, &bid)) { + print_text(COLOR_ERROR, "Broadcast_ID: invalid size"); + goto done; + } + + print_field(" Broadcast_ID: 0x%06x", bid); + + if (!l2cap_frame_get_u8((void *)frame, &pa_sync_state)) { + print_text(COLOR_ERROR, "PA_Sync_State: invalid size"); + goto done; + } + + for (i = 0; i < ARRAY_SIZE(pa_sync_state_decoders); i++) { + const struct pa_sync_state_decoder *decoder; + + decoder = &pa_sync_state_decoders[i]; + + if (decoder->code == pa_sync_state) { + print_field(" PA_Sync_State: %s", decoder->value); + break; + } + } + + if (i == ARRAY_SIZE(pa_sync_state_decoders)) + print_field(" PA_Sync_State: %s", "Invalid value"); + + if (!l2cap_frame_get_u8((void *)frame, &enc)) { + print_text(COLOR_ERROR, "BIG_Encryption: invalid size"); + goto done; + } + + for (i = 0; i < ARRAY_SIZE(big_enc_decoders); i++) { + const struct big_enc_decoder *decoder; + + decoder = &big_enc_decoders[i]; + + if (decoder->code == enc) { + print_field(" BIG_Encryption: %s", decoder->value); + break; + } + } + + if (i == ARRAY_SIZE(big_enc_decoders)) + print_field(" BIG_Encryption: %s", "Invalid value"); + + if (enc == 0x03) { + bad_code = l2cap_frame_pull((void *)frame, frame, 16); + if (!bad_code) { + print_text(COLOR_ERROR, "Bad_Code: invalid size"); + goto done; + } + + print_hex_field(" Bad_Code", bad_code, 16); + } + + if (!l2cap_frame_get_u8((void *)frame, &num_subgroups)) { + print_text(COLOR_ERROR, "Num_Subgroups: invalid size"); + goto done; + } + + print_field(" Num_Subgroups: %u", num_subgroups); + + for (i = 0; i < num_subgroups; i++) { + print_field(" Subgroup #%u:", i); + + if (!l2cap_frame_get_le32((void *)frame, &bis_sync_state)) { + print_text(COLOR_ERROR, "BIS_Sync State: invalid size"); + goto done; + } + + print_field(" BIS_Sync State: 0x%8.8x", bis_sync_state); + + if (!print_subgroup_metadata(" Metadata", frame)) + goto done; + } + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void bcast_recv_state_read(const struct l2cap_frame *frame) +{ + print_bcast_recv_state(frame); +} + +static void bcast_recv_state_notify(const struct l2cap_frame *frame) +{ + print_bcast_recv_state(frame); +} + +#define BCAST_AUDIO_SCAN_CP_CMD(_op, _desc, _func) \ +[_op] = { \ + .desc = _desc, \ + .func = _func, \ +} + +static void bcast_audio_scan_cp_add_src_cmd(const struct l2cap_frame *frame) +{ + uint8_t i; + uint8_t addr_type; + uint8_t *addr; + uint8_t sid; + uint32_t bid; + uint8_t pa_sync_state; + uint16_t pa_interval; + uint8_t num_subgroups = 0; + uint32_t bis_sync_state; + + if (!l2cap_frame_get_u8((void *)frame, &addr_type)) { + print_text(COLOR_ERROR, "Source_Address_Type: invalid size"); + return; + } + + print_field(" Source_Address_Type: %u", addr_type); + + addr = l2cap_frame_pull((void *)frame, frame, sizeof(bdaddr_t)); + if (!addr) { + print_text(COLOR_ERROR, "Source_Address: invalid size"); + return; + } + + print_field(" Source_Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", + addr[5], addr[4], + addr[3], addr[2], + addr[1], addr[0]); + + if (!l2cap_frame_get_u8((void *)frame, &sid)) { + print_text(COLOR_ERROR, "Source_Adv_SID: invalid size"); + return; + } + + print_field(" Source_Adv_SID: %u", sid); + + if (!l2cap_frame_get_le24((void *)frame, &bid)) { + print_text(COLOR_ERROR, "Broadcast_ID: invalid size"); + return; + } + + print_field(" Broadcast_ID: 0x%06x", bid); + + if (!l2cap_frame_get_u8((void *)frame, &pa_sync_state)) { + print_text(COLOR_ERROR, "PA_Sync_State: invalid size"); + return; + } + + for (i = 0; i < ARRAY_SIZE(cp_pa_sync_state_decoders); i++) { + const struct cp_pa_sync_state_decoder *decoder; + + decoder = &cp_pa_sync_state_decoders[i]; + + if (decoder->code == pa_sync_state) { + print_field(" PA_Sync_State: %s", decoder->value); + break; + } + } + + if (i == ARRAY_SIZE(cp_pa_sync_state_decoders)) + print_field(" PA_Sync_State: %s", "Invalid value"); + + if (!l2cap_frame_get_le16((void *)frame, &pa_interval)) { + print_text(COLOR_ERROR, "PA_Interval: invalid size"); + return; + } + + print_field(" PA_Interval: 0x%04x", pa_interval); + + if (!l2cap_frame_get_u8((void *)frame, &num_subgroups)) { + print_text(COLOR_ERROR, "Num_Subgroups: invalid size"); + return; + } + + print_field(" Num_Subgroups: %u", num_subgroups); + + for (i = 0; i < num_subgroups; i++) { + print_field(" Subgroup #%u:", i); + + if (!l2cap_frame_get_le32((void *)frame, &bis_sync_state)) { + print_text(COLOR_ERROR, "BIS_Sync State: invalid size"); + return; + } + + print_field(" BIS_Sync State: 0x%8.8x", bis_sync_state); + + if (!print_subgroup_metadata(" Metadata", frame)) + return; + } +} + +static void bcast_audio_scan_cp_mod_src_cmd(const struct l2cap_frame *frame) { - uint32_t supported_opcodes; - uint32_t mask; + uint8_t i; + uint8_t id; + uint8_t pa_sync_state; + uint16_t pa_interval; + uint8_t num_subgroups = 0; + uint32_t bis_sync_state; - if (!l2cap_frame_get_le32((void *)frame, &supported_opcodes)) { - print_text(COLOR_ERROR, " value: invalid size"); - goto done; + if (!l2cap_frame_get_u8((void *)frame, &id)) { + print_text(COLOR_ERROR, "Source_ID: invalid size"); + return; } - print_field(" Supported Opcodes: 0x%8.8x", supported_opcodes); + print_field(" Source_ID: %u", id); - mask = print_bitfield(8, supported_opcodes, supported_opcodes_table); - if (mask) - print_text(COLOR_WHITE_BG, " Unknown fields (0x%4.4x)", - mask); + if (!l2cap_frame_get_u8((void *)frame, &pa_sync_state)) { + print_text(COLOR_ERROR, "PA_Sync_State: invalid size"); + return; + } -done: - if (frame->size) - print_hex_field(" Data", frame->data, frame->size); + for (i = 0; i < ARRAY_SIZE(cp_pa_sync_state_decoders); i++) { + const struct cp_pa_sync_state_decoder *decoder; + + decoder = &cp_pa_sync_state_decoders[i]; + + if (decoder->code == pa_sync_state) { + print_field(" PA_Sync_State: %s", decoder->value); + break; + } + } + + if (i == ARRAY_SIZE(cp_pa_sync_state_decoders)) + print_field(" PA_Sync_State: %s", "Invalid value"); + + if (!l2cap_frame_get_le16((void *)frame, &pa_interval)) { + print_text(COLOR_ERROR, "PA_Interval: invalid size"); + return; + } + + print_field(" PA_Interval: 0x%04x", pa_interval); + + if (!l2cap_frame_get_u8((void *)frame, &num_subgroups)) { + print_text(COLOR_ERROR, "Num_Subgroups: invalid size"); + return; + } + + print_field(" Num_Subgroups: %u", num_subgroups); + + for (i = 0; i < num_subgroups; i++) { + print_field(" Subgroup #%u:", i); + + if (!l2cap_frame_get_le32((void *)frame, &bis_sync_state)) { + print_text(COLOR_ERROR, "BIS_Sync State: invalid size"); + return; + } + + print_field(" BIS_Sync State: 0x%8.8x", bis_sync_state); + + if (!print_subgroup_metadata(" Metadata", frame)) + return; + } } -static void media_cp_op_supported_read(const struct l2cap_frame *frame) +static void bcast_audio_scan_cp_set_bcode_cmd(const struct l2cap_frame *frame) { - print_media_cp_op_supported(frame); + uint8_t id; + uint8_t *bcast_code; + + if (!l2cap_frame_get_u8((void *)frame, &id)) { + print_text(COLOR_ERROR, "Source_ID: invalid size"); + return; + } + + print_field(" Source_ID: %u", id); + + bcast_code = l2cap_frame_pull((void *)frame, frame, 16); + if (!bcast_code) { + print_text(COLOR_ERROR, "Broadcast_Code: invalid size"); + return; + } + + print_hex_field(" Broadcast_Code", bcast_code, 16); + } -static void media_cp_op_supported_notify(const struct l2cap_frame *frame) +static void bcast_audio_scan_cp_remove_src_cmd(const struct l2cap_frame *frame) { - print_media_cp_op_supported(frame); + uint8_t id; + + if (!l2cap_frame_get_u8((void *)frame, &id)) { + print_text(COLOR_ERROR, "Source_ID: invalid size"); + return; + } + + print_field(" Source_ID: %u", id); } -static void print_content_control_id(const struct l2cap_frame *frame) +static const struct bcast_audio_scan_cp_cmd { + const char *desc; + void (*func)(const struct l2cap_frame *frame); +} bcast_audio_scan_cp_cmd_table[] = { + /* Opcode = 0x00 (Remote Scan Stopped) */ + BCAST_AUDIO_SCAN_CP_CMD(0x00, "Remote Scan Stopped", NULL), + /* Opcode = 0x01 (Remote Scan Started) */ + BCAST_AUDIO_SCAN_CP_CMD(0x01, "Remote Scan Started", NULL), + /* Opcode = 0x02 (Add Source) */ + BCAST_AUDIO_SCAN_CP_CMD(0x02, "Add Source", + bcast_audio_scan_cp_add_src_cmd), + /* Opcode = 0x03 (Modify Source) */ + BCAST_AUDIO_SCAN_CP_CMD(0x03, "Modify Source", + bcast_audio_scan_cp_mod_src_cmd), + /* Opcode = 0x04 (Set Broadcast_Code) */ + BCAST_AUDIO_SCAN_CP_CMD(0x04, "Set Broadcast_Code", + bcast_audio_scan_cp_set_bcode_cmd), + /* Opcode = 0x05 (Remove Source) */ + BCAST_AUDIO_SCAN_CP_CMD(0x05, "Remove Source", + bcast_audio_scan_cp_remove_src_cmd), +}; + +static const struct bcast_audio_scan_cp_cmd * +bcast_audio_scan_cp_get_cmd(uint8_t op) { - int8_t ccid; + if (op > ARRAY_SIZE(bcast_audio_scan_cp_cmd_table)) + return NULL; - if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&ccid)) { - print_text(COLOR_ERROR, " Content Control ID: invalid size"); + return &bcast_audio_scan_cp_cmd_table[op]; +} + +static void print_bcast_audio_scan_cp_cmd(const struct l2cap_frame *frame) +{ + uint8_t op; + const struct bcast_audio_scan_cp_cmd *cmd; + + if (!l2cap_frame_get_u8((void *)frame, &op)) { + print_text(COLOR_ERROR, "Opcode: invalid size"); goto done; } - print_field(" Content Control ID: 0x%2.2x", ccid); + cmd = bcast_audio_scan_cp_get_cmd(op); + if (!cmd) { + print_field(" Opcode: Reserved (0x%2.2x)", op); + goto done; + } + + print_field(" Opcode: %s (0x%2.2x)", cmd->desc, op); + if (cmd->func) + cmd->func(frame); done: if (frame->size) print_hex_field(" Data", frame->data, frame->size); } -static void content_control_id_read(const struct l2cap_frame *frame) +static void bcast_audio_scan_cp_write(const struct l2cap_frame *frame) { - print_content_control_id(frame); + print_bcast_audio_scan_cp_cmd(frame); +} + +static const struct bitfield_data gmap_role_table[] = { + { 0, "Unicast Game Gateway (UGG) (0x0001)" }, + { 1, "Unicast Game Terminal (UGT) (0x0002)" }, + { 2, "Broadcast Game Sender (BGS) (0x0004)" }, + { 3, "Broadcast Game Receiver (BGR) (0x0008)" }, + { } +}; + +static void gmap_role_read(const struct l2cap_frame *frame) +{ + uint8_t role; + uint8_t mask; + + if (!l2cap_frame_get_u8((void *)frame, &role)) { + print_text(COLOR_ERROR, " invalid size"); + return; + } + + print_field(" Role: 0x%2.2x", role); + + mask = print_bitfield(6, role, gmap_role_table); + if (mask) + print_text(COLOR_WHITE_BG, " Unknown fields (0x%2.2x)", + mask); } +static const struct bitfield_data ugg_features_table[] = { + { 0, "UGG Multiplex (0x0001)" }, + { 1, "UGG 96 kbps Source (0x0002)" }, + { 2, "UGG Multilink (0x0004)" }, + { } +}; + +static void ugg_features_read(const struct l2cap_frame *frame) +{ + uint8_t value; + uint8_t mask; + + if (!l2cap_frame_get_u8((void *)frame, &value)) { + print_text(COLOR_ERROR, " invalid size"); + return; + } + + print_field(" Value: 0x%2.2x", value); + + mask = print_bitfield(6, value, ugg_features_table); + if (mask) + print_text(COLOR_WHITE_BG, " Unknown fields (0x%2.2x)", + mask); +} + +static const struct bitfield_data ugt_features_table[] = { + { 0, "UGT Source (0x0001)" }, + { 1, "UGT 80 kbps Source (0x0002)" }, + { 2, "UGT Sink (0x0004)" }, + { 3, "UGT 64 kbps Sink (0x0008)" }, + { 4, "UGT Multiplex (0x0010)" }, + { 5, "UGT Multisink (0x0020)" }, + { 6, "UGT Multisource (0x0040)" }, + { } +}; + +static void ugt_features_read(const struct l2cap_frame *frame) +{ + uint8_t value; + uint8_t mask; + + if (!l2cap_frame_get_u8((void *)frame, &value)) { + print_text(COLOR_ERROR, " invalid size"); + return; + } + + print_field(" Value: 0x%2.2x", value); + + mask = print_bitfield(6, value, ugt_features_table); + if (mask) + print_text(COLOR_WHITE_BG, " Unknown fields (0x%2.2x)", + mask); +} + +static const struct bitfield_data bgs_features_table[] = { + { 0, "BGS 96 kbps (0x0001)" }, + { } +}; + +static void bgs_features_read(const struct l2cap_frame *frame) +{ + uint8_t value; + uint8_t mask; + + if (!l2cap_frame_get_u8((void *)frame, &value)) { + print_text(COLOR_ERROR, " invalid size"); + return; + } + + print_field(" Value: 0x%2.2x", value); + + mask = print_bitfield(6, value, bgs_features_table); + if (mask) + print_text(COLOR_WHITE_BG, " Unknown fields (0x%2.2x)", + mask); +} + +static const struct bitfield_data bgr_features_table[] = { + { 0, "BGR Multisink (0x0001)" }, + { 1, "BGR Multiplex (0x0002)" }, + { } +}; + +static void bgr_features_read(const struct l2cap_frame *frame) +{ + uint8_t value; + uint8_t mask; + + if (!l2cap_frame_get_u8((void *)frame, &value)) { + print_text(COLOR_ERROR, " invalid size"); + return; + } + + print_field(" Value: 0x%2.2x", value); + + mask = print_bitfield(6, value, bgr_features_table); + if (mask) + print_text(COLOR_WHITE_BG, " Unknown fields (0x%2.2x)", + mask); +} + +#define GMAS \ + GATT_HANDLER(0x2c00, gmap_role_read, NULL, NULL), \ + GATT_HANDLER(0x2c01, ugg_features_read, NULL, NULL), \ + GATT_HANDLER(0x2c02, ugt_features_read, NULL, NULL), \ + GATT_HANDLER(0x2c02, bgs_features_read, NULL, NULL), \ + GATT_HANDLER(0x2c03, bgr_features_read, NULL, NULL) + #define GATT_HANDLER(_uuid, _read, _write, _notify) \ { \ .uuid = { \ @@ -2348,12 +4022,14 @@ static void content_control_id_read(const struct l2cap_frame *frame) .notify = _notify \ } -struct gatt_handler { +static const struct gatt_handler { bt_uuid_t uuid; void (*read)(const struct l2cap_frame *frame); void (*write)(const struct l2cap_frame *frame); void (*notify)(const struct l2cap_frame *frame); } gatt_handlers[] = { + GATT_HANDLER(0x2800, pri_svc_read, NULL, NULL), + GATT_HANDLER(0x2801, sec_svc_read, NULL, NULL), GATT_HANDLER(0x2803, chrc_read, NULL, NULL), GATT_HANDLER(0x2902, ccc_read, ccc_write, NULL), GATT_HANDLER(0x2bc4, ase_read, NULL, ase_notify), @@ -2368,6 +4044,12 @@ struct gatt_handler { GATT_HANDLER(0x2b7d, vol_state_read, NULL, vol_state_notify), GATT_HANDLER(0x2b7e, NULL, vol_cp_write, NULL), GATT_HANDLER(0x2b7f, vol_flag_read, NULL, vol_flag_notify), + + GATT_HANDLER(0x2b84, csip_sirk_read, NULL, csip_sirk_notify), + GATT_HANDLER(0x2b85, csip_size_read, NULL, csip_size_notify), + GATT_HANDLER(0x2b86, csip_lock_read, NULL, NULL), + GATT_HANDLER(0x2b87, csip_rank_read, NULL, NULL), + GATT_HANDLER(0x2b93, mp_name_read, NULL, mp_name_notify), GATT_HANDLER(0x2b96, NULL, NULL, track_changed_notify), GATT_HANDLER(0x2b97, track_title_read, NULL, track_title_notify), @@ -2385,14 +4067,44 @@ struct gatt_handler { GATT_HANDLER(0x2ba5, media_cp_op_supported_read, NULL, media_cp_op_supported_notify), GATT_HANDLER(0x2bba, content_control_id_read, NULL, NULL), + + GATT_HANDLER(0x2bc7, NULL, bcast_audio_scan_cp_write, NULL), + GATT_HANDLER(0x2bc8, bcast_recv_state_read, NULL, + bcast_recv_state_notify), + GATT_HANDLER(0x2bb3, bearer_name_read, NULL, bearer_name_notify), + GATT_HANDLER(0x2bb4, bearer_uci_read, NULL, NULL), + GATT_HANDLER(0x2bb5, bearer_technology_read, NULL, + bearer_technology_notify), + GATT_HANDLER(0x2bb6, bearer_uri_schemes_list_read, NULL, NULL), + GATT_HANDLER(0x2bb7, bearer_signal_strength_read, NULL, + bearer_signal_strength_notify), + GATT_HANDLER(0x2bb8, bearer_signal_strength_rep_intrvl_read, + bearer_signal_strength_rep_intrvl_write, NULL), + GATT_HANDLER(0x2bb9, bearer_current_call_list_read, NULL, + bearer_current_call_list_notify), + GATT_HANDLER(0x2bba, call_content_control_id_read, NULL, NULL), + GATT_HANDLER(0x2bbb, status_flag_read, NULL, status_flag_notify), + GATT_HANDLER(0x2bbc, incom_target_bearer_uri_read, NULL, + incom_target_bearer_uri_notify), + GATT_HANDLER(0x2bbd, call_state_read, NULL, call_state_notify), + GATT_HANDLER(0x2bbe, NULL, call_cp_write, call_cp_notify), + GATT_HANDLER(0x2bbf, call_cp_opt_opcodes_read, NULL, NULL), + GATT_HANDLER(0x2bc0, NULL, NULL, call_termination_reason_notify), + GATT_HANDLER(0x2bc1, incoming_call_read, NULL, incoming_call_notify), + GATT_HANDLER(0x2bc2, call_friendly_name_read, NULL, + call_friendly_name_notify), + GMAS }; -static struct gatt_handler *get_handler_uuid(const bt_uuid_t *uuid) +static const struct gatt_handler *get_handler_uuid(const bt_uuid_t *uuid) { size_t i; + if (!uuid) + return NULL; + for (i = 0; i < ARRAY_SIZE(gatt_handlers); i++) { - struct gatt_handler *handler = &gatt_handlers[i]; + const struct gatt_handler *handler = &gatt_handlers[i]; if (!bt_uuid_cmp(&handler->uuid, uuid)) return handler; @@ -2401,7 +4113,7 @@ static struct gatt_handler *get_handler_uuid(const bt_uuid_t *uuid) return NULL; } -static struct gatt_handler *get_handler(struct gatt_db_attribute *attr) +static const struct gatt_handler *get_handler(struct gatt_db_attribute *attr) { return get_handler_uuid(gatt_db_attribute_get_type(attr)); } @@ -2415,9 +4127,23 @@ static void att_exchange_mtu_req(const struct l2cap_frame *frame) static void att_exchange_mtu_rsp(const struct l2cap_frame *frame) { - const struct bt_l2cap_att_exchange_mtu_rsp *pdu = frame->data; + struct packet_conn_data *conn; + struct att_conn_data *data; + uint16_t mtu; + + if (!l2cap_frame_get_le16((void *)frame, &mtu)) { + print_text(COLOR_ERROR, " invalid size"); + return; + } - print_field("Server RX MTU: %d", le16_to_cpu(pdu->mtu)); + print_field("Server RX MTU: %d", mtu); + + conn = packet_get_conn_data(frame->handle); + data = att_get_conn_data(conn); + if (!data) + return; + + data->mtu = mtu; } static void att_find_info_req(const struct l2cap_frame *frame) @@ -2437,45 +4163,96 @@ static const char *att_format_str(uint8_t format) } } -static uint16_t print_info_data_16(const void *data, uint16_t len) +static struct gatt_db_attribute *insert_desc(const struct l2cap_frame *frame, + uint16_t handle, + bt_uuid_t *uuid, bool rsp) { - while (len >= 4) { - print_field("Handle: 0x%4.4x", get_le16(data)); - print_uuid("UUID", data + 2, 2); - data += 4; - len -= 4; - } + struct gatt_db *db; + + db = get_db(frame, rsp); + if (!db) + return NULL; - return len; + return gatt_db_insert_descriptor(db, handle, uuid, 0, NULL, NULL, NULL); } -static uint16_t print_info_data_128(const void *data, uint16_t len) +static void att_find_info_rsp_16(const struct l2cap_frame *frame) { - while (len >= 18) { - print_field("Handle: 0x%4.4x", get_le16(data)); - print_uuid("UUID", data + 2, 16); - data += 18; - len -= 18; + while (frame->size >= 4) { + uint16_t handle; + uint16_t u16; + bt_uuid_t uuid; + + if (!l2cap_frame_get_le16((void *)frame, &handle)) { + print_text(COLOR_ERROR, " Handle: invalid size"); + return; + } + + if (!l2cap_frame_get_le16((void *)frame, &u16)) { + print_text(COLOR_ERROR, " UUID: invalid size"); + return; + } + + print_field("Handle: 0x%4.4x", handle); + print_uuid("UUID", &u16, 2); + + bt_uuid16_create(&uuid, u16); + + insert_desc(frame, handle, &uuid, true); } +} + +static void att_find_info_rsp_128(const struct l2cap_frame *frame) +{ + while (frame->size >= 18) { + uint16_t handle; + bt_uuid_t uuid; + + if (!l2cap_frame_get_le16((void *)frame, &handle)) { + print_text(COLOR_ERROR, " Handle: invalid size"); + return; + } + + if (frame->size < 16) { + print_text(COLOR_ERROR, " UUID: invalid size"); + return; + } + + print_field("Handle: 0x%4.4x", handle); + print_uuid("UUID", frame->data, 16); + + bt_uuid_from_data(&uuid, frame->data, 16); - return len; + if (!l2cap_frame_pull((void *)frame, frame, 16)) + return; + + insert_desc(frame, handle, &uuid, true); + } } static void att_find_info_rsp(const struct l2cap_frame *frame) { - const uint8_t *format = frame->data; - uint16_t len; + uint8_t format; + + if (!l2cap_frame_get_u8((void *)frame, &format)) { + print_text(COLOR_ERROR, " Format: invalid size"); + goto done; + } - print_field("Format: %s (0x%2.2x)", att_format_str(*format), *format); + print_field("Format: %s (0x%2.2x)", att_format_str(format), format); - if (*format == 0x01) - len = print_info_data_16(frame->data + 1, frame->size - 1); - else if (*format == 0x02) - len = print_info_data_128(frame->data + 1, frame->size - 1); - else - len = frame->size - 1; + switch (format) { + case 0x01: + att_find_info_rsp_16(frame); + break; + case 0x02: + att_find_info_rsp_128(frame); + break; + } - packet_hexdump(frame->data + (frame->size - len), len); +done: + if (frame->size) + packet_hexdump(frame->data, frame->size); } static void att_find_by_type_val_req(const struct l2cap_frame *frame) @@ -2502,194 +4279,77 @@ static void att_find_by_type_val_rsp(const struct l2cap_frame *frame) packet_hexdump(ptr, len); } -static int bt_uuid_from_data(bt_uuid_t *uuid, const void *data, uint16_t size) -{ - uint128_t u128; - - switch (size) { - case 2: - return bt_uuid16_create(uuid, get_le16(data)); - case 4: - return bt_uuid32_create(uuid, get_le32(data)); - case 16: - memcpy(u128.data, data, sizeof(u128.data)); - return bt_uuid128_create(uuid, u128); - } - - return -EINVAL; -} - -static void att_conn_data_free(void *data) -{ - struct att_conn_data *att_data = data; - - gatt_db_unref(att_data->rdb); - gatt_db_unref(att_data->ldb); - queue_destroy(att_data->reads, free); - free(att_data); -} - -static struct att_conn_data *att_get_conn_data(struct packet_conn_data *conn) +static struct gatt_db_attribute *get_attribute(const struct l2cap_frame *frame, + uint16_t handle, bool rsp) { - struct att_conn_data *data = conn->data; - - if (data) - return data; + struct gatt_db *db; - data = new0(struct att_conn_data, 1); - data->rdb = gatt_db_new(); - data->ldb = gatt_db_new(); - conn->data = data; - conn->destroy = att_conn_data_free; + db = get_db(frame, rsp); + if (!db) + return NULL; - return data; + return gatt_db_get_attribute(db, handle); } -static void att_read_type_req(const struct l2cap_frame *frame) +static void queue_read(const struct l2cap_frame *frame, bt_uuid_t *uuid, + uint16_t handle) { - bt_uuid_t uuid; struct packet_conn_data *conn; struct att_conn_data *data; struct att_read *read; - struct gatt_handler *handler; - - print_handle_range("Handle range", frame->data); - print_uuid("Attribute type", frame->data + 4, frame->size - 4); + struct gatt_db_attribute *attr = NULL; + const struct gatt_handler *handler; - if (bt_uuid_from_data(&uuid, frame->data + 4, frame->size - 4)) - return; + if (handle) { + attr = get_attribute(frame, handle, false); + if (!attr) + return; + } - handler = get_handler_uuid(&uuid); - if (!handler || !handler->read) - return; + handler = attr ? get_handler(attr) : get_handler_uuid(uuid); conn = packet_get_conn_data(frame->handle); data = att_get_conn_data(conn); + if (!data) + return; if (!data->reads) data->reads = queue_new(); read = new0(struct att_read, 1); + read->conn = data; + read->attr = attr; read->in = frame->in; read->chan = frame->chan; - read->func = handler->read; + read->func = handler ? handler->read : NULL; queue_push_tail(data->reads, read); } -static void att_read_type_rsp(const struct l2cap_frame *frame) +static void att_read_type_req(const struct l2cap_frame *frame) { - uint8_t len; - - if (!l2cap_frame_get_u8((void *)frame, &len)) { - print_text(COLOR_ERROR, "invalid size"); - return; - } - - print_field("Attribute data length: %d", len); - print_data_list("Attribute data list", len, frame); -} + bt_uuid_t uuid; -static void gatt_load_db(struct gatt_db *db, const char *filename, - struct timespec *mtim) -{ - struct stat st; + print_handle_range("Handle range", frame->data); + print_uuid("Attribute type", frame->data + 4, frame->size - 4); - if (lstat(filename, &st)) + if (bt_uuid_from_data(&uuid, frame->data + 4, frame->size - 4)) return; - if (!gatt_db_isempty(db)) { - /* Check if file has been modified since last time */ - if (st.st_mtim.tv_sec == mtim->tv_sec && - st.st_mtim.tv_nsec == mtim->tv_nsec) - return; - /* Clear db before reloading */ - gatt_db_clear(db); - } - - *mtim = st.st_mtim; - - btd_settings_gatt_db_load(db, filename); -} - -static void load_gatt_db(struct packet_conn_data *conn) -{ - struct att_conn_data *data = att_get_conn_data(conn); - char filename[PATH_MAX]; - char local[18]; - char peer[18]; - - ba2str((bdaddr_t *)conn->src, local); - ba2str((bdaddr_t *)conn->dst, peer); - - create_filename(filename, PATH_MAX, "/%s/attributes", local); - gatt_load_db(data->ldb, filename, &data->ldb_mtim); - - create_filename(filename, PATH_MAX, "/%s/cache/%s", local, peer); - gatt_load_db(data->rdb, filename, &data->rdb_mtim); -} - -static struct gatt_db_attribute *get_attribute(const struct l2cap_frame *frame, - uint16_t handle, bool rsp) -{ - struct packet_conn_data *conn; - struct att_conn_data *data; - struct gatt_db *db; - - conn = packet_get_conn_data(frame->handle); - if (!conn) - return NULL; - - /* Try loading local and remote gatt_db if not loaded yet */ - load_gatt_db(conn); - - data = conn->data; - if (!data) - return NULL; - - if (frame->in) { - if (rsp) - db = data->rdb; - else - db = data->ldb; - } else { - if (rsp) - db = data->ldb; - else - db = data->rdb; - } - - return gatt_db_get_attribute(db, handle); + queue_read(frame, &uuid, 0x0000); } -static void print_attribute(struct gatt_db_attribute *attr) +static void att_read_type_rsp(const struct l2cap_frame *frame) { - uint16_t handle = gatt_db_attribute_get_handle(attr); - const bt_uuid_t *uuid; - char label[21]; - - uuid = gatt_db_attribute_get_type(attr); - if (!uuid) - goto done; + uint8_t len; - switch (uuid->type) { - case BT_UUID16: - sprintf(label, "Handle: 0x%4.4x Type", handle); - print_field("%s: %s (0x%4.4x)", label, - bt_uuid16_to_str(uuid->value.u16), - uuid->value.u16); - return; - case BT_UUID128: - sprintf(label, "Handle: 0x%4.4x Type", handle); - print_uuid(label, &uuid->value.u128, 16); + if (!l2cap_frame_get_u8((void *)frame, &len)) { + print_text(COLOR_ERROR, "invalid size"); return; - case BT_UUID_UNSPEC: - case BT_UUID32: - break; } -done: - print_field("Handle: 0x%4.4x", handle); + print_field("Attribute data length: %d", len); + print_data_list("Attribute data list", len, frame); } static void print_handle(const struct l2cap_frame *frame, uint16_t handle, @@ -2710,74 +4370,104 @@ static void att_read_req(const struct l2cap_frame *frame) { const struct bt_l2cap_att_read_req *pdu = frame->data; uint16_t handle; - struct packet_conn_data *conn; - struct att_conn_data *data; - struct att_read *read; - struct gatt_db_attribute *attr; - struct gatt_handler *handler; l2cap_frame_pull((void *)frame, frame, sizeof(*pdu)); handle = le16_to_cpu(pdu->handle); print_handle(frame, handle, false); - attr = get_attribute(frame, handle, false); - if (!attr) - return; + queue_read(frame, NULL, handle); +} - handler = get_handler(attr); - if (!handler || !handler->read) - return; +static void att_read_append(struct att_read *read, + const struct l2cap_frame *frame) +{ + if (!read->iov) + read->iov = new0(struct iovec, 1); + util_iov_append(read->iov, frame->data, frame->size); +} - conn = packet_get_conn_data(frame->handle); - data = conn->data; +static void att_read_func(struct att_read *read, + const struct l2cap_frame *frame) +{ + att_read_append(read, frame); - if (!data->reads) - data->reads = queue_new(); + print_attribute(read->attr); + print_hex_field("Value", read->iov->iov_base, read->iov->iov_len); - read = new0(struct att_read, 1); - read->attr = attr; - read->in = frame->in; - read->chan = frame->chan; - read->func = handler->read; + if (read->func) { + struct l2cap_frame f = *frame; - queue_push_tail(data->reads, read); + f.data = read->iov->iov_base; + f.size = read->iov->iov_len; + + read->func(&f); + } + + att_read_free(read); } static void att_read_rsp(const struct l2cap_frame *frame) { - struct packet_conn_data *conn; - struct att_conn_data *data; struct att_read *read; print_hex_field("Value", frame->data, frame->size); - conn = packet_get_conn_data(frame->handle); - if (!conn) - return; - - data = conn->data; - - read = queue_remove_if(data->reads, match_read_frame, (void *)frame); + read = att_get_read(frame); if (!read) return; - print_attribute(read->attr); - - read->func(frame); + /* Check if the data size is equal to the MTU then read long procedure + * maybe used. + */ + if (frame->size == read->conn->mtu - 1) { + att_read_append(read, frame); + print_hex_field("Long Value", read->iov->iov_base, + read->iov->iov_len); + queue_push_head(read->conn->reads, read); + return; + } - free(read); + att_read_func(read, frame); } static void att_read_blob_req(const struct l2cap_frame *frame) { - print_handle(frame, get_le16(frame->data), false); - print_field("Offset: 0x%4.4x", get_le16(frame->data + 2)); + uint16_t handle, offset; + struct att_read *read; + + if (!l2cap_frame_get_le16((void *)frame, &handle)) { + print_text(COLOR_ERROR, "invalid size"); + return; + } + + if (!l2cap_frame_get_le16((void *)frame, &offset)) { + print_text(COLOR_ERROR, "invalid size"); + return; + } + + print_handle(frame, handle, false); + print_field("Offset: 0x%4.4x", offset); + + read = att_get_read(frame); + if (!read) + return; + + /* Check if attribute handle and offset match so the read object shall + * be keeped. + */ + if (gatt_db_attribute_get_handle(read->attr) == handle && + offset == read->iov->iov_len) { + queue_push_head(read->conn->reads, read); + return; + } + + att_read_func(read, frame); } static void att_read_blob_rsp(const struct l2cap_frame *frame) { - packet_hexdump(frame->data, frame->size); + att_read_rsp(frame); } static void att_read_multiple_req(const struct l2cap_frame *frame) @@ -2792,62 +4482,83 @@ static void att_read_multiple_req(const struct l2cap_frame *frame) static void att_read_group_type_req(const struct l2cap_frame *frame) { + bt_uuid_t uuid; + print_handle_range("Handle range", frame->data); print_uuid("Attribute group type", frame->data + 4, frame->size - 4); + + if (bt_uuid_from_data(&uuid, frame->data + 4, frame->size - 4)) + return; + + queue_read(frame, &uuid, 0x0000); } static void print_group_list(const char *label, uint8_t length, - const void *data, uint16_t size) + const struct l2cap_frame *frame) { + struct att_read *read; uint8_t count; if (length == 0) return; - count = size / length; + read = att_get_read(frame); + + count = frame->size / length; print_field("%s: %u entr%s", label, count, count == 1 ? "y" : "ies"); - while (size >= length) { - print_handle_range("Handle range", data); - print_uuid("UUID", data + 4, length - 4); + while (frame->size >= length) { + print_handle_range("Handle range", frame->data); + print_uuid("UUID", frame->data + 4, length - 4); + + if (read && read->func) { + struct l2cap_frame f; + + l2cap_frame_clone_size(&f, frame, length); + + read->func(&f); + } - data += length; - size -= length; + if (!l2cap_frame_pull((void *)frame, frame, length)) + break; } - packet_hexdump(data, size); + packet_hexdump(frame->data, frame->size); + att_read_free(read); } static void att_read_group_type_rsp(const struct l2cap_frame *frame) { const struct bt_l2cap_att_read_group_type_rsp *pdu = frame->data; + l2cap_frame_pull((void *)frame, frame, sizeof(*pdu)); + print_field("Attribute data length: %d", pdu->length); - print_group_list("Attribute group list", pdu->length, - frame->data + 1, frame->size - 1); + print_group_list("Attribute group list", pdu->length, frame); } static void print_write(const struct l2cap_frame *frame, uint16_t handle, size_t len) { struct gatt_db_attribute *attr; - struct gatt_handler *handler; + const struct gatt_handler *handler; print_handle(frame, handle, false); - print_hex_field(" Data", frame->data, frame->size); if (len > frame->size) { print_text(COLOR_ERROR, "invalid size"); return; } + print_hex_field(" Data", frame->data, len); + attr = get_attribute(frame, handle, false); if (!attr) return; handler = get_handler(attr); - if (!handler) + if (!handler || !handler->write) return; handler->write(frame); @@ -2907,7 +4618,7 @@ static void print_notify(const struct l2cap_frame *frame, uint16_t handle, size_t len) { struct gatt_db_attribute *attr; - struct gatt_handler *handler; + const struct gatt_handler *handler; struct l2cap_frame clone; print_handle(frame, handle, true); @@ -2935,7 +4646,8 @@ static void print_notify(const struct l2cap_frame *frame, uint16_t handle, frame = &clone; } - handler->notify(frame); + if (handler->notify) + handler->notify(frame); } static void att_handle_value_notify(const struct l2cap_frame *frame) @@ -3006,7 +4718,6 @@ static void att_signed_write_command(const struct l2cap_frame *frame) } print_write(frame, handle, frame->size - 12); - print_hex_field(" Data", frame->data, frame->size - 12); print_hex_field(" Signature", frame->data + frame->size - 12, 12); } diff --git a/monitor/avctp.c b/monitor/avctp.c index fb26282825c9f4bd8c84eb6392383bf7a4874489..4da448750be5869b7d5a481097cf7b26b7b14e8d 100644 --- a/monitor/avctp.c +++ b/monitor/avctp.c @@ -156,6 +156,7 @@ #define AVRCP_MEDIA_ATTRIBUTE_TOTAL 0x05 #define AVRCP_MEDIA_ATTRIBUTE_GENRE 0x06 #define AVRCP_MEDIA_ATTRIBUTE_DURATION 0x07 +#define AVRCP_MEDIA_ATTRIBUTE_IMG_HANDLE 0x08 /* play status */ #define AVRCP_PLAY_STATUS_STOPPED 0x00 @@ -582,6 +583,8 @@ static const char *mediattr2str(uint32_t attr) return "Genre"; case AVRCP_MEDIA_ATTRIBUTE_DURATION: return "Track duration"; + case AVRCP_MEDIA_ATTRIBUTE_IMG_HANDLE: + return "Imaging handle"; default: return "Reserved"; } @@ -1802,7 +1805,7 @@ response: } -static struct { +static const struct { const char *str; bool reserved; } features_table[] = { diff --git a/monitor/broadcom.c b/monitor/broadcom.c index 72da56da2124977e5464d52fefe55e7d3d067a28..80c95e91db0a442fc6e7433b1aa5d046e8a0aea2 100644 --- a/monitor/broadcom.c +++ b/monitor/broadcom.c @@ -706,7 +706,8 @@ void broadcom_lm_diag(const void *data, uint8_t size) } } -static void lm_diag_evt(uint16_t index, const void *data, uint8_t size) +static void lm_diag_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { broadcom_lm_diag(data, 63); } diff --git a/monitor/bt.h b/monitor/bt.h index 7aa016a0e2a8abf5aa05184d64749e76ba2abf8a..6fb81abfe98e148421b8473ef0261b0c0ff68f57 100644 --- a/monitor/bt.h +++ b/monitor/bt.h @@ -5,6 +5,7 @@ * * Copyright (C) 2011-2014 Intel Corporation * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org> + * Copyright 2023 NXP * * */ @@ -94,8 +95,36 @@ struct bt_ll_peripheral_feature_req { } __attribute__ ((packed)); #define BT_LL_CONN_PARAM_REQ 0x0f +struct bt_ll_conn_param_req { + uint16_t interval_min; + uint16_t interval_max; + uint16_t latency; + uint16_t timeout; + uint8_t pref_period; + uint16_t pref_conn_evt_count; + uint8_t offset_0; + uint8_t offset_1; + uint8_t offset_2; + uint8_t offset_3; + uint8_t offset_4; + uint8_t offset_5; +} __attribute__ ((packed)); #define BT_LL_CONN_PARAM_RSP 0x10 +struct bt_ll_conn_param_rsp { + uint16_t interval_min; + uint16_t interval_max; + uint16_t latency; + uint16_t timeout; + uint8_t pref_period; + uint16_t pref_conn_evt_count; + uint8_t offset_0; + uint8_t offset_1; + uint8_t offset_2; + uint8_t offset_3; + uint8_t offset_4; + uint8_t offset_5; +} __attribute__ ((packed)); #define BT_LL_REJECT_IND_EXT 0x11 struct bt_ll_reject_ind_ext { @@ -561,6 +590,10 @@ struct bt_hci_cmd_add_sco_conn { struct bt_hci_cmd_create_conn_cancel { uint8_t bdaddr[6]; } __attribute__ ((packed)); +struct bt_hci_rsp_create_conn_cancel { + uint8_t status; + uint8_t bdaddr[6]; +} __attribute__ ((packed)); #define BT_HCI_CMD_ACCEPT_CONN_REQUEST 0x0409 struct bt_hci_cmd_accept_conn_request { @@ -1787,6 +1820,12 @@ struct bt_hci_rsp_read_local_pairing_options { #define BT_HCI_LOCAL_CODEC_LE_CIS BIT(2) #define BT_HCI_LOCAL_CODEC_LE_BIS BIT(3) +struct bt_hci_vnd_codec_v2 { + uint16_t cid; + uint16_t vid; + uint8_t transport; +} __attribute__ ((packed)); + struct bt_hci_vnd_codec { uint8_t id; uint16_t cid; @@ -2601,7 +2640,7 @@ struct bt_hci_cmd_periodic_sync_trans { struct bt_hci_cmd_pa_set_info_trans { uint16_t handle; uint16_t service_data; - uint16_t adv_handle; + uint8_t adv_handle; } __attribute__ ((packed)); #define BT_HCI_CMD_PA_SYNC_TRANS_PARAMS 0x205c @@ -2770,20 +2809,19 @@ struct bt_hci_bis_test { uint16_t iso_interval; uint8_t nse; uint16_t sdu; - uint8_t pdu; + uint16_t pdu; uint8_t phy; uint8_t packing; uint8_t framing; uint8_t bn; uint8_t irc; uint8_t pto; - uint8_t adv_handle; uint8_t encryption; uint8_t bcode[16]; } __attribute__ ((packed)); struct bt_hci_cmd_le_create_big_test { - uint8_t big_id; + uint8_t big_handle; uint8_t adv_handle; uint8_t num_bis; struct bt_hci_bis_test bis[0]; @@ -2856,6 +2894,11 @@ struct bt_hci_cmd_le_remove_iso_path { uint8_t direction; } __attribute__ ((packed)); +struct bt_hci_rsp_le_remove_iso_path { + uint8_t status; + uint16_t handle; +} __attribute__ ((packed)); + #define BT_HCI_CMD_LE_ISO_TX_TEST 0x2070 #define BT_HCI_BIT_LE_ISO_TX_TEST BT_HCI_CMD_BIT(43, 5) @@ -2875,6 +2918,24 @@ struct bt_hci_cmd_le_set_host_feature { uint8_t bit_value; } __attribute__ ((packed)); +#define BT_HCI_CMD_LE_READ_ISO_LINK_QUALITY 0x2075 +#define BT_HCI_BIT_LE_READ_ISO_LINK_QUALITY BT_HCI_CMD_BIT(45, 1) +struct bt_hci_cmd_le_read_iso_link_quality { + uint16_t handle; +} __attribute__ ((packed)); + +struct bt_hci_rsp_le_read_iso_link_quality { + uint8_t status; + uint16_t handle; + uint32_t tx_unacked_packets; + uint32_t tx_flushed_packets; + uint32_t tx_last_subevent_packets; + uint32_t retransmitted_packets; + uint32_t crc_error_packets; + uint32_t rx_unreceived_packets; + uint32_t duplicated_packets; +} __attribute__ ((packed)); + #define BT_HCI_EVT_INQUIRY_COMPLETE 0x01 struct bt_hci_evt_inquiry_complete { uint8_t status; @@ -3670,7 +3731,7 @@ struct bt_hci_evt_le_big_sync_estabilished { #define BT_HCI_EVT_LE_BIG_SYNC_LOST 0x1e struct bt_hci_evt_le_big_sync_lost { - uint8_t big_id; + uint8_t big_handle; uint8_t reason; } __attribute__ ((packed)); @@ -3706,14 +3767,17 @@ struct bt_hci_evt_le_big_info_adv_report { #define BT_HCI_ERR_AUTH_FAILURE 0x05 #define BT_HCI_ERR_PIN_OR_KEY_MISSING 0x06 #define BT_HCI_ERR_MEM_CAPACITY_EXCEEDED 0x07 +#define BT_HCI_ERR_CONN_ALREADY_EXISTS 0x0b #define BT_HCI_ERR_COMMAND_DISALLOWED 0x0c #define BT_HCI_ERR_UNSUPPORTED_FEATURE 0x11 #define BT_HCI_ERR_INVALID_PARAMETERS 0x12 +#define BT_HCI_ERR_LOCAL_HOST_TERM 0x16 #define BT_HCI_ERR_UNSPECIFIED_ERROR 0x1f #define BT_HCI_ERR_ADV_TIMEOUT 0x3c #define BT_HCI_ERR_CONN_FAILED_TO_ESTABLISH 0x3e #define BT_HCI_ERR_UNKNOWN_ADVERTISING_ID 0x42 #define BT_HCI_ERR_CANCELLED 0x44 +#define BT_HCI_ERR_ENC_MODE_NOT_ACCEPTABLE 0x25 struct bt_l2cap_hdr { uint16_t len; diff --git a/monitor/btmon.1 b/monitor/btmon.1 new file mode 100644 index 0000000000000000000000000000000000000000..80254f683981c1f232971f2b842483a332bf96b6 --- /dev/null +++ b/monitor/btmon.1 @@ -0,0 +1,258 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BTMON" "1" "April 2021" "BlueZ" "Linux System Administration" +.SH NAME +btmon \- Bluetooth monitor +.SH SYNOPSYS +.sp +\fBbtmon\fP [\fIOPTIONS\fP ...] +.SH DESCRIPTION +.sp +The btmon(1) command provides access to the Bluetooth subsystem monitor +infrastructure for reading HCI traces. +.SH OPTIONS +.INDENT 0.0 +.TP +.BI \-r \ FILE\fR,\fB \ \-\-read \ FILE +Read traces in btsnoop format from \fIFILE\fP\&. +.TP +.BI \-w \ FILE\fR,\fB \ \-\-write \ FILE +Save traces in btsnoop format to \fIFILE\fP\&. +.TP +.BI \-a \ FILE\fR,\fB \ \-\-analyze \ FILE +Analyze traces in btsnoop format from \fIFILE\fP\&. +It displays the devices found in the \fIFILE\fP with +its packets by type. If gnuplot is installed on +the system it also attempts to plot packet latency +graph. +.TP +.BI \-s \ SOCKET\fR,\fB \ \-\-server \ SOCKET +Start monitor server socket. +.TP +.BI \-p \ PRIORITY\fR,\fB \ \-\-priority \ PRIORITY +Show only priority or lower for user log. +.UNINDENT +.TS +box center; +l|l. +T{ +\fIPRIORITY\fP +T} T{ +NAME +T} +_ +T{ +\fB3\fP +T} T{ +Error +T} +_ +T{ +\fB4\fP +T} T{ +Warning +T} +_ +T{ +\fB6\fP +T} T{ +Information (Default) +T} +_ +T{ +\fB7\fP +T} T{ +Debug. \fBdebug\fP can be used. +T} +.TE +.INDENT 0.0 +.TP +.BI \-i \ NUM\fR,\fB \ \-\-index \ NUM +Show only specified controller. \fIhciNUM\fP is also +acceptable. This is useful to capture the traces +from the specific controller when the multiple +controllers are presented. +.TP +.BI \-d \ TTY\fR,\fB \ \-\-tty \ TTY +Read data from \fITTY\fP\&. +.TP +.BI \-B \ SPEED\fR,\fB \ \-\-rate \ SPEED +Set TTY speed. The default \fISPEED\fP is 115300 +.TP +.BI \-V \ COMPID\fR,\fB \ \-\-vendor \ COMPID +Set the default company identifier. The \fICOMPID\fP is +a unique number assigned by the Bluetooth SIG to +a member company and can be found/searched from the +Bluetooth SIG webpage. +.sp +For example, Intel is 2 and Realtek is 93. +.TP +.B \-M\fP,\fB \-\-mgmt +Open channel for mgmt events. +.TP +.B \-t\fP,\fB \-\-time +Show a time instead of time offset. +.TP +.B \-T\fP,\fB \-\-date +Show a time and date information instead of +time offset. +.TP +.B \-S\fP,\fB \-\-sco +Dump SCO traffic in raw hex format. +.TP +.B \-A\fP,\fB \-\-a2dp +Dump A2DP stream traffic in a raw hex format. +.TP +.BI \-E \ IP\fR,\fB \ \-\-ellisys \ IP +Send Ellisys HCI Injection. +.TP +.B \-P\fP,\fB \-\-no\-pager +Disable pager usage while reading the log file. +.TP +.BI \-J \ OPTIONS\fR,\fB \ \-\-jlink \ OPTIONS +Read data from RTT. Each options are comma(,) +seprated without spaces. +.UNINDENT +.TS +box center; +l|l. +T{ +\fIOPTIONS\fP +T} T{ +Description +T} +_ +T{ +\fBDEVICE\fP +T} T{ +Required. Set the target device. +T} +_ +T{ +\fBSERIALNO\fP +T} T{ +(Optional) Set the USB serial number. Default is \fB0\fP\&. +T} +_ +T{ +\fBINTERFACE\fP +T} T{ +(Optional) Target interface. Default is \fBswd\fP\&. +T} +_ +T{ +\fBSPEED\fP +T} T{ +(Optional) Set target interface speed in kHz. Default is \fB1000\fP\&. +T} +.TE +.INDENT 0.0 +.TP +.BI \-R \ OPTIONS\fR,\fB \ \-\-rtt \ OPTIONS +RTT control block parameters. Each options are +comma(,) seprated without spaces. +.UNINDENT +.TS +box center; +l|l. +T{ +\fIOPTIONS\fP +T} T{ +Description +T} +_ +T{ +\fBADDRESS\fP +T} T{ +(Optional) Address of RTT buffer. Default is \fB0x00\fP +T} +_ +T{ +\fBAREA\fP +T} T{ +(Optional) Size of range to search in RTT buffer. Default is \fB0\fP +T} +_ +T{ +\fBNAME\fP +T} T{ +(Optional) Buffer name. Default is \fBbtmonitor\fP +T} +.TE +.INDENT 0.0 +.TP +.BI \-C \ WIDTH\fR,\fB \ \-\-columns \ WIDTH +Output width if not a terminal +.TP +.BI \-c \ MODE\fR,\fB \ \-\-color \ MODE +Set output color. The possible \fIMODE\fP values are: +\fBauto|always|never\fP\&. +.sp +Default value is \fBauto\fP +.TP +.B \-v\fP,\fB \-\-version +Show version +.TP +.B \-h\fP,\fB \-\-help +Show help options +.UNINDENT +.SH EXAMPLES +.SS Capture the traces from hci0 to hcidump.log file +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +$ btmon \-i hci0 \-w hcidump.log +.EE +.UNINDENT +.UNINDENT +.SS Open the trace file +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +$ btmon \-r hcidump.log +.EE +.UNINDENT +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH AUTHOR +Marcel Holtmann <marcel@holtmann.org>, Tedd Ho-Jeong An <tedd.an@intel.com> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/monitor/btmon.rst b/monitor/btmon.rst index 0ab13eb2eb5c640e64b8ade93df64cc3bf8be65e..82f9381c151db89ee10976d158a2a0e5a99cc91c 100644 --- a/monitor/btmon.rst +++ b/monitor/btmon.rst @@ -33,7 +33,9 @@ OPTIONS -w FILE, --write FILE Save traces in btsnoop format to *FILE*. -a FILE, --analyze FILE Analyze traces in btsnoop format from *FILE*. It displays the devices found in the *FILE* with - its packets by type. + its packets by type. If gnuplot is installed on + the system it also attempts to plot packet latency + graph. -s SOCKET, --server SOCKET Start monitor server socket. -p PRIORITY, --priority PRIORITY Show only priority or lower for user log. diff --git a/monitor/display.h b/monitor/display.h index 5a82f8e6fd9365edf311f4a1ca1e03f3517119b4..ee076448cc3171dad1f860121457c1775aa7fe61 100644 --- a/monitor/display.h +++ b/monitor/display.h @@ -87,7 +87,7 @@ static inline void print_hex_field(const char *label, const uint8_t *data, for (i = 0; i < len; i++) sprintf(str + (i * 2), "%2.2x", data[i]); - print_field("%s: %s", label, str); + print_field("%s[%u]: %s", label, len, str); } void set_default_pager_num_columns(int num_columns); diff --git a/monitor/hwdb.c b/monitor/hwdb.c index 22de9edfb47b5f4290b8d7c0cf28a39636c8d7ba..6c0d052bb97ff2ad0a55bca11868b944679255f5 100644 --- a/monitor/hwdb.c +++ b/monitor/hwdb.c @@ -19,7 +19,7 @@ #include "hwdb.h" -#ifdef HAVE_UDEV_HWDB_NEW +#ifdef HAVE_UDEV #include <libudev.h> bool hwdb_get_vendor_model(const char *modalias, char **vendor, char **model) diff --git a/monitor/intel.c b/monitor/intel.c index f5e9f5932cf4dd149e2e7838ddf59bf4b2e6e3c5..0de864d8a41eb4591d52b69c63027f91d24e94b7 100644 --- a/monitor/intel.c +++ b/monitor/intel.c @@ -171,25 +171,25 @@ struct intel_version_tlv { }; static void print_version_tlv_u32(const struct intel_version_tlv *tlv, - char *type_str) + const char *type_str) { print_field("%s(%u): 0x%8.8x", type_str, tlv->type, get_le32(tlv->val)); } static void print_version_tlv_u16(const struct intel_version_tlv *tlv, - char *type_str) + const char *type_str) { print_field("%s(%u): 0x%4.4x", type_str, tlv->type, get_le16(tlv->val)); } static void print_version_tlv_u8(const struct intel_version_tlv *tlv, - char *type_str) + const char *type_str) { print_field("%s(%u): 0x%2.2x", type_str, tlv->type, get_u8(tlv->val)); } static void print_version_tlv_enabled(const struct intel_version_tlv *tlv, - char *type_str) + const char *type_str) { print_field("%s(%u): %s(%u)", type_str, tlv->type, tlv->val[0] ? "Enabled" : "Disabled", @@ -197,7 +197,7 @@ static void print_version_tlv_enabled(const struct intel_version_tlv *tlv, } static void print_version_tlv_img_type(const struct intel_version_tlv *tlv, - char *type_str) + const char *type_str) { const char *str; @@ -217,34 +217,34 @@ static void print_version_tlv_img_type(const struct intel_version_tlv *tlv, } static void print_version_tlv_timestamp(const struct intel_version_tlv *tlv, - char *type_str) + const char *type_str) { print_field("%s(%u): %u-%u", type_str, tlv->type, tlv->val[1], tlv->val[0]); } static void print_version_tlv_min_fw(const struct intel_version_tlv *tlv, - char *type_str) + const char *type_str) { print_field("%s(%u): %u-%u.%u", type_str, tlv->type, tlv->val[0], tlv->val[1], 2000 + tlv->val[2]); } static void print_version_tlv_otp_bdaddr(const struct intel_version_tlv *tlv, - char *type_str) + const char *type_str) { packet_print_addr(type_str, tlv->val, 0x00); } static void print_version_tlv_unknown(const struct intel_version_tlv *tlv, - char *type_str) + const char *type_str) { print_field("%s(%u): ", type_str, tlv->type); packet_hexdump(tlv->val, tlv->len); } static void print_version_tlv_mfg(const struct intel_version_tlv *tlv, - char *type_str) + const char *type_str) { uint16_t mfg_id = get_le16(tlv->val); @@ -254,8 +254,8 @@ static void print_version_tlv_mfg(const struct intel_version_tlv *tlv, static const struct intel_version_tlv_desc { uint8_t type; - char *type_str; - void (*func)(const struct intel_version_tlv *tlv, char *type_str); + const char *type_str; + void (*func)(const struct intel_version_tlv *tlv, const char *type_str); } intel_version_tlv_table[] = { { 16, "CNVi TOP", print_version_tlv_u32 }, { 17, "CNVr TOP", print_version_tlv_u32 }, @@ -365,7 +365,7 @@ static void read_version_rsp(uint16_t index, const void *data, uint8_t size) static void read_version_cmd(uint16_t index, const void *data, uint8_t size) { - char *str; + const char *str; uint8_t type; /* This is the legacy read version command format and no further action @@ -712,6 +712,29 @@ static void read_supported_features_rsp(uint16_t index, const void *data, packet_hexdump(data + 3, size - 3); } +static void ppag_enable(uint16_t index, const void *data, uint8_t size) +{ + uint32_t enable = get_le32(data); + char *ppag_enable_flags; + + switch (enable) { + case 0x01: + ppag_enable_flags = "EU"; + break; + case 0x02: + ppag_enable_flags = "China"; + break; + case 0x03: + ppag_enable_flags = "EU and China"; + break; + default: + ppag_enable_flags = "Unknown"; + break; + } + + print_field("Enable: %s (0x%8.8x)", ppag_enable_flags, enable); +} + static const struct vendor_ocf vendor_ocf_table[] = { { 0x001, "Reset", reset_cmd, 8, true, @@ -777,7 +800,9 @@ static const struct vendor_ocf vendor_ocf_table[] = { { 0x0a6, "Read Supported Features", read_supported_features_cmd, 1, true, read_supported_features_rsp, 19, true }, - + { 0x20b, "PPAG Enable", + ppag_enable, 4, true, + status_rsp, 1, true }, { } }; @@ -793,11 +818,13 @@ const struct vendor_ocf *intel_vendor_ocf(uint16_t ocf) return NULL; } -static void startup_evt(uint16_t index, const void *data, uint8_t size) +static void startup_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { } -static void fatal_exception_evt(uint16_t index, const void *data, uint8_t size) +static void fatal_exception_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { uint16_t line = get_le16(data); uint8_t module = get_u8(data + 2); @@ -808,7 +835,8 @@ static void fatal_exception_evt(uint16_t index, const void *data, uint8_t size) print_field("Reason: 0x%2.2x", reason); } -static void bootup_evt(uint16_t index, const void *data, uint8_t size) +static void bootup_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { uint8_t zero = get_u8(data); uint8_t num_packets = get_u8(data + 1); @@ -911,7 +939,8 @@ static void bootup_evt(uint16_t index, const void *data, uint8_t size) print_field("DDC status: %s (0x%2.2x)", str, ddc_status); } -static void default_bd_data_evt(uint16_t index, const void *data, uint8_t size) +static void default_bd_data_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { uint8_t mem_status = get_u8(data); const char *str; @@ -928,8 +957,8 @@ static void default_bd_data_evt(uint16_t index, const void *data, uint8_t size) print_field("Memory status: %s (0x%2.2x)", str, mem_status); } -static void secure_send_commands_result_evt(uint16_t index, const void *data, - uint8_t size) +static void secure_send_commands_result_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { uint8_t result = get_u8(data); uint16_t opcode = get_le16(data + 1); @@ -973,7 +1002,8 @@ static void secure_send_commands_result_evt(uint16_t index, const void *data, print_status(status); } -static void debug_exception_evt(uint16_t index, const void *data, uint8_t size) +static void debug_exception_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { uint16_t line = get_le16(data); uint8_t module = get_u8(data + 2); @@ -984,8 +1014,8 @@ static void debug_exception_evt(uint16_t index, const void *data, uint8_t size) print_field("Reason: 0x%2.2x", reason); } -static void le_link_established_evt(uint16_t index, const void *data, - uint8_t size) +static void le_link_established_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { uint16_t handle = get_le16(data); uint32_t access_addr = get_le32(data + 10); @@ -999,7 +1029,8 @@ static void le_link_established_evt(uint16_t index, const void *data, packet_hexdump(data + 14, size - 14); } -static void scan_status_evt(uint16_t index, const void *data, uint8_t size) +static void scan_status_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { uint8_t enable = get_u8(data); @@ -1014,15 +1045,16 @@ static void scan_status_evt(uint16_t index, const void *data, uint8_t size) } -static void act_deact_traces_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void act_deact_traces_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { uint8_t status = get_u8(data); print_status(status); } -static void lmp_pdu_trace_evt(uint16_t index, const void *data, uint8_t size) +static void lmp_pdu_trace_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { uint8_t type, len, id; uint16_t handle, count; @@ -1116,16 +1148,16 @@ static void lmp_pdu_trace_evt(uint16_t index, const void *data, uint8_t size) } } -static void write_bd_data_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void write_bd_data_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { uint8_t status = get_u8(data); print_status(status); } -static void sco_rejected_via_lmp_evt(uint16_t index, const void *data, - uint8_t size) +static void sco_rejected_via_lmp_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { uint8_t reason = get_u8(data + 6); @@ -1133,8 +1165,8 @@ static void sco_rejected_via_lmp_evt(uint16_t index, const void *data, packet_print_error("Reason", reason); } -static void ptt_switch_notification_evt(uint16_t index, const void *data, - uint8_t size) +static void ptt_switch_notification_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { uint16_t handle = get_le16(data); uint8_t table = get_u8(data + 2); @@ -1157,7 +1189,8 @@ static void ptt_switch_notification_evt(uint16_t index, const void *data, print_field("Packet type table: %s (0x%2.2x)", str, table); } -static void system_exception_evt(uint16_t index, const void *data, uint8_t size) +static void system_exception_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { uint8_t type = get_u8(data); const char *str; @@ -1257,11 +1290,9 @@ static void ext_evt_type(const struct intel_tlv *tlv) str = "Disconnection Event"; break; case 0x05: - str = "Audio Link Quality Report Type"; - break; - case 0x06: - str = "Stats for BR/EDR Link Type"; + str = "Performance Stats"; break; + default: print_text(COLOR_UNKNOWN_EXT_EVENT, "Unknown extended telemetry event type (0x%2.2x)", @@ -1287,6 +1318,10 @@ static void ext_acl_evt_hec_errors(const struct intel_tlv *tlv) { uint32_t num = get_le32(tlv->value); + /* Skip if 0 */ + if (!num) + return; + print_field("Rx HEC errors (0x%2.2x): %d", tlv->subevent_id, num); } @@ -1294,6 +1329,10 @@ static void ext_acl_evt_crc_errors(const struct intel_tlv *tlv) { uint32_t num = get_le32(tlv->value); + /* Skip if 0 */ + if (!num) + return; + print_field("Rx CRC errors (0x%2.2x): %d", tlv->subevent_id, num); } @@ -1301,6 +1340,10 @@ static void ext_acl_evt_num_pkt_from_host(const struct intel_tlv *tlv) { uint32_t num = get_le32(tlv->value); + /* Skip if 0 */ + if (!num) + return; + print_field("Packets from host (0x%2.2x): %d", tlv->subevent_id, num); } @@ -1309,6 +1352,10 @@ static void ext_acl_evt_num_tx_pkt_to_air(const struct intel_tlv *tlv) { uint32_t num = get_le32(tlv->value); + /* Skip if 0 */ + if (!num) + return; + print_field("Tx packets (0x%2.2x): %d", tlv->subevent_id, num); } @@ -1317,6 +1364,10 @@ static void ext_acl_evt_num_tx_pkt_retry(const struct intel_tlv *tlv) char *subevent_str; uint32_t num = get_le32(tlv->value); + /* Skip if 0 */ + if (!num) + return; + switch (tlv->subevent_id) { case 0x4f: subevent_str = "Tx packets 0 retries"; @@ -1346,6 +1397,10 @@ static void ext_acl_evt_num_tx_pkt_type(const struct intel_tlv *tlv) char *packet_type_str; uint32_t num = get_le32(tlv->value); + /* Skip if 0 */ + if (!num) + return; + switch (tlv->subevent_id) { case 0x54: packet_type_str = "DH1"; @@ -1387,6 +1442,10 @@ static void ext_acl_evt_num_rx_pkt_from_air(const struct intel_tlv *tlv) { uint32_t num = get_le32(tlv->value); + /* Skip if 0 */ + if (!num) + return; + print_field("Rx packets (0x%2.2x): %d", tlv->subevent_id, num); } @@ -1395,7 +1454,11 @@ static void ext_acl_evt_link_throughput(const struct intel_tlv *tlv) { uint32_t num = get_le32(tlv->value); - print_field("ACL link throughput (KBps) (0x%2.2x): %d", + /* Skip if 0 */ + if (!num) + return; + + print_field("ACL link throughput (bps) (0x%2.2x): %d", tlv->subevent_id, num); } @@ -1403,7 +1466,11 @@ static void ext_acl_evt_max_packet_latency(const struct intel_tlv *tlv) { uint32_t num = get_le32(tlv->value); - print_field("ACL max packet latency (ms) (0x%2.2x): %d", + /* Skip if 0 */ + if (!num) + return; + + print_field("ACL max packet latency (us) (0x%2.2x): %d", tlv->subevent_id, num); } @@ -1411,10 +1478,55 @@ static void ext_acl_evt_avg_packet_latency(const struct intel_tlv *tlv) { uint32_t num = get_le32(tlv->value); - print_field("ACL avg packet latency (ms) (0x%2.2x): %d", + /* Skip if 0 */ + if (!num) + return; + + print_field("ACL avg packet latency (us) (0x%2.2x): %d", tlv->subevent_id, num); } +static void ext_acl_evt_rssi_moving_avg(const struct intel_tlv *tlv) +{ + uint32_t num = get_le16(tlv->value); + + /* Skip if 0 */ + if (!num) + return; + + print_field("ACL RX RSSI moving avg (0x%2.2x): %d", + tlv->subevent_id, num); +} + +static void ext_acl_evt_bad_cnt(const char *prefix, const struct intel_tlv *tlv) +{ + uint32_t c_1m = get_le32(tlv->value); + uint32_t c_2m = get_le32(tlv->value + 4); + uint32_t c_3m = get_le32(tlv->value + 8); + + /* Skip if all 0 */ + if (!c_1m && !c_2m && !c_3m) + return; + + print_field("%s (0x%2.2x): 1M %d 2M %d 3M %d", + prefix, tlv->subevent_id, c_1m, c_2m, c_3m); +} + +static void ext_acl_evt_snr_bad_cnt(const struct intel_tlv *tlv) +{ + ext_acl_evt_bad_cnt("ACL RX SNR Bad Margin Counter", tlv); +} + +static void ext_acl_evt_rx_rssi_bad_cnt(const struct intel_tlv *tlv) +{ + ext_acl_evt_bad_cnt("ACL RX RSSI Bad Counter", tlv); +} + +static void ext_acl_evt_tx_rssi_bad_cnt(const struct intel_tlv *tlv) +{ + ext_acl_evt_bad_cnt("ACL TX RSSI Bad Counter", tlv); +} + static void ext_sco_evt_conn_handle(const struct intel_tlv *tlv) { uint16_t conn_handle = get_le16(tlv->value); @@ -1427,6 +1539,10 @@ static void ext_sco_evt_num_rx_pkt_from_air(const struct intel_tlv *tlv) { uint32_t num = get_le32(tlv->value); + /* Skip if 0 */ + if (!num) + return; + print_field("Packets from host (0x%2.2x): %d", tlv->subevent_id, num); } @@ -1434,6 +1550,10 @@ static void ext_sco_evt_num_tx_pkt_to_air(const struct intel_tlv *tlv) { uint32_t num = get_le32(tlv->value); + /* Skip if 0 */ + if (!num) + return; + print_field("Tx packets (0x%2.2x): %d", tlv->subevent_id, num); } @@ -1441,6 +1561,10 @@ static void ext_sco_evt_num_rx_payloads_lost(const struct intel_tlv *tlv) { uint32_t num = get_le32(tlv->value); + /* Skip if 0 */ + if (!num) + return; + print_field("Rx payload lost (0x%2.2x): %d", tlv->subevent_id, num); } @@ -1449,6 +1573,10 @@ static void ext_sco_evt_num_tx_payloads_lost(const struct intel_tlv *tlv) uint32_t num = get_le32(tlv->value); + /* Skip if 0 */ + if (!num) + return; + print_field("Tx payload lost (0x%2.2x): %d", tlv->subevent_id, num); } @@ -1508,6 +1636,10 @@ static void ext_sco_evt_samples_inserted(const struct intel_tlv *tlv) { uint32_t num = get_le32(tlv->value); + /* Skip if 0 */ + if (!num) + return; + print_field("Late samples inserted based on CDC (0x%2.2x): %d", tlv->subevent_id, num); } @@ -1516,6 +1648,10 @@ static void ext_sco_evt_samples_dropped(const struct intel_tlv *tlv) { uint32_t num = get_le32(tlv->value); + /* Skip if 0 */ + if (!num) + return; + print_field("Samples dropped (0x%2.2x): %d", tlv->subevent_id, num); } @@ -1523,6 +1659,10 @@ static void ext_sco_evt_mute_samples(const struct intel_tlv *tlv) { uint32_t num = get_le32(tlv->value); + /* Skip if 0 */ + if (!num) + return; + print_field("Mute samples sent at initial connection (0x%2.2x): %d", tlv->subevent_id, num); } @@ -1531,6 +1671,10 @@ static void ext_sco_evt_plc_injection_data(const struct intel_tlv *tlv) { uint32_t num = get_le32(tlv->value); + /* Skip if 0 */ + if (!num) + return; + print_field("PLC injection data (0x%2.2x): %d", tlv->subevent_id, num); } @@ -1565,6 +1709,10 @@ static const struct intel_ext_subevent { { 0x5e, 4, ext_acl_evt_link_throughput }, { 0x5f, 4, ext_acl_evt_max_packet_latency }, { 0x60, 4, ext_acl_evt_avg_packet_latency }, + { 0x61, 2, ext_acl_evt_rssi_moving_avg }, + { 0x62, 12, ext_acl_evt_snr_bad_cnt }, + { 0x63, 12, ext_acl_evt_rx_rssi_bad_cnt }, + { 0x64, 12, ext_acl_evt_tx_rssi_bad_cnt }, /* SCO/eSCO audio link quality subevents */ { 0x6a, 2, ext_sco_evt_conn_handle }, @@ -1606,7 +1754,8 @@ static const struct intel_tlv *process_ext_subevent(const struct intel_tlv *tlv, print_text(COLOR_UNKNOWN_EXT_EVENT, "Unknown extended subevent 0x%2.2x", tlv->subevent_id); - return NULL; + packet_hexdump(tlv->value, tlv->length); + return next_tlv; } if (tlv->length != subevent->length) { @@ -1625,7 +1774,8 @@ static const struct intel_tlv *process_ext_subevent(const struct intel_tlv *tlv, return next_tlv; } -static void intel_vendor_ext_evt(uint16_t index, const void *data, uint8_t size) +static void intel_vendor_ext_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { /* The data pointer points to a number of tlv.*/ const struct intel_tlv *tlv = data; @@ -1648,7 +1798,7 @@ static const struct vendor_evt vendor_prefix_evt_table[] = { { } }; -const uint8_t intel_vendor_prefix[] = {0x87, 0x80}; +static const uint8_t intel_vendor_prefix[] = {0x87, 0x80}; #define INTEL_VENDOR_PREFIX_SIZE sizeof(intel_vendor_prefix) /* diff --git a/monitor/jlink.c b/monitor/jlink.c index f9d4037f4cdfe18003291189fa7de8460620c496..e08cc87139c9173496e01a2b817b05cc5efeae4c 100644 --- a/monitor/jlink.c +++ b/monitor/jlink.c @@ -47,6 +47,7 @@ struct rtt_desc { }; static struct rtt_desc rtt_desc; +static void *so = NULL; typedef int (*jlink_emu_selectbyusbsn_func) (unsigned int sn); typedef int (*jlink_open_func) (void); @@ -80,7 +81,6 @@ static struct jlink jlink; int jlink_init(void) { - void *so; unsigned int i; for (i = 0; i < NELEM(jlink_so_name); i++) { @@ -109,6 +109,7 @@ int jlink_init(void) !jlink.emu_getproductname || !jlink.rtterminal_control || !jlink.rtterminal_read) { dlclose(so); + so = NULL; return -EIO; } diff --git a/monitor/keys.c b/monitor/keys.c index d2fa3b23ffec628c0d6d9f5cca16436b52f44939..c1eebae82ac22d649debd1589c35971170638638 100644 --- a/monitor/keys.c +++ b/monitor/keys.c @@ -112,3 +112,29 @@ bool keys_resolve_identity(const uint8_t addr[6], uint8_t ident[6], return false; } + +static bool match_key(const void *data, const void *match_data) +{ + const struct irk_data *irk = data; + const uint8_t *key = match_data; + + return !memcmp(irk->key, key, 16); +} + +bool keys_add_identity(const uint8_t addr[6], uint8_t addr_type, + const uint8_t key[16]) +{ + struct irk_data *irk; + + irk = queue_find(irk_list, match_key, key); + if (!irk) { + irk = new0(struct irk_data, 1); + memcpy(irk->key, key, 16); + queue_push_tail(irk_list, irk); + } + + memcpy(irk->addr, addr, 6); + irk->addr_type = addr_type; + + return true; +} diff --git a/monitor/keys.h b/monitor/keys.h index e40c90fa9c72cf1753d8ed758830bcba5ac507dc..f44d332952693d0cd5d584a49b49d538a9cc4b73 100644 --- a/monitor/keys.h +++ b/monitor/keys.h @@ -20,3 +20,5 @@ void keys_update_identity_addr(const uint8_t addr[6], uint8_t addr_type); bool keys_resolve_identity(const uint8_t addr[6], uint8_t ident[6], uint8_t *ident_type); +bool keys_add_identity(const uint8_t addr[6], uint8_t addr_type, + const uint8_t key[16]); diff --git a/monitor/l2cap.c b/monitor/l2cap.c index 3f5554e5e33fedd3d2121f8ba68967e6bddee4b8..dff183bd0972c68991816877062ec4eb0a695e13 100644 --- a/monitor/l2cap.c +++ b/monitor/l2cap.c @@ -23,6 +23,7 @@ #include "lib/uuid.h" #include "src/shared/util.h" +#include "src/shared/queue.h" #include "bt.h" #include "packet.h" #include "display.h" @@ -99,6 +100,7 @@ struct chan_data { uint8_t ext_ctrl; uint8_t seq_num; uint16_t sdu; + struct packet_latency tx_l; }; static struct chan_data chan_list[MAX_CHAN]; @@ -716,7 +718,7 @@ static void print_config_result(uint16_t result) print_field("Result: %s (0x%4.4x)", str, le16_to_cpu(result)); } -static struct { +static const struct { uint8_t type; uint8_t len; const char *str; @@ -1538,6 +1540,23 @@ static const struct sig_opcode_data le_sig_opcode_table[] = { { }, }; +static void l2cap_queue_frame(struct l2cap_frame *frame) +{ + struct packet_conn_data *conn; + struct l2cap_frame *tx; + + conn = packet_get_conn_data(frame->handle); + if (!conn) + return; + + if (!conn->chan_q) + conn->chan_q = queue_new(); + + tx = new0(struct l2cap_frame, 1); + memcpy(tx, frame, sizeof(*frame)); + queue_push_tail(conn->chan_q, tx); +} + void l2cap_frame_init(struct l2cap_frame *frame, uint16_t index, bool in, uint16_t handle, uint8_t ident, uint16_t cid, uint16_t psm, @@ -1554,6 +1573,9 @@ void l2cap_frame_init(struct l2cap_frame *frame, uint16_t index, bool in, frame->psm = psm ? psm : get_psm(frame); frame->mode = get_mode(frame); frame->seq_num = psm ? 1 : get_seq_num(frame); + + if (!in) + l2cap_queue_frame(frame); } static void bredr_sig_packet(uint16_t index, bool in, uint16_t handle, @@ -2773,3 +2795,29 @@ void l2cap_packet(uint16_t index, bool in, uint16_t handle, uint8_t flags, return; } } + +void l2cap_dequeue_frame(struct timeval *delta, struct packet_conn_data *conn) +{ + struct l2cap_frame *frame; + struct chan_data *chan; + + frame = queue_pop_head(conn->chan_q); + if (!frame) + return; + + chan = get_chan(frame); + if (!chan) + return; + + packet_latency_add(&chan->tx_l, delta); + + print_field("Channel: %d [PSM %d mode %s (0x%02x)] {chan %d}", + frame->cid, frame->psm, mode2str(frame->mode), + frame->mode, frame->chan); + + print_field("Channel Latency: %lld msec (%lld-%lld msec ~%lld msec)", + TV_MSEC(*delta), TV_MSEC(chan->tx_l.min), + TV_MSEC(chan->tx_l.max), TV_MSEC(chan->tx_l.med)); + + free(frame); +} diff --git a/monitor/l2cap.h b/monitor/l2cap.h index 935066e6e7dc9a5e9fc53322c7df35ad7cfc1b96..b545bf686c055c0f9aaacd641eb9d12234ee33fe 100644 --- a/monitor/l2cap.h +++ b/monitor/l2cap.h @@ -355,3 +355,5 @@ void l2cap_packet(uint16_t index, bool in, uint16_t handle, uint8_t flags, const void *data, uint16_t size); void rfcomm_packet(const struct l2cap_frame *frame); + +void l2cap_dequeue_frame(struct timeval *delta, struct packet_conn_data *conn); diff --git a/monitor/ll.c b/monitor/ll.c index f588d5e9926a0f8f5cc3c481589b7e73bb51db7d..feeb13e9282ad5f24bb1df4987ce96e5b8f3046f 100644 --- a/monitor/ll.c +++ b/monitor/ll.c @@ -458,6 +458,64 @@ static void peripheral_feature_req(const void *data, uint8_t size) packet_print_features_ll(pdu->features); } +static void conn_param_req(const void *data, uint8_t size) +{ + const struct bt_ll_conn_param_req *pdu = data; + + print_field("Interval min: %.2f msec (0x%4.4x)", + pdu->interval_min * 1.25, pdu->interval_min); + print_field("Interval max: %.2f msec (0x%4.4x)", + pdu->interval_max * 1.25, pdu->interval_max); + print_field("Latency: %d (0x%4.4x)", pdu->latency, pdu->latency); + print_field("Timeout: %d msec (0x%4.4x)", pdu->timeout * 10, + pdu->timeout); + print_field("Preffered periodicity: %.2f (0x%2.2x)", + pdu->pref_period * 1.25, pdu->pref_period); + print_field("Reference connection event count: %d (0x%2.2x)", + pdu->pref_conn_evt_count, pdu->pref_conn_evt_count); + print_field("Offset 0: %.2f msec (0x%2.2x)", pdu->offset_0 * 1.25, + pdu->offset_0); + print_field("Offset 1: %.2f msec (0x%2.2x)", pdu->offset_1 * 1.25, + pdu->offset_1); + print_field("Offset 2: %.2f msec (0x%2.2x)", pdu->offset_2 * 1.25, + pdu->offset_2); + print_field("Offset 3: %.2f msec (0x%2.2x)", pdu->offset_3 * 1.25, + pdu->offset_3); + print_field("Offset 4: %.2f msec (0x%2.2x)", pdu->offset_4 * 1.25, + pdu->offset_4); + print_field("Offset 5: %.2f msec (0x%2.2x)", pdu->offset_5 * 1.25, + pdu->offset_5); +} + +static void conn_param_rsp(const void *data, uint8_t size) +{ + const struct bt_ll_conn_param_rsp *pdu = data; + + print_field("Interval min: %.2f msec (0x%4.4x)", + pdu->interval_min * 1.25, pdu->interval_min); + print_field("Interval max: %.2f msec (0x%4.4x)", + pdu->interval_max * 1.25, pdu->interval_max); + print_field("Latency: %d (0x%4.4x)", pdu->latency, pdu->latency); + print_field("Timeout: %d msec (0x%4.4x)", pdu->timeout * 10, + pdu->timeout); + print_field("Preffered periodicity: %.2f (0x%2.2x)", + pdu->pref_period * 1.25, pdu->pref_period); + print_field("Reference connection event count: %d (0x%2.2x)", + pdu->pref_conn_evt_count, pdu->pref_conn_evt_count); + print_field("Offset 0: %.2f msec (0x%2.2x)", pdu->offset_0 * 1.25, + pdu->offset_0); + print_field("Offset 1: %.2f msec (0x%2.2x)", pdu->offset_1 * 1.25, + pdu->offset_1); + print_field("Offset 2: %.2f msec (0x%2.2x)", pdu->offset_2 * 1.25, + pdu->offset_2); + print_field("Offset 3: %.2f msec (0x%2.2x)", pdu->offset_3 * 1.25, + pdu->offset_3); + print_field("Offset 4: %.2f msec (0x%2.2x)", pdu->offset_4 * 1.25, + pdu->offset_4); + print_field("Offset 5: %.2f msec (0x%2.2x)", pdu->offset_5 * 1.25, + pdu->offset_5); +} + static void reject_ind_ext(const void *data, uint8_t size) { const struct bt_ll_reject_ind_ext *pdu = data; @@ -707,8 +765,8 @@ static const struct llcp_data llcp_table[] = { { 0x0c, "LL_VERSION_IND", version_ind, 5, true }, { 0x0d, "LL_REJECT_IND", reject_ind, 1, true }, { 0x0e, "LL_PERIPHERAL_FEATURE_REQ", peripheral_feature_req, 8, true }, - { 0x0f, "LL_CONNECTION_PARAM_REQ", NULL, 23, true }, - { 0x10, "LL_CONNECTION_PARAM_RSP", NULL, 23, true }, + { 0x0f, "LL_CONNECTION_PARAM_REQ", conn_param_req, 23, true }, + { 0x10, "LL_CONNECTION_PARAM_RSP", conn_param_rsp, 23, true }, { 0x11, "LL_REJECT_IND_EXT", reject_ind_ext, 2, true }, { 0x12, "LL_PING_REQ", null_pdu, 0, true }, { 0x13, "LL_PING_RSP", null_pdu, 0, true }, diff --git a/monitor/main.c b/monitor/main.c index 3ec3a5f08a01f0076d842fc60dcfb66b8c02e5b6..fa56fcb29f3813306abba58d5098626ec56de1ce 100644 --- a/monitor/main.c +++ b/monitor/main.c @@ -51,6 +51,9 @@ static void usage(void) "\t-r, --read <file> Read traces in btsnoop format\n" "\t-w, --write <file> Save traces in btsnoop format\n" "\t-a, --analyze <file> Analyze traces in btsnoop format\n" + "\t If gnuplot is installed on the\n" + "\t system it will also attempt to plot\n" + "\t packet latency graph.\n" "\t-s, --server <socket> Start monitor server socket\n" "\t-p, --priority <level> Show only priority or lower\n" "\t-i, --index <num> Show only specified controller\n" @@ -62,6 +65,7 @@ static void usage(void) "\t-T, --date Show time and date information\n" "\t-S, --sco Dump SCO traffic\n" "\t-A, --a2dp Dump A2DP stream traffic\n" + "\t-I, --iso Dump ISO traffic\n" "\t-E, --ellisys [ip] Send Ellisys HCI Injection\n" "\t-P, --no-pager Disable pager usage\n" "\t-J --jlink <device>,[<serialno>],[<interface>],[<speed>]\n" @@ -89,6 +93,7 @@ static const struct option main_options[] = { { "date", no_argument, NULL, 'T' }, { "sco", no_argument, NULL, 'S' }, { "a2dp", no_argument, NULL, 'A' }, + { "iso", no_argument, NULL, 'I' }, { "ellisys", required_argument, NULL, 'E' }, { "no-pager", no_argument, NULL, 'P' }, { "jlink", required_argument, NULL, 'J' }, @@ -126,8 +131,8 @@ int main(int argc, char *argv[]) struct sockaddr_un addr; opt = getopt_long(argc, argv, - "r:w:a:s:p:i:d:B:V:MNtTSAE:PJ:R:C:c:vh", - main_options, NULL); + "r:w:a:s:p:i:d:B:V:MNtTSAIE:PJ:R:C:c:vh", + main_options, NULL); if (opt < 0) break; @@ -197,6 +202,9 @@ int main(int argc, char *argv[]) case 'A': filter_mask |= PACKET_FILTER_SHOW_A2DP_STREAM; break; + case 'I': + filter_mask |= PACKET_FILTER_SHOW_ISO_DATA; + break; case 'E': ellisys_server = optarg; ellisys_port = 24352; diff --git a/monitor/msft.c b/monitor/msft.c index 38af6722e6d096c38160971201acb0815990c60c..096fedd5931769d6954f09fd2b258a521e43896d 100644 --- a/monitor/msft.c +++ b/monitor/msft.c @@ -299,7 +299,8 @@ const struct vendor_ocf *msft_vendor_ocf(void) return &vendor_ocf_entry; } -static void msft_evt(uint16_t index, const void *data, uint8_t size) +static void msft_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { packet_hexdump(data, size); } diff --git a/monitor/packet.c b/monitor/packet.c index dae763e22e61d4ed2972697990b9353e45dee25e..32a440bbea6888ab6321e973dbb23d9728864557 100644 --- a/monitor/packet.c +++ b/monitor/packet.c @@ -5,6 +5,7 @@ * * Copyright (C) 2011-2014 Intel Corporation * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org> + * Copyright 2023 NXP * * */ @@ -25,6 +26,7 @@ #include <time.h> #include <sys/time.h> #include <sys/socket.h> +#include <limits.h> #include "lib/bluetooth.h" #include "lib/uuid.h" @@ -33,18 +35,20 @@ #include "src/shared/util.h" #include "src/shared/btsnoop.h" +#include "src/shared/queue.h" +#include "src/shared/bap-debug.h" #include "display.h" #include "bt.h" #include "ll.h" #include "hwdb.h" #include "keys.h" +#include "packet.h" #include "l2cap.h" #include "control.h" #include "vendor.h" #include "msft.h" #include "intel.h" #include "broadcom.h" -#include "packet.h" #define COLOR_CHANNEL_LABEL COLOR_WHITE #define COLOR_FRAME_LABEL COLOR_WHITE @@ -65,6 +69,7 @@ #define COLOR_HCI_EVENT_UNKNOWN COLOR_WHITE_BG #define COLOR_HCI_ACLDATA COLOR_CYAN #define COLOR_HCI_SCODATA COLOR_YELLOW +#define COLOR_HCI_ISODATA COLOR_YELLOW #define COLOR_UNKNOWN_ERROR COLOR_WHITE_BG #define COLOR_UNKNOWN_FEATURE_BIT COLOR_WHITE_BG @@ -169,44 +174,82 @@ static uint16_t get_format(uint32_t cookie) #define MAX_CONN 16 -static struct packet_conn_data conn_list[MAX_CONN]; +static struct packet_conn_data conn_list[MAX_CONN] = { + [0 ... MAX_CONN - 1].handle = 0xffff +}; -static void assign_handle(uint16_t index, uint16_t handle, uint8_t type, - uint8_t *dst, uint8_t dst_type) +static struct packet_conn_data *lookup_parent(uint16_t handle) { int i; for (i = 0; i < MAX_CONN; i++) { - if (conn_list[i].handle == 0x0000) { - if (hci_devba(index, (bdaddr_t *)conn_list[i].src) < 0) - return; + if (conn_list[i].link == handle) + return &conn_list[i]; + } - conn_list[i].index = index; - conn_list[i].handle = handle; - conn_list[i].type = type; + return NULL; +} - if (!dst) - break; +static struct packet_conn_data *release_handle(uint16_t handle) +{ + int i; - memcpy(conn_list[i].dst, dst, sizeof(conn_list[i].dst)); - conn_list[i].dst_type = dst_type; - break; + for (i = 0; i < MAX_CONN; i++) { + struct packet_conn_data *conn = &conn_list[i]; + + if (conn->handle == handle) { + if (conn->destroy) + conn->destroy(conn->data); + + queue_destroy(conn->tx_q, free); + queue_destroy(conn->chan_q, free); + memset(conn, 0, sizeof(*conn)); + conn->handle = 0xffff; + return conn; } } + + return NULL; } -static void release_handle(uint16_t handle) +static void assign_handle(uint16_t index, uint16_t handle, uint8_t type, + uint8_t *dst, uint8_t dst_type) { + struct packet_conn_data *conn = release_handle(handle); int i; - for (i = 0; i < MAX_CONN; i++) { - if (conn_list[i].handle == handle) { - if (conn_list[i].destroy) - conn_list[i].destroy(conn_list[i].data); + if (!conn) { + for (i = 0; i < MAX_CONN; i++) { + if (conn_list[i].handle == 0xffff) { + conn = &conn_list[i]; + break; + } + } + } - memset(&conn_list[i], 0, sizeof(conn_list[i])); - break; + if (!conn) + return; + + hci_devba(index, (bdaddr_t *)conn->src); + + conn->index = index; + conn->handle = handle; + conn->type = type; + + if (!dst) { + struct packet_conn_data *p; + + /* If destination is not set attempt to use the parent one if + * that exists. + */ + p = lookup_parent(handle); + if (p) { + memcpy(conn->dst, p->dst, sizeof(conn->dst)); + conn->dst_type = p->dst_type; } + } else { + memcpy(conn->dst, dst, sizeof(conn->dst)); + conn->dst_type = dst_type; } } @@ -308,13 +351,33 @@ void packet_set_msft_evt_prefix(const uint8_t *prefix, uint8_t len) memcpy(index_list[index_current].msft_evt_prefix, prefix, len); } +static void cred_pid(struct ucred *cred, char *str, size_t len) +{ + char *path = alloca(24); + char line[128]; + FILE *fp; + + snprintf(path, 23, "/proc/%u/comm", cred->pid); + + fp = fopen(path, "re"); + if (fp) { + if (fgets(line, sizeof(line), fp)) { + line[strcspn(line, "\r\n")] = '\0'; + snprintf(str, len, "%s[%u]", line, cred->pid); + } else + snprintf(str, len, "[%u]", cred->pid); + fclose(fp); + } else + snprintf(str, len, "[%u]", cred->pid); +} + static void print_packet(struct timeval *tv, struct ucred *cred, char ident, uint16_t index, const char *channel, const char *color, const char *label, const char *text, const char *extra) { int col = num_columns(); - char line[256], ts_str[96]; + char line[LINE_MAX], ts_str[96], pid_str[140]; int n, ts_len = 0, ts_pos = 0, len = 0, pos = 0; static size_t last_frame; @@ -411,7 +474,13 @@ static void print_packet(struct timeval *tv, struct ucred *cred, char ident, pos += n; } - n = sprintf(line + pos, "%c %s", ident, label ? label : ""); + if (cred && cred->pid) { + cred_pid(cred, pid_str, sizeof(pid_str)); + n = sprintf(line + pos, "%s: %c %s", pid_str, ident, + label ? label : ""); + } else + n = sprintf(line + pos, "%c %s", ident, label ? label : ""); + if (n > 0) { pos += n; len += n; @@ -2391,6 +2460,9 @@ void packet_print_version(const char *label, uint8_t version, case 0x0c: str = "Bluetooth 5.3"; break; + case 0x0d: + str = "Bluetooth 5.4"; + break; default: str = "Reserved"; break; @@ -2663,7 +2735,7 @@ static const struct bitfield_data features_le[] = { { 29, "Connected Isochronous Stream - Peripheral" }, { 30, "Isochronous Broadcaster" }, { 31, "Synchronized Receiver" }, - { 32, "Isochronous Channels (Host Support)" }, + { 32, "Connected Isochronous Stream (Host Support)" }, { 33, "LE Power Control Request" }, { 34, "LE Power Control Request" }, { 35, "LE Path Loss Monitoring" }, @@ -3054,12 +3126,21 @@ static const struct bitfield_data events_le_table[] = { { 17, "LE Extended Advertising Set Terminated" }, { 18, "LE Scan Request Received" }, { 19, "LE Channel Selection Algorithm" }, + { 20, "LE Connectionless IQ Report" }, + { 21, "LE Connection IQ Report" }, + { 22, "LE CTE Request Failed" }, + { 23, "LE Periodic Advertising Sync Transfer Rvc"}, { 24, "LE CIS Established" }, { 25, "LE CIS Request" }, { 26, "LE Create BIG Complete" }, { 27, "LE Terminate BIG Complete" }, { 28, "LE BIG Sync Estabilished Complete" }, { 29, "LE BIG Sync Lost" }, + { 30, "LE Request Peer SCA Complete"}, + { 31, "LE Path Loss Threshold" }, + { 32, "LE Transmit Power Reporting" }, + { 33, "LE BIG Info Advertising Report" }, + { 34, "LE Subrate Change" }, { } }; @@ -3123,6 +3204,7 @@ static void print_fec(uint8_t fec) #define BT_EIR_MESH_PROV 0x29 #define BT_EIR_MESH_DATA 0x2a #define BT_EIR_MESH_BEACON 0x2b +#define BT_EIR_CSIP_RSI 0x2e #define BT_EIR_3D_INFO_DATA 0x3d #define BT_EIR_MANUFACTURER_DATA 0xff @@ -3332,86 +3414,11 @@ static void print_uuid128_list(const char *label, const void *data, } } -static void *iov_pull(struct iovec *iov, size_t len) +static void print_ltv(const char *str, void *user_data) { - void *data; - - if (iov->iov_len < len) - return NULL; - - data = iov->iov_base; - iov->iov_base += len; - iov->iov_len -= len; + const char *label = user_data; - return data; -} - -static struct packet_ltv_decoder* -get_ltv_decoder(struct packet_ltv_decoder *decoder, size_t num, uint8_t type) -{ - size_t i; - - if (!decoder || !num) - return NULL; - - for (i = 0; i < num; i++) { - struct packet_ltv_decoder *dec = &decoder[i]; - - if (dec->type == type) - return dec; - } - - return NULL; -} - -static void print_ltv(const char *label, const uint8_t *data, uint8_t len, - struct packet_ltv_decoder *decoder, size_t num) -{ - struct iovec iov; - int i; - - iov.iov_base = (void *) data; - iov.iov_len = len; - - for (i = 0; iov.iov_len; i++) { - uint8_t l, t, *v; - struct packet_ltv_decoder *dec; - - l = get_u8(iov_pull(&iov, sizeof(l))); - if (!l) { - print_field("%s #%d: len 0x%02x", label, i, l); - break; - } - - v = iov_pull(&iov, sizeof(*v)); - if (!v) - break; - - t = get_u8(v); - - print_field("%s #%d: len 0x%02x type 0x%02x", label, i, l, t); - - l -= 1; - - v = iov_pull(&iov, l); - if (!v) - break; - - dec = get_ltv_decoder(decoder, num, t); - if (dec) - dec->func(v, l); - else - print_hex_field(label, v, l); - } - - if (iov.iov_len) - print_hex_field(label, iov.iov_base, iov.iov_len); -} - -void packet_print_ltv(const char *label, const uint8_t *data, uint8_t len, - struct packet_ltv_decoder *decoder, size_t decoder_len) -{ - print_ltv(label, data, len, decoder, decoder_len); + print_field("%s: %s", label, str); } static void print_base_annoucement(const uint8_t *data, uint8_t data_len) @@ -3423,7 +3430,7 @@ static void print_base_annoucement(const uint8_t *data, uint8_t data_len) iov.iov_base = (void *) data; iov.iov_len = data_len; - base_data = iov_pull(&iov, sizeof(*base_data)); + base_data = util_iov_pull_mem(&iov, sizeof(*base_data)); if (!base_data) goto done; @@ -3437,10 +3444,11 @@ static void print_base_annoucement(const uint8_t *data, uint8_t data_len) struct bt_hci_lv_data *codec_cfg; struct bt_hci_lv_data *metadata; uint8_t j; + const char *label; print_field(" Subgroup #%u:", i); - subgroup = iov_pull(&iov, sizeof(*subgroup)); + subgroup = util_iov_pull_mem(&iov, sizeof(*subgroup)); if (!subgroup) goto done; @@ -3457,26 +3465,31 @@ static void print_base_annoucement(const uint8_t *data, uint8_t data_len) subgroup->codec.vid); } - codec_cfg = iov_pull(&iov, sizeof(*codec_cfg)); + codec_cfg = util_iov_pull_mem(&iov, sizeof(*codec_cfg)); if (!codec_cfg) goto done; - if (!iov_pull(&iov, codec_cfg->len)) + if (!util_iov_pull_mem(&iov, codec_cfg->len)) goto done; - print_ltv(" Codec Specific Configuration", - codec_cfg->data, codec_cfg->len, - NULL, 0); + label = " Codec Specific Configuration"; - metadata = iov_pull(&iov, sizeof(*metadata)); + bt_bap_debug_config(codec_cfg->data, codec_cfg->len, + print_ltv, (void *)label); + + metadata = util_iov_pull_mem(&iov, sizeof(*metadata)); if (!metadata) goto done; - if (!iov_pull(&iov, metadata->len)) + if (!util_iov_pull(&iov, metadata->len)) goto done; - print_ltv(" Metadata", metadata->data, metadata->len, - NULL, 0); + label = " Metadata"; + + bt_bap_debug_metadata(metadata->data, metadata->len, + print_ltv, (void *)label); + + label = " Codec Specific Configuration"; /* Level 3 - BIS(s)*/ for (j = 0; j < subgroup->num_bis; j++) { @@ -3484,21 +3497,21 @@ static void print_base_annoucement(const uint8_t *data, uint8_t data_len) print_field(" BIS #%u:", j); - bis = iov_pull(&iov, sizeof(*bis)); + bis = util_iov_pull_mem(&iov, sizeof(*bis)); if (!bis) goto done; print_field(" Index: %u", bis->index); - codec_cfg = iov_pull(&iov, sizeof(*codec_cfg)); + codec_cfg = util_iov_pull_mem(&iov, sizeof(*codec_cfg)); if (!codec_cfg) goto done; - if (!iov_pull(&iov, codec_cfg->len)) + if (!util_iov_pull(&iov, codec_cfg->len)) goto done; - print_hex_field(" Codec Specific Configuration", - codec_cfg->data, codec_cfg->len); + bt_bap_debug_config(codec_cfg->data, codec_cfg->len, + print_ltv, (void *)label); } } @@ -3767,7 +3780,7 @@ static void print_transport_data(const uint8_t *data, uint8_t len) print_field(" Provider Only"); break; case 0x03: - print_field(" Both Seeker an Provider"); + print_field(" Both Seeker and Provider"); break; } @@ -3954,6 +3967,18 @@ static void print_eir(const uint8_t *eir, uint8_t eir_len, bool le) print_service_data(data, data_len); break; + case BT_EIR_SERVICE_DATA128: + if (data_len <= 16) + break; + + print_field("Service Data UUID 128: %s ", + bt_uuid128_to_str(&data[0])); + + if (data_len > 16) + print_hex_field(" Data", &data[16], + data_len - 16); + + break; case BT_EIR_RANDOM_ADDRESS: if (data_len < 6) break; @@ -4017,6 +4042,14 @@ static void print_eir(const uint8_t *eir, uint8_t eir_len, bool le) print_mesh_beacon(data, data_len); break; + case BT_EIR_CSIP_RSI: + if (data_len < 6) + break; + print_addr("Resolvable Set Identifier", data, 0xff); + print_field(" Hash: 0x%6x", get_le24(data)); + print_field(" Random: 0x%6x", get_le24(data + 3)); + break; + case BT_EIR_MANUFACTURER_DATA: if (data_len < 2) break; @@ -4261,10 +4294,26 @@ void packet_monitor(struct timeval *tv, struct ucred *cred, */ index_list[index].msft_opcode = 0xFC1E; break; + case 29: + /* + * Qualcomm controllers that support the + * Microsoft vendor extensions are using + * 0xFD70 for VsMsftOpCode. + */ + index_list[index].msft_opcode = 0xFD70; + break; + case 70: + /* + * Mediatek controllers that support the + * Microsoft vendor extensions are using + * 0xFD30 for VsMsftOpCode. + */ + index_list[index].msft_opcode = 0xFD30; + break; case 93: /* * Realtek controllers that support the - * Microsoft vendor extenions are using + * Microsoft vendor extensions are using * 0xFCF0 for VsMsftOpCode. */ index_list[index].msft_opcode = 0xFCF0; @@ -4273,7 +4322,7 @@ void packet_monitor(struct timeval *tv, struct ucred *cred, /* * Emulator controllers use Linux Foundation as * manufacturer and support the - * Microsoft vendor extenions using + * Microsoft vendor extensions using * 0xFC1E for VsMsftOpCode. */ index_list[index].msft_opcode = 0xFC1E; @@ -4797,6 +4846,50 @@ static void flow_spec_modify_cmd(uint16_t index, const void *data, uint8_t size) print_flow_spec("RX", cmd->rx_flow_spec); } +static void print_coding_format(const char *label, + const uint8_t coding_format[5]) +{ + print_field("%s:", label); + packet_print_codec_id(" Codec", coding_format[0]); + if (coding_format[0] == 0xff) { + print_field(" Company: %s", + bt_compidtostr(get_le16(coding_format + 1))); + print_field(" Vendor Specific Codec: 0x%4.4x", + get_le16(coding_format + 3)); + } +} + +static void print_pcm_data_format(const char *label, uint8_t pcm) +{ + switch (pcm) { + case 0: + print_field("%s: NA", label); + break; + case 1: + print_field("%s: 1's complement", label); + break; + case 2: + print_field("%s: 2's complement", label); + break; + case 3: + print_field("%s: Sign-magnitude", label); + break; + case 4: + print_field("%s: Unsigned", label); + break; + default: + print_field("%s: Unknown (0x%2.2x)", label, pcm); + } +} + +static void print_data_path(const char *label, uint8_t data_path) +{ + if (data_path == 0) + print_field("%s: HCI", label); + else + print_field("%s: Vendor Specific (0x%2.2x)", label, data_path); +} + static void enhanced_setup_sync_conn_cmd(uint16_t index, const void *data, uint8_t size) { @@ -4805,9 +4898,30 @@ static void enhanced_setup_sync_conn_cmd(uint16_t index, const void *data, print_handle(cmd->handle); print_field("Transmit bandwidth: %d", le32_to_cpu(cmd->tx_bandwidth)); print_field("Receive bandwidth: %d", le32_to_cpu(cmd->rx_bandwidth)); - - /* TODO */ - + print_coding_format("Transmit Coding Format", cmd->tx_coding_format); + print_coding_format("Receive Coding Format", cmd->rx_coding_format); + print_field("Transmit Codec Frame Size: %d", + le16_to_cpu(cmd->tx_codec_frame_size)); + print_field("Receive Codec Frame Size: %d", + le16_to_cpu(cmd->rx_codec_frame_size)); + print_coding_format("Input Coding Format", cmd->input_coding_format); + print_coding_format("Output Coding Format", cmd->output_coding_format); + print_field("Input Coded Data Size: %d", + le16_to_cpu(cmd->input_coded_data_size)); + print_field("Output Coded Data Size: %d", + le16_to_cpu(cmd->output_coded_data_size)); + print_pcm_data_format("Input PCM Data Format", + cmd->input_pcm_data_format); + print_pcm_data_format("Output PCM Data Format", + cmd->output_pcm_data_format); + print_field("Input PCM Sample Payload MSB Position: %d", + cmd->input_pcm_msb_position); + print_field("Output PCM Sample Payload MSB Position: %d", + cmd->output_pcm_msb_position); + print_data_path("Input Data Path", cmd->input_data_path); + print_data_path("Output Data Path", cmd->output_data_path); + print_field("Input Transport Unit Size: %d", cmd->input_unit_size); + print_field("Output Transport Unit Size: %d", cmd->output_unit_size); print_field("Max latency: %d", le16_to_cpu(cmd->max_latency)); print_pkt_type_sco(cmd->pkt_type); print_retransmission_effort(cmd->retrans_effort); @@ -4822,9 +4936,30 @@ static void enhanced_accept_sync_conn_request_cmd(uint16_t index, print_bdaddr(cmd->bdaddr); print_field("Transmit bandwidth: %d", le32_to_cpu(cmd->tx_bandwidth)); print_field("Receive bandwidth: %d", le32_to_cpu(cmd->rx_bandwidth)); - - /* TODO */ - + print_coding_format("Transmit Coding Format", cmd->tx_coding_format); + print_coding_format("Receive Coding Format", cmd->rx_coding_format); + print_field("Transmit Codec Frame Size: %d", + le16_to_cpu(cmd->tx_codec_frame_size)); + print_field("Receive Codec Frame Size: %d", + le16_to_cpu(cmd->rx_codec_frame_size)); + print_coding_format("Input Coding Format", cmd->input_coding_format); + print_coding_format("Output Coding Format", cmd->output_coding_format); + print_field("Input Coded Data Size: %d", + le16_to_cpu(cmd->input_coded_data_size)); + print_field("Output Coded Data Size: %d", + le16_to_cpu(cmd->output_coded_data_size)); + print_pcm_data_format("Input PCM Data Format", + cmd->input_pcm_data_format); + print_pcm_data_format("Output PCM Data Format", + cmd->output_pcm_data_format); + print_field("Input PCM Sample Payload MSB Position: %d", + cmd->input_pcm_msb_position); + print_field("Output PCM Sample Payload MSB Position: %d", + cmd->output_pcm_msb_position); + print_data_path("Input Data Path", cmd->input_data_path); + print_data_path("Output Data Path", cmd->output_data_path); + print_field("Input Transport Unit Size: %d", cmd->input_unit_size); + print_field("Output Transport Unit Size: %d", cmd->output_unit_size); print_field("Max latency: %d", le16_to_cpu(cmd->max_latency)); print_pkt_type_sco(cmd->pkt_type); print_retransmission_effort(cmd->retrans_effort); @@ -6384,6 +6519,20 @@ static void print_list(const void *data, uint8_t size, int num_items, print_hex_field("", data, size); } +static void print_vnd_codecs_v2(const void *data, int i) +{ + const struct bt_hci_vnd_codec_v2 *codec = data; + uint8_t mask; + + packet_print_company(" Company ID", le16_to_cpu(codec->cid)); + print_field(" Vendor Codec ID: 0x%4.4x", le16_to_cpu(codec->vid)); + print_field(" Logical Transport Type: 0x%02x", codec->transport); + mask = print_bitfield(4, codec->transport, codec_transport_table); + if (mask) + print_text(COLOR_UNKNOWN_SERVICE_CLASS, + " Unknown transport (0x%2.2x)", mask); +} + static void read_local_codecs_rsp_v2(uint16_t index, const void *data, uint8_t size) { @@ -6417,7 +6566,18 @@ static void read_local_codecs_rsp_v2(uint16_t index, const void *data, num_vnd_codecs = rsp->codec[rsp->num_codecs].id; + size -= 1; + print_field("Number of vendor codecs: %d", num_vnd_codecs); + + if (size < num_vnd_codecs * sizeof(*rsp->codec)) { + print_field("Invalid number of vendor codecs."); + return; + } + + print_list(&rsp->codec[rsp->num_codecs] + 1, size, num_vnd_codecs, + sizeof(struct bt_hci_vnd_codec_v2), + print_vnd_codecs_v2); } static void print_path_direction(const char *prefix, uint8_t dir) @@ -6520,11 +6680,9 @@ static void config_data_path_cmd(uint16_t index, const void *data, uint8_t size) static void print_usec_interval(const char *prefix, const uint8_t interval[3]) { - uint32_t u24 = 0; + uint32_t value = get_le24(interval); - memcpy(&u24, interval, 3); - print_field("%s: %u us (0x%6.6x)", prefix, le32_to_cpu(u24), - le32_to_cpu(u24)); + print_field("%s: %u us (0x%6.6x)", prefix, value, value); } static void read_local_ctrl_delay_rsp(uint16_t index, const void *data, @@ -8639,9 +8797,14 @@ static void le_set_cig_params_rsp(uint16_t index, const void *data, static void print_cis(const void *data, int i) { const struct bt_hci_cis *cis = data; + struct packet_conn_data *conn; print_field("CIS Handle: %d", cis->cis_handle); print_field("ACL Handle: %d", cis->acl_handle); + + conn = packet_get_conn_data(cis->acl_handle); + if (conn) + conn->link = cis->cis_handle; } static void le_create_cis_cmd(uint16_t index, const void *data, uint8_t size) @@ -8741,7 +8904,7 @@ static void le_create_big_cmd_test_cmd(uint16_t index, const void *data, { const struct bt_hci_cmd_le_create_big_test *cmd = data; - print_field("BIG ID: 0x%2.2x", cmd->big_id); + print_field("BIG Handle: 0x%2.2x", cmd->big_handle); print_field("Advertising Handle: 0x%2.2x", cmd->adv_handle); print_field("Number of BIS: %u", cmd->num_bis); @@ -8774,7 +8937,7 @@ static void le_big_create_sync_cmd(uint16_t index, const void *data, print_field("BIG Handle: 0x%2.2x", cmd->handle); print_field("BIG Sync Handle: 0x%4.4x", le16_to_cpu(cmd->sync_handle)); print_field("Encryption: %s (0x%2.2x)", - cmd->encryption ? "Unencrypted" : "Encrypted", + cmd->encryption ? "Encrypted" : "Unencrypted", cmd->encryption); print_hex_field("Broadcast Code", cmd->bcode, 16); print_field("Maximum Number Subevents: 0x%2.2x", cmd->mse); @@ -8872,6 +9035,37 @@ static void le_set_host_feature_cmd(uint16_t index, const void *data, print_field("Bit Value: %u", cmd->bit_value); } +static void le_read_iso_link_quality_cmd(uint16_t index, const void *data, + uint8_t size) +{ + const struct bt_hci_cmd_le_read_iso_link_quality *cmd = data; + + print_field("Handle: %d", le16_to_cpu(cmd->handle)); +} + +static void status_le_read_iso_link_quality_rsp(uint16_t index, + const void *data, + uint8_t size) +{ + const struct bt_hci_rsp_le_read_iso_link_quality *rsp = data; + + print_status(rsp->status); + + if (size == 1) + return; + + print_field("Handle: %d", le16_to_cpu(rsp->handle)); + print_field("TX unacked packets %d", rsp->tx_unacked_packets); + print_field("TX flushed packets %d", rsp->tx_flushed_packets); + print_field("TX last subevent packets %d", + rsp->tx_last_subevent_packets); + print_field("TX retransmitted packets %d", + rsp->retransmitted_packets); + print_field("TX crc error packets %d", rsp->crc_error_packets); + print_field("RX unreceived packets %d", rsp->rx_unreceived_packets); + print_field("Duplicated packets %d", rsp->duplicated_packets); +} + struct opcode_data { uint16_t opcode; int bit; @@ -9801,7 +9995,9 @@ static const struct opcode_data opcode_table[] = { "LE Remove Isochronous Data Path", le_remove_iso_path_cmd, sizeof(struct bt_hci_cmd_le_remove_iso_path), - true, status_rsp, 1, true }, + true, status_handle_rsp, + sizeof(struct bt_hci_rsp_le_remove_iso_path), + true }, { BT_HCI_CMD_LE_ISO_TX_TEST, BT_HCI_BIT_LE_ISO_TX_TEST, "LE Isochronous Transmit Test", NULL, 0, false }, @@ -9819,6 +10015,16 @@ static const struct opcode_data opcode_table[] = { "LE Set Host Feature", le_set_host_feature_cmd, sizeof(struct bt_hci_cmd_le_set_host_feature), true, status_rsp, 1, true }, + { BT_HCI_CMD_LE_READ_ISO_LINK_QUALITY, + BT_HCI_BIT_LE_READ_ISO_LINK_QUALITY, + "LE Read ISO link quality", + le_read_iso_link_quality_cmd, + sizeof( + struct bt_hci_cmd_le_read_iso_link_quality), + true, status_le_read_iso_link_quality_rsp, + sizeof( + struct bt_hci_rsp_le_read_iso_link_quality), + true }, { } }; @@ -9933,14 +10139,16 @@ static const char *current_vendor_evt_str(void) return NULL; } -static void inquiry_complete_evt(uint16_t index, const void *data, uint8_t size) +static void inquiry_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_inquiry_complete *evt = data; print_status(evt->status); } -static void inquiry_result_evt(uint16_t index, const void *data, uint8_t size) +static void inquiry_result_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_inquiry_result *evt = data; @@ -9956,12 +10164,13 @@ static void inquiry_result_evt(uint16_t index, const void *data, uint8_t size) packet_hexdump(data + sizeof(*evt), size - sizeof(*evt)); } -static void conn_complete_evt(uint16_t index, const void *data, uint8_t size) +static void conn_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_conn_complete *evt = data; print_status(evt->status); - print_handle(evt->handle); + print_field("Handle: %d", le16_to_cpu(evt->handle)); print_bdaddr(evt->bdaddr); print_link_type(evt->link_type); print_enable("Encryption", evt->encr_mode); @@ -9971,7 +10180,8 @@ static void conn_complete_evt(uint16_t index, const void *data, uint8_t size) (void *)evt->bdaddr, BDADDR_BREDR); } -static void conn_request_evt(uint16_t index, const void *data, uint8_t size) +static void conn_request_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_conn_request *evt = data; @@ -9980,8 +10190,8 @@ static void conn_request_evt(uint16_t index, const void *data, uint8_t size) print_link_type(evt->link_type); } -static void disconnect_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void disconnect_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_disconnect_complete *evt = data; @@ -9993,7 +10203,8 @@ static void disconnect_complete_evt(uint16_t index, const void *data, release_handle(le16_to_cpu(evt->handle)); } -static void auth_complete_evt(uint16_t index, const void *data, uint8_t size) +static void auth_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_auth_complete *evt = data; @@ -10001,8 +10212,8 @@ static void auth_complete_evt(uint16_t index, const void *data, uint8_t size) print_handle(evt->handle); } -static void remote_name_request_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void remote_name_request_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_remote_name_request_complete *evt = data; @@ -10011,7 +10222,8 @@ static void remote_name_request_complete_evt(uint16_t index, const void *data, print_name(evt->name); } -static void encrypt_change_evt(uint16_t index, const void *data, uint8_t size) +static void encrypt_change_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_encrypt_change *evt = data; @@ -10020,8 +10232,9 @@ static void encrypt_change_evt(uint16_t index, const void *data, uint8_t size) print_encr_mode_change(evt->encr_mode, evt->handle); } -static void change_conn_link_key_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void change_conn_link_key_complete_evt(struct timeval *tv, + uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_change_conn_link_key_complete *evt = data; @@ -10029,8 +10242,8 @@ static void change_conn_link_key_complete_evt(uint16_t index, const void *data, print_handle(evt->handle); } -static void link_key_type_changed_evt(uint16_t index, const void *data, - uint8_t size) +static void link_key_type_changed_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_link_key_type_changed *evt = data; @@ -10039,8 +10252,8 @@ static void link_key_type_changed_evt(uint16_t index, const void *data, print_key_flag(evt->key_flag); } -static void remote_features_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void remote_features_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_remote_features_complete *evt = data; @@ -10049,8 +10262,8 @@ static void remote_features_complete_evt(uint16_t index, const void *data, print_features(0, evt->features, 0x00); } -static void remote_version_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void remote_version_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_remote_version_complete *evt = data; @@ -10066,8 +10279,8 @@ static void remote_version_complete_evt(uint16_t index, const void *data, } } -static void qos_setup_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void qos_setup_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_qos_setup_complete *evt = data; @@ -10083,7 +10296,8 @@ static void qos_setup_complete_evt(uint16_t index, const void *data, print_field("Delay variation: %d", le32_to_cpu(evt->delay_variation)); } -static void cmd_complete_evt(uint16_t index, const void *data, uint8_t size) +static void cmd_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_cmd_complete *evt = data; uint16_t opcode = le16_to_cpu(evt->opcode); @@ -10179,7 +10393,8 @@ static void cmd_complete_evt(uint16_t index, const void *data, uint8_t size) opcode_data->rsp_func(index, data + 3, size - 3); } -static void cmd_status_evt(uint16_t index, const void *data, uint8_t size) +static void cmd_status_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_cmd_status *evt = data; uint16_t opcode = le16_to_cpu(evt->opcode); @@ -10231,21 +10446,24 @@ static void cmd_status_evt(uint16_t index, const void *data, uint8_t size) print_status(evt->status); } -static void hardware_error_evt(uint16_t index, const void *data, uint8_t size) +static void hardware_error_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_hardware_error *evt = data; print_field("Code: 0x%2.2x", evt->code); } -static void flush_occurred_evt(uint16_t index, const void *data, uint8_t size) +static void flush_occurred_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_flush_occurred *evt = data; print_handle(evt->handle); } -static void role_change_evt(uint16_t index, const void *data, uint8_t size) +static void role_change_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_role_change *evt = data; @@ -10254,20 +10472,105 @@ static void role_change_evt(uint16_t index, const void *data, uint8_t size) print_role(evt->role); } -static void num_completed_packets_evt(uint16_t index, const void *data, - uint8_t size) +void packet_latency_add(struct packet_latency *latency, struct timeval *delta) +{ + timeradd(&latency->total, delta, &latency->total); + + if ((!timerisset(&latency->min) || timercmp(delta, &latency->min, <)) + && delta->tv_sec >= 0 && delta->tv_usec >= 0) + latency->min = *delta; + + if (!timerisset(&latency->max) || timercmp(delta, &latency->max, >)) + latency->max = *delta; + + if (timerisset(&latency->med)) { + struct timeval tmp; + + timeradd(&latency->med, delta, &tmp); + + tmp.tv_sec /= 2; + tmp.tv_usec /= 2; + if (tmp.tv_sec % 2) { + tmp.tv_usec += 500000; + if (tmp.tv_usec >= 1000000) { + tmp.tv_sec++; + tmp.tv_usec -= 1000000; + } + } + + latency->med = tmp; + } else + latency->med = *delta; +} + +static void packet_dequeue_tx(struct timeval *tv, uint16_t handle) +{ + struct packet_conn_data *conn; + struct packet_frame *frame; + struct timeval delta; + + conn = packet_get_conn_data(handle); + if (!conn) + return; + + frame = queue_pop_head(conn->tx_q); + if (!frame) + return; + + timersub(tv, &frame->tv, &delta); + + packet_latency_add(&conn->tx_l, &delta); + + if (TV_MSEC(delta)) { + print_field("#%zu: len %zu (%lld Kb/s)", frame->num, frame->len, + frame->len * 8 / TV_MSEC(delta)); + print_field("Latency: %lld msec (%lld-%lld msec ~%lld msec)", + TV_MSEC(delta), TV_MSEC(conn->tx_l.min), + TV_MSEC(conn->tx_l.max), + TV_MSEC(conn->tx_l.med)); + } + + l2cap_dequeue_frame(&delta, conn); + + free(frame); +} + +static void num_completed_packets_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { + struct iovec iov = { (void *)data, size}; const struct bt_hci_evt_num_completed_packets *evt = data; + int i; + + util_iov_pull(&iov, 1); print_field("Num handles: %d", evt->num_handles); - print_handle(evt->handle); - print_field("Count: %d", le16_to_cpu(evt->count)); - if (size > sizeof(*evt)) - packet_hexdump(data + sizeof(*evt), size - sizeof(*evt)); + for (i = 0; i < evt->num_handles; i++) { + uint16_t handle; + uint16_t count; + int j; + + if (!util_iov_pull_le16(&iov, &handle)) + break; + + print_handle_native(handle); + + if (!util_iov_pull_le16(&iov, &count)) + break; + + print_field("Count: %d", count); + + for (j = 0; j < count; j++) + packet_dequeue_tx(tv, handle); + } + + if (iov.iov_len) + packet_hexdump(iov.iov_base, iov.iov_len); } -static void mode_change_evt(uint16_t index, const void *data, uint8_t size) +static void mode_change_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_mode_change *evt = data; @@ -10277,7 +10580,8 @@ static void mode_change_evt(uint16_t index, const void *data, uint8_t size) print_interval(evt->interval); } -static void return_link_keys_evt(uint16_t index, const void *data, uint8_t size) +static void return_link_keys_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_return_link_keys *evt = data; uint8_t i; @@ -10290,21 +10594,24 @@ static void return_link_keys_evt(uint16_t index, const void *data, uint8_t size) } } -static void pin_code_request_evt(uint16_t index, const void *data, uint8_t size) +static void pin_code_request_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_pin_code_request *evt = data; print_bdaddr(evt->bdaddr); } -static void link_key_request_evt(uint16_t index, const void *data, uint8_t size) +static void link_key_request_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_link_key_request *evt = data; print_bdaddr(evt->bdaddr); } -static void link_key_notify_evt(uint16_t index, const void *data, uint8_t size) +static void link_key_notify_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_link_key_notify *evt = data; @@ -10313,20 +10620,22 @@ static void link_key_notify_evt(uint16_t index, const void *data, uint8_t size) print_key_type(evt->key_type); } -static void loopback_command_evt(uint16_t index, const void *data, uint8_t size) +static void loopback_command_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { packet_hexdump(data, size); } -static void data_buffer_overflow_evt(uint16_t index, const void *data, - uint8_t size) +static void data_buffer_overflow_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_data_buffer_overflow *evt = data; print_link_type(evt->link_type); } -static void max_slots_change_evt(uint16_t index, const void *data, uint8_t size) +static void max_slots_change_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_max_slots_change *evt = data; @@ -10334,8 +10643,8 @@ static void max_slots_change_evt(uint16_t index, const void *data, uint8_t size) print_field("Max slots: %d", evt->max_slots); } -static void clock_offset_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void clock_offset_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_clock_offset_complete *evt = data; @@ -10344,8 +10653,8 @@ static void clock_offset_complete_evt(uint16_t index, const void *data, print_clock_offset(evt->clock_offset); } -static void conn_pkt_type_changed_evt(uint16_t index, const void *data, - uint8_t size) +static void conn_pkt_type_changed_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_conn_pkt_type_changed *evt = data; @@ -10354,15 +10663,16 @@ static void conn_pkt_type_changed_evt(uint16_t index, const void *data, print_pkt_type(evt->pkt_type); } -static void qos_violation_evt(uint16_t index, const void *data, uint8_t size) +static void qos_violation_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_qos_violation *evt = data; print_handle(evt->handle); } -static void pscan_mode_change_evt(uint16_t index, const void *data, - uint8_t size) +static void pscan_mode_change_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_pscan_mode_change *evt = data; @@ -10370,8 +10680,8 @@ static void pscan_mode_change_evt(uint16_t index, const void *data, print_pscan_mode(evt->pscan_mode); } -static void pscan_rep_mode_change_evt(uint16_t index, const void *data, - uint8_t size) +static void pscan_rep_mode_change_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_pscan_rep_mode_change *evt = data; @@ -10379,8 +10689,8 @@ static void pscan_rep_mode_change_evt(uint16_t index, const void *data, print_pscan_rep_mode(evt->pscan_rep_mode); } -static void flow_spec_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void flow_spec_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_flow_spec_complete *evt = data; @@ -10398,8 +10708,8 @@ static void flow_spec_complete_evt(uint16_t index, const void *data, print_field("Access latency: %d", le32_to_cpu(evt->access_latency)); } -static void inquiry_result_with_rssi_evt(uint16_t index, const void *data, - uint8_t size) +static void inquiry_result_with_rssi_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_inquiry_result_with_rssi *evt = data; @@ -10415,8 +10725,8 @@ static void inquiry_result_with_rssi_evt(uint16_t index, const void *data, packet_hexdump(data + sizeof(*evt), size - sizeof(*evt)); } -static void remote_ext_features_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void remote_ext_features_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_remote_ext_features_complete *evt = data; @@ -10426,13 +10736,13 @@ static void remote_ext_features_complete_evt(uint16_t index, const void *data, print_features(evt->page, evt->features, 0x00); } -static void sync_conn_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void sync_conn_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_sync_conn_complete *evt = data; print_status(evt->status); - print_handle(evt->handle); + print_field("Handle: %d", le16_to_cpu(evt->handle)); print_bdaddr(evt->bdaddr); print_link_type(evt->link_type); print_field("Transmission interval: 0x%2.2x", evt->tx_interval); @@ -10440,10 +10750,14 @@ static void sync_conn_complete_evt(uint16_t index, const void *data, print_field("RX packet length: %d", le16_to_cpu(evt->rx_pkt_len)); print_field("TX packet length: %d", le16_to_cpu(evt->tx_pkt_len)); print_air_mode(evt->air_mode); + + if (evt->status == 0x00) + assign_handle(index, le16_to_cpu(evt->handle), evt->link_type, + (void *)evt->bdaddr, BDADDR_BREDR); } -static void sync_conn_changed_evt(uint16_t index, const void *data, - uint8_t size) +static void sync_conn_changed_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_sync_conn_changed *evt = data; @@ -10455,7 +10769,8 @@ static void sync_conn_changed_evt(uint16_t index, const void *data, print_field("TX packet length: %d", le16_to_cpu(evt->tx_pkt_len)); } -static void sniff_subrating_evt(uint16_t index, const void *data, uint8_t size) +static void sniff_subrating_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_sniff_subrating *evt = data; @@ -10467,8 +10782,8 @@ static void sniff_subrating_evt(uint16_t index, const void *data, uint8_t size) print_slot_625("Min local timeout", evt->min_local_timeout); } -static void ext_inquiry_result_evt(uint16_t index, const void *data, - uint8_t size) +static void ext_inquiry_result_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_ext_inquiry_result *evt = data; @@ -10482,8 +10797,8 @@ static void ext_inquiry_result_evt(uint16_t index, const void *data, print_eir(evt->data, sizeof(evt->data), false); } -static void encrypt_key_refresh_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void encrypt_key_refresh_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_encrypt_key_refresh_complete *evt = data; @@ -10491,16 +10806,16 @@ static void encrypt_key_refresh_complete_evt(uint16_t index, const void *data, print_handle(evt->handle); } -static void io_capability_request_evt(uint16_t index, const void *data, - uint8_t size) +static void io_capability_request_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_io_capability_request *evt = data; print_bdaddr(evt->bdaddr); } -static void io_capability_response_evt(uint16_t index, const void *data, - uint8_t size) +static void io_capability_response_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_io_capability_response *evt = data; @@ -10510,8 +10825,8 @@ static void io_capability_response_evt(uint16_t index, const void *data, print_authentication(evt->authentication); } -static void user_confirm_request_evt(uint16_t index, const void *data, - uint8_t size) +static void user_confirm_request_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_user_confirm_request *evt = data; @@ -10519,24 +10834,24 @@ static void user_confirm_request_evt(uint16_t index, const void *data, print_passkey(evt->passkey); } -static void user_passkey_request_evt(uint16_t index, const void *data, - uint8_t size) +static void user_passkey_request_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_user_passkey_request *evt = data; print_bdaddr(evt->bdaddr); } -static void remote_oob_data_request_evt(uint16_t index, const void *data, - uint8_t size) +static void remote_oob_data_request_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_remote_oob_data_request *evt = data; print_bdaddr(evt->bdaddr); } -static void simple_pairing_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void simple_pairing_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_simple_pairing_complete *evt = data; @@ -10544,8 +10859,8 @@ static void simple_pairing_complete_evt(uint16_t index, const void *data, print_bdaddr(evt->bdaddr); } -static void link_supv_timeout_changed_evt(uint16_t index, const void *data, - uint8_t size) +static void link_supv_timeout_changed_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_link_supv_timeout_changed *evt = data; @@ -10553,16 +10868,16 @@ static void link_supv_timeout_changed_evt(uint16_t index, const void *data, print_timeout(evt->timeout); } -static void enhanced_flush_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void enhanced_flush_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_enhanced_flush_complete *evt = data; print_handle(evt->handle); } -static void user_passkey_notify_evt(uint16_t index, const void *data, - uint8_t size) +static void user_passkey_notify_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_user_passkey_notify *evt = data; @@ -10570,7 +10885,8 @@ static void user_passkey_notify_evt(uint16_t index, const void *data, print_passkey(evt->passkey); } -static void keypress_notify_evt(uint16_t index, const void *data, uint8_t size) +static void keypress_notify_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_keypress_notify *evt = data; const char *str; @@ -10601,8 +10917,8 @@ static void keypress_notify_evt(uint16_t index, const void *data, uint8_t size) print_field("Notification type: %s (0x%2.2x)", str, evt->type); } -static void remote_host_features_notify_evt(uint16_t index, const void *data, - uint8_t size) +static void remote_host_features_notify_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_remote_host_features_notify *evt = data; @@ -10610,8 +10926,8 @@ static void remote_host_features_notify_evt(uint16_t index, const void *data, print_features(1, evt->features, 0x00); } -static void phy_link_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void phy_link_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_phy_link_complete *evt = data; @@ -10619,15 +10935,16 @@ static void phy_link_complete_evt(uint16_t index, const void *data, print_phy_handle(evt->phy_handle); } -static void channel_selected_evt(uint16_t index, const void *data, uint8_t size) +static void channel_selected_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_channel_selected *evt = data; print_phy_handle(evt->phy_handle); } -static void disconn_phy_link_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void disconn_phy_link_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_disconn_phy_link_complete *evt = data; @@ -10636,8 +10953,8 @@ static void disconn_phy_link_complete_evt(uint16_t index, const void *data, print_reason(evt->reason); } -static void phy_link_loss_early_warning_evt(uint16_t index, const void *data, - uint8_t size) +static void phy_link_loss_early_warning_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_phy_link_loss_early_warning *evt = data; const char *str; @@ -10668,16 +10985,16 @@ static void phy_link_loss_early_warning_evt(uint16_t index, const void *data, print_field("Reason: %s (0x%2.2x)", str, evt->reason); } -static void phy_link_recovery_evt(uint16_t index, const void *data, - uint8_t size) +static void phy_link_recovery_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_phy_link_recovery *evt = data; print_phy_handle(evt->phy_handle); } -static void logic_link_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void logic_link_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_logic_link_complete *evt = data; @@ -10687,8 +11004,8 @@ static void logic_link_complete_evt(uint16_t index, const void *data, print_field("TX flow spec: 0x%2.2x", evt->flow_spec); } -static void disconn_logic_link_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void disconn_logic_link_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_disconn_logic_link_complete *evt = data; @@ -10697,8 +11014,8 @@ static void disconn_logic_link_complete_evt(uint16_t index, const void *data, print_reason(evt->reason); } -static void flow_spec_modify_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void flow_spec_modify_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_flow_spec_modify_complete *evt = data; @@ -10706,8 +11023,8 @@ static void flow_spec_modify_complete_evt(uint16_t index, const void *data, print_handle(evt->handle); } -static void num_completed_data_blocks_evt(uint16_t index, const void *data, - uint8_t size) +static void num_completed_data_blocks_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_num_completed_data_blocks *evt = data; @@ -10722,8 +11039,8 @@ static void num_completed_data_blocks_evt(uint16_t index, const void *data, packet_hexdump(data + sizeof(*evt), size - sizeof(*evt)); } -static void short_range_mode_change_evt(uint16_t index, const void *data, - uint8_t size) +static void short_range_mode_change_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_short_range_mode_change *evt = data; @@ -10732,8 +11049,8 @@ static void short_range_mode_change_evt(uint16_t index, const void *data, print_enable("Short range mode", evt->mode); } -static void amp_status_change_evt(uint16_t index, const void *data, - uint8_t size) +static void amp_status_change_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_amp_status_change *evt = data; @@ -10741,8 +11058,8 @@ static void amp_status_change_evt(uint16_t index, const void *data, print_amp_status(evt->amp_status); } -static void triggered_clock_capture_evt(uint16_t index, const void *data, - uint8_t size) +static void triggered_clock_capture_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_triggered_clock_capture *evt = data; @@ -10752,16 +11069,16 @@ static void triggered_clock_capture_evt(uint16_t index, const void *data, print_clock_offset(evt->clock_offset); } -static void sync_train_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void sync_train_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_sync_train_complete *evt = data; print_status(evt->status); } -static void sync_train_received_evt(uint16_t index, const void *data, - uint8_t size) +static void sync_train_received_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_sync_train_received *evt = data; @@ -10776,8 +11093,8 @@ static void sync_train_received_evt(uint16_t index, const void *data, print_field("Service Data: 0x%2.2x", evt->service_data); } -static void peripheral_broadcast_receive_evt(uint16_t index, const void *data, - uint8_t size) +static void peripheral_broadcast_receive_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_peripheral_broadcast_receive *evt = data; @@ -10799,8 +11116,8 @@ static void peripheral_broadcast_receive_evt(uint16_t index, const void *data, packet_hexdump(data + 18, size - 18); } -static void peripheral_broadcast_timeout_evt(uint16_t index, const void *data, - uint8_t size) +static void peripheral_broadcast_timeout_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_peripheral_broadcast_timeout *evt = data; @@ -10808,8 +11125,8 @@ static void peripheral_broadcast_timeout_evt(uint16_t index, const void *data, print_lt_addr(evt->lt_addr); } -static void truncated_page_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void truncated_page_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_truncated_page_complete *evt = data; @@ -10817,21 +11134,22 @@ static void truncated_page_complete_evt(uint16_t index, const void *data, print_bdaddr(evt->bdaddr); } -static void peripheral_page_response_timeout_evt(uint16_t index, - const void *data, uint8_t size) +static void peripheral_page_response_timeout_evt(struct timeval *tv, + uint16_t index, const void *data, + uint8_t size) { } -static void channel_map_change_evt(uint16_t index, const void *data, - uint8_t size) +static void channel_map_change_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_channel_map_change *evt = data; print_channel_map(evt->map); } -static void inquiry_response_notify_evt(uint16_t index, const void *data, - uint8_t size) +static void inquiry_response_notify_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_inquiry_response_notify *evt = data; @@ -10839,20 +11157,21 @@ static void inquiry_response_notify_evt(uint16_t index, const void *data, print_rssi(evt->rssi); } -static void auth_payload_timeout_expired_evt(uint16_t index, const void *data, - uint8_t size) +static void auth_payload_timeout_expired_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_auth_payload_timeout_expired *evt = data; print_handle(evt->handle); } -static void le_conn_complete_evt(uint16_t index, const void *data, uint8_t size) +static void le_conn_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_conn_complete *evt = data; print_status(evt->status); - print_handle(evt->handle); + print_field("Handle: %d", le16_to_cpu(evt->handle)); print_role(evt->role); print_peer_addr_type("Peer address type", evt->peer_addr_type); print_addr("Peer address", evt->peer_addr, evt->peer_addr_type); @@ -10868,7 +11187,8 @@ static void le_conn_complete_evt(uint16_t index, const void *data, uint8_t size) (void *)evt->peer_addr, evt->peer_addr_type); } -static void le_adv_report_evt(uint16_t index, const void *data, uint8_t size) +static void le_adv_report_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_adv_report *evt = data; uint8_t evt_len; @@ -10896,8 +11216,8 @@ report: } } -static void le_conn_update_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void le_conn_update_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_conn_update_complete *evt = data; @@ -10910,8 +11230,8 @@ static void le_conn_update_complete_evt(uint16_t index, const void *data, le16_to_cpu(evt->supv_timeout)); } -static void le_remote_features_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void le_remote_features_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_remote_features_complete *evt = data; @@ -10920,8 +11240,8 @@ static void le_remote_features_complete_evt(uint16_t index, const void *data, print_features(0, evt->features, 0x01); } -static void le_long_term_key_request_evt(uint16_t index, const void *data, - uint8_t size) +static void le_long_term_key_request_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_long_term_key_request *evt = data; @@ -10930,8 +11250,8 @@ static void le_long_term_key_request_evt(uint16_t index, const void *data, print_encrypted_diversifier(evt->ediv); } -static void le_conn_param_request_evt(uint16_t index, const void *data, - uint8_t size) +static void le_conn_param_request_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_conn_param_request *evt = data; @@ -10944,8 +11264,8 @@ static void le_conn_param_request_evt(uint16_t index, const void *data, le16_to_cpu(evt->supv_timeout)); } -static void le_data_length_change_evt(uint16_t index, const void *data, - uint8_t size) +static void le_data_length_change_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_data_length_change *evt = data; @@ -10956,8 +11276,8 @@ static void le_data_length_change_evt(uint16_t index, const void *data, print_field("Max RX time: %d", le16_to_cpu(evt->max_rx_time)); } -static void le_read_local_pk256_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void le_read_local_pk256_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_read_local_pk256_complete *evt = data; @@ -10965,8 +11285,8 @@ static void le_read_local_pk256_complete_evt(uint16_t index, const void *data, print_pk256("Local P-256 public key", evt->local_pk256); } -static void le_generate_dhkey_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void le_generate_dhkey_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_generate_dhkey_complete *evt = data; @@ -10974,13 +11294,13 @@ static void le_generate_dhkey_complete_evt(uint16_t index, const void *data, print_dhkey(evt->dhkey); } -static void le_enhanced_conn_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void le_enhanced_conn_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_enhanced_conn_complete *evt = data; print_status(evt->status); - print_handle(evt->handle); + print_field("Handle: %d", le16_to_cpu(evt->handle)); print_role(evt->role); print_peer_addr_type("Peer address type", evt->peer_addr_type); print_addr("Peer address", evt->peer_addr, evt->peer_addr_type); @@ -10998,8 +11318,8 @@ static void le_enhanced_conn_complete_evt(uint16_t index, const void *data, (void *)evt->peer_addr, evt->peer_addr_type); } -static void le_direct_adv_report_evt(uint16_t index, const void *data, - uint8_t size) +static void le_direct_adv_report_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_direct_adv_report *evt = data; @@ -11016,8 +11336,8 @@ static void le_direct_adv_report_evt(uint16_t index, const void *data, packet_hexdump(data + sizeof(*evt), size - sizeof(*evt)); } -static void le_phy_update_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void le_phy_update_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_phy_update_complete *evt = data; @@ -11120,8 +11440,8 @@ static void print_legacy_adv_report_pdu(uint16_t flags) print_field(" Legacy PDU Type: %s (0x%4.4x)", str, flags); } -static void le_ext_adv_report_evt(uint16_t index, const void *data, - uint8_t size) +static void le_ext_adv_report_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_ext_adv_report *evt = data; const struct bt_hci_le_ext_adv_report *report; @@ -11208,7 +11528,8 @@ static void le_ext_adv_report_evt(uint16_t index, const void *data, } } -static void le_pa_sync(uint16_t index, const void *data, uint8_t size) +static void le_pa_sync_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_per_sync_established *evt = data; @@ -11226,7 +11547,8 @@ static void le_pa_sync(uint16_t index, const void *data, uint8_t size) print_field("Advertiser clock accuracy: 0x%2.2x", evt->clock_accuracy); } -static void le_pa_report_evt(uint16_t index, const void *data, uint8_t size) +static void le_pa_report_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_le_pa_report *evt = data; const char *color_on; @@ -11285,17 +11607,19 @@ static void le_pa_report_evt(uint16_t index, const void *data, uint8_t size) print_field("Data status: %s%s%s", color_on, str, COLOR_OFF); print_field("Data length: 0x%2.2x", evt->data_len); - packet_hexdump(evt->data, evt->data_len); + print_eir(evt->data, evt->data_len, true); } -static void le_pa_sync_lost(uint16_t index, const void *data, uint8_t size) +static void le_pa_sync_lost_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_per_sync_lost *evt = data; print_field("Sync handle: %d", evt->handle); } -static void le_adv_set_term_evt(uint16_t index, const void *data, uint8_t size) +static void le_adv_set_term_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_adv_set_term *evt = data; @@ -11306,8 +11630,8 @@ static void le_adv_set_term_evt(uint16_t index, const void *data, uint8_t size) evt->num_evts); } -static void le_scan_req_received_evt(uint16_t index, const void *data, - uint8_t size) +static void le_scan_req_received_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_scan_req_received *evt = data; @@ -11317,8 +11641,8 @@ static void le_scan_req_received_evt(uint16_t index, const void *data, evt->scanner_addr_type); } -static void le_chan_select_alg_evt(uint16_t index, const void *data, - uint8_t size) +static void le_chan_select_alg_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_chan_select_alg *evt = data; const char *str; @@ -11340,8 +11664,8 @@ static void le_chan_select_alg_evt(uint16_t index, const void *data, print_field("Algorithm: %s (0x%2.2x)", str, evt->algorithm); } -static void le_cte_request_failed_evt(uint16_t index, const void *data, - uint8_t size) +static void le_cte_request_failed_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_cte_request_failed *evt = data; @@ -11349,8 +11673,8 @@ static void le_cte_request_failed_evt(uint16_t index, const void *data, print_field("Connection handle: %d", evt->handle); } -static void le_pa_sync_trans_rec_evt(uint16_t index, const void *data, - uint8_t size) +static void le_pa_sync_trans_rec_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_pa_sync_trans_rec *evt = data; @@ -11368,8 +11692,8 @@ static void le_pa_sync_trans_rec_evt(uint16_t index, const void *data, print_clock_accuracy(evt->clock_accuracy); } -static void le_cis_established_evt(uint16_t index, const void *data, - uint8_t size) +static void le_cis_established_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_cis_established *evt = data; @@ -11388,17 +11712,27 @@ static void le_cis_established_evt(uint16_t index, const void *data, print_field("Peripheral to Central Flush Timeout: %u", evt->p_ft); print_field("Central to Peripheral MTU: %u", le16_to_cpu(evt->c_mtu)); print_field("Peripheral to Central MTU: %u", le16_to_cpu(evt->p_mtu)); - print_field("ISO Interval: %u", le16_to_cpu(evt->interval)); + print_slot_125("ISO Interval", evt->interval); + + if (!evt->status) + assign_handle(index, le16_to_cpu(evt->conn_handle), 0x05, + NULL, BDADDR_LE_PUBLIC); } -static void le_req_cis_evt(uint16_t index, const void *data, uint8_t size) +static void le_req_cis_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_cis_req *evt = data; + struct packet_conn_data *conn; print_field("ACL Handle: %d", le16_to_cpu(evt->acl_handle)); print_field("CIS Handle: %d", le16_to_cpu(evt->cis_handle)); print_field("CIG ID: 0x%2.2x", evt->cig_id); print_field("CIS ID: 0x%2.2x", evt->cis_id); + + conn = packet_get_conn_data(evt->acl_handle); + if (conn) + conn->link = evt->cis_handle; } static void print_bis_handle(const void *data, int i) @@ -11408,7 +11742,8 @@ static void print_bis_handle(const void *data, int i) print_field("Connection Handle #%d: %d", i, handle); } -static void le_big_complete_evt(uint16_t index, const void *data, uint8_t size) +static void le_big_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_big_complete *evt = data; @@ -11419,15 +11754,24 @@ static void le_big_complete_evt(uint16_t index, const void *data, uint8_t size) print_le_phy("PHY", evt->phy); print_field("NSE: %u", evt->nse); print_field("BN: %u", evt->bn); - print_field("PTO: %u", evt->bn); + print_field("PTO: %u", evt->pto); print_field("IRC: %u", evt->irc); print_field("Maximum PDU: %u", evt->max_pdu); print_slot_125("ISO Interval", evt->interval); print_list(evt->bis_handle, size, evt->num_bis, sizeof(*evt->bis_handle), print_bis_handle); + + if (!evt->status) { + int i; + + for (i = 0; i < evt->num_bis; i++) + assign_handle(index, le16_to_cpu(evt->bis_handle[i]), + 0x05, NULL, BDADDR_LE_PUBLIC); + } } -static void le_big_terminate_evt(uint16_t index, const void *data, uint8_t size) +static void le_big_terminate_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_big_terminate *evt = data; @@ -11435,8 +11779,8 @@ static void le_big_terminate_evt(uint16_t index, const void *data, uint8_t size) print_reason(evt->reason); } -static void le_big_sync_estabilished_evt(uint16_t index, const void *data, - uint8_t size) +static void le_big_sync_estabilished_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_big_sync_estabilished *evt = data; @@ -11451,18 +11795,27 @@ static void le_big_sync_estabilished_evt(uint16_t index, const void *data, print_slot_125("ISO Interval", evt->interval); print_list(evt->bis, size, evt->num_bis, sizeof(*evt->bis), print_bis_handle); + + if (!evt->status) { + int i; + + for (i = 0; i < evt->num_bis; i++) + assign_handle(index, le16_to_cpu(evt->bis[i]), + 0x05, NULL, BDADDR_LE_PUBLIC); + } } -static void le_big_sync_lost_evt(uint16_t index, const void *data, uint8_t size) +static void le_big_sync_lost_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_big_sync_lost *evt = data; - print_field("BIG ID: 0x%2.2x", evt->big_id); + print_field("BIG Handle: 0x%2.2x", evt->big_handle); print_reason(evt->reason); } -static void le_req_sca_complete_evt(uint16_t index, const void *data, - uint8_t size) +static void le_req_sca_complete_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_req_peer_sca_complete *evt = data; @@ -11471,7 +11824,8 @@ static void le_req_sca_complete_evt(uint16_t index, const void *data, print_sca(evt->sca); } -static void le_big_info_evt(uint16_t index, const void *data, uint8_t size) +static void le_big_info_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { const struct bt_hci_evt_le_big_info_adv_report *evt = data; @@ -11493,12 +11847,13 @@ static void le_big_info_evt(uint16_t index, const void *data, uint8_t size) struct subevent_data { uint8_t subevent; const char *str; - void (*func) (uint16_t index, const void *data, uint8_t size); + void (*func) (struct timeval *tv, uint16_t index, const void *data, + uint8_t size); uint8_t size; bool fixed; }; -static void print_subevent(uint16_t index, +static void print_subevent(struct timeval *tv, uint16_t index, const struct subevent_data *subevent_data, const void *data, uint8_t size) { @@ -11531,7 +11886,7 @@ static void print_subevent(uint16_t index, } } - subevent_data->func(index, data, size); + subevent_data->func(tv, index, data, size); } static const struct subevent_data le_meta_event_table[] = { @@ -11562,11 +11917,11 @@ static const struct subevent_data le_meta_event_table[] = { { 0x0d, "LE Extended Advertising Report", le_ext_adv_report_evt, 1, false}, { 0x0e, "LE Periodic Advertising Sync Established", - le_pa_sync, 15, true }, + le_pa_sync_evt, 15, true }, { 0x0f, "LE Periodic Advertising Report", le_pa_report_evt, 7, false}, { 0x10, "LE Periodic Advertising Sync Lost", - le_pa_sync_lost, 2, true}, + le_pa_sync_lost_evt, 2, true}, { 0x11, "LE Scan Timeout" }, { 0x12, "LE Advertising Set Terminated", le_adv_set_term_evt, 5, true}, @@ -11616,7 +11971,8 @@ static const struct subevent_data le_meta_event_table[] = { { } }; -static void le_meta_event_evt(uint16_t index, const void *data, uint8_t size) +static void le_meta_event_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { uint8_t subevent = *((const uint8_t *) data); struct subevent_data unknown; @@ -11636,10 +11992,11 @@ static void le_meta_event_evt(uint16_t index, const void *data, uint8_t size) } } - print_subevent(index, subevent_data, data + 1, size - 1); + print_subevent(tv, index, subevent_data, data + 1, size - 1); } -static void vendor_evt(uint16_t index, const void *data, uint8_t size) +static void vendor_evt(struct timeval *tv, uint16_t index, + const void *data, uint8_t size) { struct subevent_data vendor_data; char vendor_str[150]; @@ -11660,7 +12017,7 @@ static void vendor_evt(uint16_t index, const void *data, uint8_t size) vendor_data.size = vnd->evt_size; vendor_data.fixed = vnd->evt_fixed; - print_subevent(index, &vendor_data, data + consumed_size, + print_subevent(tv, index, &vendor_data, data + consumed_size, size - consumed_size); } else { uint16_t manufacturer; @@ -11677,7 +12034,8 @@ static void vendor_evt(uint16_t index, const void *data, uint8_t size) struct event_data { uint8_t event; const char *str; - void (*func) (uint16_t index, const void *data, uint8_t size); + void (*func) (struct timeval *tv, uint16_t index, const void *data, + uint8_t size); uint8_t size; bool fixed; }; @@ -11910,7 +12268,7 @@ void packet_system_note(struct timeval *tv, struct ucred *cred, struct monitor_l2cap_hdr { uint16_t cid; uint16_t psm; -}; +} __attribute__((packed)); static void packet_decode(struct timeval *tv, struct ucred *cred, char dir, uint16_t index, const char *color, @@ -11929,7 +12287,8 @@ static void packet_decode(struct timeval *tv, struct ucred *cred, char dir, NULL); /* Discard last byte since it just a filler */ - l2cap_frame(index, dir == '>', 0, hdr->cid, hdr->psm, + l2cap_frame(index, dir == '>', 0, + le16_to_cpu(hdr->cid), le16_to_cpu(hdr->psm), data + sizeof(*hdr), size - (sizeof(*hdr) + 1)); } @@ -11938,7 +12297,6 @@ void packet_user_logging(struct timeval *tv, struct ucred *cred, const char *ident, const void *data, uint16_t size) { - char pid_str[140]; const char *label; const char *color; @@ -11964,26 +12322,7 @@ void packet_user_logging(struct timeval *tv, struct ucred *cred, } if (cred) { - char *path = alloca(24); - char line[128]; - FILE *fp; - - snprintf(path, 23, "/proc/%u/comm", cred->pid); - - fp = fopen(path, "re"); - if (fp) { - if (fgets(line, sizeof(line), fp)) { - line[strcspn(line, "\r\n")] = '\0'; - snprintf(pid_str, sizeof(pid_str), "%s[%u]", - line, cred->pid); - } else - snprintf(pid_str, sizeof(pid_str), "%u", - cred->pid); - fclose(fp); - } else - snprintf(pid_str, sizeof(pid_str), "%u", cred->pid); - - label = pid_str; + label = NULL; } else { if (ident) label = ident; @@ -11993,8 +12332,8 @@ void packet_user_logging(struct timeval *tv, struct ucred *cred, if (ident && (ident[0] == '<' || ident[0] == '>')) { packet_decode(tv, cred, ident[0], index, color, - label == ident ? &ident[2] : label, - data, size); + label == ident ? &ident[2] : label, + data, size); return; } @@ -12189,7 +12528,28 @@ void packet_hci_event(struct timeval *tv, struct ucred *cred, uint16_t index, } } - event_data->func(index, data, hdr->plen); + event_data->func(tv, index, data, hdr->plen); +} + +static void packet_enqueue_tx(struct timeval *tv, uint16_t handle, + size_t num, uint16_t len) +{ + struct packet_conn_data *conn; + struct packet_frame *frame; + + conn = packet_get_conn_data(handle); + if (!conn) + return; + + if (!conn->tx_q) + conn->tx_q = queue_new(); + + frame = new0(struct packet_frame, 1); + if (tv) + memcpy(&frame->tv, tv, sizeof(*tv)); + frame->num = num; + frame->len = len; + queue_push_tail(conn->tx_q, frame); } void packet_hci_acldata(struct timeval *tv, struct ucred *cred, uint16_t index, @@ -12229,6 +12589,10 @@ void packet_hci_acldata(struct timeval *tv, struct ucred *cred, uint16_t index, in ? "ACL Data RX" : "ACL Data TX", handle_str, extra_str); + if (!in) + packet_enqueue_tx(tv, acl_handle(handle), + index_list[index].frame, dlen); + if (size != dlen) { print_text(COLOR_ERROR, "invalid packet size (%d != %d)", size, dlen); @@ -12278,6 +12642,10 @@ void packet_hci_scodata(struct timeval *tv, struct ucred *cred, uint16_t index, in ? "SCO Data RX" : "SCO Data TX", handle_str, extra_str); + if (!in) + packet_enqueue_tx(tv, acl_handle(handle), + index_list[index].frame, hdr->dlen); + if (size != hdr->dlen) { print_text(COLOR_ERROR, "invalid packet size (%d != %d)", size, hdr->dlen); @@ -12321,10 +12689,14 @@ void packet_hci_isodata(struct timeval *tv, struct ucred *cred, uint16_t index, sprintf(handle_str, "Handle %d", acl_handle(handle)); sprintf(extra_str, "flags 0x%2.2x dlen %d", flags, hdr->dlen); - print_packet(tv, cred, in ? '>' : '<', index, NULL, COLOR_HCI_SCODATA, + print_packet(tv, cred, in ? '>' : '<', index, NULL, COLOR_HCI_ISODATA, in ? "ISO Data RX" : "ISO Data TX", handle_str, extra_str); + if (!in) + packet_enqueue_tx(tv, acl_handle(handle), + index_list[index].frame, hdr->dlen); + if (size != hdr->dlen) { print_text(COLOR_ERROR, "invalid packet size (%d != %d)", size, hdr->dlen); @@ -12332,7 +12704,7 @@ void packet_hci_isodata(struct timeval *tv, struct ucred *cred, uint16_t index, return; } - if (filter_mask & PACKET_FILTER_SHOW_SCO_DATA) + if (filter_mask & PACKET_FILTER_SHOW_ISO_DATA) packet_hexdump(data, size); } @@ -12615,7 +12987,11 @@ static const struct bitfield_data mgmt_settings_table[] = { { 15, "Static Address" }, { 16, "PHY Configuration" }, { 17, "Wideband Speech" }, - { } + { 18, "CIS Central" }, + { 19, "CIS Peripheral" }, + { 20, "ISO Broadcaster" }, + { 21, "Sync Receiver" }, + {} }; static void mgmt_print_settings(const char *label, uint32_t settings) @@ -12669,6 +13045,8 @@ static const struct bitfield_data mgmt_device_flags_table[] = { { 1, "Legacy Pairing" }, { 2, "Not Connectable" }, { 3, "Connection Locally Initiated" }, + { 4, "Name Request Failed" }, + { 5, "Scan Response" }, { } }; @@ -12834,6 +13212,7 @@ static void mgmt_print_identity_resolving_key(const void *data) mgmt_print_address(data, address_type); print_hex_field("Key", data + 7, 16); + keys_add_identity(data, address_type, data + 7); } static void mgmt_print_signature_resolving_key(const void *data) @@ -13046,6 +13425,57 @@ static void mgmt_set_low_energy_cmd(const void *data, uint16_t size) print_enable("Low Energy", enable); } +static void mgmt_set_blocked_keys_cmd(const void *data, uint16_t size) +{ + struct iovec frame = { (void *)data, size }; + uint16_t num_keys; + int i; + + if (!util_iov_pull_le16(&frame, &num_keys)) { + print_field("Keys: invalid size"); + return; + } + + print_field("Keys: %u", num_keys); + + for (i = 0; i < num_keys; i++) { + uint8_t type; + uint8_t *key; + + if (!util_iov_pull_u8(&frame, &type)) { + print_field("Key type[%u]: invalid size", i); + return; + } + + switch (type) { + case 0x00: + print_field("type: Link Key (0x00)"); + break; + case 0x01: + print_field("type: Long Term Key (0x01)"); + break; + case 0x02: + print_field("type: Identity Resolving Key (0x02)"); + break; + } + + key = util_iov_pull_mem(&frame, 16); + if (!key) { + print_field("Key[%u]: invalid size", i); + return; + } + + print_link_key(key); + } +} + +static void mgmt_set_wbs_cmd(const void *data, uint16_t size) +{ + uint8_t enable = get_u8(data); + + print_enable("Wideband Speech", enable); +} + static void mgmt_new_settings_rsp(const void *data, uint16_t size) { uint32_t current_settings = get_le32(data); @@ -14501,8 +14931,12 @@ static const struct mgmt_data mgmt_command_table[] = { { 0x0045, "Set PHY Configuration", mgmt_set_phy_cmd, 4, true, mgmt_null_rsp, 0, true }, - { 0x0046, "Load Blocked Keys" }, - { 0x0047, "Set Wideband Speech" }, + { 0x0046, "Set Blocked Keys", + mgmt_set_blocked_keys_cmd, 2, false, + mgmt_null_rsp, 0, true }, + { 0x0047, "Set Wideband Speech", + mgmt_set_wbs_cmd, 1, true, + mgmt_new_settings_rsp, 4, true }, { 0x0048, "Read Controller Capabilities" }, { 0x0049, "Read Experimental Features Information", mgmt_null_cmd, 0, true, diff --git a/monitor/packet.h b/monitor/packet.h index b07d5d18ce21350fce39914f91b2ecde9a2b309f..856f74f4db16f46e3c25101c75d2177bbeab3a0f 100644 --- a/monitor/packet.h +++ b/monitor/packet.h @@ -22,19 +22,39 @@ #define PACKET_FILTER_SHOW_SCO_DATA (1 << 5) #define PACKET_FILTER_SHOW_A2DP_STREAM (1 << 6) #define PACKET_FILTER_SHOW_MGMT_SOCKET (1 << 7) +#define PACKET_FILTER_SHOW_ISO_DATA (1 << 8) +#define TV_MSEC(_tv) (long long)((_tv).tv_sec * 1000 + (_tv).tv_usec / 1000) + +struct packet_latency { + struct timeval total; + struct timeval min; + struct timeval max; + struct timeval med; +}; + +struct packet_frame { + struct timeval tv; + size_t num; + size_t len; +}; struct packet_conn_data { uint16_t index; uint8_t src[6]; uint16_t handle; + uint16_t link; uint8_t type; uint8_t dst[6]; uint8_t dst_type; + struct queue *tx_q; + struct queue *chan_q; + struct packet_latency tx_l; void *data; void (*destroy)(void *data); }; struct packet_conn_data *packet_get_conn_data(uint16_t handle); +void packet_latency_add(struct packet_latency *latency, struct timeval *delta); bool packet_has_filter(unsigned long filter); void packet_set_filter(unsigned long filter); @@ -64,20 +84,6 @@ void packet_print_io_capability(uint8_t capability); void packet_print_io_authentication(uint8_t authentication); void packet_print_codec_id(const char *label, uint8_t codec); -#define LTV_DEC(_type, _func) \ -{ \ - .type = _type, \ - .func = _func, \ -} - -struct packet_ltv_decoder { - uint8_t type; - void (*func)(const uint8_t *data, uint8_t len); -}; - -void packet_print_ltv(const char *label, const uint8_t *data, uint8_t len, - struct packet_ltv_decoder *decoder, size_t num); - void packet_control(struct timeval *tv, struct ucred *cred, uint16_t index, uint16_t opcode, const void *data, uint16_t size); diff --git a/monitor/rfcomm.c b/monitor/rfcomm.c index 02300a8b5d0ebc210a1d435e77fdf3fbf1e57a81..a855152c69c347f0a09c8302801a50150c79150d 100644 --- a/monitor/rfcomm.c +++ b/monitor/rfcomm.c @@ -32,7 +32,7 @@ #include "sdp.h" #include "rfcomm.h" -static char *cr_str[] = { +static const char *cr_str[] = { "RSP", "CMD" }; diff --git a/monitor/sdp.c b/monitor/sdp.c index daf9a9da82ccef9c1ad90cf77ec99dab839ad275..5fe4f29796f32185f0c3f1810db08243bd63d229 100644 --- a/monitor/sdp.c +++ b/monitor/sdp.c @@ -148,9 +148,9 @@ static void print_boolean(uint8_t indent, const uint8_t *data, uint32_t size) #define SIZES(args...) ((uint8_t[]) { args, 0xff } ) -static struct { +static const struct { uint8_t value; - uint8_t *sizes; + const uint8_t *sizes; bool recurse; const char *str; void (*print) (uint8_t indent, const uint8_t *data, uint32_t size); @@ -167,7 +167,7 @@ static struct { { } }; -static struct { +static const struct { uint8_t index; uint8_t bits; uint8_t size; @@ -184,7 +184,7 @@ static struct { { } }; -static bool valid_size(uint8_t size, uint8_t *sizes) +static bool valid_size(uint8_t size, const uint8_t *sizes) { int i; @@ -322,7 +322,7 @@ static uint32_t get_bytes(const uint8_t *data, uint32_t size) return 0; } -static struct { +static const struct { uint16_t id; const char *str; } attribute_table[] = { diff --git a/monitor/vendor.h b/monitor/vendor.h index 9430f3736818b1b389ae67013d32aa2049dae0a1..996ed44cb18e15895ebaad4c9034bbc9f01fe482 100644 --- a/monitor/vendor.h +++ b/monitor/vendor.h @@ -25,7 +25,8 @@ struct vendor_ocf { struct vendor_evt { uint8_t evt; const char *str; - void (*evt_func) (uint16_t index, const void *data, uint8_t size); + void (*evt_func) (struct timeval *tv, uint16_t index, + const void *data, uint8_t size); uint8_t evt_size; bool evt_fixed; }; diff --git a/obexd/client/bip-common.c b/obexd/client/bip-common.c new file mode 100644 index 0000000000000000000000000000000000000000..613b52ceb7c059e944326d5edb2eaf3c2f69652e --- /dev/null +++ b/obexd/client/bip-common.c @@ -0,0 +1,800 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * + * OBEX Client + * + * Copyright (C) 2024 Collabora Ltd. + * Based on previous work done by Jakub Adamek for GSoC 2011 + * + */ + +#define _GNU_SOURCE +#include <errno.h> +#include <regex.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include "gobex/gobex.h" + +#include "obexd/src/log.h" +#include "bip-common.h" + +#define HANDLE_LEN 7 +#define HANDLE_LIMIT 10000000 + +struct encconv_pair { + gchar *bip, *im; +}; + +struct encconv_pair encconv_table[] = { + { "JPEG", "JPEG" }, + { "GIF", "GIF" }, + { "WBMP", "WBMP" }, + { "PNG", "PNG" }, + { "JPEG2000", "JP2" }, + { "BMP", "BMP" }, + { } +}; + +static const gchar *convBIP2IM(const gchar *encoding) +{ + struct encconv_pair *et = encconv_table; + + while (et->bip) { + if (g_strcmp0(encoding, et->bip) == 0) + return et->im; + et++; + } + return NULL; +} + +gboolean parse_pixel_range(const gchar *dim, unsigned int *lower_ret, + unsigned int *upper_ret, + gboolean *fixed_ratio_ret) +{ + static regex_t no_range; + static regex_t range; + static regex_t range_fixed; + static int regex_initialized; + unsigned int lower[2], upper[2]; + gboolean fixed_ratio = FALSE; + + if (!regex_initialized) { + regcomp(&no_range, "^([[:digit:]]{1,5})\\*([[:digit:]]{1,5})$", + REG_EXTENDED); + regcomp(&range, "^([[:digit:]]{1,5})\\*([[:digit:]]{1,5})" + "-([[:digit:]]{1,5})\\*([[:digit:]]{1,5})$", + REG_EXTENDED); + regcomp(&range_fixed, "^([[:digit:]]{1,5})\\*\\*" + "-([[:digit:]]{1,5})\\*([[:digit:]]{1,5})$", + REG_EXTENDED); + regex_initialized = 1; + } + if (dim == NULL) + return FALSE; + if (regexec(&no_range, dim, 0, NULL, 0) == 0) { + if (sscanf(dim, "%u*%u", &lower[0], &lower[1]) != 2) + return FALSE; + upper[0] = lower[0]; + upper[1] = lower[1]; + fixed_ratio = FALSE; + } else if (regexec(&range, dim, 0, NULL, 0) == 0) { + if (sscanf(dim, "%u*%u-%u*%u", &lower[0], &lower[1], + &upper[0], &upper[1]) != 4) + return FALSE; + fixed_ratio = FALSE; + } else if (regexec(&range_fixed, dim, 0, NULL, 0) == 0) { + if (sscanf(dim, "%u**-%u*%u", &lower[0], &upper[0], + &upper[1]) != 3) + return FALSE; + lower[1] = 0; + fixed_ratio = TRUE; + } else { + return FALSE; + } + if (lower[0] > 65535 || lower[1] > 65535 || + upper[0] > 65535 || upper[1] > 65535) + return FALSE; + if (lower_ret == NULL || upper_ret == NULL || fixed_ratio_ret == NULL) + return TRUE; + if (upper[0] < lower[0] || upper[1] < lower[1]) + return FALSE; + lower_ret[0] = lower[0]; + lower_ret[1] = lower[1]; + upper_ret[0] = upper[0]; + upper_ret[1] = upper[1]; + *fixed_ratio_ret = fixed_ratio; + + return TRUE; +} + +static gboolean verify_unsignednumber(const char *size) +{ + static regex_t unumber; + static int regex_initialized; + + if (!regex_initialized) { + regcomp(&unumber, "^[[:digit:]]+$", REG_EXTENDED); + regex_initialized = 1; + } + if (regexec(&unumber, size, 0, NULL, 0) != 0) + return FALSE; + + return TRUE; +} + +static uint64_t parse_unsignednumber(const char *size) +{ + if (!verify_unsignednumber(size)) + return 0; + + return g_ascii_strtoll(size, NULL, 10); +} + +char *transforms[] = { + "crop", + "stretch", + "fill", + NULL +}; + +gboolean verify_encoding(const char *encoding) +{ + struct encconv_pair *et = encconv_table; + + while (et->bip) { + if (g_strcmp0(encoding, et->bip) == 0) + return TRUE; + et++; + } + return FALSE; +} + +static gboolean verify_transform(const char *transform) +{ + char **str = transforms; + + while (*str != NULL) { + if (g_str_equal(transform, *str)) + return TRUE; + str++; + } + return FALSE; +} + +char *parse_transform(const char *transform) +{ + if (!verify_transform(transform)) + return NULL; + return g_strdup(transform); +} + +static char *parse_transform_list(const char *transform) +{ + char **args = NULL, **arg = NULL; + gboolean used[3] = { FALSE, FALSE, FALSE }; + + if (transform == NULL) + return NULL; + if (strlen(transform) == 0) + return NULL; + args = g_strsplit(transform, " ", 0); + for (arg = args; *arg != NULL; arg++) { + char *t = *arg; + + if (!verify_transform(t)) { + g_strfreev(args); + return NULL; + } + switch (t[0]) { + case 's': + if (used[0]) + goto failure; + used[0] = TRUE; + break; + case 'c': + if (used[1]) + goto failure; + used[1] = TRUE; + break; + case 'f': + if (used[2]) + goto failure; + used[2] = TRUE; + break; + } + } + g_strfreev(args); + return g_strdup(transform); +failure: + g_strfreev(args); + return NULL; +} + +static time_t parse_iso8601_bip(const gchar *str, int len) +{ + gchar *tstr; + struct tm tm; + gint nr; + gchar tz; + time_t time; + time_t tz_offset = 0; + + if (str == NULL) + return -1; + + memset(&tm, 0, sizeof(struct tm)); + + /* According to spec the time doesn't have to be null terminated */ + if (str[len - 1] != '\0') { + tstr = g_malloc(len + 1); + strncpy(tstr, str, len); + tstr[len] = '\0'; + } else + tstr = g_strdup(str); + + nr = sscanf(tstr, "%04u%02u%02uT%02u%02u%02u%c", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, + &tm.tm_hour, &tm.tm_min, &tm.tm_sec, + &tz); + + g_free(tstr); + + /* Fixup the tm values */ + tm.tm_year -= 1900; /* Year since 1900 */ + tm.tm_mon--; /* Months since January, values 0-11 */ + tm.tm_isdst = -1; /* Daylight savings information not avail */ + + if (nr < 6) { + /* Invalid time format */ + return -1; + } + + time = mktime(&tm); + +#if defined(HAVE_TM_GMTOFF) + tz_offset = tm.tm_gmtoff; +#elif defined(HAVE_TIMEZONE) + tz_offset = -timezone; + if (tm.tm_isdst > 0) + tz_offset += 3600; +#endif + + if (nr == 7) { /* Date/Time was in localtime (to remote device) + * already. Since we don't know anything about the + * timezone on that one we won't try to apply UTC offset + */ + time += tz_offset; + } + + return time; +} + +static int parse_handle(const char *data) +{ + int handle; + char *ptr; + + if (data == NULL) + return -1; + if (strlen(data) != HANDLE_LEN) + return -1; + handle = strtol(data, &ptr, 10); + if (ptr != data + HANDLE_LEN) + return -1; + if (handle < 0 || handle >= HANDLE_LIMIT) + return -1; + return handle; +} + +struct native_prop { + char *encoding, *pixel; + uint64_t size; +}; + +struct variant_prop { + char *encoding, *pixel, *transform; + uint64_t maxsize; +}; + +struct att_prop { + char *content_type, *charset, *name; + uint64_t size; + time_t ctime, mtime; +}; + +struct prop_object { + char *handle, *name; + GSList *native, *variant, *att; +}; + +static void free_native_prop(struct native_prop *prop) +{ + DBG(""); + + if (prop == NULL) + return; + g_free(prop->encoding); + g_free(prop->pixel); + g_free(prop); +} + +static void free_variant_prop(struct variant_prop *prop) +{ + DBG(""); + + if (prop == NULL) + return; + g_free(prop->encoding); + g_free(prop->pixel); + g_free(prop->transform); + g_free(prop); +} + +static void free_att_prop(struct att_prop *prop) +{ + DBG(""); + + if (prop == NULL) + return; + g_free(prop->content_type); + g_free(prop->charset); + g_free(prop->name); + g_free(prop); +} + +static void free_prop_object(struct prop_object *object) +{ + GSList *list; + + DBG(""); + + if (object == NULL) + return; + for (list = object->native; list != NULL; list = g_slist_next(list)) + free_native_prop(list->data); + for (list = object->variant; list != NULL; list = g_slist_next(list)) + free_variant_prop(list->data); + for (list = object->att; list != NULL; list = g_slist_next(list)) + free_att_prop(list->data); + g_slist_free(object->native); + g_slist_free(object->variant); + g_slist_free(object->att); + g_free(object->handle); + g_free(object->name); + g_free(object); +} + +static gboolean parse_attrib_native(struct native_prop *prop, const gchar *key, + const gchar *value, GError **gerr) +{ + DBG(""); + + if (g_str_equal(key, "encoding")) { + if (convBIP2IM(value) == NULL) + goto invalid; + prop->encoding = g_strdup(value); + } else if (g_str_equal(key, "pixel")) { + if (!parse_pixel_range(value, NULL, NULL, NULL)) + goto invalid; + prop->pixel = g_strdup(value); + } else if (g_str_equal(key, "size")) { + prop->size = parse_unsignednumber(value); + if (prop->size == 0) + goto invalid; + } else { + g_set_error(gerr, G_MARKUP_ERROR, + G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, NULL); + return FALSE; + } + return TRUE; +invalid: + g_set_error(gerr, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + NULL); + return FALSE; +} + +static gboolean parse_attrib_variant(struct variant_prop *prop, + const gchar *key, + const gchar *value, GError **gerr) +{ + DBG(""); + + if (g_str_equal(key, "encoding")) { + if (convBIP2IM(value) == NULL) + goto invalid; + prop->encoding = g_strdup(value); + } else if (g_str_equal(key, "pixel")) { + if (!parse_pixel_range(value, NULL, NULL, NULL)) + goto invalid; + prop->pixel = g_strdup(value); + } else if (g_str_equal(key, "maxsize")) { + prop->maxsize = parse_unsignednumber(value); + if (prop->maxsize == 0) + goto invalid; + } else if (g_str_equal(key, "transform")) { + prop->transform = parse_transform_list(value); + if (prop->transform == NULL) + goto invalid; + } else { + g_set_error(gerr, G_MARKUP_ERROR, + G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, NULL); + return FALSE; + } + return TRUE; +invalid: + g_set_error(gerr, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + NULL); + return FALSE; +} + +static gboolean parse_attrib_att(struct att_prop *prop, const gchar *key, + const gchar *value, GError **gerr) +{ + DBG(""); + + if (g_str_equal(key, "content-type")) { + prop->content_type = g_strdup(value); + } else if (g_str_equal(key, "charset")) { + prop->charset = g_strdup(value); + } else if (g_str_equal(key, "name")) { + prop->name = g_strdup(value); + } else if (g_str_equal(key, "size")) { + prop->size = parse_unsignednumber(value); + if (prop->size == 0) + goto invalid; + } else if (g_str_equal(key, "created")) { + prop->ctime = parse_iso8601_bip(value, strlen(value)); + if (prop->ctime == -1) + goto invalid; + } else if (g_str_equal(key, "modified")) { + prop->mtime = parse_iso8601_bip(value, strlen(value)); + if (prop->mtime == -1) + goto invalid; + } else { + g_set_error(gerr, G_MARKUP_ERROR, + G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, NULL); + return FALSE; + } + return TRUE; +invalid: + g_set_error(gerr, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + NULL); + return FALSE; +} + +static struct att_prop *parse_elem_att(const gchar **names, + const gchar **values, GError **gerr) +{ + gchar **key; + struct att_prop *prop = g_new0(struct att_prop, 1); + + DBG(""); + + for (key = (gchar **) names; *key; key++, values++) { + if (!parse_attrib_att(prop, *key, *values, gerr)) { + free_att_prop(prop); + return NULL; + } + } + return prop; +} + +static struct variant_prop *parse_elem_variant(const gchar **names, + const gchar **values, GError **gerr) +{ + gchar **key; + struct variant_prop *prop = g_new0(struct variant_prop, 1); + + DBG(""); + + for (key = (gchar **) names; *key; key++, values++) { + if (!parse_attrib_variant(prop, *key, *values, gerr)) { + free_variant_prop(prop); + return NULL; + } + } + if (prop->transform == NULL) + prop->transform = g_strdup("stretch crop fill"); + return prop; +} + +static struct native_prop *parse_elem_native(const gchar **names, + const gchar **values, GError **gerr) +{ + gchar **key; + struct native_prop *prop = g_new0(struct native_prop, 1); + + DBG(""); + + for (key = (gchar **) names; *key; key++, values++) { + if (!parse_attrib_native(prop, *key, *values, gerr)) { + free_native_prop(prop); + return NULL; + } + } + return prop; +} + +static gboolean parse_attrib_prop(struct prop_object *prop, const gchar *key, + const gchar *value, GError **gerr) +{ + DBG(""); + + if (g_str_equal(key, "handle")) { + if (parse_handle(value) < 0) + goto invalid; + prop->handle = g_strdup(value); + } else if (g_str_equal(key, "friendly-name")) { + prop->name = g_strdup(value); + } else if (g_str_equal(key, "version")) { + // pass; + } else { + g_set_error(gerr, G_MARKUP_ERROR, + G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, NULL); + return FALSE; + } + return TRUE; +invalid: + g_set_error(gerr, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + NULL); + return FALSE; +} + +static struct prop_object *parse_elem_prop(const gchar **names, + const gchar **values, GError **gerr) +{ + gchar **key; + struct prop_object *prop = g_new0(struct prop_object, 1); + + DBG(""); + + for (key = (gchar **) names; *key; key++, values++) { + if (!parse_attrib_prop(prop, *key, *values, gerr)) { + free_prop_object(prop); + return NULL; + } + } + return prop; +} + +static void prop_element(GMarkupParseContext *ctxt, + const gchar *element, + const gchar **names, + const gchar **values, + gpointer user_data, + GError **gerr) +{ + struct prop_object **obj = user_data; + + DBG(""); + + if (g_str_equal(element, "image-properties")) { + if (*obj != NULL) { + free_prop_object(*obj); + *obj = NULL; + goto invalid; + } + *obj = parse_elem_prop(names, values, gerr); + } else if (g_str_equal(element, "native")) { + struct native_prop *prop; + + if (*obj == NULL) + goto invalid; + prop = parse_elem_native(names, values, gerr); + (*obj)->native = g_slist_append((*obj)->native, prop); + } else if (g_str_equal(element, "variant")) { + struct variant_prop *prop; + + if (*obj == NULL) + goto invalid; + prop = parse_elem_variant(names, values, gerr); + (*obj)->variant = g_slist_append((*obj)->variant, prop); + } else if (g_str_equal(element, "attachment")) { + struct att_prop *prop; + + if (*obj == NULL) + goto invalid; + prop = parse_elem_att(names, values, gerr); + (*obj)->att = g_slist_append((*obj)->att, prop); + } else { + if (*obj != NULL) { + free_prop_object(*obj); + *obj = NULL; + } + goto invalid; + } + + return; +invalid: + g_set_error(gerr, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + NULL); +} + +static const GMarkupParser properties_parser = { + prop_element, + NULL, + NULL, + NULL, + NULL +}; + +struct prop_object *parse_properties(char *data, unsigned int length, + int *err) +{ + struct prop_object *prop = NULL; + gboolean status; + GError *gerr = NULL; + GMarkupParseContext *ctxt = g_markup_parse_context_new( + &properties_parser, 0, &prop, NULL); + + DBG(""); + + if (err != NULL) + *err = 0; + status = g_markup_parse_context_parse(ctxt, data, length, &gerr); + g_markup_parse_context_free(ctxt); + if (!status) { + if (err != NULL) + *err = -EINVAL; + free_prop_object(prop); + prop = NULL; + } + return prop; +} + +gboolean verify_properties(struct prop_object *obj) +{ + GSList *list; + + if (obj->handle == NULL) + return FALSE; + + for (list = obj->native; list != NULL; list = g_slist_next(list)) { + struct native_prop *prop = list->data; + + if (prop->encoding == NULL || prop->pixel == NULL) + return FALSE; + } + + for (list = obj->variant; list != NULL; list = g_slist_next(list)) { + struct variant_prop *prop = list->data; + + if (prop->encoding == NULL || prop->pixel == NULL) + return FALSE; + } + + for (list = obj->att; list != NULL; list = g_slist_next(list)) { + struct att_prop *prop = list->data; + + if (prop->content_type == NULL || prop->name == NULL) + return FALSE; + } + + return TRUE; +} + +void append_properties(DBusMessageIter *args, struct prop_object *obj) +{ + DBusMessageIter dict, iter; + GSList *list; + + dbus_message_iter_open_container(args, DBUS_TYPE_ARRAY, + DBUS_TYPE_ARRAY_AS_STRING + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &dict); + + dbus_message_iter_open_container(&dict, 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, + &iter); + g_dbus_dict_append_entry(&iter, "handle", DBUS_TYPE_STRING, + &obj->handle); + g_dbus_dict_append_entry(&iter, "name", DBUS_TYPE_STRING, &obj->name); + dbus_message_iter_close_container(&dict, &iter); + + for (list = obj->native; list != NULL; list = g_slist_next(list)) { + struct native_prop *prop = list->data; + static char *native_str = "native"; + + dbus_message_iter_open_container(&dict, 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, + &iter); + g_dbus_dict_append_entry(&iter, "type", DBUS_TYPE_STRING, + &native_str); + if (prop->encoding) + g_dbus_dict_append_entry(&iter, "encoding", + DBUS_TYPE_STRING, + &prop->encoding); + if (prop->pixel) + g_dbus_dict_append_entry(&iter, "pixel", + DBUS_TYPE_STRING, + &prop->pixel); + if (prop->size) + g_dbus_dict_append_entry(&iter, "size", + DBUS_TYPE_UINT64, + &prop->size); + dbus_message_iter_close_container(&dict, &iter); + } + + for (list = obj->variant; list != NULL; list = g_slist_next(list)) { + struct variant_prop *prop = list->data; + static char *variant_str = "variant"; + + dbus_message_iter_open_container(&dict, 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, + &iter); + g_dbus_dict_append_entry(&iter, "type", DBUS_TYPE_STRING, + &variant_str); + if (prop->encoding) + g_dbus_dict_append_entry(&iter, "encoding", + DBUS_TYPE_STRING, + &prop->encoding); + if (prop->pixel) + g_dbus_dict_append_entry(&iter, "pixel", + DBUS_TYPE_STRING, + &prop->pixel); + if (prop->maxsize) + g_dbus_dict_append_entry(&iter, "maxsize", + DBUS_TYPE_UINT64, + &prop->maxsize); + if (prop->transform) + g_dbus_dict_append_entry(&iter, "transformation", + DBUS_TYPE_STRING, + &prop->transform); + dbus_message_iter_close_container(&dict, &iter); + } + + for (list = obj->att; list != NULL; list = g_slist_next(list)) { + struct att_prop *prop = list->data; + static char *attachment_str = "attachment"; + + dbus_message_iter_open_container(&dict, 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, + &iter); + g_dbus_dict_append_entry(&iter, "type", DBUS_TYPE_STRING, + &attachment_str); + if (prop->content_type) + g_dbus_dict_append_entry(&iter, "content-type", + DBUS_TYPE_STRING, + &prop->content_type); + if (prop->charset) + g_dbus_dict_append_entry(&iter, "charset", + DBUS_TYPE_STRING, + &prop->charset); + if (prop->name) + g_dbus_dict_append_entry(&iter, "name", + DBUS_TYPE_STRING, + &prop->name); + if (prop->size) + g_dbus_dict_append_entry(&iter, "size", + DBUS_TYPE_UINT64, + &prop->size); + if (prop->ctime) + g_dbus_dict_append_entry(&iter, "ctime", + DBUS_TYPE_UINT64, + &prop->ctime); + if (prop->mtime) + g_dbus_dict_append_entry(&iter, "mtime", + DBUS_TYPE_UINT64, + &prop->mtime); + dbus_message_iter_close_container(&dict, &iter); + } + + dbus_message_iter_close_container(args, &dict); +} diff --git a/obexd/client/bip-common.h b/obexd/client/bip-common.h new file mode 100644 index 0000000000000000000000000000000000000000..6e7aac3750ecd9f5bb7bb0a4b2025c1f64157e49 --- /dev/null +++ b/obexd/client/bip-common.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * + * OBEX Client + * + * Copyright (C) 2024 Collabora Ltd. + * + * + */ + +#include <glib.h> +#include "gdbus/gdbus.h" + +struct prop_object; + +gboolean parse_pixel_range(const gchar *dim, unsigned int *lower_ret, + unsigned int *upper_ret, + gboolean *fixed_ratio_ret); +gboolean verify_encoding(const char *encoding); +char *parse_transform(const char *transform); +struct prop_object *parse_properties(char *data, unsigned int length, + int *err); +gboolean verify_properties(struct prop_object *obj); +void append_properties(DBusMessageIter *args, struct prop_object *obj); diff --git a/obexd/client/bip.c b/obexd/client/bip.c new file mode 100644 index 0000000000000000000000000000000000000000..9d9ecec812b07d0ec6cf73a997d4012b2330080f --- /dev/null +++ b/obexd/client/bip.c @@ -0,0 +1,440 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * + * OBEX Client + * + * Copyright (C) 2024 Collabora Ltd. + * + * + */ + +#define _GNU_SOURCE +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include "gdbus/gdbus.h" +#include "gobex/gobex.h" + +#include "obexd/src/log.h" +#include "transfer.h" +#include "session.h" +#include "driver.h" +#include "bip-common.h" +#include "bip.h" + +#define OBEX_BIP_AVRCP_UUID \ + "\x71\x63\xDD\x54\x4A\x7E\x11\xE2\xB4\x7C\x00\x50\xC2\x49\x00\x48" +#define OBEX_BIP_AVRCP_UUID_LEN 16 + +#define IMAGE_INTERFACE "org.bluez.obex.Image1" +#define ERROR_INTERFACE "org.bluez.obex.Error" +#define IMAGE_UUID "0000111A-0000-1000-8000-00805f9b34fb" + +#define IMG_HANDLE_TAG 0x30 +#define IMG_DESC_TAG 0x71 + +#define EOL_CHARS "\n" +#define IMG_DESC_BEGIN "<image-descriptor version=\"1.0\">" EOL_CHARS +#define IMG_BEGIN "<image encoding=\"%s\" pixel=\"%s\"" +#define IMG_TRANSFORM " transformation=\"%s\"" +#define IMG_END "/>" EOL_CHARS +#define IMG_DESC_END "</image-descriptor>" EOL_CHARS + +static DBusConnection *conn; + +struct bip_avrcp_data { + struct obc_session *session; +}; + +static void image_properties_complete_cb(struct obc_session *session, + struct obc_transfer *transfer, + GError *err, void *user_data) +{ + DBusMessage *message = user_data; + DBusMessage *reply = NULL; + DBusMessageIter iter; + char *contents = NULL; + size_t size; + int perr; + struct prop_object *prop = NULL; + + if (err != NULL) { + reply = g_dbus_create_error(message, + ERROR_INTERFACE ".Failed", + "%s", err->message); + goto done; + } + + perr = obc_transfer_get_contents(transfer, &contents, &size); + if (perr < 0) { + reply = g_dbus_create_error(message, + ERROR_INTERFACE ".Failed", + "Error reading contents: %s", + strerror(-perr)); + goto done; + } + + prop = parse_properties(contents, size, &perr); + if (prop == NULL) { + reply = g_dbus_create_error(message, + ERROR_INTERFACE ".Failed", + "Error parsing contents: %s", + strerror(-perr)); + goto done; + } + + if (!verify_properties(prop)) { + reply = g_dbus_create_error(message, + ERROR_INTERFACE ".Failed", + "Error verifying contents"); + goto done; + } + + reply = dbus_message_new_method_return(message); + dbus_message_iter_init_append(reply, &iter); + append_properties(&iter, prop); + +done: + g_dbus_send_message(conn, reply); + g_free(contents); + dbus_message_unref(message); +} + +static DBusMessage *get_image_properties(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + struct bip_avrcp_data *bip_avrcp = user_data; + const char *handle = NULL; + struct obc_transfer *transfer; + GObexHeader *header; + DBusMessage *reply = NULL; + GError *err = NULL; + + DBG(""); + + if (dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &handle, + DBUS_TYPE_INVALID) == FALSE) { + reply = g_dbus_create_error(message, + ERROR_INTERFACE ".InvalidArguments", NULL); + return reply; + } + + transfer = obc_transfer_get("x-bt/img-properties", NULL, NULL, &err); + if (transfer == NULL) + goto fail; + + header = g_obex_header_new_unicode(IMG_HANDLE_TAG, handle); + obc_transfer_add_header(transfer, header); + + if (!obc_session_queue(bip_avrcp->session, transfer, + image_properties_complete_cb, message, &err)) + goto fail; + + dbus_message_ref(message); + + return NULL; + +fail: + reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s", + err->message); + g_error_free(err); + return reply; +} + +static DBusMessage *get_thumbnail(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + struct bip_avrcp_data *bip_avrcp = user_data; + const char *handle = NULL, *image_path = NULL; + struct obc_transfer *transfer; + GObexHeader *header; + DBusMessage *reply = NULL; + GError *err = NULL; + + DBG(""); + + if (dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &image_path, + DBUS_TYPE_STRING, &handle, + DBUS_TYPE_INVALID) == FALSE) { + reply = g_dbus_create_error(message, + ERROR_INTERFACE ".InvalidArguments", NULL); + return reply; + } + + transfer = obc_transfer_get("x-bt/img-thm", NULL, image_path, &err); + if (transfer == NULL) + goto fail; + + header = g_obex_header_new_unicode(IMG_HANDLE_TAG, handle); + obc_transfer_add_header(transfer, header); + + if (!obc_session_queue(bip_avrcp->session, transfer, NULL, NULL, &err)) + goto fail; + + return obc_transfer_create_dbus_reply(transfer, message); + +fail: + reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s", + err->message); + g_error_free(err); + return reply; +} + +static gboolean parse_get_image_dict(DBusMessage *msg, char **path, + char **handle, char **pixel, + char **encoding, uint64_t *maxsize, + char **transform) +{ + DBusMessageIter iter, array; + + DBG(""); + + *path = NULL; + *handle = NULL; + *pixel = NULL; + *encoding = NULL; + *transform = NULL; + + dbus_message_iter_init(msg, &iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + goto failed; + dbus_message_iter_get_basic(&iter, path); + *path = g_strdup(*path); + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + goto failed; + dbus_message_iter_next(&iter); + dbus_message_iter_get_basic(&iter, handle); + *handle = g_strdup(*handle); + dbus_message_iter_next(&iter); + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) + goto failed; + + dbus_message_iter_recurse(&iter, &array); + + while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter entry, value; + const char *key, *val; + + dbus_message_iter_recurse(&array, &entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) + return FALSE; + dbus_message_iter_get_basic(&entry, &key); + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &value); + switch (dbus_message_iter_get_arg_type(&value)) { + case DBUS_TYPE_STRING: + dbus_message_iter_get_basic(&value, &val); + if (g_str_equal(key, "pixel")) { + if (!parse_pixel_range(val, NULL, NULL, NULL)) + goto failed; + *pixel = g_strdup(val); + } else if (g_str_equal(key, "encoding")) { + if (!verify_encoding(val)) + goto failed; + *encoding = g_strdup(val); + if (*encoding == NULL) + goto failed; + } else if (g_str_equal(key, "transformation")) { + *transform = parse_transform(val); + if (*transform == NULL) + goto failed; + } + break; + case DBUS_TYPE_UINT64: + if (g_str_equal(key, "maxsize") == TRUE) { + dbus_message_iter_get_basic(&value, maxsize); + if (*maxsize == 0) + goto failed; + } + break; + } + dbus_message_iter_next(&array); + } + + if (*pixel == NULL) + *pixel = strdup(""); + if (*encoding == NULL) + *encoding = strdup(""); + + DBG("pixel: '%s' encoding: '%s' maxsize: '%lu' transform: '%s'", + *pixel, *encoding, *maxsize, *transform + ); + + return TRUE; +failed: + g_free(*path); + g_free(*handle); + g_free(*pixel); + g_free(*encoding); + g_free(*transform); + return FALSE; +} + +static DBusMessage *get_image(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + struct bip_avrcp_data *bip_avrcp = user_data; + char *handle = NULL, *image_path = NULL, *transform = NULL, + *encoding = NULL, *pixel = NULL; + uint64_t maxsize; + struct obc_transfer *transfer; + GObexHeader *header; + DBusMessage *reply = NULL; + GString *descriptor = NULL; + GError *err = NULL; + + DBG(""); + + if (!parse_get_image_dict(message, &image_path, &handle, &pixel, + &encoding, &maxsize, &transform)) + return g_dbus_create_error(message, + ERROR_INTERFACE ".InvalidArguments", NULL); + + transfer = obc_transfer_get("x-bt/img-img", NULL, image_path, &err); + if (transfer == NULL) { + reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", + "%s", + err->message); + g_error_free(err); + goto fail; + } + + header = g_obex_header_new_unicode(IMG_HANDLE_TAG, handle); + obc_transfer_add_header(transfer, header); + + descriptor = g_string_new(IMG_DESC_BEGIN); + g_string_append_printf(descriptor, IMG_BEGIN, encoding, pixel); + if (transform != NULL) + g_string_append_printf(descriptor, IMG_TRANSFORM, transform); + g_string_append(descriptor, IMG_END); + descriptor = g_string_append(descriptor, IMG_DESC_END); + header = g_obex_header_new_bytes(IMG_DESC_TAG, descriptor->str, + descriptor->len); + obc_transfer_add_header(transfer, header); + g_string_free(descriptor, TRUE); + + if (!obc_session_queue(bip_avrcp->session, transfer, NULL, NULL, + &err)) { + reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", + "%s", + err->message); + g_error_free(err); + goto fail; + } + + reply = obc_transfer_create_dbus_reply(transfer, message); + +fail: + g_free(handle); + g_free(image_path); + g_free(transform); + g_free(encoding); + g_free(pixel); + return reply; +} + +static const GDBusMethodTable bip_avrcp_methods[] = { + { GDBUS_ASYNC_METHOD("Properties", + GDBUS_ARGS({ "handle", "s"}), + GDBUS_ARGS({ "properties", "aa{sv}" }), + get_image_properties) }, + { GDBUS_ASYNC_METHOD("Get", + GDBUS_ARGS({ "file", "s" }, { "handle", "s"}, + {"properties", "a{sv}"}), + GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }), + get_image) }, + { GDBUS_ASYNC_METHOD("GetThumbnail", + GDBUS_ARGS({ "file", "s" }, { "handle", "s"}), + GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }), + get_thumbnail) }, + { } +}; + +static void bip_avrcp_free(void *data) +{ + struct bip_avrcp_data *bip_avrcp = data; + + obc_session_unref(bip_avrcp->session); + g_free(bip_avrcp); +} + +static int bip_avrcp_probe(struct obc_session *session) +{ + struct bip_avrcp_data *bip_avrcp; + const char *path; + + path = obc_session_get_path(session); + + DBG("%s", path); + + bip_avrcp = g_try_new0(struct bip_avrcp_data, 1); + if (!bip_avrcp) + return -ENOMEM; + + bip_avrcp->session = obc_session_ref(session); + + if (!g_dbus_register_interface(conn, path, IMAGE_INTERFACE, + bip_avrcp_methods, + NULL, NULL, + bip_avrcp, bip_avrcp_free)) { + bip_avrcp_free(bip_avrcp); + return -ENOMEM; + } + + return 0; +} + +static void bip_avrcp_remove(struct obc_session *session) +{ + const char *path = obc_session_get_path(session); + + DBG("%s", path); + + g_dbus_unregister_interface(conn, path, IMAGE_INTERFACE); +} + +static struct obc_driver bip_avrcp = { + .service = "BIP-AVRCP", + .uuid = IMAGE_UUID, + .target = OBEX_BIP_AVRCP_UUID, + .target_len = OBEX_BIP_AVRCP_UUID_LEN, + .probe = bip_avrcp_probe, + .remove = bip_avrcp_remove +}; + +int bip_init(void) +{ + int err; + + DBG(""); + + conn = dbus_bus_get(DBUS_BUS_SESSION, NULL); + if (!conn) + return -EIO; + + err = obc_driver_register(&bip_avrcp); + if (err < 0) + goto failed; + + return 0; + +failed: + dbus_connection_unref(conn); + conn = NULL; + return err; +} + +void bip_exit(void) +{ + DBG(""); + + dbus_connection_unref(conn); + conn = NULL; + + obc_driver_unregister(&bip_avrcp); +} diff --git a/obexd/client/bip.h b/obexd/client/bip.h new file mode 100644 index 0000000000000000000000000000000000000000..18e3360f3d83fa64300e142b907dbf2dbd329627 --- /dev/null +++ b/obexd/client/bip.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * + * OBEX Client + * + * Copyright (C) 2024 Collabora Ltd. + * + * + */ + +int bip_init(void); +void bip_exit(void); diff --git a/obexd/client/manager.c b/obexd/client/manager.c index 75f1bfb043ddc8954c456b8f6179dd52f8aaac98..52f4d0179dbd3e2a7ff5b6ce9509ee5784562936 100644 --- a/obexd/client/manager.c +++ b/obexd/client/manager.c @@ -32,6 +32,7 @@ #include "pbap.h" #include "sync.h" #include "map.h" +#include "bip.h" #include "manager.h" #define CLIENT_INTERFACE "org.bluez.obex.Client1" @@ -107,7 +108,8 @@ done: } static int parse_device_dict(DBusMessageIter *iter, - const char **source, const char **target, uint8_t *channel) + const char **source, const char **target, uint8_t *channel, + uint16_t *psm) { while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_DICT_ENTRY) { DBusMessageIter entry, value; @@ -130,6 +132,10 @@ static int parse_device_dict(DBusMessageIter *iter, if (g_str_equal(key, "Channel") == TRUE) dbus_message_iter_get_basic(&value, channel); break; + case DBUS_TYPE_UINT16: + if (g_str_equal(key, "PSM") == TRUE) + dbus_message_iter_get_basic(&value, psm); + break; } dbus_message_iter_next(iter); @@ -160,6 +166,7 @@ static DBusMessage *create_session(DBusConnection *connection, struct send_data *data; const char *source = NULL, *dest = NULL, *target = NULL; uint8_t channel = 0; + uint16_t psm = 0; dbus_message_iter_init(message, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) @@ -175,8 +182,8 @@ static DBusMessage *create_session(DBusConnection *connection, dbus_message_iter_recurse(&iter, &dict); - parse_device_dict(&dict, &source, &target, &channel); - if (dest == NULL || target == NULL) + parse_device_dict(&dict, &source, &target, &channel, &psm); + if (dest == NULL || target == NULL || (channel && psm)) return g_dbus_create_error(message, ERROR_INTERFACE ".InvalidArguments", NULL); @@ -188,7 +195,7 @@ static DBusMessage *create_session(DBusConnection *connection, data->connection = dbus_connection_ref(connection); data->message = dbus_message_ref(message); - session = obc_session_create(source, dest, target, channel, + session = obc_session_create(source, dest, target, channel, psm, dbus_message_get_sender(message), create_callback, data); if (session != NULL) { @@ -241,7 +248,7 @@ static const GDBusMethodTable client_methods[] = { static DBusConnection *conn = NULL; -static struct obc_module { +static const struct obc_module { const char *name; int (*init) (void); void (*exit) (void); @@ -252,13 +259,14 @@ static struct obc_module { { "pbap", pbap_init, pbap_exit }, { "sync", sync_init, sync_exit }, { "map", map_init, map_exit }, + { "bip", bip_init, bip_exit }, { } }; int client_manager_init(void) { DBusError derr; - struct obc_module *module; + const struct obc_module *module; dbus_error_init(&derr); @@ -289,7 +297,7 @@ int client_manager_init(void) void client_manager_exit(void) { - struct obc_module *module; + const struct obc_module *module; if (conn == NULL) return; diff --git a/obexd/client/map.c b/obexd/client/map.c index 74828cddbce51129479f00eefe671dec2c4a90d2..513dcaf1422ef9c207a7735bb894bb6beb812b78 100644 --- a/obexd/client/map.c +++ b/obexd/client/map.c @@ -1060,7 +1060,7 @@ static void parse_protected(struct map_msg *msg, const char *value) MAP_MSG_INTERFACE, "Protected"); } -static struct map_msg_parser { +static const struct map_msg_parser { const char *name; void (*func) (struct map_msg *msg, const char *value); } msg_parsers[] = { @@ -1120,7 +1120,7 @@ static void msg_element(GMarkupParseContext *ctxt, const char *element, &msg->path); for (i = 0, key = names[i]; key; key = names[++i]) { - struct map_msg_parser *parser; + const struct map_msg_parser *parser; for (parser = msg_parsers; parser && parser->name; parser++) { if (strcasecmp(key, parser->name) == 0) { diff --git a/obexd/client/mns.c b/obexd/client/mns.c index e52505642854f34ebb62f56e48a900a02384653c..c7f86afdcdf5be873ea94241ccf75f38ed6e95ee 100644 --- a/obexd/client/mns.c +++ b/obexd/client/mns.c @@ -233,7 +233,7 @@ static void parse_event_report_priority(struct map_event *event, event->priority = g_strdup(value); } -static struct map_event_report_parser { +static const struct map_event_report_parser { const char *name; void (*func) (struct map_event *event, const char *value); } event_report_parsers[] = { @@ -262,7 +262,7 @@ static void event_report_element(GMarkupParseContext *ctxt, return; for (i = 0, key = names[i]; key; key = names[++i]) { - struct map_event_report_parser *parser; + const struct map_event_report_parser *parser; for (parser = event_report_parsers; parser && parser->name; parser++) { @@ -346,7 +346,7 @@ static ssize_t event_report_write(void *obj, const void *buf, size_t count) return count; } -static struct obex_service_driver mns = { +static const struct obex_service_driver mns = { .name = "Message Notification server", .service = OBEX_MNS, .target = MNS_TARGET, @@ -356,7 +356,7 @@ static struct obex_service_driver mns = { .disconnect = mns_disconnect, }; -static struct obex_mime_type_driver mime_event_report = { +static const struct obex_mime_type_driver mime_event_report = { .target = MNS_TARGET, .target_size = TARGET_SIZE, .mimetype = "x-bt/MAP-event-report", diff --git a/obexd/client/pbap.c b/obexd/client/pbap.c index 1ed8c68eccd00097a8539aaa9ede9feed9b6d060..2d2aa950898c38984d544e7708610d4c2af43b59 100644 --- a/obexd/client/pbap.c +++ b/obexd/client/pbap.c @@ -285,7 +285,7 @@ static void read_version(struct pbap_data *pbap, GObexApparam *apparam) data = value; } - if (memcmp(pbap->primary, data, len)) { + if (len == sizeof(pbap->primary) && memcmp(pbap->primary, data, len)) { memcpy(pbap->primary, data, len); g_dbus_emit_property_changed(conn, obc_session_get_path(pbap->session), @@ -299,7 +299,8 @@ static void read_version(struct pbap_data *pbap, GObexApparam *apparam) data = value; } - if (memcmp(pbap->secondary, data, len)) { + if (len == sizeof(pbap->secondary) && + memcmp(pbap->secondary, data, len)) { memcpy(pbap->secondary, data, len); g_dbus_emit_property_changed(conn, obc_session_get_path(pbap->session), diff --git a/obexd/client/session.c b/obexd/client/session.c index 7d8ebb04ef474bc8ae75b5b231de3bb01c71301d..13a834e14f3c756faa40b729ceaf6dea268c1e40 100644 --- a/obexd/client/session.c +++ b/obexd/client/session.c @@ -88,6 +88,7 @@ struct obc_session { char *source; char *destination; uint8_t channel; + uint16_t psm; struct obc_transport *transport; struct obc_driver *driver; char *path; /* Session path */ @@ -471,6 +472,7 @@ static struct obc_session *session_find(const char *source, const char *destination, const char *service, uint8_t channel, + uint16_t psm, const char *owner) { GSList *l; @@ -490,6 +492,9 @@ static struct obc_session *session_find(const char *source, if (channel && session->channel != channel) continue; + if (psm && session->psm != psm) + continue; + if (g_strcmp0(owner, session->owner)) continue; @@ -541,8 +546,9 @@ static int session_connect(struct obc_session *session, } session->id = transport->connect(session->source, session->destination, - driver->uuid, session->channel, - transport_func, callback); + driver->uuid, + session->channel ? session->channel : session->psm, + transport_func, callback); if (session->id == 0) { obc_session_unref(callback->session); g_free(callback); @@ -558,6 +564,7 @@ struct obc_session *obc_session_create(const char *source, const char *destination, const char *service, uint8_t channel, + uint16_t psm, const char *owner, session_callback_t function, void *user_data) @@ -570,7 +577,8 @@ struct obc_session *obc_session_create(const char *source, if (destination == NULL) return NULL; - session = session_find(source, destination, service, channel, owner); + session = session_find(source, destination, service, channel, psm, + owner); if (session != NULL) goto proceed; @@ -598,6 +606,7 @@ struct obc_session *obc_session_create(const char *source, session->source = g_strdup(source); session->destination = g_strdup(destination); session->channel = channel; + session->psm = psm; session->queue = g_queue_new(); session->folder = g_strdup("/"); @@ -762,6 +771,17 @@ static gboolean get_channel(const GDBusPropertyTable *property, return TRUE; } +static gboolean get_psm(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct obc_session *session = data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, + &session->psm); + + return TRUE; +} + static const GDBusMethodTable session_methods[] = { { GDBUS_ASYNC_METHOD("GetCapabilities", NULL, GDBUS_ARGS({ "capabilities", "s" }), @@ -794,6 +814,7 @@ static const GDBusPropertyTable session_properties[] = { { "Source", "s", get_source, NULL, source_exists }, { "Destination", "s", get_destination }, { "Channel", "y", get_channel }, + { "PSM", "q", get_psm }, { "Target", "s", get_target, NULL, target_exists }, { } }; diff --git a/obexd/client/session.h b/obexd/client/session.h index 2c646df1a63540e254bd6e6e1b9ae1a282b84b65..19c3f3687d1b4302318ef1291af4791b89874c09 100644 --- a/obexd/client/session.h +++ b/obexd/client/session.h @@ -22,6 +22,7 @@ struct obc_session *obc_session_create(const char *source, const char *destination, const char *service, uint8_t channel, + uint16_t psm, const char *owner, session_callback_t function, void *user_data); diff --git a/obexd/client/transfer.c b/obexd/client/transfer.c index a7a85a0c0463982b6a2a7e32600152e44f995eb5..879d67d581a74c5a39ee942ffe9292c4749c6d60 100644 --- a/obexd/client/transfer.c +++ b/obexd/client/transfer.c @@ -57,6 +57,7 @@ struct obc_transfer { GObex *obex; uint8_t status; GObexApparam *apparam; + GSList *headers; guint8 op; struct transfer_callback *callback; DBusConnection *conn; @@ -400,6 +401,11 @@ static const GDBusPropertyTable obc_transfer_properties[] = { { } }; +static void header_free(void *data, void *user_data) +{ + g_obex_header_free(data); +} + static void obc_transfer_free(struct obc_transfer *transfer) { DBG("%p", transfer); @@ -441,6 +447,8 @@ static void obc_transfer_free(struct obc_transfer *transfer) if (transfer->obex) g_obex_unref(transfer->obex); + g_slist_foreach(transfer->headers, header_free, NULL); + g_slist_free(transfer->headers); g_free(transfer->callback); g_free(transfer->owner); g_free(transfer->filename); @@ -820,6 +828,12 @@ static gboolean transfer_start_get(struct obc_transfer *transfer, GError **err) g_obex_packet_add_bytes(req, G_OBEX_HDR_TYPE, transfer->type, strlen(transfer->type) + 1); + while (transfer->headers) { + hdr = transfer->headers->data; + g_obex_packet_add_header(req, hdr); + transfer->headers = g_slist_remove(transfer->headers, hdr); + } + if (transfer->apparam != NULL) { hdr = g_obex_header_new_apparam(transfer->apparam); g_obex_packet_add_header(req, hdr); @@ -974,3 +988,8 @@ gint64 obc_transfer_get_size(struct obc_transfer *transfer) { return transfer->size; } + +void obc_transfer_add_header(struct obc_transfer *transfer, void *data) +{ + transfer->headers = g_slist_append(transfer->headers, data); +} diff --git a/obexd/client/transfer.h b/obexd/client/transfer.h index 323332a624a68e37504309138bc0558be27447ca..1ed195984ffb2460ead5ed287cd5695d8b9dc2e0 100644 --- a/obexd/client/transfer.h +++ b/obexd/client/transfer.h @@ -47,3 +47,5 @@ gint64 obc_transfer_get_size(struct obc_transfer *transfer); DBusMessage *obc_transfer_create_dbus_reply(struct obc_transfer *transfer, DBusMessage *message); + +void obc_transfer_add_header(struct obc_transfer *transfer, void *data); diff --git a/obexd/plugins/bluetooth.c b/obexd/plugins/bluetooth.c index d232d3fd55254cb83a06c495dc7c4d1461947baf..51afdc9d075081288a135fb740d18be9ed8b69c3 100644 --- a/obexd/plugins/bluetooth.c +++ b/obexd/plugins/bluetooth.c @@ -41,7 +41,7 @@ struct bluetooth_profile { struct obex_server *server; - struct obex_service_driver *driver; + const struct obex_service_driver *driver; char *uuid; char *path; }; @@ -355,7 +355,7 @@ static void *bluetooth_start(struct obex_server *server, int *err) const GSList *l; for (l = server->drivers; l; l = l->next) { - struct obex_service_driver *driver = l->data; + const struct obex_service_driver *driver = l->data; struct bluetooth_profile *profile; const char *uuid; @@ -416,7 +416,7 @@ static int bluetooth_getsockname(GIOChannel *io, char **name) return 0; } -static struct obex_transport_driver driver = { +static const struct obex_transport_driver driver = { .name = "bluetooth", .start = bluetooth_start, .getpeername = bluetooth_getpeername, diff --git a/obexd/plugins/filesystem.c b/obexd/plugins/filesystem.c index 09bff8ad06c10e953cedb553b47c86253ff0a707..a57b25a8397cdd93a4da12f1139c74ab07df62a9 100644 --- a/obexd/plugins/filesystem.c +++ b/obexd/plugins/filesystem.c @@ -113,6 +113,7 @@ static char *file_stat_line(char *filename, struct stat *fstat, { char perm[51], atime[18], ctime[18], mtime[18]; char *escaped, *ret = NULL; + struct tm a_gmtime, c_gmtime, m_gmtime; snprintf(perm, 50, "user-perm=\"%s%s%s\" group-perm=\"%s%s%s\" " "other-perm=\"%s%s%s\"", @@ -126,9 +127,16 @@ static char *file_stat_line(char *filename, struct stat *fstat, (fstat->st_mode & 0002 ? "W" : ""), (dstat->st_mode & 0002 ? "D" : "")); - strftime(atime, 17, "%Y%m%dT%H%M%SZ", gmtime(&fstat->st_atime)); - strftime(ctime, 17, "%Y%m%dT%H%M%SZ", gmtime(&fstat->st_ctime)); - strftime(mtime, 17, "%Y%m%dT%H%M%SZ", gmtime(&fstat->st_mtime)); + if (!gmtime_r(&fstat->st_atime, &a_gmtime) || + !gmtime_r(&fstat->st_ctime, &c_gmtime) || + !gmtime_r(&fstat->st_mtime, &m_gmtime)) { + error("gmtime_r() returned NULL"); + return ret; + } + + strftime(atime, 17, "%Y%m%dT%H%M%SZ", &a_gmtime); + strftime(ctime, 17, "%Y%m%dT%H%M%SZ", &c_gmtime); + strftime(mtime, 17, "%Y%m%dT%H%M%SZ", &m_gmtime); escaped = g_markup_escape_text(filename, -1); @@ -416,6 +424,7 @@ static void *capability_open(const char *name, int oflag, mode_t mode, } object->buffer = g_string_new(buf); + g_free(buf); if (size) *size = object->buffer->len; @@ -642,7 +651,7 @@ done: return err; } -static struct obex_mime_type_driver file = { +static const struct obex_mime_type_driver file = { .open = filesystem_open, .close = filesystem_close, .read = filesystem_read, @@ -652,7 +661,7 @@ static struct obex_mime_type_driver file = { .copy = filesystem_copy, }; -static struct obex_mime_type_driver capability = { +static const struct obex_mime_type_driver capability = { .target = FTP_TARGET, .target_size = FTP_TARGET_SIZE, .mimetype = "x-obex/capability", @@ -661,7 +670,7 @@ static struct obex_mime_type_driver capability = { .read = capability_read, }; -static struct obex_mime_type_driver folder = { +static const struct obex_mime_type_driver folder = { .target = FTP_TARGET, .target_size = FTP_TARGET_SIZE, .mimetype = "x-obex/folder-listing", @@ -670,7 +679,7 @@ static struct obex_mime_type_driver folder = { .read = folder_read, }; -static struct obex_mime_type_driver pcsuite = { +static const struct obex_mime_type_driver pcsuite = { .target = FTP_TARGET, .target_size = FTP_TARGET_SIZE, .who = PCSUITE_WHO, diff --git a/obexd/plugins/ftp.c b/obexd/plugins/ftp.c index 4b04bab063cf6239ea2bfe2b3b5672c6b0e5cabe..6c841d207dae7fbf7591cc3eea4671c3702a3cd6 100644 --- a/obexd/plugins/ftp.c +++ b/obexd/plugins/ftp.c @@ -175,6 +175,11 @@ int ftp_chkput(struct obex_session *os, void *user_data) ret = obex_put_stream_start(os, path); + if (ret == 0 && obex_get_size(os) != OBJECT_SIZE_DELETE && + obex_get_size(os) != OBJECT_SIZE_UNKNOWN) { + manager_emit_transfer_property(ftp->transfer, "Size"); + } + if (ret == 0) manager_emit_transfer_started(ftp->transfer); @@ -494,7 +499,7 @@ static void ftp_reset(struct obex_session *os, void *user_data) manager_emit_transfer_completed(ftp->transfer); } -static struct obex_service_driver ftp = { +static const struct obex_service_driver ftp = { .name = "File Transfer server", .service = OBEX_FTP, .target = FTP_TARGET, diff --git a/obexd/plugins/irmc.c b/obexd/plugins/irmc.c index cd143e7a3d4546a59cc73214e209dcfc994a8068..cab97b620ac20d5ab65c20ba4fdb6c13f2051804 100644 --- a/obexd/plugins/irmc.c +++ b/obexd/plugins/irmc.c @@ -419,7 +419,7 @@ static ssize_t irmc_read(void *object, void *buf, size_t count) return len; } -static struct obex_mime_type_driver irmc_driver = { +static const struct obex_mime_type_driver irmc_driver = { .target = IRMC_TARGET, .target_size = IRMC_TARGET_SIZE, .open = irmc_open, @@ -427,7 +427,7 @@ static struct obex_mime_type_driver irmc_driver = { .read = irmc_read, }; -static struct obex_service_driver irmc = { +static const struct obex_service_driver irmc = { .name = "IRMC Sync server", .service = OBEX_IRMC, .target = IRMC_TARGET, diff --git a/obexd/plugins/mas.c b/obexd/plugins/mas.c index 5d00bc5630438e05bd6b04f666bcd9754785e809..10b972d655d92a0f9dcd9ddde55342e25de32905 100644 --- a/obexd/plugins/mas.c +++ b/obexd/plugins/mas.c @@ -781,7 +781,7 @@ static void *notification_registration_open(const char *name, int oflag, return mas; } -static struct obex_service_driver mas = { +static const struct obex_service_driver mas = { .name = "Message Access server", .service = OBEX_MAS, .target = MAS_TARGET, @@ -793,7 +793,7 @@ static struct obex_service_driver mas = { .disconnect = mas_disconnect, }; -static struct obex_mime_type_driver mime_map = { +static const struct obex_mime_type_driver mime_map = { .target = MAS_TARGET, .target_size = TARGET_SIZE, .mimetype = NULL, @@ -803,7 +803,7 @@ static struct obex_mime_type_driver mime_map = { .write = any_write, }; -static struct obex_mime_type_driver mime_message = { +static const struct obex_mime_type_driver mime_message = { .target = MAS_TARGET, .target_size = TARGET_SIZE, .mimetype = "x-bt/message", @@ -813,7 +813,7 @@ static struct obex_mime_type_driver mime_message = { .write = any_write, }; -static struct obex_mime_type_driver mime_folder_listing = { +static const struct obex_mime_type_driver mime_folder_listing = { .target = MAS_TARGET, .target_size = TARGET_SIZE, .mimetype = "x-obex/folder-listing", @@ -824,7 +824,7 @@ static struct obex_mime_type_driver mime_folder_listing = { .write = any_write, }; -static struct obex_mime_type_driver mime_msg_listing = { +static const struct obex_mime_type_driver mime_msg_listing = { .target = MAS_TARGET, .target_size = TARGET_SIZE, .mimetype = "x-bt/MAP-msg-listing", @@ -835,7 +835,7 @@ static struct obex_mime_type_driver mime_msg_listing = { .write = any_write, }; -static struct obex_mime_type_driver mime_notification_registration = { +static const struct obex_mime_type_driver mime_notification_registration = { .target = MAS_TARGET, .target_size = TARGET_SIZE, .mimetype = "x-bt/MAP-NotificationRegistration", @@ -845,7 +845,7 @@ static struct obex_mime_type_driver mime_notification_registration = { .write = any_write, }; -static struct obex_mime_type_driver mime_message_status = { +static const struct obex_mime_type_driver mime_message_status = { .target = MAS_TARGET, .target_size = TARGET_SIZE, .mimetype = "x-bt/messageStatus", @@ -855,7 +855,7 @@ static struct obex_mime_type_driver mime_message_status = { .write = any_write, }; -static struct obex_mime_type_driver mime_message_update = { +static const struct obex_mime_type_driver mime_message_update = { .target = MAS_TARGET, .target_size = TARGET_SIZE, .mimetype = "x-bt/MAP-messageUpdate", @@ -865,7 +865,7 @@ static struct obex_mime_type_driver mime_message_update = { .write = any_write, }; -static struct obex_mime_type_driver *map_drivers[] = { +static const struct obex_mime_type_driver *map_drivers[] = { &mime_map, &mime_message, &mime_folder_listing, diff --git a/obexd/plugins/messages-dummy.c b/obexd/plugins/messages-dummy.c index e37b52df62667c216065a77842541ffca760b166..e313c6163ec44a06f70de84c793177acd42cac96 100644 --- a/obexd/plugins/messages-dummy.c +++ b/obexd/plugins/messages-dummy.c @@ -359,36 +359,45 @@ static void msg_element(GMarkupParseContext *ctxt, const char *element, for (i = 0 ; names[i]; ++i) { if (g_strcmp0(names[i], "handle") == 0) { + g_free(entry->handle); entry->handle = g_strdup(values[i]); mld->size++; continue; } if (g_strcmp0(names[i], "attachment_size") == 0) { + g_free(entry->attachment_size); entry->attachment_size = g_strdup(values[i]); continue; } if (g_strcmp0(names[i], "datetime") == 0) { + g_free(entry->datetime); entry->datetime = g_strdup(values[i]); continue; } if (g_strcmp0(names[i], "subject") == 0) { + g_free(entry->subject); entry->subject = g_strdup(values[i]); continue; } if (g_strcmp0(names[i], "recipient_addressing") == 0) { + g_free(entry->recipient_addressing); entry->recipient_addressing = g_strdup(values[i]); continue; } if (g_strcmp0(names[i], "sender_addressing") == 0) { + g_free(entry->sender_addressing); entry->sender_addressing = g_strdup(values[i]); continue; } if (g_strcmp0(names[i], "type") == 0) { + g_free(entry->type); entry->type = g_strdup(values[i]); continue; } - if (g_strcmp0(names[i], "reception_status") == 0) + if (g_strcmp0(names[i], "reception_status") == 0) { + g_free(entry->reception_status); entry->reception_status = g_strdup(values[i]); + } } if (mld->size > mld->offset) @@ -397,6 +406,7 @@ static void msg_element(GMarkupParseContext *ctxt, const char *element, g_free(entry->reception_status); g_free(entry->type); g_free(entry->sender_addressing); + g_free(entry->recipient_addressing); g_free(entry->subject); g_free(entry->datetime); g_free(entry->attachment_size); diff --git a/obexd/plugins/messages-tracker.c b/obexd/plugins/messages-tracker.c deleted file mode 100644 index 4ce9f221d91b6f484ce7c043f7264c3518b8232d..0000000000000000000000000000000000000000 --- a/obexd/plugins/messages-tracker.c +++ /dev/null @@ -1,332 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * OBEX Server - * - * Copyright (C) 2010-2011 Nokia Corporation - * - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <glib.h> -#include <string.h> - -#include "messages.h" - -struct message_folder { - char *name; - GSList *subfolders; - char *query; -}; - -struct session { - char *cwd; - struct message_folder *folder; - char *name; - uint16_t max; - uint16_t offset; - void *user_data; - void (*folder_list_cb)(void *session, int err, uint16_t size, - const char *name, void *user_data); -}; - -static struct message_folder *folder_tree = NULL; - -static struct message_folder *get_folder(const char *folder) -{ - GSList *folders = folder_tree->subfolders; - struct message_folder *last = NULL; - char **path; - int i; - - if (g_strcmp0(folder, "/") == 0) - return folder_tree; - - path = g_strsplit(folder, "/", 0); - - for (i = 1; path[i] != NULL; i++) { - gboolean match_found = FALSE; - GSList *l; - - for (l = folders; l != NULL; l = g_slist_next(l)) { - struct message_folder *folder = l->data; - - if (g_strcmp0(folder->name, path[i]) == 0) { - match_found = TRUE; - last = l->data; - folders = folder->subfolders; - break; - } - } - - if (!match_found) { - g_strfreev(path); - return NULL; - } - } - - g_strfreev(path); - - return last; -} - -static struct message_folder *create_folder(const char *name, const char *query) -{ - struct message_folder *folder = g_new0(struct message_folder, 1); - - folder->name = g_strdup(name); - folder->query = g_strdup(query); - - return folder; -} - -static void destroy_folder_tree(void *root) -{ - struct message_folder *folder = root; - GSList *tmp, *next; - - if (folder == NULL) - return; - - g_free(folder->name); - g_free(folder->query); - - tmp = folder->subfolders; - while (tmp != NULL) { - next = g_slist_next(tmp); - destroy_folder_tree(tmp->data); - tmp = next; - } - - g_slist_free(folder->subfolders); - g_free(folder); -} - -static void create_folder_tree(void) -{ - struct message_folder *parent, *child; - - folder_tree = create_folder("/", "FILTER (!BOUND(?msg))"); - - parent = create_folder("telecom", "FILTER (!BOUND(?msg))"); - folder_tree->subfolders = g_slist_append(folder_tree->subfolders, - parent); - - child = create_folder("msg", "FILTER (!BOUND(?msg))"); - parent->subfolders = g_slist_append(parent->subfolders, child); - - parent = child; - - child = create_folder("inbox", "?msg nmo:isSent \"false\" ; " - "nmo:isDeleted \"false\" ; " - "nmo:isDraft \"false\". "); - parent->subfolders = g_slist_append(parent->subfolders, child); - - child = create_folder("sent", "?msg nmo:isDeleted \"false\" ; " - "nmo:isSent \"true\" . "); - parent->subfolders = g_slist_append(parent->subfolders, child); - - child = create_folder("deleted", "?msg nmo:isDeleted \"true\" . "); - parent->subfolders = g_slist_append(parent->subfolders, child); -} - -int messages_init(void) -{ - create_folder_tree(); - - return 0; -} - -void messages_exit(void) -{ - destroy_folder_tree(folder_tree); -} - -int messages_connect(void **s) -{ - struct session *session = g_new0(struct session, 1); - - session->cwd = g_strdup("/"); - session->folder = folder_tree; - - *s = session; - - return 0; -} - -void messages_disconnect(void *s) -{ - struct session *session = s; - - g_free(session->cwd); - g_free(session); -} - -int messages_set_notification_registration(void *session, - void (*send_event)(void *session, - const struct messages_event *event, void *user_data), - void *user_data) -{ - return -ENOSYS; -} - -int messages_set_folder(void *s, const char *name, gboolean cdup) -{ - struct session *session = s; - char *newrel = NULL; - char *newabs; - char *tmp; - - if (name && (strchr(name, '/') || strcmp(name, "..") == 0)) - return -EBADR; - - if (cdup) { - if (session->cwd[0] == 0) - return -ENOENT; - - newrel = g_path_get_dirname(session->cwd); - - /* We use empty string for indication of the root directory */ - if (newrel[0] == '.' && newrel[1] == 0) - newrel[0] = 0; - } - - tmp = newrel; - if (!cdup && (!name || name[0] == 0)) - newrel = g_strdup(""); - else - newrel = g_build_filename(newrel ? newrel : session->cwd, name, - NULL); - g_free(tmp); - - if (newrel[0] != '/') - newabs = g_build_filename("/", newrel, NULL); - else - newabs = g_strdup(newrel); - - session->folder = get_folder(newabs); - if (session->folder == NULL) { - g_free(newrel); - g_free(newabs); - - return -ENOENT; - } - - g_free(newrel); - g_free(session->cwd); - session->cwd = newabs; - - return 0; -} - -static gboolean async_get_folder_listing(void *s) -{ - struct session *session = s; - gboolean count = FALSE; - int folder_count = 0; - char *path = NULL; - struct message_folder *folder; - GSList *dir; - - if (session->name && strchr(session->name, '/') != NULL) - goto done; - - path = g_build_filename(session->cwd, session->name, NULL); - - if (path == NULL || strlen(path) == 0) - goto done; - - folder = get_folder(path); - - if (folder == NULL) - goto done; - - if (session->max == 0) { - session->max = 0xffff; - session->offset = 0; - count = TRUE; - } - - for (dir = folder->subfolders; dir && - (folder_count - session->offset) < session->max; - folder_count++, dir = g_slist_next(dir)) { - struct message_folder *dir_data = dir->data; - - if (count == FALSE && session->offset <= folder_count) - session->folder_list_cb(session, -EAGAIN, 0, - dir_data->name, session->user_data); - } - - done: - session->folder_list_cb(session, 0, folder_count, NULL, - session->user_data); - - g_free(path); - g_free(session->name); - - return FALSE; -} - -int messages_get_folder_listing(void *s, const char *name, - uint16_t max, uint16_t offset, - messages_folder_listing_cb callback, - void *user_data) -{ - struct session *session = s; - session->name = g_strdup(name); - session->max = max; - session->offset = offset; - session->folder_list_cb = callback; - session->user_data = user_data; - - g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, async_get_folder_listing, - session, NULL); - - return 0; -} - -int messages_get_messages_listing(void *session, const char *name, - uint16_t max, uint16_t offset, - uint8_t subject_len, - const struct messages_filter *filter, - messages_get_messages_listing_cb callback, - void *user_data) -{ - return -ENOSYS; -} - -int messages_get_message(void *session, const char *handle, - unsigned long flags, - messages_get_message_cb callback, - void *user_data) -{ - return -ENOSYS; -} - -int messages_update_inbox(void *session, messages_status_cb callback, - void *user_data) -{ - return -ENOSYS; -} - -int messages_set_read(void *session, const char *handle, uint8_t value, - messages_status_cb callback, void *user_data) -{ - return -ENOSYS; -} - -int messages_set_delete(void *session, const char *handle, uint8_t value, - messages_status_cb callback, - void *user_data) -{ - return -ENOSYS; -} - -void messages_abort(void *session) -{ -} diff --git a/obexd/plugins/opp.c b/obexd/plugins/opp.c index 860161303712a51add358d5b243f97b791ceafad..2220efd49b7cba5815e22453b432816e0b2451f6 100644 --- a/obexd/plugins/opp.c +++ b/obexd/plugins/opp.c @@ -87,6 +87,11 @@ skip_auth: err = obex_put_stream_start(os, path); + if (err == 0 && obex_get_size(os) != OBJECT_SIZE_DELETE && + obex_get_size(os) != OBJECT_SIZE_UNKNOWN) { + manager_emit_transfer_property(user_data, "Size"); + } + g_free(path); if (err < 0) @@ -155,7 +160,7 @@ static void opp_reset(struct obex_session *os, void *user_data) manager_emit_transfer_completed(user_data); } -static struct obex_service_driver driver = { +static const struct obex_service_driver driver = { .name = "Object Push server", .service = OBEX_OPP, .connect = opp_connect, diff --git a/obexd/plugins/pbap.c b/obexd/plugins/pbap.c index ab5236316b713c4a591f5e28a4ebde38fafe99d4..4175f9de814c0ce3109b135849b578e938f1be4c 100644 --- a/obexd/plugins/pbap.c +++ b/obexd/plugins/pbap.c @@ -634,7 +634,7 @@ static int pbap_chkput(struct obex_session *os, void *user_data) return -EBADR; } -static struct obex_service_driver pbap = { +static const struct obex_service_driver pbap = { .name = "Phonebook Access server", .service = OBEX_PBAP, .target = PBAP_TARGET, @@ -929,7 +929,7 @@ static ssize_t vobject_vcard_read(void *object, void *buf, size_t count) return string_read(obj->buffer, buf, count); } -static struct obex_mime_type_driver mime_pull = { +static const struct obex_mime_type_driver mime_pull = { .target = PBAP_TARGET, .target_size = TARGET_SIZE, .mimetype = "x-bt/phonebook", @@ -939,7 +939,7 @@ static struct obex_mime_type_driver mime_pull = { .get_next_header = vobject_pull_get_next_header, }; -static struct obex_mime_type_driver mime_list = { +static const struct obex_mime_type_driver mime_list = { .target = PBAP_TARGET, .target_size = TARGET_SIZE, .mimetype = "x-bt/vcard-listing", @@ -949,7 +949,7 @@ static struct obex_mime_type_driver mime_list = { .get_next_header = vobject_list_get_next_header, }; -static struct obex_mime_type_driver mime_vcard = { +static const struct obex_mime_type_driver mime_vcard = { .target = PBAP_TARGET, .target_size = TARGET_SIZE, .mimetype = "x-bt/vcard", diff --git a/obexd/plugins/pcsuite.c b/obexd/plugins/pcsuite.c index f5a9d9ae81dc5e3640d2c5980ef512f700f7af42..07c444ff27e0e0701068a1896c119b58698bb24f 100644 --- a/obexd/plugins/pcsuite.c +++ b/obexd/plugins/pcsuite.c @@ -231,7 +231,7 @@ static void pcsuite_disconnect(struct obex_session *os, void *user_data) g_free(pcsuite); } -static struct obex_service_driver pcsuite = { +static const struct obex_service_driver pcsuite = { .name = "Nokia OBEX PC Suite Services", .service = OBEX_PCSUITE, .channel = PCSUITE_CHANNEL, @@ -376,6 +376,7 @@ static void *backup_open(const char *name, int oflag, mode_t mode, obj->error_code = 0; if (send_backup_dbus_message("open", obj, size) == FALSE) { + g_free(obj->cmd); g_free(obj); obj = NULL; } @@ -467,7 +468,7 @@ static int backup_flush(void *object) return 0; } -static struct obex_mime_type_driver backup = { +static const struct obex_mime_type_driver backup = { .target = FTP_TARGET, .target_size = TARGET_SIZE, .mimetype = "application/vnd.nokia-backup", diff --git a/obexd/plugins/phonebook-ebook.c b/obexd/plugins/phonebook-ebook.c index 29ec9d213c37c65f0d03eb31ab2854a4fe4be685..e509dd29af95f0c891ec040bd996b1deeec28589 100644 --- a/obexd/plugins/phonebook-ebook.c +++ b/obexd/plugins/phonebook-ebook.c @@ -55,7 +55,7 @@ struct query_context { gboolean canceled; }; -static char *attribute_mask[] = { +static const char *attribute_mask[] = { /* 0 */ "VERSION", "FN", "N", diff --git a/obexd/plugins/syncevolution.c b/obexd/plugins/syncevolution.c deleted file mode 100644 index 88744f28ac32af884630f2cde082b7560e3f308f..0000000000000000000000000000000000000000 --- a/obexd/plugins/syncevolution.c +++ /dev/null @@ -1,470 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * OBEX Server - * - * Copyright (C) 2007-2010 Intel Corporation - * Copyright (C) 2007-2010 Marcel Holtmann <marcel@holtmann.org> - * - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include <stdio.h> -#include <errno.h> -#include <sys/types.h> - -#include <glib.h> -#include <dbus/dbus.h> - -#include "lib/bluetooth.h" - -#include "gdbus/gdbus.h" - -#include "btio/btio.h" -#include "obexd/src/plugin.h" -#include "obexd/src/obex.h" -#include "obexd/src/service.h" -#include "obexd/src/mimetype.h" -#include "obexd/src/log.h" -#include "obexd/src/manager.h" -#include "obexd/src/obexd.h" -#include "filesystem.h" - -#define SYNCML_TARGET_SIZE 11 - -static const uint8_t SYNCML_TARGET[SYNCML_TARGET_SIZE] = { - 0x53, 0x59, 0x4E, 0x43, 0x4D, 0x4C, 0x2D, 0x53, - 0x59, 0x4E, 0x43 }; - -#define SYNCEVOLUTION_CHANNEL 19 - -#define SYNCEVOLUTION_RECORD "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\ -<record> \ - <attribute id=\"0x0001\"> \ - <sequence> \ - <uuid value=\"00000002-0000-1000-8000-0002ee000002\"/> \ - </sequence> \ - </attribute> \ - \ - <attribute id=\"0x0004\"> \ - <sequence> \ - <sequence> \ - <uuid value=\"0x0100\"/> \ - </sequence> \ - <sequence> \ - <uuid value=\"0x0003\"/> \ - <uint8 value=\"%u\" name=\"channel\"/> \ - </sequence> \ - <sequence> \ - <uuid value=\"0x0008\"/> \ - </sequence> \ - </sequence> \ - </attribute> \ - \ - <attribute id=\"0x0100\"> \ - <text value=\"%s\" name=\"name\"/> \ - </attribute> \ -</record>" - -#define SYNCE_BUS_NAME "org.syncevolution" -#define SYNCE_PATH "/org/syncevolution/Server" -#define SYNCE_SERVER_INTERFACE "org.syncevolution.Server" -#define SYNCE_CONN_INTERFACE "org.syncevolution.Connection" - -struct synce_context { - struct obex_session *os; - DBusConnection *dbus_conn; - char *conn_obj; - unsigned int reply_watch; - unsigned int abort_watch; - GString *buffer; - int lasterr; - char *id; -}; - -static void 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_basic(&entry, DBUS_TYPE_STRING, &val); - dbus_message_iter_close_container(dict, &entry); -} - -static gboolean reply_signal(DBusConnection *conn, DBusMessage *msg, - void *data) -{ - struct synce_context *context = data; - const char *path = dbus_message_get_path(msg); - DBusMessageIter iter, array_iter; - char *value; - int length; - - if (strcmp(context->conn_obj, path) != 0) { - obex_object_set_io_flags(context, G_IO_ERR, -EPERM); - context->lasterr = -EPERM; - return FALSE; - } - - dbus_message_iter_init(msg, &iter); - - dbus_message_iter_recurse(&iter, &array_iter); - dbus_message_iter_get_fixed_array(&array_iter, &value, &length); - - context->buffer = g_string_new_len(value, length); - obex_object_set_io_flags(context, G_IO_IN, 0); - context->lasterr = 0; - - return TRUE; -} - -static gboolean abort_signal(DBusConnection *conn, DBusMessage *msg, - void *data) -{ - struct synce_context *context = data; - - obex_object_set_io_flags(context, G_IO_ERR, -EPERM); - context->lasterr = -EPERM; - - return TRUE; -} - -static void connect_cb(DBusPendingCall *call, void *user_data) -{ - struct synce_context *context = user_data; - DBusConnection *conn; - DBusMessage *reply; - DBusError err; - char *path; - - conn = context->dbus_conn; - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&err); - if (dbus_message_get_args(reply, &err, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID) == FALSE) { - error("%s", err.message); - dbus_error_free(&err); - goto failed; - } - - DBG("Got conn object %s from syncevolution", path); - context->conn_obj = g_strdup(path); - - context->reply_watch = g_dbus_add_signal_watch(conn, NULL, path, - SYNCE_CONN_INTERFACE, "Reply", - reply_signal, context, NULL); - - context->abort_watch = g_dbus_add_signal_watch(conn, NULL, path, - SYNCE_CONN_INTERFACE, "Abort", - abort_signal, context, NULL); - - dbus_message_unref(reply); - - return; - -failed: - obex_object_set_io_flags(context, G_IO_ERR, -EPERM); - context->lasterr = -EPERM; -} - -static void process_cb(DBusPendingCall *call, void *user_data) -{ - struct synce_context *context = user_data; - DBusMessage *reply; - DBusError derr; - - reply = dbus_pending_call_steal_reply(call); - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - error("process_cb(): syncevolution replied with an error:" - " %s, %s", derr.name, derr.message); - dbus_error_free(&derr); - - obex_object_set_io_flags(context, G_IO_ERR, -EPERM); - context->lasterr = -EPERM; - goto done; - } - - obex_object_set_io_flags(context, G_IO_OUT, 0); - context->lasterr = 0; - -done: - dbus_message_unref(reply); -} - -static void *synce_connect(struct obex_session *os, int *err) -{ - DBusConnection *conn; - struct synce_context *context; - char *address; - - manager_register_session(os); - - conn = manager_dbus_get_connection(); - if (!conn) - goto failed; - - context = g_new0(struct synce_context, 1); - context->dbus_conn = conn; - context->lasterr = -EAGAIN; - context->os = os; - - if (obex_getpeername(os, &address) == 0) { - context->id = g_strdup_printf("%s+%d", address, - SYNCEVOLUTION_CHANNEL); - g_free(address); - } - - if (err) - *err = 0; - - return context; - -failed: - if (err) - *err = -EPERM; - - return NULL; -} - -static int synce_put(struct obex_session *os, void *user_data) -{ - return 0; -} - -static int synce_get(struct obex_session *os, void *user_data) -{ - return obex_get_stream_start(os, NULL); -} - -static void close_cb(DBusPendingCall *call, void *user_data) -{ - DBusMessage *reply; - DBusError derr; - - reply = dbus_pending_call_steal_reply(call); - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - error("close_cb(): syncevolution replied with an error:" - " %s, %s", derr.name, derr.message); - dbus_error_free(&derr); - } - - dbus_message_unref(reply); -} - -static void synce_disconnect(struct obex_session *os, void *user_data) -{ - struct synce_context *context = user_data; - - g_free(context); -} - -static void *synce_open(const char *name, int oflag, mode_t mode, - void *user_data, size_t *size, int *err) -{ - struct synce_context *context = user_data; - - if (err) - *err = context ? 0 : -EFAULT; - - return user_data; -} - -static int synce_close(void *object) -{ - struct synce_context *context = object; - DBusMessage *msg; - const char *error; - gboolean normal; - DBusPendingCall *call; - - if (!context->conn_obj) - goto done; - - msg = dbus_message_new_method_call(SYNCE_BUS_NAME, context->conn_obj, - SYNCE_CONN_INTERFACE, "Close"); - if (!msg) - goto failed; - - normal = TRUE; - error = "none"; - dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &normal, - DBUS_TYPE_STRING, &error, DBUS_TYPE_INVALID); - - g_dbus_send_message_with_reply(context->dbus_conn, msg, &call, -1); - dbus_pending_call_set_notify(call, close_cb, NULL, NULL); - dbus_message_unref(msg); - dbus_pending_call_unref(call); - -failed: - g_dbus_remove_watch(context->dbus_conn, context->reply_watch); - context->reply_watch = 0; - g_dbus_remove_watch(context->dbus_conn, context->abort_watch); - context->abort_watch = 0; - - g_free(context->conn_obj); - context->conn_obj = NULL; - -done: - dbus_connection_unref(context->dbus_conn); - g_free(context); - return 0; -} - -static ssize_t synce_read(void *object, void *buf, size_t count) -{ - struct synce_context *context = object; - DBusConnection *conn; - char transport[36], transport_description[24]; - const char *session; - DBusMessage *msg; - DBusMessageIter iter, dict; - gboolean authenticate; - DBusPendingCall *call; - - if (context->buffer) - return string_read(context->buffer, buf, count); - - conn = manager_dbus_get_connection(); - if (conn == NULL) - return -EPERM; - - msg = dbus_message_new_method_call(SYNCE_BUS_NAME, SYNCE_PATH, - SYNCE_SERVER_INTERFACE, "Connect"); - if (!msg) - return -EPERM; - - dbus_message_iter_init_append(msg, &iter); - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING - DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING - DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); - - append_dict_entry(&dict, "id", DBUS_TYPE_STRING, context->id); - - snprintf(transport, sizeof(transport), "%s.obexd", OBEXD_SERVICE); - append_dict_entry(&dict, "transport", DBUS_TYPE_STRING, transport); - - snprintf(transport_description, sizeof(transport_description), - "version %s", VERSION); - append_dict_entry(&dict, "transport_description", DBUS_TYPE_STRING, - transport_description); - - dbus_message_iter_close_container(&iter, &dict); - - authenticate = FALSE; - session = ""; - dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &authenticate, - DBUS_TYPE_STRING, &session, DBUS_TYPE_INVALID); - - if (!g_dbus_send_message_with_reply(conn, msg, &call, -1)) { - error("D-Bus call to %s failed.", SYNCE_SERVER_INTERFACE); - dbus_message_unref(msg); - return -EPERM; - } - - dbus_pending_call_set_notify(call, connect_cb, context, NULL); - - dbus_pending_call_unref(call); - dbus_message_unref(msg); - - return -EAGAIN; -} - -static ssize_t synce_write(void *object, const void *buf, size_t count) -{ - struct synce_context *context = object; - DBusMessage *msg; - DBusMessageIter iter, array_iter; - DBusPendingCall *call; - const char *type = obex_get_type(context->os); - - if (context->lasterr == 0) - return count; - - if (!context->conn_obj) - return -EFAULT; - - msg = dbus_message_new_method_call(SYNCE_BUS_NAME, context->conn_obj, - SYNCE_CONN_INTERFACE, "Process"); - if (!msg) - return -EFAULT; - - dbus_message_iter_init_append(msg, &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, - &buf, count); - dbus_message_iter_close_container(&iter, &array_iter); - - dbus_message_append_args(msg, DBUS_TYPE_STRING, &type, - DBUS_TYPE_INVALID); - - if (!g_dbus_send_message_with_reply(context->dbus_conn, msg, - &call, -1)) { - error("D-Bus call to %s failed.", SYNCE_CONN_INTERFACE); - dbus_message_unref(msg); - return -EPERM; - } - - dbus_pending_call_set_notify(call, process_cb, context, NULL); - - dbus_message_unref(msg); - dbus_pending_call_unref(call); - - return -EAGAIN; -} - -static struct obex_mime_type_driver synce_driver = { - .target = SYNCML_TARGET, - .target_size = SYNCML_TARGET_SIZE, - .open = synce_open, - .close = synce_close, - .read = synce_read, - .write = synce_write, -}; - -static struct obex_service_driver synce = { - .name = "OBEX server for SyncML, using SyncEvolution", - .service = OBEX_SYNCEVOLUTION, - .channel = SYNCEVOLUTION_CHANNEL, - .secure = TRUE, - .record = SYNCEVOLUTION_RECORD, - .target = SYNCML_TARGET, - .target_size = SYNCML_TARGET_SIZE, - .get = synce_get, - .put = synce_put, - .connect = synce_connect, - .disconnect = synce_disconnect, -}; - -static int synce_init(void) -{ - int err; - - err = obex_mime_type_driver_register(&synce_driver); - if (err < 0) - return err; - - return obex_service_driver_register(&synce); -} - -static void synce_exit(void) -{ - obex_service_driver_unregister(&synce); - obex_mime_type_driver_unregister(&synce_driver); -} - -OBEX_PLUGIN_DEFINE(syncevolution, synce_init, synce_exit) diff --git a/obexd/src/genbuiltin b/obexd/src/genbuiltin index 39f773527501843f7d65582124f12ca59b7d7085..e60b5189a1bd432a61b0b22e8cfdbaf7fc5bf33b 100755 --- a/obexd/src/genbuiltin +++ b/obexd/src/genbuiltin @@ -2,11 +2,11 @@ for i in $* do - echo "extern struct obex_plugin_desc __obex_builtin_$i;" + echo "extern const struct obex_plugin_desc __obex_builtin_$i;" done echo -echo "static struct obex_plugin_desc *__obex_builtin[] = {" +echo "static const struct obex_plugin_desc *__obex_builtin[] = {" for i in $* do diff --git a/obexd/src/main.c b/obexd/src/main.c index d950883f09ded56fcb447c45aa953172066150ad..151574afad0a5e0091273c07f4ece00107143c29 100644 --- a/obexd/src/main.c +++ b/obexd/src/main.c @@ -138,7 +138,7 @@ static gboolean parse_debug(const char *key, const char *value, return TRUE; } -static GOptionEntry options[] = { +static const GOptionEntry options[] = { { "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, parse_debug, "Enable debug information output", "DEBUG" }, diff --git a/obexd/src/manager.c b/obexd/src/manager.c index 01741fe62c9041b8776f305081b0ca8de2d67ea0..3c0c2a7cc523b8240abf1262cfa5e3087f7299b1 100644 --- a/obexd/src/manager.c +++ b/obexd/src/manager.c @@ -38,6 +38,7 @@ #define TRANSFER_INTERFACE OBEXD_SERVICE ".Transfer1" #define SESSION_INTERFACE OBEXD_SERVICE ".Session1" #define AGENT_INTERFACE OBEXD_SERVICE ".Agent1" +#define OBEX_ERROR_REJECT "org.bluez.obex.Error.Rejected" #define TIMEOUT 60*1000 /* Timeout for user response (miliseconds) */ @@ -45,6 +46,7 @@ struct agent { char *bus_name; char *path; gboolean auth_pending; + gboolean auth_reject; char *new_name; char *new_folder; unsigned int watch_id; @@ -523,11 +525,16 @@ void manager_cleanup(void) void manager_emit_transfer_property(struct obex_transfer *transfer, char *name) { - if (!transfer->path) + if (transfer->path == NULL) return; - g_dbus_emit_property_changed(connection, transfer->path, - TRANSFER_INTERFACE, name); + if (strcasecmp("Size", name) == 0) + g_dbus_emit_property_changed_full(connection, transfer->path, + TRANSFER_INTERFACE, name, + G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH); + else + g_dbus_emit_property_changed(connection, transfer->path, + TRANSFER_INTERFACE, name); } void manager_emit_transfer_started(struct obex_transfer *transfer) @@ -540,9 +547,6 @@ void manager_emit_transfer_started(struct obex_transfer *transfer) static void emit_transfer_completed(struct obex_transfer *transfer, gboolean success) { - if (transfer->path == NULL) - return; - transfer->status = success ? TRANSFER_STATUS_COMPLETE : TRANSFER_STATUS_ERROR; @@ -630,6 +634,8 @@ static void agent_reply(DBusPendingCall *call, void *user_data) if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) agent_cancel(); + else if (dbus_error_has_name(&derr, OBEX_ERROR_REJECT)) + agent->auth_reject = TRUE; dbus_error_free(&derr); dbus_message_unref(reply); @@ -646,7 +652,10 @@ static void agent_reply(DBusPendingCall *call, void *user_data) agent->new_name = g_strdup(name); agent->new_folder = NULL; } else { - agent->new_name = g_strdup(slash + 1); + if (strlen(slash) == 1) + agent->new_name = NULL; + else + agent->new_name = g_strdup(slash + 1); agent->new_folder = g_strndup(name, slash - name); } } @@ -694,6 +703,7 @@ int manager_request_authorization(struct obex_transfer *transfer, dbus_message_unref(msg); agent->auth_pending = TRUE; + agent->auth_reject = FALSE; got_reply = FALSE; /* Catches errors before authorization response comes */ @@ -716,7 +726,7 @@ int manager_request_authorization(struct obex_transfer *transfer, dbus_pending_call_unref(call); - if (!agent || !agent->new_name) + if (!agent || agent->auth_reject) return -EPERM; *new_folder = agent->new_folder; diff --git a/obexd/src/mimetype.c b/obexd/src/mimetype.c index 212f24b18996071ede4517670c19f0fdc4e14892..066a71e88606e47a7b5308e197db3af8d1c35b60 100644 --- a/obexd/src/mimetype.c +++ b/obexd/src/mimetype.c @@ -73,7 +73,7 @@ static struct io_watch *find_io_watch(void *object) return NULL; } -static void reset_io_watch(void *object) +void obex_object_reset_io_watch(void *object) { struct io_watch *watch; @@ -85,16 +85,11 @@ static void reset_io_watch(void *object) g_free(watch); } -static int set_io_watch(void *object, obex_object_io_func func, +int obex_object_set_io_watch(void *object, obex_object_io_func func, void *user_data) { struct io_watch *watch; - if (func == NULL) { - reset_io_watch(object); - return 0; - } - watch = find_io_watch(object); if (watch) return -EPERM; @@ -109,7 +104,7 @@ static int set_io_watch(void *object, obex_object_io_func func, return 0; } -static struct obex_mime_type_driver *find_driver(const uint8_t *target, +static const struct obex_mime_type_driver *find_driver(const uint8_t *target, unsigned int target_size, const char *mimetype, const uint8_t *who, unsigned int who_size) @@ -117,7 +112,7 @@ static struct obex_mime_type_driver *find_driver(const uint8_t *target, GSList *l; for (l = drivers; l; l = l->next) { - struct obex_mime_type_driver *driver = l->data; + const struct obex_mime_type_driver *driver = l->data; if (memncmp0(target, target_size, driver->target, driver->target_size)) continue; @@ -139,12 +134,12 @@ static struct obex_mime_type_driver *find_driver(const uint8_t *target, return NULL; } -struct obex_mime_type_driver *obex_mime_type_driver_find(const uint8_t *target, - unsigned int target_size, +const struct obex_mime_type_driver * +obex_mime_type_driver_find(const uint8_t *target, unsigned int target_size, const char *mimetype, const uint8_t *who, unsigned int who_size) { - struct obex_mime_type_driver *driver; + const struct obex_mime_type_driver *driver; driver = find_driver(target, target_size, mimetype, who, who_size); if (driver == NULL) { @@ -167,7 +162,7 @@ struct obex_mime_type_driver *obex_mime_type_driver_find(const uint8_t *target, return driver; } -int obex_mime_type_driver_register(struct obex_mime_type_driver *driver) +int obex_mime_type_driver_register(const struct obex_mime_type_driver *driver) { if (!driver) { error("Invalid driver"); @@ -181,17 +176,15 @@ int obex_mime_type_driver_register(struct obex_mime_type_driver *driver) return -EPERM; } - if (driver->set_io_watch == NULL) - driver->set_io_watch = set_io_watch; - DBG("driver %p mimetype %s registered", driver, driver->mimetype); - drivers = g_slist_append(drivers, driver); + drivers = g_slist_append(drivers, (gpointer)driver); return 0; } -void obex_mime_type_driver_unregister(struct obex_mime_type_driver *driver) +void +obex_mime_type_driver_unregister(const struct obex_mime_type_driver *driver) { if (!g_slist_find(drivers, driver)) { error("Unable to unregister: No such driver %p", driver); diff --git a/obexd/src/mimetype.h b/obexd/src/mimetype.h index e1c14f405a90d5f2a5c98e9b69a3b036815bca1f..d948e2c83c11521b04f3965cdab23dad6310a1ce 100644 --- a/obexd/src/mimetype.h +++ b/obexd/src/mimetype.h @@ -28,15 +28,19 @@ struct obex_mime_type_driver { int (*copy) (const char *name, const char *destname); int (*move) (const char *name, const char *destname); int (*remove) (const char *name); - int (*set_io_watch) (void *object, obex_object_io_func func, - void *user_data); }; -int obex_mime_type_driver_register(struct obex_mime_type_driver *driver); -void obex_mime_type_driver_unregister(struct obex_mime_type_driver *driver); -struct obex_mime_type_driver *obex_mime_type_driver_find(const uint8_t *target, +int obex_mime_type_driver_register(const struct obex_mime_type_driver *driver); +void +obex_mime_type_driver_unregister(const struct obex_mime_type_driver *driver); +const struct obex_mime_type_driver * +obex_mime_type_driver_find(const uint8_t *target, unsigned int target_size, const char *mimetype, const uint8_t *who, unsigned int who_size); void obex_object_set_io_flags(void *object, int flags, int err); + +void obex_object_reset_io_watch(void *object); +int obex_object_set_io_watch(void *object, obex_object_io_func func, + void *user_data); diff --git a/obexd/src/obex-priv.h b/obexd/src/obex-priv.h index db409e7e472e764936514242875e697ce381a48d..d2c62a59605ca966bf0812e543ce90d3f19bc322 100644 --- a/obexd/src/obex-priv.h +++ b/obexd/src/obex-priv.h @@ -33,12 +33,12 @@ struct obex_session { void *object; gboolean aborted; int err; - struct obex_service_driver *service; + const struct obex_service_driver *service; void *service_data; struct obex_server *server; gboolean checked; GObex *obex; - struct obex_mime_type_driver *driver; + const struct obex_mime_type_driver *driver; gboolean headers_sent; }; diff --git a/obexd/src/obex.c b/obexd/src/obex.c index 3a68fd66c23424b4a9304de578f8dbd93a3c710d..370bfac9e660a919ef4fe5345c2297a082847d18 100644 --- a/obexd/src/obex.c +++ b/obexd/src/obex.c @@ -55,7 +55,7 @@ struct auth_header { } __attribute__ ((packed)); /* Possible commands */ -static struct { +static const struct { int cmd; const char *name; } obex_command[] = { @@ -119,7 +119,7 @@ static void os_reset_session(struct obex_session *os) os_session_mark_aborted(os); if (os->object) { - os->driver->set_io_watch(os->object, NULL, NULL); + obex_object_reset_io_watch(os->object); os->driver->close(os->object); if (os->aborted && os->cmd == G_OBEX_OP_PUT && os->path && os->driver->remove) @@ -357,7 +357,7 @@ static gssize driver_read(struct obex_session *os, void *buf, gsize size) if (len == -ENOSTR) return 0; if (len == -EAGAIN) - os->driver->set_io_watch(os->object, handle_async_io, + obex_object_set_io_watch(os->object, handle_async_io, os); } @@ -395,7 +395,7 @@ static void transfer_complete(GObex *obex, GError *err, gpointer user_data) if (os->object && os->driver && os->driver->flush) { if (os->driver->flush(os->object) == -EAGAIN) { g_obex_suspend(os->obex); - os->driver->set_io_watch(os->object, handle_async_io, + obex_object_set_io_watch(os->object, handle_async_io, os); return; } @@ -525,7 +525,7 @@ static gboolean recv_data(const void *buf, gsize size, gpointer user_data) if (ret == -EAGAIN) { g_obex_suspend(os->obex); - os->driver->set_io_watch(os->object, handle_async_io, os); + obex_object_set_io_watch(os->object, handle_async_io, os); return TRUE; } @@ -699,7 +699,7 @@ int obex_get_stream_start(struct obex_session *os, const char *filename) return err; g_obex_suspend(os->obex); - os->driver->set_io_watch(os->object, handle_async_io, os); + obex_object_set_io_watch(os->object, handle_async_io, os); return 0; } @@ -716,9 +716,6 @@ int obex_put_stream_start(struct obex_session *os, const char *filename) return err; } - if (os->size != OBJECT_SIZE_DELETE && os->size != OBJECT_SIZE_UNKNOWN) - manager_emit_transfer_property(os->service_data, "Size"); - os->path = g_strdup(filename); return 0; @@ -772,7 +769,7 @@ static gboolean check_put(GObex *obex, GObexPacket *req, void *user_data) break; case -EAGAIN: g_obex_suspend(os->obex); - os->driver->set_io_watch(os->object, handle_async_io, os); + obex_object_set_io_watch(os->object, handle_async_io, os); return TRUE; default: os_set_response(os, ret); @@ -1085,7 +1082,7 @@ ssize_t obex_get_non_header_data(struct obex_session *os, int obex_getpeername(struct obex_session *os, char **name) { - struct obex_transport_driver *transport = os->server->transport; + const struct obex_transport_driver *transport = os->server->transport; if (transport == NULL || transport->getpeername == NULL) return -ENOTSUP; @@ -1095,7 +1092,7 @@ int obex_getpeername(struct obex_session *os, char **name) int obex_getsockname(struct obex_session *os, char **name) { - struct obex_transport_driver *transport = os->server->transport; + const struct obex_transport_driver *transport = os->server->transport; if (transport == NULL || transport->getsockname == NULL) return -ENOTSUP; diff --git a/obexd/src/obex.service.in b/obexd/src/obex.service.in index fc0dce99327e42d3baae1757e112bfe4de8e6267..cf4d8c9850e8d826778089c5e4a9fbcd2f6744d0 100644 --- a/obexd/src/obex.service.in +++ b/obexd/src/obex.service.in @@ -4,7 +4,7 @@ Description=Bluetooth OBEX service [Service] Type=dbus BusName=org.bluez.obex -ExecStart=@pkglibexecdir@/obexd +ExecStart=@PKGLIBEXECDIR@/obexd [Install] Alias=dbus-org.bluez.obex.service diff --git a/obexd/src/obexd.h b/obexd/src/obexd.h index fe312a65b4fd331cdda4f3c55f199aa20cf189bb..af5265da50af352e7a3b2c12298f5621ed65242a 100644 --- a/obexd/src/obexd.h +++ b/obexd/src/obexd.h @@ -18,7 +18,7 @@ #define OBEX_MAS (1 << 8) #define OBEX_MNS (1 << 9) -gboolean plugin_init(const char *pattern, const char *exclude); +void plugin_init(const char *pattern, const char *exclude); void plugin_cleanup(void); gboolean manager_init(void); diff --git a/obexd/src/org.bluez.obex.service b/obexd/src/org.bluez.obex.service.in similarity index 74% rename from obexd/src/org.bluez.obex.service rename to obexd/src/org.bluez.obex.service.in index a53808884554cc8d4105731bb18610b2cee17275..873b9d1fd95d18493db57f4597a9d366e4619e97 100644 --- a/obexd/src/org.bluez.obex.service +++ b/obexd/src/org.bluez.obex.service.in @@ -1,4 +1,4 @@ [D-BUS Service] Name=org.bluez.obex -Exec=/bin/false +Exec=@PKGLIBEXECDIR@/obexd SystemdService=dbus-org.bluez.obex.service diff --git a/obexd/src/plugin.c b/obexd/src/plugin.c index 0df9d5258e5f513058896674149a5c15c5fe1594..14327782ddd94144d37cab5c3169ef7d90cdea51 100644 --- a/obexd/src/plugin.c +++ b/obexd/src/plugin.c @@ -34,14 +34,17 @@ #define PLUGINFLAG (RTLD_NOW) #endif +#define IS_ENABLED(x) (x) + static GSList *plugins = NULL; struct obex_plugin { void *handle; - struct obex_plugin_desc *desc; + const struct obex_plugin_desc *desc; }; -static gboolean add_plugin(void *handle, struct obex_plugin_desc *desc) +static gboolean add_external_plugin(void *handle, + const struct obex_plugin_desc *desc) { struct obex_plugin *plugin; @@ -66,7 +69,26 @@ static gboolean add_plugin(void *handle, struct obex_plugin_desc *desc) return TRUE; } -static gboolean check_plugin(struct obex_plugin_desc *desc, +static void add_plugin(const struct obex_plugin_desc *desc) +{ + struct obex_plugin *plugin; + + plugin = g_try_new0(struct obex_plugin, 1); + if (plugin == NULL) + return; + + plugin->desc = desc; + + if (desc->init() < 0) { + g_free(plugin); + return; + } + + plugins = g_slist_append(plugins, plugin); + DBG("Plugin %s loaded", desc->name); +} + +static gboolean check_plugin(const struct obex_plugin_desc *desc, char **patterns, char **excludes) { if (excludes) { @@ -93,46 +115,26 @@ static gboolean check_plugin(struct obex_plugin_desc *desc, } -#include "builtin.h" - -gboolean plugin_init(const char *pattern, const char *exclude) +static void external_plugin_init(char **patterns, char **excludes) { - char **patterns = NULL; - char **excludes = NULL; GDir *dir; const char *file; - unsigned int i; - if (strlen(PLUGINDIR) == 0) - return FALSE; + info("Using external plugins is not officially supported.\n"); + info("Consider upstreaming your plugins into the BlueZ project."); - if (pattern) - patterns = g_strsplit_set(pattern, ":, ", -1); - - if (exclude) - excludes = g_strsplit_set(exclude, ":, ", -1); - - DBG("Loading builtin plugins"); - - for (i = 0; __obex_builtin[i]; i++) { - if (check_plugin(__obex_builtin[i], - patterns, excludes) == FALSE) - continue; - - add_plugin(NULL, __obex_builtin[i]); - } + if (strlen(PLUGINDIR) == 0) + return; DBG("Loading plugins %s", PLUGINDIR); dir = g_dir_open(PLUGINDIR, 0, NULL); if (!dir) { - g_strfreev(patterns); - g_strfreev(excludes); - return FALSE; + return; } while ((file = g_dir_read_name(dir)) != NULL) { - struct obex_plugin_desc *desc; + const struct obex_plugin_desc *desc; void *handle; char *filename; @@ -164,15 +166,42 @@ gboolean plugin_init(const char *pattern, const char *exclude) continue; } - if (add_plugin(handle, desc) == FALSE) + if (add_external_plugin(handle, desc) == FALSE) dlclose(handle); } g_dir_close(dir); +} + +#include "builtin.h" + +void plugin_init(const char *pattern, const char *exclude) +{ + char **patterns = NULL; + char **excludes = NULL; + unsigned int i; + + if (pattern) + patterns = g_strsplit_set(pattern, ":, ", -1); + + if (exclude) + excludes = g_strsplit_set(exclude, ":, ", -1); + + DBG("Loading builtin plugins"); + + for (i = 0; __obex_builtin[i]; i++) { + if (check_plugin(__obex_builtin[i], + patterns, excludes) == FALSE) + continue; + + add_plugin(__obex_builtin[i]); + } + + if IS_ENABLED(EXTERNAL_PLUGINS) + external_plugin_init(patterns, excludes); + g_strfreev(patterns); g_strfreev(excludes); - - return TRUE; } void plugin_cleanup(void) diff --git a/obexd/src/plugin.h b/obexd/src/plugin.h index 70387846062cf925774777684350b60d989fcd44..e1756b9bfc4f5fa15f90389e7905586fa2205008 100644 --- a/obexd/src/plugin.h +++ b/obexd/src/plugin.h @@ -16,14 +16,18 @@ struct obex_plugin_desc { #ifdef OBEX_PLUGIN_BUILTIN #define OBEX_PLUGIN_DEFINE(name, init, exit) \ - struct obex_plugin_desc __obex_builtin_ ## name = { \ + const struct obex_plugin_desc __obex_builtin_ ## name = { \ #name, init, exit \ }; #else +#if EXTERNAL_PLUGINS #define OBEX_PLUGIN_DEFINE(name,init,exit) \ extern struct obex_plugin_desc obex_plugin_desc \ __attribute__ ((visibility("default"))); \ - struct obex_plugin_desc obex_plugin_desc = { \ + const struct obex_plugin_desc obex_plugin_desc = { \ #name, init, exit \ }; +#else +#error "Requested non built-in plugin, while external plugins is disabled" +#endif #endif diff --git a/obexd/src/server.c b/obexd/src/server.c index a8fc45092b7084a519230c1fa54dcdd83f7dea10..0dca728d2ec2f1daed5093a85a7bab21300eb69c 100644 --- a/obexd/src/server.c +++ b/obexd/src/server.c @@ -34,12 +34,12 @@ static GSList *servers = NULL; -static void init_server(uint16_t service, GSList *transports) +static void init_server(uint16_t service, const GSList *transports) { - GSList *l; + const GSList *l; for (l = transports; l; l = l->next) { - struct obex_transport_driver *transport = l->data; + const struct obex_transport_driver *transport = l->data; struct obex_server *server; int err; @@ -66,7 +66,7 @@ static void init_server(uint16_t service, GSList *transports) int obex_server_init(void) { GSList *drivers; - GSList *transports; + const GSList *transports; GSList *l; drivers = obex_service_driver_list(0); @@ -82,7 +82,7 @@ int obex_server_init(void) } for (l = drivers; l; l = l->next) { - struct obex_service_driver *driver = l->data; + const struct obex_service_driver *driver = l->data; init_server(driver->service, transports); } diff --git a/obexd/src/server.h b/obexd/src/server.h index c31236ec034a2f1e279340cdb1c3a900411022bb..ec063ae2edb8d82d7d70ae11ae9f23bf2820a68b 100644 --- a/obexd/src/server.h +++ b/obexd/src/server.h @@ -10,7 +10,7 @@ */ struct obex_server { - struct obex_transport_driver *transport; + const struct obex_transport_driver *transport; void *transport_data; GSList *drivers; }; diff --git a/obexd/src/service.c b/obexd/src/service.c index 0f4e420e80663cee83aec342e29206783b397879..332d6193943da02a0c0fb555cfc16f01004d6b32 100644 --- a/obexd/src/service.c +++ b/obexd/src/service.c @@ -26,14 +26,14 @@ static GSList *drivers = NULL; -struct obex_service_driver *obex_service_driver_find(GSList *drivers, +const struct obex_service_driver *obex_service_driver_find(GSList *drivers, const uint8_t *target, unsigned int target_size, const uint8_t *who, unsigned int who_size) { GSList *l; for (l = drivers; l; l = l->next) { - struct obex_service_driver *driver = l->data; + const struct obex_service_driver *driver = l->data; /* who is optional, so only check for it if not NULL */ if (who != NULL && memncmp0(who, who_size, driver->who, @@ -57,10 +57,10 @@ GSList *obex_service_driver_list(uint16_t services) return drivers; for (l = drivers; l && services; l = l->next) { - struct obex_service_driver *driver = l->data; + const struct obex_service_driver *driver = l->data; if (driver->service & services) { - list = g_slist_append(list, driver); + list = g_slist_append(list, (gpointer)driver); services &= ~driver->service; } } @@ -68,12 +68,12 @@ GSList *obex_service_driver_list(uint16_t services) return list; } -static struct obex_service_driver *find_driver(uint16_t service) +static const struct obex_service_driver *find_driver(uint16_t service) { GSList *l; for (l = drivers; l; l = l->next) { - struct obex_service_driver *driver = l->data; + const struct obex_service_driver *driver = l->data; if (driver->service == service) return driver; @@ -82,7 +82,7 @@ static struct obex_service_driver *find_driver(uint16_t service) return NULL; } -int obex_service_driver_register(struct obex_service_driver *driver) +int obex_service_driver_register(const struct obex_service_driver *driver) { if (!driver) { error("Invalid driver"); @@ -99,14 +99,14 @@ int obex_service_driver_register(struct obex_service_driver *driver) /* Drivers that support who has priority */ if (driver->who) - drivers = g_slist_prepend(drivers, driver); + drivers = g_slist_prepend(drivers, (gpointer)driver); else - drivers = g_slist_append(drivers, driver); + drivers = g_slist_append(drivers, (gpointer)driver); return 0; } -void obex_service_driver_unregister(struct obex_service_driver *driver) +void obex_service_driver_unregister(const struct obex_service_driver *driver) { if (!g_slist_find(drivers, driver)) { error("Unable to unregister: No such driver %p", driver); diff --git a/obexd/src/service.h b/obexd/src/service.h index e3aee3bf3748aef4400b8666645f71d0596762e8..8d9f70558a4996a2178cc25b26d3c55c770ef4b7 100644 --- a/obexd/src/service.h +++ b/obexd/src/service.h @@ -32,9 +32,9 @@ struct obex_service_driver { void (*reset) (struct obex_session *os, void *user_data); }; -int obex_service_driver_register(struct obex_service_driver *driver); -void obex_service_driver_unregister(struct obex_service_driver *driver); +int obex_service_driver_register(const struct obex_service_driver *driver); +void obex_service_driver_unregister(const struct obex_service_driver *driver); GSList *obex_service_driver_list(uint16_t services); -struct obex_service_driver *obex_service_driver_find(GSList *drivers, +const struct obex_service_driver *obex_service_driver_find(GSList *drivers, const uint8_t *target, unsigned int target_size, const uint8_t *who, unsigned int who_size); diff --git a/obexd/src/transport.c b/obexd/src/transport.c index 4b5895e5d4e81deb0e035d22f0ac5cec343d86b0..527d9ffced216d3e731054bed1e14105d9670d8d 100644 --- a/obexd/src/transport.c +++ b/obexd/src/transport.c @@ -27,13 +27,13 @@ static GSList *drivers = NULL; -static struct obex_transport_driver *obex_transport_driver_find( - const char *name) +static const struct obex_transport_driver * +obex_transport_driver_find(const char *name) { - GSList *l; + const GSList *l; for (l = drivers; l; l = l->next) { - struct obex_transport_driver *driver = l->data; + const struct obex_transport_driver *driver = l->data; if (g_strcmp0(name, driver->name) == 0) return driver; @@ -42,12 +42,12 @@ static struct obex_transport_driver *obex_transport_driver_find( return NULL; } -GSList *obex_transport_driver_list(void) +const GSList *obex_transport_driver_list(void) { return drivers; } -int obex_transport_driver_register(struct obex_transport_driver *driver) +int obex_transport_driver_register(const struct obex_transport_driver *driver) { if (!driver) { error("Invalid driver"); @@ -62,12 +62,13 @@ int obex_transport_driver_register(struct obex_transport_driver *driver) DBG("driver %p transport %s registered", driver, driver->name); - drivers = g_slist_prepend(drivers, driver); + drivers = g_slist_prepend(drivers, (gpointer)driver); return 0; } -void obex_transport_driver_unregister(struct obex_transport_driver *driver) +void +obex_transport_driver_unregister(const struct obex_transport_driver *driver) { if (!g_slist_find(drivers, driver)) { error("Unable to unregister: No such driver %p", driver); diff --git a/obexd/src/transport.h b/obexd/src/transport.h index 3a16b76205ac7580dfc44f63a8dec9c3ba6d0392..322d8f5260ebae52d75f031b4933aa9d43cffb76 100644 --- a/obexd/src/transport.h +++ b/obexd/src/transport.h @@ -17,6 +17,7 @@ struct obex_transport_driver { void (*stop) (void *data); }; -int obex_transport_driver_register(struct obex_transport_driver *driver); -void obex_transport_driver_unregister(struct obex_transport_driver *driver); -GSList *obex_transport_driver_list(void); +int obex_transport_driver_register(const struct obex_transport_driver *driver); +void +obex_transport_driver_unregister(const struct obex_transport_driver *driver); +const GSList *obex_transport_driver_list(void); diff --git a/peripheral/efivars.c b/peripheral/efivars.c index 987572b63968ad0d5c4cf257ab2ca240df9c0a24..d4e724e2ded6af25102d898a5c159d5971b35a6b 100644 --- a/peripheral/efivars.c +++ b/peripheral/efivars.c @@ -20,6 +20,7 @@ #include <string.h> #include <stdlib.h> #include <stdint.h> +#include <limits.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/param.h> diff --git a/plugins/admin.c b/plugins/admin.c index 0787e8381ed7acf5616743539382d8f8092192d4..16b74cfbf04d67c36ecfd09bb96e733fe181421b 100644 --- a/plugins/admin.c +++ b/plugins/admin.c @@ -502,7 +502,6 @@ static int admin_policy_adapter_probe(struct btd_adapter *adapter) if (policy_data) { btd_warn(policy_data->adapter_id, "Policy data already exists"); - admin_policy_free(policy_data); policy_data = NULL; } @@ -618,13 +617,12 @@ static struct btd_adapter_driver admin_policy_driver = { .resume = NULL, .remove = admin_policy_remove, .device_resolved = admin_policy_device_added, - .device_removed = admin_policy_device_removed + .device_removed = admin_policy_device_removed, + .experimental = true, }; static int admin_init(void) { - DBG(""); - dbus_conn = btd_get_dbus_connection(); return btd_register_adapter_driver(&admin_policy_driver); @@ -632,8 +630,6 @@ static int admin_init(void) static void admin_exit(void) { - DBG(""); - btd_unregister_adapter_driver(&admin_policy_driver); } diff --git a/plugins/external-dummy.c b/plugins/external-dummy.c deleted file mode 100644 index 1c209e8b78b1fa2929da16c1ac705331b72d9b0a..0000000000000000000000000000000000000000 --- a/plugins/external-dummy.c +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "src/plugin.h" -#include "src/log.h" - -static int dummy_init(void) -{ - DBG(""); - - return 0; -} - -static void dummy_exit(void) -{ - DBG(""); -} - -BLUETOOTH_PLUGIN_DEFINE(external_dummy, VERSION, - BLUETOOTH_PLUGIN_PRIORITY_LOW, dummy_init, dummy_exit) diff --git a/plugins/hostname.c b/plugins/hostname.c index 1a9513adb887613fd7ee7b895a8c1ce33cb59de2..51707f07dc5c51dad12ff8e92bc8b4bd211aca25 100644 --- a/plugins/hostname.c +++ b/plugins/hostname.c @@ -16,6 +16,8 @@ #include <stdint.h> #include <stdlib.h> #include <string.h> +#include <fcntl.h> +#include <sys/utsname.h> #include "lib/bluetooth.h" #include "lib/sdp.h" @@ -44,8 +46,10 @@ static uint8_t major_class = MAJOR_CLASS_MISCELLANEOUS; static uint8_t minor_class = MINOR_CLASS_UNCATEGORIZED; -static char *pretty_hostname = NULL; -static char *static_hostname = NULL; +static char *pretty_hostname = NULL; +static char *static_hostname = NULL; +static char *transient_hostname = NULL; +static guint hostname_id = 0; /* * Fallback to static hostname only if empty pretty hostname was already @@ -60,6 +64,10 @@ static const char *get_hostname(void) if (static_hostname && g_str_equal(static_hostname, "") == FALSE) return static_hostname; + + if (transient_hostname && + g_str_equal(transient_hostname, "") == FALSE) + return transient_hostname; } return NULL; @@ -128,7 +136,7 @@ static void property_changed(GDBusProxy *proxy, const char *name, dbus_message_iter_get_basic(iter, &str); - DBG("pretty hostname: %s", str); + DBG("pretty hostname: '%s'", str); g_free(pretty_hostname); pretty_hostname = g_strdup(str); @@ -146,7 +154,7 @@ static void property_changed(GDBusProxy *proxy, const char *name, dbus_message_iter_get_basic(iter, &str); - DBG("static hostname: %s", str); + DBG("static hostname: '%s'", str); g_free(static_hostname); static_hostname = g_strdup(str); @@ -165,7 +173,7 @@ static void property_changed(GDBusProxy *proxy, const char *name, dbus_message_iter_get_basic(iter, &str); - DBG("chassis: %s", str); + DBG("chassis: '%s'", str); for (i = 0; chassis_table[i].chassis; i++) { if (strcmp(chassis_table[i].chassis, str)) @@ -181,6 +189,32 @@ static void property_changed(GDBusProxy *proxy, const char *name, } } +static void read_transient_hostname(void) +{ + struct utsname u; + + if (uname(&u) != 0) { + g_free(transient_hostname); + transient_hostname = NULL; + DBG("failed to read transient hostname"); + return; + } + + g_free(transient_hostname); + transient_hostname = g_strdup(u.nodename); + + DBG("read transient hostname: '%s'", transient_hostname); +} + +static gboolean hostname_cb(GIOChannel *io, GIOCondition cond, + gpointer user_data) +{ + DBG("transient hostname changed"); + read_transient_hostname(); + adapter_foreach(update_class, NULL); + return TRUE; +} + static int hostname_probe(struct btd_adapter *adapter) { DBG(""); @@ -261,9 +295,11 @@ static GDBusProxy *hostname_proxy = NULL; static int hostname_init(void) { DBusConnection *conn = btd_get_dbus_connection(); + int fd; int err; read_dmi_fallback(); + read_transient_hostname(); hostname_client = g_dbus_client_new(conn, "org.freedesktop.hostname1", "/org/freedesktop/hostname1"); @@ -289,6 +325,17 @@ static int hostname_init(void) hostname_client = NULL; } + fd = open("/proc/sys/kernel/hostname", O_RDONLY); + if (fd < 0) { + error("open(/proc/sys/kernel/hostname): %s (%d)", + strerror(errno), errno); + } else { + GIOChannel *io = g_io_channel_unix_new(fd); + + hostname_id = g_io_add_watch(io, G_IO_ERR, hostname_cb, NULL); + g_io_channel_unref(io); + } + return err; } @@ -306,8 +353,14 @@ static void hostname_exit(void) hostname_client = NULL; } + if (hostname_id != 0) { + g_source_remove(hostname_id); + hostname_id = 0; + } + g_free(pretty_hostname); g_free(static_hostname); + g_free(transient_hostname); } BLUETOOTH_PLUGIN_DEFINE(hostname, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, diff --git a/plugins/policy.c b/plugins/policy.c index 0bbdbfc882d8c11907fb4a87167214c86a81b89b..9a449da61545f7996f0447bde304e0dfe864e4bb 100644 --- a/plugins/policy.c +++ b/plugins/policy.c @@ -74,6 +74,7 @@ static GSList *reconnects = NULL; static unsigned int service_id = 0; static GSList *devices = NULL; +static const bool default_auto_enable = true; static bool auto_enable = false; struct policy_data { @@ -858,6 +859,7 @@ static int policy_init(void) sizeof(*reconnect_intervals); reconnect_intervals = util_memdup(default_intervals, sizeof(default_intervals)); + auto_enable = default_auto_enable; goto done; } @@ -895,7 +897,7 @@ static int policy_init(void) &gerr); if (gerr) { g_clear_error(&gerr); - auto_enable = true; + auto_enable = default_auto_enable; } resume_delay = g_key_file_get_integer( diff --git a/plugins/sixaxis.c b/plugins/sixaxis.c index 544ab399ad31fcce4799aff3402fc894d017af60..3e69f1dd2fee14544a7ede70ed74e039998a21ef 100644 --- a/plugins/sixaxis.c +++ b/plugins/sixaxis.c @@ -346,6 +346,11 @@ static bool setup_device(int fd, const char *sysfs_path, device = btd_adapter_get_device(adapter, &device_bdaddr, BDADDR_BREDR); + if (!device) { + error("sixaxis: unable to set up a new device"); + return false; + } + info("sixaxis: setting up new device"); btd_device_device_set_name(device, cp->name); diff --git a/profiles/audio/a2dp-codecs.h b/profiles/audio/a2dp-codecs.h index 6f567094778f64e0cc566cc88adf7a3b1eecdf8b..38b9038f87a681134d37e4c13b35a3809d81ec8d 100644 --- a/profiles/audio/a2dp-codecs.h +++ b/profiles/audio/a2dp-codecs.h @@ -250,6 +250,18 @@ #define LDAC_CHANNEL_MODE_DUAL 0x02 #define LDAC_CHANNEL_MODE_STEREO 0x01 +#define OPUS_G_VENDOR_ID 0x000000e0 +#define OPUS_G_CODEC_ID 0x0001 + +#define OPUS_G_FREQUENCY_48000 0x80 + +#define OPUS_G_DURATION_100 0x08 +#define OPUS_G_DURATION_200 0x10 + +#define OPUS_G_CHANNELS_MONO 0x01 +#define OPUS_G_CHANNELS_STEREO 0x02 +#define OPUS_G_CHANNELS_DUAL 0x04 + typedef struct { uint8_t vendor_id4; uint8_t vendor_id3; @@ -420,3 +432,8 @@ typedef struct { uint8_t reserved2; uint8_t reserved3; } __attribute__ ((packed)) a2dp_aptx_hd_t; + +typedef struct { + a2dp_vendor_codec_t info; + uint8_t data; +} __attribute__ ((packed)) a2dp_opus_g_t; diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c index 47b5dd7c3d25c7141b59cd49830a9c40f958b0c1..d6c97e7bfde1251057125802a07e037582d8f325 100644 --- a/profiles/audio/a2dp.c +++ b/profiles/audio/a2dp.c @@ -19,6 +19,7 @@ #include <stdlib.h> #include <stdio.h> #include <errno.h> +#include <limits.h> #include <dbus/dbus.h> #include <glib.h> @@ -222,6 +223,7 @@ static void setup_free(struct a2dp_setup *s) avdtp_unref(s->session); g_slist_free_full(s->cb, g_free); g_slist_free_full(s->caps, g_free); + g_free(s->err); g_free(s); } @@ -270,17 +272,34 @@ static void setup_cb_free(struct a2dp_setup_cb *cb) g_free(cb); } +static void setup_error_set(struct a2dp_setup *setup, struct avdtp_error *err) +{ + if (!err) { + g_free(setup->err); + setup->err = NULL; + } else { + if (!setup->err) + setup->err = g_new0(struct avdtp_error, 1); + memcpy(setup->err, err, sizeof(struct avdtp_error)); + } +} + +static void setup_error_init(struct a2dp_setup *setup, uint8_t type, int id) +{ + struct avdtp_error err; + + avdtp_error_init(&err, type, id); + setup_error_set(setup, &err); +} + static void finalize_setup_errno(struct a2dp_setup *s, int err, GSourceFunc cb1, ...) { GSourceFunc finalize; va_list args; - struct avdtp_error avdtp_err; - if (err < 0) { - avdtp_error_init(&avdtp_err, AVDTP_ERRNO, -err); - s->err = &avdtp_err; - } + if (err < 0) + setup_error_init(s, AVDTP_ERRNO, -err); va_start(args, cb1); finalize = cb1; @@ -307,6 +326,8 @@ static int error_to_errno(struct avdtp_error *err) switch (perr) { case EHOSTDOWN: case ECONNABORTED: + case EBADE: + case ECONNREFUSED: return -perr; default: /* @@ -575,10 +596,7 @@ done: finalize_config(setup); - if (setup->err) { - g_free(setup->err); - setup->err = NULL; - } + setup_error_set(setup, NULL); setup_unref(setup); @@ -587,11 +605,9 @@ done: static void endpoint_setconf_cb(struct a2dp_setup *setup, gboolean ret) { - if (ret == FALSE) { - setup->err = g_new(struct avdtp_error, 1); - avdtp_error_init(setup->err, AVDTP_MEDIA_CODEC, + if (ret == FALSE) + setup_error_init(setup, AVDTP_MEDIA_CODEC, AVDTP_UNSUPPORTED_CONFIGURATION); - } auto_config(setup); setup_unref(setup); @@ -670,8 +686,7 @@ static gboolean endpoint_setconf_ind(struct avdtp *session, if (cap->category == AVDTP_DELAY_REPORTING && !a2dp_sep->delay_reporting) { - setup->err = g_new(struct avdtp_error, 1); - avdtp_error_init(setup->err, AVDTP_DELAY_REPORTING, + setup_error_init(setup, AVDTP_DELAY_REPORTING, AVDTP_UNSUPPORTED_CONFIGURATION); goto done; } @@ -682,8 +697,7 @@ static gboolean endpoint_setconf_ind(struct avdtp *session, codec = (struct avdtp_media_codec_capability *) cap->data; if (codec->media_codec_type != a2dp_sep->codec) { - setup->err = g_new(struct avdtp_error, 1); - avdtp_error_init(setup->err, AVDTP_MEDIA_CODEC, + setup_error_init(setup, AVDTP_MEDIA_CODEC, AVDTP_UNSUPPORTED_CONFIGURATION); goto done; } @@ -703,10 +717,9 @@ static gboolean endpoint_setconf_ind(struct avdtp *session, return TRUE; } - setup_unref(setup); - setup->err = g_new(struct avdtp_error, 1); - avdtp_error_init(setup->err, AVDTP_MEDIA_CODEC, + setup_error_init(setup, AVDTP_MEDIA_CODEC, AVDTP_UNSUPPORTED_CONFIGURATION); + setup_unref(setup); break; } @@ -885,7 +898,7 @@ static void invalidate_remote_cache(struct a2dp_setup *setup, /* Set error to -EAGAIN so the likes of policy plugin can * reattempt to connect. */ - avdtp_error_init(setup->err, AVDTP_ERRNO, -EAGAIN); + setup_error_init(setup, AVDTP_ERRNO, -EAGAIN); } } @@ -909,10 +922,10 @@ static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep, if (err) { if (setup) { setup_ref(setup); - setup->err = err; + setup_error_set(setup, err); invalidate_remote_cache(setup, err); finalize_config(setup); - setup->err = NULL; + setup_error_set(setup, NULL); setup_unref(setup); } @@ -1115,7 +1128,7 @@ static void open_cfm(struct avdtp *session, struct avdtp_local_sep *sep, if (err) { setup->stream = NULL; - setup->err = err; + setup_error_set(setup, err); if (setup->start) finalize_resume(setup); } else if (setup->chan) @@ -1190,7 +1203,7 @@ static void start_cfm(struct avdtp *session, struct avdtp_local_sep *sep, if (err) { setup->stream = NULL; - setup->err = err; + setup_error_set(setup, err); } finalize_resume(setup); @@ -1269,7 +1282,7 @@ static void suspend_cfm(struct avdtp *session, struct avdtp_local_sep *sep, if (err) { setup->stream = NULL; - setup->err = err; + setup_error_set(setup, err); } finalize_suspend(setup); @@ -1316,6 +1329,9 @@ static struct a2dp_remote_sep *find_remote_sep(struct a2dp_channel *chan, { struct avdtp_remote_sep *rsep; + if (!chan || !sep) + return NULL; + rsep = avdtp_find_remote_sep(chan->session, sep->lsep); return queue_find(chan->seps, match_remote_sep, rsep); @@ -1417,7 +1433,7 @@ static void close_cfm(struct avdtp *session, struct avdtp_local_sep *sep, if (err) { setup->stream = NULL; - setup->err = err; + setup_error_set(setup, err); finalize_config(setup); return; } @@ -1527,7 +1543,7 @@ static void reconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep, if (err) { setup->stream = NULL; - setup->err = err; + setup_error_set(setup, err); } finalize_config(setup); @@ -2884,7 +2900,7 @@ static void discover_cb(struct avdtp *session, GSList *seps, setup->seps = seps; if (err) - setup->err = err; + setup_error_set(setup, err); if (!err) { g_slist_foreach(seps, foreach_register_remote_sep, setup->chan); diff --git a/profiles/audio/asha.c b/profiles/audio/asha.c new file mode 100644 index 0000000000000000000000000000000000000000..10115b92d8e6130965a7c7c3799419b6281d5585 --- /dev/null +++ b/profiles/audio/asha.c @@ -0,0 +1,525 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2024 Asymptotic Inc. + * + * Author: Arun Raghavan <arun@asymptotic.io> + * + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <errno.h> + +#include <stdbool.h> +#include <stdint.h> +#include <unistd.h> +#include <sys/socket.h> + +#include <dbus/dbus.h> +#include <glib.h> + +#include "btio/btio.h" +#include "gdbus/gdbus.h" +#include "lib/bluetooth.h" +#include "lib/l2cap.h" +#include "lib/uuid.h" + +#include "src/dbus-common.h" +#include "src/adapter.h" +#include "src/device.h" +#include "src/log.h" +#include "src/plugin.h" +#include "src/profile.h" +#include "src/service.h" +#include "src/shared/util.h" + +#include "profiles/audio/asha.h" +#include "profiles/audio/media.h" +#include "profiles/audio/transport.h" + +#define MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint1" + +/* 2 byte SDU length, 1 byte sequence number, and then 20ms of G.722 */ +#define ASHA_MIN_MTU 163 +/* The default of 672 does not work */ +#define ASHA_CONNECTION_MTU 512 + +struct bt_asha_device { + struct bt_asha *asha; + struct btd_device *device; + struct media_transport *transport; + + GIOChannel *io; + uint16_t imtu, omtu; + + unsigned int resume_id; +}; + +static char *make_endpoint_path(struct bt_asha_device *asha_dev) +{ + char *path; + int err; + + err = asprintf(&path, "%s/asha", device_get_path(asha_dev->device)); + if (err < 0) { + error("Could not allocate path for remote %s", + device_get_path(asha_dev->device)); + return NULL; + } + + return path; +} + +struct connect_data { + struct bt_asha_device *asha_dev; + bt_asha_cb_t cb; + void *cb_user_data; +}; + +static void connect_cb(GIOChannel *io, GError *err, gpointer user_data) +{ + struct connect_data *conn_data = user_data; + struct bt_asha_device *asha_dev = conn_data->asha_dev; + GError *gerr = NULL; + + if (!bt_io_get(io, &gerr, + BT_IO_OPT_IMTU, &asha_dev->imtu, + BT_IO_OPT_OMTU, &asha_dev->omtu, + BT_IO_OPT_INVALID)) { + /* Let this be non-fatal? */ + asha_dev->omtu = ASHA_MIN_MTU; + asha_dev->imtu = ASHA_CONNECTION_MTU; + error("Could not get L2CAP CoC socket MTU: %s", err->message); + g_error_free(gerr); + } + + asha_dev->io = io; + + bt_asha_start(asha_dev->asha, conn_data->cb, + conn_data->cb_user_data); +} + +static int asha_connect_socket(struct bt_asha_device *asha_dev, + bt_asha_cb_t cb, void *user_data) +{ + GError *gerr = NULL; + const bdaddr_t *src_addr; + struct connect_data *conn_data; + + if (asha_dev->asha->state != ASHA_STOPPED) { + error("ASHA device connect failed. Bad state %d", + asha_dev->asha->state); + return 0; + } + + conn_data = g_new0(struct connect_data, 1); + conn_data->asha_dev = asha_dev; + conn_data->cb = cb; + conn_data->cb_user_data = user_data; + + src_addr = btd_adapter_get_address( + device_get_adapter(asha_dev->device)); + + if (!bt_io_connect(connect_cb, conn_data, + g_free, &gerr, + BT_IO_OPT_MODE, BT_IO_MODE_LE_FLOWCTL, + BT_IO_OPT_SOURCE_TYPE, BDADDR_LE_PUBLIC, + BT_IO_OPT_SOURCE_BDADDR, src_addr, + BT_IO_OPT_DEST_TYPE, BDADDR_LE_PUBLIC, + BT_IO_OPT_DEST_BDADDR, + device_get_address(asha_dev->device), + BT_IO_OPT_PSM, asha_dev->asha->psm, + BT_IO_OPT_OMTU, ASHA_MIN_MTU, + BT_IO_OPT_IMTU, ASHA_CONNECTION_MTU, + BT_IO_OPT_INVALID)) { + error("Could not open L2CAP CoC socket: %s", gerr->message); + g_error_free(gerr); + goto error; + } + + DBG("L2CAP CoC socket is open"); + return 0; + +error: + return -1; +} + +unsigned int bt_asha_device_start(struct bt_asha_device *asha_dev, + bt_asha_cb_t cb, void *user_data) +{ + int ret; + + btd_device_set_conn_param(asha_dev->device, + 0x0010 /* min interval = 1.25ms intervals => 20ms */, + 0x0010 /* max interval = 1.25ms intervals => 20ms */, + 0x000A /* 10 events' latency */, + 0x0064 /* 1s timeout */); + + ret = asha_connect_socket(asha_dev, cb, user_data); + + if (ret < 0) + return 0; + else + return (++asha_dev->resume_id); +} + +unsigned int bt_asha_device_stop(struct bt_asha_device *asha_dev, + bt_asha_cb_t cb, void *user_data) +{ + bt_asha_stop(asha_dev->asha, cb, user_data); + + if (asha_dev->io) { + g_io_channel_shutdown(asha_dev->io, TRUE, NULL); + g_io_channel_unref(asha_dev->io); + asha_dev->io = NULL; + }; + + return asha_dev->resume_id; +} + +void bt_asha_device_state_reset(struct bt_asha_device *asha_dev) +{ + if (asha_dev->io) { + g_io_channel_shutdown(asha_dev->io, TRUE, NULL); + g_io_channel_unref(asha_dev->io); + asha_dev->io = NULL; + }; + + bt_asha_state_reset(asha_dev->asha); + + asha_dev->resume_id = 0; +} + +unsigned int bt_asha_device_device_get_resume_id( + struct bt_asha_device *asha_dev) +{ + return asha_dev->resume_id; +} + +enum bt_asha_state_t bt_asha_device_get_state( + struct bt_asha_device *asha_dev) +{ + return asha_dev->asha->state; +} + +uint16_t bt_asha_device_get_render_delay(struct bt_asha_device *asha_dev) +{ + return asha_dev->asha->render_delay; +} + +int8_t bt_asha_device_get_volume(struct bt_asha_device *asha_dev) +{ + return asha_dev->asha->volume; +} + +bool bt_asha_device_set_volume(struct bt_asha_device *asha_dev, int8_t volume) +{ + return bt_asha_set_volume(asha_dev->asha, volume); +} + +int bt_asha_device_get_fd(struct bt_asha_device *asha_dev) +{ + return g_io_channel_unix_get_fd(asha_dev->io); +} + +uint16_t bt_asha_device_get_imtu(struct bt_asha_device *asha_dev) +{ + return asha_dev->imtu; +} + +uint16_t bt_asha_device_get_omtu(struct bt_asha_device *asha_dev) +{ + return asha_dev->omtu; +} + + +static gboolean get_uuid(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + const char *uuid; + + uuid = ASHA_PROFILE_UUID; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid); + + return TRUE; +} + +static gboolean get_side(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct bt_asha_device *asha_dev = data; + const char *side = asha_dev->asha->right_side ? "right" : "left"; + + /* Use a string in case we want to support more types in the future */ + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &side); + + return TRUE; +} + + +static gboolean get_binaural(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct bt_asha_device *asha_dev = data; + dbus_bool_t binaural = asha_dev->asha->binaural; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &binaural); + + return TRUE; +} + +static gboolean get_hisyncid(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct bt_asha_device *asha_dev = data; + DBusMessageIter array; + uint8_t *hisyncid = asha_dev->asha->hisyncid; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, &array); + + dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, + &hisyncid, sizeof(asha_dev->asha->hisyncid)); + + dbus_message_iter_close_container(iter, &array); + + return TRUE; +} + +static gboolean get_codecs(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct bt_asha_device *asha_dev = data; + dbus_uint16_t codecs = asha_dev->asha->codec_ids; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &codecs); + + return TRUE; +} + +static gboolean get_device(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct bt_asha_device *asha_dev = data; + const char *path; + + path = device_get_path(asha_dev->device); + + dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path); + + return TRUE; +} + +static gboolean get_transport(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct bt_asha_device *asha_dev = data; + const char *path; + + path = media_transport_get_path(asha_dev->transport); + + dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path); + + return TRUE; +} + +static int asha_source_device_probe(struct btd_service *service) +{ + struct bt_asha_device *asha_dev; + struct btd_device *device = btd_service_get_device(service); + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("Probing ASHA device %s", addr); + + asha_dev = g_new0(struct bt_asha_device, 1); + + asha_dev->device = device; + asha_dev->asha = bt_asha_new(); + asha_dev->io = NULL; + + btd_service_set_user_data(service, asha_dev); + + return 0; +} + +static void asha_source_device_remove(struct btd_service *service) +{ + struct bt_asha_device *asha_dev; + struct btd_device *device = btd_service_get_device(service); + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("Removing ASHA device %s", addr); + + asha_dev = btd_service_get_user_data(service); + if (!asha_dev) { + /* Can this actually happen? */ + DBG("Not handlihng ASHA profile"); + return; + } + + bt_asha_free(asha_dev->asha); + g_free(asha_dev); +} + +static const GDBusMethodTable asha_ep_methods[] = { + { }, +}; + +static const GDBusPropertyTable asha_ep_properties[] = { + { "UUID", "s", get_uuid, NULL, NULL, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { "Side", "s", get_side, NULL, NULL, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { "Binaural", "b", get_binaural, NULL, NULL, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { "HiSyncId", "ay", get_hisyncid, NULL, NULL, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { "Codecs", "q", get_codecs, NULL, NULL, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { "Device", "o", get_device, NULL, NULL, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { "Transport", "o", get_transport, NULL, NULL, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { } +}; + +static void asha_source_endpoint_register(struct bt_asha_device *asha_dev) +{ + char *path; + const struct media_endpoint *asha_ep; + + path = make_endpoint_path(asha_dev); + if (!path) + goto error; + + if (g_dbus_register_interface(btd_get_dbus_connection(), + path, MEDIA_ENDPOINT_INTERFACE, + asha_ep_methods, NULL, + asha_ep_properties, + asha_dev, NULL) == FALSE) { + error("Could not register remote ep %s", path); + goto error; + } + + asha_ep = media_endpoint_get_asha(); + asha_dev->transport = media_transport_create(asha_dev->device, path, + NULL, 0, (void *) asha_ep, asha_dev); + +error: + if (path) + free(path); +} + +static void asha_source_endpoint_unregister(struct bt_asha_device *asha) +{ + char *path; + + path = make_endpoint_path(asha); + if (!path) + goto error; + + g_dbus_unregister_interface(btd_get_dbus_connection(), + path, MEDIA_ENDPOINT_INTERFACE); + + if (asha->transport) { + media_transport_destroy(asha->transport); + asha->transport = NULL; + } + +error: + if (path) + free(path); +} + +static int asha_source_accept(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + struct gatt_db *db = btd_device_get_gatt_db(device); + struct bt_gatt_client *client = btd_device_get_gatt_client(device); + struct bt_asha_device *asha_dev = btd_service_get_user_data(service); + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("Accepting ASHA connection on %s", addr); + + if (!asha_dev) { + /* Can this actually happen? */ + DBG("Not handling ASHA profile"); + return -1; + } + + if (!bt_asha_probe(asha_dev->asha, db, client)) + return -1; + + asha_source_endpoint_register(asha_dev); + + btd_service_connecting_complete(service, 0); + + return 0; +} + +static int asha_source_disconnect(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + struct bt_asha_device *asha_dev = btd_service_get_user_data(service); + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("Disconnecting ASHA on %s", addr); + + if (!asha_dev) { + /* Can this actually happen? */ + DBG("Not handlihng ASHA profile"); + return -1; + } + + asha_source_endpoint_unregister(asha_dev); + bt_asha_reset(asha_dev->asha); + + btd_service_disconnecting_complete(service, 0); + + return 0; +} + +static struct btd_profile asha_source_profile = { + .name = "asha-source", + .priority = BTD_PROFILE_PRIORITY_MEDIUM, + .remote_uuid = ASHA_PROFILE_UUID, + .experimental = true, + + .device_probe = asha_source_device_probe, + .device_remove = asha_source_device_remove, + + .auto_connect = true, + .accept = asha_source_accept, + .disconnect = asha_source_disconnect, +}; + +static int asha_init(void) +{ + int err; + + err = btd_profile_register(&asha_source_profile); + if (err) + return err; + + return 0; +} + +static void asha_exit(void) +{ + btd_profile_unregister(&asha_source_profile); +} + +BLUETOOTH_PLUGIN_DEFINE(asha, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, + asha_init, asha_exit) diff --git a/profiles/audio/asha.h b/profiles/audio/asha.h new file mode 100644 index 0000000000000000000000000000000000000000..afd23e1371efd2d6f3f6e58bc5628c63286dfe49 --- /dev/null +++ b/profiles/audio/asha.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2024 Asymptotic Inc. + * + * Author: Arun Raghavan <arun@asymptotic.io> + * + * + */ + +#include <stdbool.h> +#include <stdint.h> + +#include "src/shared/asha.h" + +struct bt_asha_device; + +unsigned int bt_asha_device_start(struct bt_asha_device *asha_dev, + bt_asha_cb_t cb, void *user_data); +unsigned int bt_asha_device_stop(struct bt_asha_device *asha_dev, + bt_asha_cb_t cb, void *user_data); + +void bt_asha_device_state_reset(struct bt_asha_device *asha_dev); +unsigned int bt_asha_device_device_get_resume_id( + struct bt_asha_device *asha_dev); + +uint16_t bt_asha_device_get_render_delay(struct bt_asha_device *asha_dev); +enum bt_asha_state_t bt_asha_device_get_state( + struct bt_asha_device *asha_dev); + +int bt_asha_device_get_fd(struct bt_asha_device *asha_dev); +uint16_t bt_asha_device_get_omtu(struct bt_asha_device *asha_dev); +uint16_t bt_asha_device_get_imtu(struct bt_asha_device *asha_dev); + +int8_t bt_asha_device_get_volume(struct bt_asha_device *asha_dev); +bool bt_asha_device_set_volume(struct bt_asha_device *asha_dev, int8_t volume); diff --git a/profiles/audio/avctp.c b/profiles/audio/avctp.c index 6f64f162bf8614924ba6000bd510759ae272b0cd..8ad146df106e99d7635d56ad33ef1a5abccceb89 100644 --- a/profiles/audio/avctp.c +++ b/profiles/audio/avctp.c @@ -228,7 +228,7 @@ struct avctp_browsing_pdu_handler { GDestroyNotify destroy; }; -static struct { +static const struct { const char *name; uint8_t avc; uint16_t uinput; diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c index 10ef380d498422bc3e0fc0f0e655c9f38961c305..80fbe847e0433c7476cccc75b396c03c8abd030b 100644 --- a/profiles/audio/avdtp.c +++ b/profiles/audio/avdtp.c @@ -184,13 +184,17 @@ struct getcap_resp { } __attribute__ ((packed)); struct start_req { - struct seid first_seid; - struct seid other_seids[0]; + union { + struct seid required[1]; + struct seid seids[0]; + }; } __attribute__ ((packed)); struct suspend_req { - struct seid first_seid; - struct seid other_seids[0]; + union { + struct seid required[1]; + struct seid seids[0]; + }; } __attribute__ ((packed)); struct seid_rej { @@ -286,7 +290,6 @@ struct in_buf { gboolean active; int no_of_packets; uint8_t transaction; - uint8_t message_type; uint8_t signal_id; uint8_t buf[1024]; uint8_t data_size; @@ -397,7 +400,8 @@ struct avdtp { uint16_t imtu; uint16_t omtu; - struct in_buf in; + struct in_buf in_resp; + struct in_buf in_cmd; char *buf; @@ -1462,15 +1466,16 @@ static void setconf_cb(struct avdtp *session, struct avdtp_stream *stream, if (err != NULL) { rej.error = AVDTP_UNSUPPORTED_CONFIGURATION; rej.category = err->err.error_code; - avdtp_send(session, session->in.transaction, - AVDTP_MSG_TYPE_REJECT, AVDTP_SET_CONFIGURATION, - &rej, sizeof(rej)); + avdtp_send(session, session->in_cmd.transaction, + AVDTP_MSG_TYPE_REJECT, AVDTP_SET_CONFIGURATION, + &rej, sizeof(rej)); stream_free(stream); return; } - if (!avdtp_send(session, session->in.transaction, AVDTP_MSG_TYPE_ACCEPT, - AVDTP_SET_CONFIGURATION, NULL, 0)) { + if (!avdtp_send(session, session->in_cmd.transaction, + AVDTP_MSG_TYPE_ACCEPT, + AVDTP_SET_CONFIGURATION, NULL, 0)) { stream_free(stream); return; } @@ -1671,12 +1676,12 @@ static void check_seid_collision(struct pending_req *req, uint8_t id) static void check_start_collision(struct pending_req *req, uint8_t id) { struct start_req *start = req->data; - struct seid *seid = &start->first_seid; int count = 1 + req->data_size - sizeof(struct start_req); int i; - for (i = 0; i < count; i++, seid++) { - if (seid->seid == id) { + for (i = 0; i < count; i++) { + struct seid seid = start->seids[i]; + if (seid.seid == id) { req->collided = TRUE; return; } @@ -1686,12 +1691,12 @@ static void check_start_collision(struct pending_req *req, uint8_t id) static void check_suspend_collision(struct pending_req *req, uint8_t id) { struct suspend_req *suspend = req->data; - struct seid *seid = &suspend->first_seid; int count = 1 + req->data_size - sizeof(struct suspend_req); int i; - for (i = 0; i < count; i++, seid++) { - if (seid->seid == id) { + for (i = 0; i < count; i++) { + struct seid seid = suspend->seids[i]; + if (seid.seid == id) { req->collided = TRUE; return; } @@ -1784,7 +1789,6 @@ static gboolean avdtp_start_cmd(struct avdtp *session, uint8_t transaction, struct avdtp_local_sep *sep; struct avdtp_stream *stream; struct stream_rej rej; - struct seid *seid; uint8_t err, failed_seid; int seid_count, i; @@ -1795,12 +1799,12 @@ static gboolean avdtp_start_cmd(struct avdtp *session, uint8_t transaction, seid_count = 1 + size - sizeof(struct start_req); - seid = &req->first_seid; + for (i = 0; i < seid_count; i++) { + struct seid seid = req->seids[i]; - for (i = 0; i < seid_count; i++, seid++) { - failed_seid = seid->seid; + failed_seid = seid.seid; - sep = find_local_sep_by_seid(session, seid->seid); + sep = find_local_sep_by_seid(session, seid.seid); if (!sep || !sep->stream) { err = AVDTP_BAD_ACP_SEID; goto failed; @@ -1897,7 +1901,6 @@ static gboolean avdtp_suspend_cmd(struct avdtp *session, uint8_t transaction, struct avdtp_local_sep *sep; struct avdtp_stream *stream; struct stream_rej rej; - struct seid *seid; uint8_t err, failed_seid; int seid_count, i; @@ -1908,12 +1911,11 @@ static gboolean avdtp_suspend_cmd(struct avdtp *session, uint8_t transaction, seid_count = 1 + size - sizeof(struct suspend_req); - seid = &req->first_seid; - - for (i = 0; i < seid_count; i++, seid++) { - failed_seid = seid->seid; + for (i = 0; i < seid_count; i++) { + struct seid seid = req->seids[i]; + failed_seid = seid.seid; - sep = find_local_sep_by_seid(session, seid->seid); + sep = find_local_sep_by_seid(session, seid.seid); if (!sep || !sep->stream) { err = AVDTP_BAD_ACP_SEID; goto failed; @@ -2035,6 +2037,14 @@ failed: static gboolean avdtp_parse_cmd(struct avdtp *session, uint8_t transaction, uint8_t signal_id, void *buf, int size) { + /* Reset disconnect timer if command is received */ + if (session->dc_timer) { + timeout_remove(session->dc_timer); + session->dc_timer = timeout_add_seconds(session->dc_timeout, + disconnect_timeout, + session, NULL); + } + switch (signal_id) { case AVDTP_DISCOVER: DBG("Received DISCOVER_CMD"); @@ -2092,6 +2102,12 @@ static enum avdtp_parse_result avdtp_parse_data(struct avdtp *session, struct avdtp_start_header *start = (void *) session->buf; void *payload; gsize payload_size; + struct in_buf *in; + + if (header->message_type == AVDTP_MSG_TYPE_COMMAND) + in = &session->in_cmd; + else + in = &session->in_resp; switch (header->packet_type) { case AVDTP_PKT_TYPE_SINGLE: @@ -2099,7 +2115,7 @@ static enum avdtp_parse_result avdtp_parse_data(struct avdtp *session, error("Received too small single packet (%zu bytes)", size); return PARSE_ERROR; } - if (session->in.active) { + if (in->active) { error("SINGLE: Invalid AVDTP packet fragmentation"); return PARSE_ERROR; } @@ -2107,12 +2123,11 @@ static enum avdtp_parse_result avdtp_parse_data(struct avdtp *session, payload = session->buf + sizeof(*single); payload_size = size - sizeof(*single); - session->in.active = TRUE; - session->in.data_size = 0; - session->in.no_of_packets = 1; - session->in.transaction = header->transaction; - session->in.message_type = header->message_type; - session->in.signal_id = single->signal_id; + in->active = TRUE; + in->data_size = 0; + in->no_of_packets = 1; + in->transaction = header->transaction; + in->signal_id = single->signal_id; break; case AVDTP_PKT_TYPE_START: @@ -2120,17 +2135,16 @@ static enum avdtp_parse_result avdtp_parse_data(struct avdtp *session, error("Received too small start packet (%zu bytes)", size); return PARSE_ERROR; } - if (session->in.active) { + if (in->active) { error("START: Invalid AVDTP packet fragmentation"); return PARSE_ERROR; } - session->in.active = TRUE; - session->in.data_size = 0; - session->in.transaction = header->transaction; - session->in.message_type = header->message_type; - session->in.no_of_packets = start->no_of_packets; - session->in.signal_id = start->signal_id; + in->active = TRUE; + in->data_size = 0; + in->transaction = header->transaction; + in->no_of_packets = start->no_of_packets; + in->signal_id = start->signal_id; payload = session->buf + sizeof(*start); payload_size = size - sizeof(*start); @@ -2142,15 +2156,15 @@ static enum avdtp_parse_result avdtp_parse_data(struct avdtp *session, size); return PARSE_ERROR; } - if (!session->in.active) { + if (!in->active) { error("CONTINUE: Invalid AVDTP packet fragmentation"); return PARSE_ERROR; } - if (session->in.transaction != header->transaction) { + if (in->transaction != header->transaction) { error("Continue transaction id doesn't match"); return PARSE_ERROR; } - if (session->in.no_of_packets <= 1) { + if (in->no_of_packets <= 1) { error("Too few continue packets"); return PARSE_ERROR; } @@ -2164,15 +2178,15 @@ static enum avdtp_parse_result avdtp_parse_data(struct avdtp *session, error("Received too small end packet (%zu bytes)", size); return PARSE_ERROR; } - if (!session->in.active) { + if (!in->active) { error("END: Invalid AVDTP packet fragmentation"); return PARSE_ERROR; } - if (session->in.transaction != header->transaction) { + if (in->transaction != header->transaction) { error("End transaction id doesn't match"); return PARSE_ERROR; } - if (session->in.no_of_packets > 1) { + if (in->no_of_packets > 1) { error("Got an end packet too early"); return PARSE_ERROR; } @@ -2186,23 +2200,23 @@ static enum avdtp_parse_result avdtp_parse_data(struct avdtp *session, return PARSE_ERROR; } - if (session->in.data_size + payload_size > - sizeof(session->in.buf)) { + if (in->data_size + payload_size > + sizeof(in->buf)) { error("Not enough incoming buffer space!"); return PARSE_ERROR; } - memcpy(session->in.buf + session->in.data_size, payload, payload_size); - session->in.data_size += payload_size; + memcpy(in->buf + in->data_size, payload, payload_size); + in->data_size += payload_size; - if (session->in.no_of_packets > 1) { - session->in.no_of_packets--; + if (in->no_of_packets > 1) { + in->no_of_packets--; DBG("Received AVDTP fragment. %d to go", - session->in.no_of_packets); + in->no_of_packets); return PARSE_FRAGMENT; } - session->in.active = FALSE; + in->active = FALSE; return PARSE_SUCCESS; } @@ -2246,11 +2260,11 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond, break; } - if (session->in.message_type == AVDTP_MSG_TYPE_COMMAND) { - if (!avdtp_parse_cmd(session, session->in.transaction, - session->in.signal_id, - session->in.buf, - session->in.data_size)) { + if (header->message_type == AVDTP_MSG_TYPE_COMMAND) { + if (!avdtp_parse_cmd(session, session->in_cmd.transaction, + session->in_cmd.signal_id, + session->in_cmd.buf, + session->in_cmd.data_size)) { error("Unable to handle command. Disconnecting"); goto failed; } @@ -2273,7 +2287,7 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond, return TRUE; } - if (session->in.signal_id != session->req->signal_id) { + if (session->in_resp.signal_id != session->req->signal_id) { error("Response signal doesn't match"); return TRUE; } @@ -2284,20 +2298,20 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond, switch (header->message_type) { case AVDTP_MSG_TYPE_ACCEPT: if (!avdtp_parse_resp(session, session->req->stream, - session->in.transaction, - session->in.signal_id, - session->in.buf, - session->in.data_size)) { + session->in_resp.transaction, + session->in_resp.signal_id, + session->in_resp.buf, + session->in_resp.data_size)) { error("Unable to parse accept response"); goto failed; } break; case AVDTP_MSG_TYPE_REJECT: if (!avdtp_parse_rej(session, session->req->stream, - session->in.transaction, - session->in.signal_id, - session->in.buf, - session->in.data_size)) { + session->in_resp.transaction, + session->in_resp.signal_id, + session->in_resp.buf, + session->in_resp.data_size)) { error("Unable to parse reject response"); goto failed; } @@ -3197,6 +3211,10 @@ gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream, return TRUE; } +gboolean avdtp_stream_has_delay_reporting(struct avdtp_stream *stream) { + return stream->delay_reporting; +} + struct avdtp_remote_sep *avdtp_stream_get_remote_sep( struct avdtp_stream *stream) { @@ -3658,7 +3676,7 @@ int avdtp_start(struct avdtp *session, struct avdtp_stream *stream) } memset(&req, 0, sizeof(req)); - req.first_seid.seid = stream->rseid; + req.required->seid = stream->rseid; ret = send_request(session, FALSE, stream, AVDTP_START, &req, sizeof(req)); @@ -3763,11 +3781,12 @@ int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream, return -EINVAL; if (stream->lsep->state != AVDTP_STATE_CONFIGURED && + stream->lsep->state != AVDTP_STATE_OPEN && stream->lsep->state != AVDTP_STATE_STREAMING) return -EINVAL; if (!stream->delay_reporting || session->version < 0x0103) - return -EINVAL; + return -ENOTSUP; stream->delay = delay; @@ -3913,6 +3932,9 @@ struct btd_device *avdtp_get_device(struct avdtp *session) gboolean avdtp_has_stream(struct avdtp *session, struct avdtp_stream *stream) { + if (!session || !stream) + return FALSE; + return g_slist_find(session->streams, stream) ? TRUE : FALSE; } diff --git a/profiles/audio/avdtp.h b/profiles/audio/avdtp.h index 102a2603e3a2ca4431b8cfc34324a84e186e8830..500b814ac499db71c35208503b70ee8112047d64 100644 --- a/profiles/audio/avdtp.h +++ b/profiles/audio/avdtp.h @@ -252,6 +252,7 @@ struct avdtp_service_capability *avdtp_stream_get_codec( struct avdtp_stream *stream); gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream, GSList *caps); +gboolean avdtp_stream_has_delay_reporting(struct avdtp_stream *stream); struct avdtp_remote_sep *avdtp_stream_get_remote_sep( struct avdtp_stream *stream); diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c index 80f34c7a77a17ddad89abe62e8a7a028c6fecf3c..b5e6548e66008d678787bd4451d34cca8900e015 100644 --- a/profiles/audio/avrcp.c +++ b/profiles/audio/avrcp.c @@ -48,6 +48,7 @@ #include "src/dbus-common.h" #include "src/shared/timeout.h" #include "src/shared/util.h" +#include "src/btd.h" #include "avctp.h" #include "avrcp.h" @@ -118,8 +119,14 @@ #define AVRCP_FEATURE_CATEGORY_2 0x0002 #define AVRCP_FEATURE_CATEGORY_3 0x0004 #define AVRCP_FEATURE_CATEGORY_4 0x0008 -#define AVRCP_FEATURE_PLAYER_SETTINGS 0x0010 -#define AVRCP_FEATURE_BROWSING 0x0040 +#define AVRCP_FEATURE_TG_PLAYER_SETTINGS 0x0010 +#define AVRCP_FEATURE_TG_GROUP_NAVIGATION 0x0020 +#define AVRCP_FEATURE_BROWSING 0x0040 +#define AVRCP_FEATURE_TG_MULTIPLE_PLAYER 0x0080 +#define AVRCP_FEATURE_TG_COVERT_ART 0x0100 +#define AVRCP_FEATURE_CT_GET_IMAGE_PROP 0x0080 +#define AVRCP_FEATURE_CT_GET_IMAGE 0x0100 +#define AVRCP_FEATURE_CT_GET_THUMBNAIL 0x0200 #define AVRCP_BATTERY_STATUS_NORMAL 0 #define AVRCP_BATTERY_STATUS_WARNING 1 @@ -254,6 +261,7 @@ struct avrcp_data { struct avrcp_player *player; uint16_t version; int features; + uint16_t obex_port; GSList *players; }; @@ -290,7 +298,7 @@ struct control_pdu_handler { uint8_t transaction); }; -static struct { +static const struct { uint8_t feature_bit; uint8_t avc; } passthrough_map[] = { @@ -361,7 +369,7 @@ static unsigned int avctp_id = 0; static uint8_t default_features[16]; /* Company IDs supported by this device */ -static uint32_t company_ids[] = { +static const uint32_t company_ids[] = { IEEEID_BTSIG, }; @@ -408,9 +416,12 @@ static sdp_record_t *avrcp_ct_record(bool browsing) uint16_t lp = AVCTP_CONTROL_PSM; uint16_t avctp_ver = 0x0103; uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 | - AVRCP_FEATURE_CATEGORY_2 | - AVRCP_FEATURE_CATEGORY_3 | - AVRCP_FEATURE_CATEGORY_4); + AVRCP_FEATURE_CATEGORY_2 | + AVRCP_FEATURE_CATEGORY_3 | + AVRCP_FEATURE_CATEGORY_4 | + AVRCP_FEATURE_CT_GET_IMAGE_PROP | + AVRCP_FEATURE_CT_GET_IMAGE | + AVRCP_FEATURE_CT_GET_THUMBNAIL); record = sdp_record_alloc(); if (!record) @@ -487,7 +498,7 @@ static sdp_record_t *avrcp_tg_record(bool browsing) AVRCP_FEATURE_CATEGORY_2 | AVRCP_FEATURE_CATEGORY_3 | AVRCP_FEATURE_CATEGORY_4 | - AVRCP_FEATURE_PLAYER_SETTINGS ); + AVRCP_FEATURE_TG_PLAYER_SETTINGS); record = sdp_record_alloc(); if (!record) @@ -876,6 +887,8 @@ static const char *metadata_to_str(uint32_t id) return "NumberOfTracks"; case AVRCP_MEDIA_ATTRIBUTE_DURATION: return "Duration"; + case AVRCP_MEDIA_ATTRIBUTE_IMG_HANDLE: + return "ImgHandle"; } return NULL; @@ -1190,6 +1203,8 @@ static uint32_t str_to_metadata(const char *str) return AVRCP_MEDIA_ATTRIBUTE_N_TRACKS; else if (strcasecmp(str, "Duration") == 0) return AVRCP_MEDIA_ATTRIBUTE_DURATION; + else if (strcasecmp(str, "ImgHandle") == 0) + return AVRCP_MEDIA_ATTRIBUTE_IMG_HANDLE; return 0; } @@ -1210,6 +1225,10 @@ static GList *player_list_metadata(struct avrcp_player *player) GUINT_TO_POINTER(str_to_metadata(key))); } + if (attrs == NULL) + return g_list_prepend(NULL, + GUINT_TO_POINTER(AVRCP_MEDIA_ATTRIBUTE_TITLE)); + return attrs; } @@ -1746,6 +1765,19 @@ err: return AVC_CTYPE_REJECTED; } +/* SetAbsoluteVolume requires at least version 1.4 and a category-2 */ +static bool avrcp_volume_supported(struct avrcp_data *data) +{ + if (!data || data->version < 0x0104) + return false; + + if (btd_opts.avrcp.volume_category && + !(data->features & AVRCP_FEATURE_CATEGORY_2)) + return false; + + return true; +} + static uint8_t avrcp_handle_set_absolute_volume(struct avrcp *session, struct avrcp_header *pdu, uint8_t transaction) @@ -1756,6 +1788,11 @@ static uint8_t avrcp_handle_set_absolute_volume(struct avrcp *session, if (len != 1) goto err; + if (!avrcp_volume_supported(session->target)) { + error("SetAbsoluteVolume not supported"); + goto err; + } + volume = pdu->params[0] & 0x7F; media_transport_update_device_volume(session->dev, volume); @@ -2118,7 +2155,7 @@ failed: pdu->param_len = cpu_to_be16(1); } -static struct browsing_pdu_handler { +static const struct browsing_pdu_handler { uint8_t pdu_id; void (*func) (struct avrcp *session, struct avrcp_browsing_header *pdu, uint8_t transaction); @@ -2147,7 +2184,7 @@ static size_t handle_browsing_pdu(struct avctp *conn, size_t operand_count, void *user_data) { struct avrcp *session = user_data; - struct browsing_pdu_handler *handler; + const struct browsing_pdu_handler *handler; struct avrcp_browsing_header *pdu = (void *) operands; DBG("AVRCP Browsing PDU 0x%02X, len 0x%04X", pdu->pdu_id, @@ -2396,16 +2433,12 @@ static void avrcp_list_player_attributes(struct avrcp *session) } static void avrcp_parse_attribute_list(struct avrcp_player *player, + struct media_item *item, uint8_t *operands, uint8_t count) { struct media_player *mp = player->user_data; - struct media_item *item; int i; - media_player_clear_metadata(mp); - - item = media_player_set_playlist_item(mp, player->uid); - for (i = 0; count > 0; count--) { uint32_t id; uint16_t charset, len; @@ -2430,8 +2463,6 @@ static void avrcp_parse_attribute_list(struct avrcp_player *player, i += len; } - - media_player_metadata_changed(mp); } static gboolean avrcp_get_element_attributes_rsp(struct avctp *conn, @@ -2444,6 +2475,8 @@ static gboolean avrcp_get_element_attributes_rsp(struct avctp *conn, struct avrcp *session = user_data; struct avrcp_player *player = session->controller->player; struct avrcp_header *pdu = (void *) operands; + struct media_player *mp = player->user_data; + struct media_item *item; uint8_t count; if (code == AVC_CTYPE_REJECTED) @@ -2456,7 +2489,13 @@ static gboolean avrcp_get_element_attributes_rsp(struct avctp *conn, return FALSE; } - avrcp_parse_attribute_list(player, &pdu->params[1], count); + media_player_clear_metadata(mp); + + item = media_player_set_playlist_item(mp, player->uid); + + avrcp_parse_attribute_list(player, item, &pdu->params[1], count); + + media_player_metadata_changed(mp); avrcp_get_play_status(session); @@ -2542,20 +2581,23 @@ static struct media_item *parse_media_element(struct avrcp *session, struct avrcp_player *player; struct media_player *mp; struct media_item *item; - uint16_t namelen; + uint16_t namelen, namesize; char name[255]; uint64_t uid; + uint8_t count; if (len < 13) return NULL; uid = get_be64(&operands[0]); - namelen = MIN(get_be16(&operands[11]), sizeof(name) - 1); - if (namelen > 0) { + memset(name, 0, sizeof(name)); + namesize = get_be16(&operands[11]); + namelen = MIN(namesize, sizeof(name) - 1); + if (namelen > 0) memcpy(name, &operands[13], namelen); - name[namelen] = '\0'; - } + + count = operands[13 + namesize]; player = session->controller->player; mp = player->user_data; @@ -2566,6 +2608,9 @@ static struct media_item *parse_media_element(struct avrcp *session, media_item_set_playable(item, true); + avrcp_parse_attribute_list(player, item, &operands[14 + namesize], + count); + return item; } @@ -2588,11 +2633,10 @@ static struct media_item *parse_media_folder(struct avrcp *session, type = operands[8]; playable = operands[9]; + memset(name, 0, sizeof(name)); namelen = MIN(get_be16(&operands[12]), sizeof(name) - 1); - if (namelen > 0) { + if (namelen > 0) memcpy(name, &operands[14], namelen); - name[namelen] = '\0'; - } item = media_player_create_folder(mp, name, type, uid); if (!item) @@ -2701,20 +2745,25 @@ static void avrcp_list_items(struct avrcp *session, uint32_t start, memset(buf, 0, sizeof(buf)); pdu->pdu_id = AVRCP_GET_FOLDER_ITEMS; - pdu->param_len = cpu_to_be16(10 + sizeof(uint32_t)); + pdu->param_len = cpu_to_be16(10 + (6 * sizeof(uint32_t))); pdu->params[0] = player->scope; put_be32(start, &pdu->params[1]); put_be32(end, &pdu->params[5]); - pdu->params[9] = 1; + pdu->params[9] = 6; /* Only the title (0x01) is mandatory. This can be extended to * support AVRCP_MEDIA_ATTRIBUTE_* attributes */ put_be32(AVRCP_MEDIA_ATTRIBUTE_TITLE, &pdu->params[10]); + put_be32(AVRCP_MEDIA_ATTRIBUTE_ARTIST, &pdu->params[14]); + put_be32(AVRCP_MEDIA_ATTRIBUTE_ALBUM, &pdu->params[18]); + put_be32(AVRCP_MEDIA_ATTRIBUTE_TRACK, &pdu->params[22]); + put_be32(AVRCP_MEDIA_ATTRIBUTE_DURATION, &pdu->params[26]); + put_be32(AVRCP_MEDIA_ATTRIBUTE_IMG_HANDLE, &pdu->params[30]); - length += sizeof(uint32_t); + length += 6 * sizeof(uint32_t); avctp_send_browsing_req(session->conn, buf, length, avrcp_list_items_rsp, session); @@ -2839,6 +2888,8 @@ static gboolean avrcp_get_item_attributes_rsp(struct avctp *conn, struct avrcp *session = user_data; struct avrcp_player *player = session->controller->player; struct avrcp_browsing_header *pdu = (void *) operands; + struct media_player *mp = player->user_data; + struct media_item *item; uint8_t count; if (pdu == NULL) { @@ -2858,7 +2909,13 @@ static gboolean avrcp_get_item_attributes_rsp(struct avctp *conn, return FALSE; } - avrcp_parse_attribute_list(player, &pdu->params[2], count); + media_player_clear_metadata(mp); + + item = media_player_set_playlist_item(mp, player->uid); + + avrcp_parse_attribute_list(player, item, &pdu->params[2], count); + + media_player_metadata_changed(mp); avrcp_get_play_status(session); @@ -3520,6 +3577,7 @@ static struct avrcp_player *create_ct_player(struct avrcp *session, return NULL; } + media_player_set_obex_port(mp, session->controller->obex_port); media_player_set_callbacks(mp, &ct_cbs, player); player->user_data = mp; player->destroy = (GDestroyNotify) media_player_destroy; @@ -3727,6 +3785,11 @@ static void avrcp_volume_changed(struct avrcp *session, struct avrcp_player *player = target_get_player(session); int8_t volume; + if (!avrcp_volume_supported(session->controller)) { + error("EVENT_VOLUME_CHANGED not supported"); + return; + } + volume = pdu->params[1] & 0x7F; /* Always attempt to update the transport volume */ @@ -3802,6 +3865,17 @@ static void avrcp_setting_changed(struct avrcp *session, } } +static void avrcp_now_playing_changed(struct avrcp *session, + struct avrcp_header *pdu) +{ + struct avrcp_player *player = session->controller->player; + struct media_player *mp = player->user_data; + + DBG("NowPlaying changed"); + + media_player_clear_playlist(mp); +} + static void avrcp_available_players_changed(struct avrcp *session, struct avrcp_header *pdu) { @@ -3892,6 +3966,9 @@ static gboolean avrcp_handle_event(struct avctp *conn, uint8_t code, case AVRCP_EVENT_SETTINGS_CHANGED: avrcp_setting_changed(session, pdu); break; + case AVRCP_EVENT_NOW_PLAYING_CHANGED: + avrcp_now_playing_changed(session, pdu); + break; case AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED: avrcp_available_players_changed(session, pdu); break; @@ -3901,6 +3978,12 @@ static gboolean avrcp_handle_event(struct avctp *conn, uint8_t code, case AVRCP_EVENT_UIDS_CHANGED: avrcp_uids_changed(session, pdu); break; + default: + if (event > AVRCP_EVENT_LAST) { + warn("Unsupported event: %u", event); + return FALSE; + } + break; } session->registered_events |= (1 << event); @@ -3977,10 +4060,11 @@ static gboolean avrcp_get_capabilities_resp(struct avctp *conn, uint8_t code, case AVRCP_EVENT_TRACK_CHANGED: case AVRCP_EVENT_PLAYBACK_POS_CHANGED: case AVRCP_EVENT_SETTINGS_CHANGED: + case AVRCP_EVENT_NOW_PLAYING_CHANGED: case AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED: case AVRCP_EVENT_UIDS_CHANGED: case AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED: - /* These events above requires a player */ + /* These events above require a player */ if (!session->controller || !session->controller->player) break; @@ -3998,7 +4082,8 @@ static gboolean avrcp_get_capabilities_resp(struct avctp *conn, uint8_t code, if (events == (1 << AVRCP_EVENT_VOLUME_CHANGED)) return FALSE; - if ((session->controller->features & AVRCP_FEATURE_PLAYER_SETTINGS) && + if ((session->controller->features & + AVRCP_FEATURE_TG_PLAYER_SETTINGS) && !(events & (1 << AVRCP_EVENT_SETTINGS_CHANGED))) avrcp_list_player_attributes(session); @@ -4067,8 +4152,9 @@ static struct avrcp_data *data_init(struct avrcp *session, const char *uuid) { struct avrcp_data *data; const sdp_record_t *rec; - sdp_list_t *list; + sdp_list_t *list, *protos; sdp_profile_desc_t *desc; + int port = 0; data = g_new0(struct avrcp_data, 1); @@ -4084,6 +4170,35 @@ static struct avrcp_data *data_init(struct avrcp *session, const char *uuid) sdp_get_int_attr(rec, SDP_ATTR_SUPPORTED_FEATURES, &data->features); sdp_list_free(list, free); + if ((g_strcmp0(uuid, AVRCP_TARGET_UUID) != 0) || + !(data->features & AVRCP_FEATURE_TG_COVERT_ART) || + (sdp_get_add_access_protos(rec, &protos) != 0)) + return data; + + /* Get the PSM port from the Additional Protocol Descriptor list + * entry containing OBEX UUID + */ + for (list = protos; list; list = list->next) { + sdp_list_t *p; + + for (p = list->data; p; p = p->next) { + sdp_data_t *seq = p->data; + + if ((sdp_uuid_to_proto(&seq->val.uuid) == OBEX_UUID) && + SDP_IS_UUID(seq->dtd)) { + port = sdp_get_proto_port(list, L2CAP_UUID); + goto done; + } + } + } + +done: + if (port > 0) + data->obex_port = port; + + sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL); + sdp_list_free(protos, NULL); + return data; } @@ -4153,10 +4268,13 @@ static void target_init(struct avrcp *session) if (target->version < 0x0104) return; + if (!avrcp_volume_supported(target)) + session->supported_events |= + (1 << AVRCP_EVENT_VOLUME_CHANGED); + session->supported_events |= (1 << AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED) | - (1 << AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED) | - (1 << AVRCP_EVENT_VOLUME_CHANGED); + (1 << AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED); /* Only check capabilities if controller is not supported */ if (session->controller == NULL) @@ -4181,6 +4299,8 @@ static void controller_init(struct avrcp *session) session->controller = controller; DBG("%p version 0x%04x", controller, controller->version); + if (controller->obex_port) + DBG("%p OBEX PSM 0x%04x", controller, controller->obex_port); service = btd_device_get_service(session->dev, AVRCP_TARGET_UUID); btd_service_connecting_complete(service, 0); @@ -4571,15 +4691,26 @@ int avrcp_set_volume(struct btd_device *dev, int8_t volume, bool notify) return -ENOTCONN; if (notify) { - if (!session->target) + if (!avrcp_volume_supported(session->target)) { + error("EVENT_VOLUME_CHANGED not supported"); return -ENOTSUP; + } return avrcp_event(session, AVRCP_EVENT_VOLUME_CHANGED, &volume); } - if (!session->controller && !avrcp_event_registered(session, - AVRCP_EVENT_VOLUME_CHANGED)) + if (btd_opts.avrcp.volume_without_target) { + /* If there is no target profile (we didn't create a controller + * for it), allow the call to pass through if the remote + * controller registered for a volume changed event. + */ + if (!session->controller && !avrcp_event_registered(session, + AVRCP_EVENT_VOLUME_CHANGED)) + return -ENOTSUP; + } else if (!avrcp_volume_supported(session->controller)) { + error("SetAbsoluteVolume not supported"); return -ENOTSUP; + } memset(buf, 0, sizeof(buf)); diff --git a/profiles/audio/avrcp.h b/profiles/audio/avrcp.h index dcc580e3776d06eba70ef412d841b3354b8c8c61..887753ddf28643800fabbddb1bf0941ed3930463 100644 --- a/profiles/audio/avrcp.h +++ b/profiles/audio/avrcp.h @@ -46,7 +46,8 @@ #define AVRCP_MEDIA_ATTRIBUTE_N_TRACKS 0x05 #define AVRCP_MEDIA_ATTRIBUTE_GENRE 0x06 #define AVRCP_MEDIA_ATTRIBUTE_DURATION 0x07 -#define AVRCP_MEDIA_ATTRIBUTE_LAST AVRCP_MEDIA_ATTRIBUTE_DURATION +#define AVRCP_MEDIA_ATTRIBUTE_IMG_HANDLE 0x08 +#define AVRCP_MEDIA_ATTRIBUTE_LAST AVRCP_MEDIA_ATTRIBUTE_IMG_HANDLE /* play status */ #define AVRCP_PLAY_STATUS_STOPPED 0x00 @@ -63,6 +64,7 @@ #define AVRCP_EVENT_TRACK_REACHED_START 0x04 #define AVRCP_EVENT_PLAYBACK_POS_CHANGED 0x05 #define AVRCP_EVENT_SETTINGS_CHANGED 0x08 +#define AVRCP_EVENT_NOW_PLAYING_CHANGED 0x09 #define AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED 0x0a #define AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED 0x0b #define AVRCP_EVENT_UIDS_CHANGED 0x0c diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c index 67aba3bd76d950f62ba662156864d4a0e50f272e..df685c6d34b84f2d573d54768f1adc0a60cb005f 100644 --- a/profiles/audio/bap.c +++ b/profiles/audio/bap.c @@ -4,6 +4,7 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2022 Intel Corporation. All rights reserved. + * Copyright 2023-2024 NXP * * */ @@ -33,7 +34,9 @@ #include "lib/hci.h" #include "lib/sdp.h" #include "lib/uuid.h" +#include "lib/iso.h" +#include "src/btd.h" #include "src/dbus-common.h" #include "src/shared/util.h" #include "src/shared/att.h" @@ -53,27 +56,60 @@ #include "src/log.h" #include "src/error.h" +#include "bap.h" +#include "bass.h" + +#define ISO_SOCKET_UUID "6fbaf188-05e0-496a-9885-d6ddfdb4e03e" #define PACS_UUID_STR "00001850-0000-1000-8000-00805f9b34fb" +#define BCAAS_UUID_STR "00001852-0000-1000-8000-00805f9b34fb" #define MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint1" +#define MEDIA_INTERFACE "org.bluez.Media1" -struct bap_ep { - char *path; - struct bap_data *data; - struct bt_bap_pac *lpac; - struct bt_bap_pac *rpac; +/* Periodic advertisments are performed by an idle timer, which, + * at every tick, checks a queue for pending PA requests. + * When there is no pending requests, an item is popped from the + * queue, marked as pending and then it gets processed. + */ +#define PA_IDLE_TIMEOUT 2 + +struct bap_setup { + struct bap_ep *ep; struct bt_bap_stream *stream; + struct bt_bap_qos qos; + int (*qos_parser)(struct bap_setup *setup, const char *key, int var, + DBusMessageIter *iter); GIOChannel *io; unsigned int io_id; bool recreate; + bool cig_active; struct iovec *caps; struct iovec *metadata; - struct bt_bap_qos qos; unsigned int id; + struct iovec *base; DBusMessage *msg; + void (*destroy)(struct bap_setup *setup); +}; + +struct bap_ep { + char *path; + struct bap_data *data; + struct bt_bap_pac *lpac; + struct bt_bap_pac *rpac; + uint32_t locations; + uint16_t supported_context; + uint16_t context; + struct queue *setups; +}; + +struct bap_adapter { + struct btd_adapter *adapter; + unsigned int pa_timer_id; + struct queue *bcast_pa_requests; }; struct bap_data { struct btd_device *device; + struct bap_adapter *adapter; struct btd_service *service; struct bt_bap *bap; unsigned int ready_id; @@ -81,11 +117,83 @@ struct bap_data { unsigned int pac_id; struct queue *srcs; struct queue *snks; + struct queue *bcast; + struct queue *bcast_snks; struct queue *streams; GIOChannel *listen_io; + int selecting; + void *user_data; +}; + +enum { + BAP_PA_SHORT_REQ = 0, /* Request for short PA sync */ + BAP_PA_LONG_REQ, /* Request for long PA sync */ + BAP_PA_BIG_SYNC_REQ, /* Request for PA Sync and BIG Sync */ +}; + +struct bap_bcast_pa_req { + uint8_t type; + bool in_progress; + struct bap_data *bap_data; + union { + struct btd_service *service; + struct queue *setups; + } data; + unsigned int io_id; /* io_id for BIG Info watch */ + GIOChannel *io; }; static struct queue *sessions; +static struct queue *adapters; + +/* Structure holding the parameters for Periodic Advertisement create sync. + * The full QOS is populated at the time the user selects and endpoint and + * configures it using SetConfiguration. + */ +static struct bt_iso_qos bap_sink_pa_qos = { + .bcast = { + .options = 0x00, + .skip = 0x0000, + .sync_timeout = BT_ISO_SYNC_TIMEOUT, + .sync_cte_type = 0x00, + /* TODO: The following parameters are not needed for PA Sync. + * They will be removed when the kernel checks will be removed. + */ + .big = BT_ISO_QOS_BIG_UNSET, + .bis = BT_ISO_QOS_BIS_UNSET, + .encryption = 0x00, + .bcode = {0x00}, + .mse = 0x00, + .timeout = BT_ISO_SYNC_TIMEOUT, + .sync_factor = 0x07, + .packing = 0x00, + .framing = 0x00, + .in = { + .interval = 10000, + .latency = 10, + .sdu = 40, + .phy = 0x02, + .rtn = 2, + }, + .out = { + .interval = 10000, + .latency = 10, + .sdu = 40, + .phy = 0x02, + .rtn = 2, + } + } +}; + +static bool bap_data_set_user_data(struct bap_data *data, void *user_data) +{ + if (!data) + return false; + + data->user_data = user_data; + + return true; +} static void bap_debug(const char *str, void *user_data) { @@ -102,6 +210,8 @@ static void ep_unregister(void *data) MEDIA_ENDPOINT_INTERFACE); } +static void setup_free(void *data); + static void bap_data_free(struct bap_data *data) { if (data->listen_io) { @@ -116,10 +226,12 @@ static void bap_data_free(struct bap_data *data) queue_destroy(data->snks, ep_unregister); queue_destroy(data->srcs, ep_unregister); + queue_destroy(data->bcast, ep_unregister); queue_destroy(data->streams, NULL); + queue_destroy(data->bcast_snks, setup_free); bt_bap_ready_unregister(data->bap, data->ready_id); bt_bap_state_unregister(data->bap, data->state_id); - bt_bap_pac_unregister(data->pac_id); + bt_bap_pac_unregister(data->bap, data->pac_id); bt_bap_unref(data->bap); free(data); } @@ -165,8 +277,13 @@ static gboolean get_uuid(const GDBusPropertyTable *property, if (queue_find(ep->data->snks, NULL, ep)) uuid = PAC_SINK_UUID; - else + else if (queue_find(ep->data->srcs, NULL, ep)) uuid = PAC_SOURCE_UUID; + else if ((queue_find(ep->data->bcast, NULL, ep) + && (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SINK))) + uuid = BCAA_SERVICE_UUID; + else + uuid = BAA_SERVICE_UUID; dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid); @@ -179,13 +296,32 @@ static gboolean get_codec(const GDBusPropertyTable *property, struct bap_ep *ep = data; uint8_t codec; - bt_bap_pac_get_codec(ep->rpac, &codec, NULL, NULL); + /* For broadcast source, rpac is null so the codec + * is retrieved from the lpac + */ + if (ep->rpac == NULL) + bt_bap_pac_get_codec(ep->lpac, &codec, NULL, NULL); + else + bt_bap_pac_get_codec(ep->rpac, &codec, NULL, NULL); dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE, &codec); return TRUE; } +static gboolean has_capabilities(const GDBusPropertyTable *property, void *data) +{ + struct bap_ep *ep = data; + struct iovec *d = NULL; + + bt_bap_pac_get_codec(ep->rpac, NULL, &d, NULL); + + if (d) + return TRUE; + + return FALSE; +} + static gboolean get_capabilities(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { @@ -206,57 +342,353 @@ static gboolean get_capabilities(const GDBusPropertyTable *property, return TRUE; } +static gboolean has_metadata(const GDBusPropertyTable *property, void *data) +{ + struct bap_ep *ep = data; + struct iovec *d = NULL; + + bt_bap_pac_get_codec(ep->rpac, NULL, NULL, &d); + + if (d) + return TRUE; + + return FALSE; +} + +static gboolean get_metadata(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct bap_ep *ep = data; + DBusMessageIter array; + struct iovec *d; + + bt_bap_pac_get_codec(ep->rpac, NULL, NULL, &d); + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, &array); + + dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, + &d->iov_base, d->iov_len); + + dbus_message_iter_close_container(iter, &array); + + return TRUE; +} + static gboolean get_device(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { struct bap_ep *ep = data; const char *path; - path = device_get_path(ep->data->device); + if (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SOURCE) + path = adapter_get_path(ep->data->adapter->adapter); + else + path = device_get_path(ep->data->device); dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path); return TRUE; } +static gboolean get_locations(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct bap_ep *ep = data; + + ep->locations = bt_bap_pac_get_locations(ep->rpac); + + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &ep->locations); + + return TRUE; +} + +static gboolean get_supported_context(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct bap_ep *ep = data; + + ep->supported_context = bt_bap_pac_get_supported_context(ep->rpac); + + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, + &ep->supported_context); + + return TRUE; +} + +static gboolean get_context(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct bap_ep *ep = data; + + ep->context = bt_bap_pac_get_context(ep->rpac); + + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &ep->context); + + return TRUE; +} + +static gboolean qos_exists(const GDBusPropertyTable *property, void *data) +{ + struct bap_ep *ep = data; + struct bt_bap_pac_qos *qos; + + qos = bt_bap_pac_get_qos(ep->rpac); + if (!qos) + return FALSE; + + return TRUE; +} + +static gboolean get_qos(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct bap_ep *ep = data; + struct bt_bap_pac_qos *qos; + DBusMessageIter dict; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &dict); + + qos = bt_bap_pac_get_qos(ep->rpac); + if (!qos) + return FALSE; + + dict_append_entry(&dict, "Framing", DBUS_TYPE_BYTE, &qos->framing); + dict_append_entry(&dict, "PHY", DBUS_TYPE_BYTE, &qos->phy); + dict_append_entry(&dict, "Retransmissions", DBUS_TYPE_BYTE, &qos->rtn); + dict_append_entry(&dict, "MaximumLatency", DBUS_TYPE_UINT16, + &qos->latency); + dict_append_entry(&dict, "MimimumDelay", DBUS_TYPE_UINT32, + &qos->pd_min); + dict_append_entry(&dict, "MaximumDelay", DBUS_TYPE_UINT32, + &qos->pd_max); + dict_append_entry(&dict, "PreferredMimimumDelay", DBUS_TYPE_UINT32, + &qos->ppd_min); + dict_append_entry(&dict, "PreferredMaximumDelay", DBUS_TYPE_UINT32, + &qos->ppd_max); + + dbus_message_iter_close_container(iter, &dict); + + return TRUE; +} + static const GDBusPropertyTable ep_properties[] = { { "UUID", "s", get_uuid, NULL, NULL, G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, { "Codec", "y", get_codec, NULL, NULL, G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, - { "Capabilities", "ay", get_capabilities, NULL, NULL, + { "Capabilities", "ay", get_capabilities, NULL, has_capabilities, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { "Metadata", "ay", get_metadata, NULL, has_metadata, G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, { "Device", "o", get_device, NULL, NULL, G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { "Locations", "u", get_locations, NULL, NULL, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { "SupportedContext", "q", get_supported_context, NULL, NULL, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { "Context", "q", get_context, NULL, NULL, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { "QoS", "a{sv}", get_qos, NULL, qos_exists, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, { } }; -static int parse_array(DBusMessageIter *iter, struct iovec **iov) +static int parse_array(DBusMessageIter *iter, struct iovec *iov) { DBusMessageIter array; if (!iov) return 0; - if (!(*iov)) - *iov = new0(struct iovec, 1); - dbus_message_iter_recurse(iter, &array); - dbus_message_iter_get_fixed_array(&array, &(*iov)->iov_base, - (int *)&(*iov)->iov_len); + dbus_message_iter_get_fixed_array(&array, &iov->iov_base, + (int *)&iov->iov_len); + + return 0; +} + +static int parse_io_qos(const char *key, int var, DBusMessageIter *iter, + struct bt_bap_io_qos *qos) +{ + if (!strcasecmp(key, "Interval")) { + if (var != DBUS_TYPE_UINT32) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->interval); + } else if (!strcasecmp(key, "PHY")) { + if (var != DBUS_TYPE_BYTE) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->phy); + } else if (!strcasecmp(key, "SDU")) { + if (var != DBUS_TYPE_UINT16) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->sdu); + } else if (!strcasecmp(key, "Retransmissions")) { + if (var != DBUS_TYPE_BYTE) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->rtn); + } else if (!strcasecmp(key, "Latency")) { + if (var != DBUS_TYPE_UINT16) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->latency); + } + + return 0; +} + +static int setup_parse_ucast_qos(struct bap_setup *setup, const char *key, + int var, DBusMessageIter *iter) +{ + struct bt_bap_qos *qos = &setup->qos; + + if (!strcasecmp(key, "CIG")) { + if (var != DBUS_TYPE_BYTE) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->ucast.cig_id); + } else if (!strcasecmp(key, "CIS")) { + if (var != DBUS_TYPE_BYTE) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->ucast.cis_id); + } else if (!strcasecmp(key, "Framing")) { + if (var != DBUS_TYPE_BYTE) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->ucast.framing); + } else if (!strcasecmp(key, "PresentationDelay")) { + if (var != DBUS_TYPE_UINT32) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->ucast.delay); + } else if (!strcasecmp(key, "TargetLatency")) { + if (var != DBUS_TYPE_BYTE) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->ucast.target_latency); + } else { + int err; + + err = parse_io_qos(key, var, iter, &qos->ucast.io_qos); + if (err) + return err; + } + + return 0; +} + +static void setup_bcast_destroy(struct bap_setup *setup) +{ + struct bt_bap_qos *qos = &setup->qos; + + util_iov_free(qos->bcast.bcode, 1); +} + +static int setup_parse_bcast_qos(struct bap_setup *setup, const char *key, + int var, DBusMessageIter *iter) +{ + struct bt_bap_qos *qos = &setup->qos; + + if (!strcasecmp(key, "Encryption")) { + if (var != DBUS_TYPE_BYTE) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->bcast.encryption); + } else if (!strcasecmp(key, "BIG")) { + if (var != DBUS_TYPE_BYTE) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->bcast.big); + } else if (!strcasecmp(key, "Options")) { + if (var != DBUS_TYPE_BYTE) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->bcast.options); + } else if (!strcasecmp(key, "Skip")) { + if (var != DBUS_TYPE_UINT16) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->bcast.skip); + } else if (!strcasecmp(key, "SyncTimeout")) { + if (var != DBUS_TYPE_UINT16) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->bcast.sync_timeout); + } else if (!strcasecmp(key, "SyncType")) { + if (var != DBUS_TYPE_BYTE) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->bcast.sync_cte_type); + } else if (!strcasecmp(key, "SyncFactor")) { + if (var != DBUS_TYPE_BYTE) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->bcast.sync_factor); + } else if (!strcasecmp(key, "MSE")) { + if (var != DBUS_TYPE_BYTE) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->bcast.mse); + } else if (!strcasecmp(key, "Timeout")) { + if (var != DBUS_TYPE_UINT16) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->bcast.timeout); + } else if (!strcasecmp(key, "PresentationDelay")) { + if (var != DBUS_TYPE_UINT32) + return -EINVAL; + + dbus_message_iter_get_basic(iter, &qos->bcast.delay); + } else if (!strcasecmp(key, "BCode")) { + struct iovec iov; + + if (var != DBUS_TYPE_ARRAY) + return -EINVAL; + + memset(&iov, 0, sizeof(iov)); + + parse_array(iter, &iov); + + if (iov.iov_len != 16) { + error("Invalid size for BCode: %zu != 16", iov.iov_len); + return -EINVAL; + } + + util_iov_free(qos->bcast.bcode, 1); + qos->bcast.bcode = util_iov_dup(&iov, 1); + } else { + int err; + + err = parse_io_qos(key, var, iter, &qos->bcast.io_qos); + if (err) + return err; + } + return 0; } -static int parse_properties(DBusMessageIter *props, struct iovec **caps, - struct iovec **metadata, struct bt_bap_qos *qos) +static int setup_parse_qos(struct bap_setup *setup, DBusMessageIter *iter) { + DBusMessageIter array; const char *key; - while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) { + dbus_message_iter_recurse(iter, &array); + + while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) { DBusMessageIter value, entry; - int var; + int var, err; - dbus_message_iter_recurse(props, &entry); + dbus_message_iter_recurse(&array, &entry); dbus_message_iter_get_basic(&entry, &key); dbus_message_iter_next(&entry); @@ -264,82 +696,62 @@ static int parse_properties(DBusMessageIter *props, struct iovec **caps, var = dbus_message_iter_get_arg_type(&value); - if (!strcasecmp(key, "Capabilities")) { - if (var != DBUS_TYPE_ARRAY) - goto fail; + err = setup->qos_parser(setup, key, var, &value); + if (err) { + DBG("Failed parsing %s", key); + return err; + } - if (parse_array(&value, caps)) - goto fail; - } else if (!strcasecmp(key, "Metadata")) { - if (var != DBUS_TYPE_ARRAY) - goto fail; + dbus_message_iter_next(&array); + } - if (parse_array(&value, metadata)) - goto fail; - } else if (!strcasecmp(key, "CIG")) { - if (var != DBUS_TYPE_BYTE) - goto fail; + return 0; +} - dbus_message_iter_get_basic(&value, &qos->cig_id); - } else if (!strcasecmp(key, "CIS")) { - if (var != DBUS_TYPE_BYTE) - goto fail; +static int setup_parse_configuration(struct bap_setup *setup, + DBusMessageIter *props) +{ + const char *key; + struct iovec iov; - dbus_message_iter_get_basic(&value, &qos->cis_id); - } else if (!strcasecmp(key, "Interval")) { - if (var != DBUS_TYPE_UINT32) - goto fail; + memset(&iov, 0, sizeof(iov)); - dbus_message_iter_get_basic(&value, &qos->interval); - } else if (!strcasecmp(key, "Framing")) { - dbus_bool_t val; + while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter value, entry; + int var; - if (var != DBUS_TYPE_BOOLEAN) - goto fail; + dbus_message_iter_recurse(props, &entry); + dbus_message_iter_get_basic(&entry, &key); - dbus_message_iter_get_basic(&value, &val); + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &value); - qos->framing = val; - } else if (!strcasecmp(key, "PHY")) { - const char *str; + var = dbus_message_iter_get_arg_type(&value); - if (var != DBUS_TYPE_STRING) + if (!strcasecmp(key, "Capabilities")) { + if (var != DBUS_TYPE_ARRAY) goto fail; - dbus_message_iter_get_basic(&value, &str); - - if (!strcasecmp(str, "1M")) - qos->phy = 0x01; - else if (!strcasecmp(str, "2M")) - qos->phy = 0x02; - else - goto fail; - } else if (!strcasecmp(key, "SDU")) { - if (var != DBUS_TYPE_UINT16) + if (parse_array(&value, &iov)) goto fail; - dbus_message_iter_get_basic(&value, &qos->sdu); - } else if (!strcasecmp(key, "Retransmissions")) { - if (var != DBUS_TYPE_BYTE) + util_iov_free(setup->caps, 1); + setup->caps = util_iov_dup(&iov, 1); + } else if (!strcasecmp(key, "Metadata")) { + if (var != DBUS_TYPE_ARRAY) goto fail; - dbus_message_iter_get_basic(&value, &qos->rtn); - } else if (!strcasecmp(key, "Latency")) { - if (var != DBUS_TYPE_UINT16) + if (parse_array(&value, &iov)) goto fail; - dbus_message_iter_get_basic(&value, &qos->latency); - } else if (!strcasecmp(key, "Delay")) { - if (var != DBUS_TYPE_UINT32) + util_iov_free(setup->metadata, 1); + setup->metadata = util_iov_dup(&iov, 1); + } else if (!strcasecmp(key, "QoS")) { + if (var != DBUS_TYPE_ARRAY) goto fail; - dbus_message_iter_get_basic(&value, &qos->delay); - } else if (!strcasecmp(key, "TargetLatency")) { - if (var != DBUS_TYPE_BYTE) + if (setup_parse_qos(setup, &value)) goto fail; - - dbus_message_iter_get_basic(&value, - &qos->target_latency); } dbus_message_iter_next(props); @@ -350,92 +762,184 @@ static int parse_properties(DBusMessageIter *props, struct iovec **caps, fail: DBG("Failed parsing %s", key); - if (*caps) { - free(*caps); - *caps = NULL; - } - return -EINVAL; } static void qos_cb(struct bt_bap_stream *stream, uint8_t code, uint8_t reason, void *user_data) { - struct bap_ep *ep = user_data; + struct bap_setup *setup = user_data; DBusMessage *reply; DBG("stream %p code 0x%02x reason 0x%02x", stream, code, reason); - if (!ep->msg) + setup->id = 0; + + if (!setup->msg) return; if (!code) - reply = dbus_message_new_method_return(ep->msg); + reply = dbus_message_new_method_return(setup->msg); else - reply = btd_error_failed(ep->msg, "Unable to configure"); + reply = btd_error_failed(setup->msg, "Unable to configure"); g_dbus_send_message(btd_get_dbus_connection(), reply); - dbus_message_unref(ep->msg); - ep->msg = NULL; + dbus_message_unref(setup->msg); + setup->msg = NULL; } static void config_cb(struct bt_bap_stream *stream, uint8_t code, uint8_t reason, void *user_data) { - struct bap_ep *ep = user_data; + struct bap_setup *setup = user_data; DBusMessage *reply; DBG("stream %p code 0x%02x reason 0x%02x", stream, code, reason); - ep->id = 0; + setup->id = 0; + + if (!code) { + /* Check state is already set to config then proceed to qos */ + if (bt_bap_stream_get_state(stream) == + BT_BAP_STREAM_STATE_CONFIG) { + setup->id = bt_bap_stream_qos(stream, &setup->qos, + qos_cb, setup); + if (!setup->id) { + error("Failed to Configure QoS"); + bt_bap_stream_release(stream, NULL, NULL); + } + } - if (!code) return; + } - if (!ep->msg) + if (!setup->msg) return; - reply = btd_error_failed(ep->msg, "Unable to configure"); + reply = btd_error_failed(setup->msg, "Unable to configure"); g_dbus_send_message(btd_get_dbus_connection(), reply); - dbus_message_unref(ep->msg); - ep->msg = NULL; + dbus_message_unref(setup->msg); + setup->msg = NULL; } -static void bap_io_close(struct bap_ep *ep) +static void setup_io_close(void *data, void *user_data) { + struct bap_setup *setup = data; int fd; - if (ep->io_id) { - g_source_remove(ep->io_id); - ep->io_id = 0; + if (setup->io_id) { + g_source_remove(setup->io_id); + setup->io_id = 0; } - if (!ep->io) + if (!setup->io) return; - DBG("ep %p", ep); + DBG("setup %p", setup); - fd = g_io_channel_unix_get_fd(ep->io); + fd = g_io_channel_unix_get_fd(setup->io); close(fd); - g_io_channel_unref(ep->io); - ep->io = NULL; + g_io_channel_unref(setup->io); + setup->io = NULL; + setup->cig_active = false; + + bt_bap_stream_io_connecting(setup->stream, -1); +} + +static void ep_close(struct bap_ep *ep) +{ + if (!ep) + return; + + queue_foreach(ep->setups, setup_io_close, NULL); +} + +static struct bap_setup *setup_new(struct bap_ep *ep) +{ + struct bap_setup *setup; + + setup = new0(struct bap_setup, 1); + setup->ep = ep; + + /* Broadcast Source has endpoints in bcast list, Broadcast Sink + * does not have endpoints + */ + if (((ep != NULL) && queue_find(ep->data->bcast, NULL, ep)) || + (ep == NULL)) { + /* Mark BIG and BIS to be auto assigned */ + setup->qos.bcast.big = BT_ISO_QOS_BIG_UNSET; + setup->qos.bcast.bis = BT_ISO_QOS_BIS_UNSET; + setup->qos.bcast.sync_factor = 0x01; + setup->qos.bcast.sync_timeout = BT_ISO_SYNC_TIMEOUT; + setup->qos.bcast.timeout = BT_ISO_SYNC_TIMEOUT; + setup->qos_parser = setup_parse_bcast_qos; + setup->destroy = setup_bcast_destroy; + } else { + /* Mark CIG and CIS to be auto assigned */ + setup->qos.ucast.cig_id = BT_ISO_QOS_CIG_UNSET; + setup->qos.ucast.cis_id = BT_ISO_QOS_CIS_UNSET; + setup->qos_parser = setup_parse_ucast_qos; + } + + if (ep) { + if (!ep->setups) + ep->setups = queue_new(); + + queue_push_tail(ep->setups, setup); + + DBG("ep %p setup %p", ep, setup); + } + + return setup; +} + +static void setup_free(void *data) +{ + struct bap_setup *setup = data; + DBusMessage *reply; + + DBG("%p", setup); + + if (setup->stream && setup->id) { + bt_bap_stream_cancel(setup->stream, setup->id); + setup->id = 0; + } + + if (setup->msg) { + reply = btd_error_failed(setup->msg, "Canceled"); + g_dbus_send_message(btd_get_dbus_connection(), reply); + dbus_message_unref(setup->msg); + setup->msg = NULL; + } + + if (setup->ep) + queue_remove(setup->ep->setups, setup); + + setup_io_close(setup, NULL); + + util_iov_free(setup->caps, 1); + util_iov_free(setup->metadata, 1); + util_iov_free(setup->base, 1); + + if (setup->destroy) + setup->destroy(setup); + + free(setup); } static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg, void *data) { struct bap_ep *ep = data; + struct bap_setup *setup; const char *path; DBusMessageIter args, props; - if (ep->msg) - return btd_error_busy(msg); - dbus_message_iter_init(msg, &args); dbus_message_iter_get_basic(&args, &path); @@ -445,67 +949,526 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg, if (dbus_message_iter_get_arg_type(&props) != DBUS_TYPE_DICT_ENTRY) return btd_error_invalid_args(msg); - /* Disconnect IO if connecting since QoS is going to be reconfigured */ - if (bt_bap_stream_io_is_connecting(ep->stream, NULL)) { - bap_io_close(ep); - bt_bap_stream_io_connecting(ep->stream, -1); - } + /* Broadcast source supports multiple setups, each setup will be BIS + * and will be configured with the set_configuration command + * TO DO reconfiguration of a BIS. + */ + if (bt_bap_pac_get_type(ep->lpac) != BT_BAP_BCAST_SOURCE) + ep_close(ep); - /* Mark CIG and CIS to be auto assigned */ - ep->qos.cig_id = BT_ISO_QOS_CIG_UNSET; - ep->qos.cis_id = BT_ISO_QOS_CIS_UNSET; + setup = setup_new(ep); - if (parse_properties(&props, &ep->caps, &ep->metadata, &ep->qos) < 0) { - DBG("Unable to parse properties"); + if (setup_parse_configuration(setup, &props) < 0) { + DBG("Unable to parse configuration"); + setup_free(setup); return btd_error_invalid_args(msg); } - /* TODO: Check if stream capabilities match add support for Latency - * and PHY. - */ - if (ep->stream) - ep->id = bt_bap_stream_config(ep->stream, &ep->qos, ep->caps, - config_cb, ep); - else - ep->stream = bt_bap_config(ep->data->bap, ep->lpac, ep->rpac, - &ep->qos, ep->caps, - config_cb, ep); - - if (!ep->stream) { + setup->stream = bt_bap_stream_new(ep->data->bap, ep->lpac, ep->rpac, + &setup->qos, setup->caps); + bt_bap_stream_set_user_data(setup->stream, ep->path); + setup->id = bt_bap_stream_config(setup->stream, &setup->qos, + setup->caps, config_cb, setup); + if (!setup->id) { DBG("Unable to config stream"); - free(ep->caps); - ep->caps = NULL; + setup_free(setup); return btd_error_invalid_args(msg); } - bt_bap_stream_set_user_data(ep->stream, ep->path); - ep->msg = dbus_message_ref(msg); + if (setup->metadata && setup->metadata->iov_len) + bt_bap_stream_metadata(setup->stream, setup->metadata, NULL, + NULL); + + switch (bt_bap_stream_get_type(setup->stream)) { + case BT_BAP_STREAM_TYPE_UCAST: + setup->msg = dbus_message_ref(msg); + break; + case BT_BAP_STREAM_TYPE_BCAST: + /* No message sent over the air for broadcast */ + setup->id = 0; + + if (ep->data->service) + service_set_connecting(ep->data->service); + + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + } return NULL; } -static const GDBusMethodTable ep_methods[] = { +static void iso_bcast_confirm_cb(GIOChannel *io, GError *err, void *user_data) +{ + struct bap_bcast_pa_req *req = user_data; + struct bap_setup *setup; + int fd; + struct bap_data *bap_data = req->bap_data; + + DBG("BIG Sync completed"); + + /* The order of the BIS fds notified from kernel corresponds + * to the order of the BISes that were enqueued before + * calling bt_io_bcast_accept. + */ + setup = queue_pop_head(req->data.setups); + + if (queue_isempty(req->data.setups)) { + /* All fds have been notified. Mark service as connected. */ + btd_service_connecting_complete(bap_data->service, 0); + + if (req->io) { + g_io_channel_unref(req->io); + g_io_channel_shutdown(req->io, TRUE, NULL); + req->io = NULL; + } + + queue_remove(bap_data->adapter->bcast_pa_requests, req); + queue_destroy(req->data.setups, NULL); + free(req); + } + + fd = g_io_channel_unix_get_fd(io); + + if (bt_bap_stream_set_io(setup->stream, fd)) { + g_io_channel_set_close_on_unref(io, FALSE); + return; + } +} + +static void print_ltv(size_t i, uint8_t l, uint8_t t, uint8_t *v, + void *user_data) +{ + util_debug(user_data, NULL, "CC #%zu: l:%u t:%u", i, l, t); + util_hexdump(' ', v, l, user_data, NULL); +} + +static void create_stream_for_bis(struct bap_data *bap_data, + struct bt_bap_pac *lpac, struct bt_iso_qos *qos, + struct iovec *caps, struct iovec *meta, char *path) +{ + struct bap_setup *setup; + + setup = setup_new(NULL); + + /* Create BAP QoS structure */ + setup->qos.bcast.big = qos->bcast.big; + setup->qos.bcast.bis = qos->bcast.bis; + setup->qos.bcast.sync_factor = qos->bcast.sync_factor; + setup->qos.bcast.packing = qos->bcast.packing; + setup->qos.bcast.framing = qos->bcast.framing; + setup->qos.bcast.encryption = qos->bcast.encryption; + if (setup->qos.bcast.encryption) + setup->qos.bcast.bcode = util_iov_new(qos->bcast.bcode, + sizeof(qos->bcast.bcode)); + setup->qos.bcast.options = qos->bcast.options; + setup->qos.bcast.skip = qos->bcast.skip; + setup->qos.bcast.sync_timeout = qos->bcast.sync_timeout; + setup->qos.bcast.sync_cte_type = + qos->bcast.sync_cte_type; + setup->qos.bcast.mse = qos->bcast.mse; + setup->qos.bcast.timeout = qos->bcast.timeout; + setup->qos.bcast.io_qos.interval = + qos->bcast.in.interval; + setup->qos.bcast.io_qos.latency = qos->bcast.in.latency; + setup->qos.bcast.io_qos.phy = qos->bcast.in.phy; + setup->qos.bcast.io_qos.rtn = qos->bcast.in.rtn; + setup->qos.bcast.io_qos.sdu = qos->bcast.in.sdu; + + queue_push_tail(bap_data->bcast_snks, setup); + + /* Create and configure stream */ + setup->stream = bt_bap_stream_new(bap_data->bap, + lpac, NULL, &setup->qos, caps); + + bt_bap_stream_set_user_data(setup->stream, path); + bt_bap_stream_config(setup->stream, &setup->qos, + caps, NULL, NULL); + bt_bap_stream_metadata(setup->stream, meta, + NULL, NULL); +} + +static bool parse_base(struct bap_data *bap_data, struct bt_iso_base *base, + struct bt_iso_qos *qos, util_debug_func_t func) +{ + struct iovec iov = { + .iov_base = base->base, + .iov_len = base->base_len, + }; + uint32_t pres_delay; + uint8_t num_subgroups; + bool ret = true; + + util_debug(func, NULL, "BASE len: %ld", iov.iov_len); + + if (!util_iov_pull_le24(&iov, &pres_delay)) + return false; + util_debug(func, NULL, "PresentationDelay: %d", pres_delay); + + if (!util_iov_pull_u8(&iov, &num_subgroups)) + return false; + util_debug(func, NULL, "Number of Subgroups: %d", num_subgroups); + + /* Loop subgroups */ + for (int idx = 0; idx < num_subgroups; idx++) { + uint8_t num_bis; + struct bt_bap_codec codec; + struct iovec *l2_caps = NULL; + struct iovec *meta = NULL; + + util_debug(func, NULL, "Subgroup #%d", idx); + + if (!util_iov_pull_u8(&iov, &num_bis)) { + ret = false; + goto fail; + } + util_debug(func, NULL, "Number of BISes: %d", num_bis); + + memcpy(&codec, + util_iov_pull_mem(&iov, + sizeof(struct bt_bap_codec)), + sizeof(struct bt_bap_codec)); + util_debug(func, NULL, "Codec: ID %d CID 0x%2.2x VID 0x%2.2x", + codec.id, codec.cid, codec.vid); + + /* Level 2 */ + /* Read Codec Specific Configuration */ + l2_caps = new0(struct iovec, 1); + if (!util_iov_pull_u8(&iov, (void *)&l2_caps->iov_len)) { + ret = false; + goto group_fail; + } + + util_iov_memcpy(l2_caps, util_iov_pull_mem(&iov, + l2_caps->iov_len), + l2_caps->iov_len); + + /* Print Codec Specific Configuration */ + util_debug(func, NULL, "CC len: %ld", l2_caps->iov_len); + util_ltv_foreach(l2_caps->iov_base, l2_caps->iov_len, NULL, + print_ltv, func); + + /* Read Metadata */ + meta = new0(struct iovec, 1); + if (!util_iov_pull_u8(&iov, (void *)&meta->iov_len)) { + ret = false; + goto group_fail; + } + + util_iov_memcpy(meta, + util_iov_pull_mem(&iov, meta->iov_len), + meta->iov_len); + + /* Print Metadata */ + util_debug(func, NULL, "Metadata len: %i", + (uint8_t)meta->iov_len); + util_hexdump(' ', meta->iov_base, meta->iov_len, func, NULL); + + /* Level 3 */ + for (; num_bis; num_bis--) { + uint8_t bis_index; + struct iovec *l3_caps; + struct iovec *merged_caps; + struct bt_bap_pac *matched_lpac; + char *path; + int err; + + if (!util_iov_pull_u8(&iov, &bis_index)) { + ret = false; + goto group_fail; + } + + util_debug(func, NULL, "BIS #%d", bis_index); + err = asprintf(&path, "%s/bis%d", + device_get_path(bap_data->device), + bis_index); + if (err < 0) + continue; + + /* Read Codec Specific Configuration */ + l3_caps = new0(struct iovec, 1); + if (!util_iov_pull_u8(&iov, + (void *)&l3_caps->iov_len)) { + free(l3_caps); + free(path); + ret = false; + goto group_fail; + } + + util_iov_memcpy(l3_caps, + util_iov_pull_mem(&iov, + l3_caps->iov_len), + l3_caps->iov_len); + + /* Print Codec Specific Configuration */ + util_debug(func, NULL, "CC Len: %d", + (uint8_t)l3_caps->iov_len); + util_ltv_foreach(l3_caps->iov_base, + l3_caps->iov_len, NULL, print_ltv, + func); + + merged_caps = bt_bap_merge_caps(l2_caps, l3_caps); + if (!merged_caps) { + free(path); + continue; + } + + bass_add_stream(bap_data->device, meta, merged_caps, + qos, idx, bis_index); + + if (!bass_check_bis(bap_data->device, bis_index)) { + /* If this Broadcast Sink is acting as a Scan + * Delegator, only attempt to create streams + * for the BISes required by the peer Broadcast + * Assistant. + */ + continue; + } + + /* Check if this BIS matches any local PAC */ + bt_bap_verify_bis(bap_data->bap, bis_index, + merged_caps, &matched_lpac); + + if (matched_lpac == NULL) { + free(path); + continue; + } + + create_stream_for_bis(bap_data, matched_lpac, qos, + merged_caps, meta, path); + } + +group_fail: + if (l2_caps != NULL) + free(l2_caps); + if (meta != NULL) + free(meta); + if (!ret) + break; + } + +fail: + if (!ret) + util_debug(func, NULL, "Unable to parse Base"); + + return ret; +} + +static gboolean big_info_report_cb(GIOChannel *io, GIOCondition cond, + gpointer user_data) +{ + GError *err = NULL; + struct bap_bcast_pa_req *req = user_data; + struct bap_data *data = btd_service_get_user_data(req->data.service); + struct bt_iso_base base; + struct bt_iso_qos qos; + + DBG("BIG Info received"); + + bt_io_get(io, &err, + BT_IO_OPT_BASE, &base, + BT_IO_OPT_QOS, &qos, + BT_IO_OPT_INVALID); + if (err) { + error("%s", err->message); + g_error_free(err); + g_io_channel_shutdown(io, TRUE, NULL); + req->io_id = 0; + return FALSE; + } + + /* Close the listen io */ + g_io_channel_shutdown(data->listen_io, TRUE, NULL); + g_io_channel_unref(data->listen_io); + data->listen_io = NULL; + + if (req->type == BAP_PA_LONG_REQ) { + /* If long-lived PA sync was requested, keep a reference + * to the PA sync io to keep the sync active. + */ + data->listen_io = io; + g_io_channel_ref(io); + } else { + /* For short-lived PA, the sync is no longer needed at + * this point, so the io can be closed. + */ + g_io_channel_shutdown(io, TRUE, NULL); + } + + /* Notify the BASS plugin about the session. */ + bass_bcast_probe(data->device, data->bap); + + /* Analyze received BASE data and create remote media endpoints for each + * BIS matching our capabilities + */ + parse_base(data, &base, &qos, bap_debug); + + service_set_connecting(req->data.service); + + queue_remove(data->adapter->bcast_pa_requests, req); + req->io_id = 0; + free(req); + + return FALSE; +} + +static void iso_pa_sync_confirm_cb(GIOChannel *io, void *user_data) +{ + struct bap_bcast_pa_req *req = user_data; + /* PA Sync was established, wait for BIG Info report so that the + * encryption flag is also available. + */ + DBG("PA Sync done"); + req->io_id = g_io_add_watch(io, G_IO_OUT, big_info_report_cb, + user_data); +} + +static bool match_data_bap_data(const void *data, const void *match_data) +{ + const struct bap_data *bdata = data; + const struct btd_adapter *adapter = match_data; + + return bdata->user_data == adapter; +} + +static const GDBusMethodTable ep_methods[] = { { GDBUS_EXPERIMENTAL_ASYNC_METHOD("SetConfiguration", GDBUS_ARGS({ "endpoint", "o" }, - { "properties", "a{sv}" } ), + { "Configuration", "a{sv}" } ), NULL, set_configuration) }, { }, }; +static void ep_cancel_select(struct bap_ep *ep); + static void ep_free(void *data) { struct bap_ep *ep = data; + struct queue *setups = ep->setups; - if (ep->id) - bt_bap_stream_cancel(ep->stream, ep->id); + ep_cancel_select(ep); - bap_io_close(ep); - - free(ep->caps); + ep->setups = NULL; + queue_destroy(setups, setup_free); free(ep->path); free(ep); } +struct match_ep { + struct bt_bap_pac *lpac; + struct bt_bap_pac *rpac; +}; + +static bool match_ep(const void *data, const void *user_data) +{ + const struct bap_ep *ep = data; + const struct match_ep *match = user_data; + + if (ep->lpac != match->lpac) + return false; + + return ep->rpac == match->rpac; +} + +static struct bap_ep *ep_register_bcast(struct bap_data *data, + struct bt_bap_pac *lpac, + struct bt_bap_pac *rpac) +{ + struct btd_adapter *adapter = data->adapter->adapter; + struct btd_device *device = data->device; + struct bap_ep *ep; + struct queue *queue; + int i, err = 0; + const char *suffix; + struct match_ep match = { lpac, rpac }; + + switch (bt_bap_pac_get_type(lpac)) { + case BT_BAP_BCAST_SOURCE: + case BT_BAP_BCAST_SINK: + queue = data->bcast; + i = queue_length(data->bcast); + suffix = "bcast"; + break; + default: + return NULL; + } + + ep = queue_find(queue, match_ep, &match); + if (ep) + return ep; + + ep = new0(struct bap_ep, 1); + ep->data = data; + ep->lpac = lpac; + ep->rpac = rpac; + + if (device) + ep->data->device = device; + + switch (bt_bap_pac_get_type(lpac)) { + case BT_BAP_BCAST_SOURCE: + err = asprintf(&ep->path, "%s/pac_%s%d", + adapter_get_path(adapter), suffix, i); + break; + case BT_BAP_BCAST_SINK: + err = asprintf(&ep->path, "%s/pac_%s%d", + device_get_path(device), suffix, i); + break; + } + + if (err < 0) { + error("Could not allocate path for remote pac %s/pac%d", + adapter_get_path(adapter), i); + free(ep); + return NULL; + } + + if (g_dbus_register_interface(btd_get_dbus_connection(), + ep->path, MEDIA_ENDPOINT_INTERFACE, + ep_methods, NULL, ep_properties, + ep, ep_free) == FALSE) { + error("Could not register remote ep %s", ep->path); + ep_free(ep); + return NULL; + } + + /* + * The broadcast source local endpoint has only lpac and broadcast + * sink local endpoint has a rpac and a lpac + */ + if (rpac) + bt_bap_pac_set_user_data(rpac, ep->path); + + DBG("ep %p lpac %p rpac %p path %s", ep, ep->lpac, ep->rpac, ep->path); + + queue_push_tail(queue, ep); + + return ep; +} + +static void ep_update_properties(struct bap_ep *ep) +{ + if (!ep->rpac) + return; + + if (ep->locations != bt_bap_pac_get_locations(ep->rpac)) + g_dbus_emit_property_changed(btd_get_dbus_connection(), + ep->path, + MEDIA_ENDPOINT_INTERFACE, + "Locations"); + + if (ep->supported_context != + bt_bap_pac_get_supported_context(ep->rpac)) + g_dbus_emit_property_changed(btd_get_dbus_connection(), + ep->path, + MEDIA_ENDPOINT_INTERFACE, + "SupportedContext"); + + if (ep->context != bt_bap_pac_get_context(ep->rpac)) + g_dbus_emit_property_changed(btd_get_dbus_connection(), + ep->path, + MEDIA_ENDPOINT_INTERFACE, + "Context"); +} + static struct bap_ep *ep_register(struct btd_service *service, struct bt_bap_pac *lpac, struct bt_bap_pac *rpac) @@ -516,6 +1479,7 @@ static struct bap_ep *ep_register(struct btd_service *service, struct queue *queue; int i, err; const char *suffix; + struct match_ep match = { lpac, rpac }; switch (bt_bap_pac_get_type(rpac)) { case BT_BAP_SINK: @@ -532,6 +1496,12 @@ static struct bap_ep *ep_register(struct btd_service *service, return NULL; } + ep = queue_find(queue, match_ep, &match); + if (ep) { + ep_update_properties(ep); + return ep; + } + ep = new0(struct bap_ep, 1); ep->data = data; ep->lpac = lpac; @@ -564,42 +1534,75 @@ static struct bap_ep *ep_register(struct btd_service *service, return ep; } +static void setup_config(void *data, void *user_data) +{ + struct bap_setup *setup = data; + struct bap_ep *ep = setup->ep; + + DBG("setup %p caps %p metadata %p", setup, setup->caps, + setup->metadata); + + /* TODO: Check if stream capabilities match add support for Latency + * and PHY. + */ + if (!setup->stream) + setup->stream = bt_bap_stream_new(ep->data->bap, ep->lpac, + ep->rpac, &setup->qos, + setup->caps); + + setup->id = bt_bap_stream_config(setup->stream, &setup->qos, + setup->caps, config_cb, setup); + if (!setup->id) { + DBG("Unable to config stream"); + setup_free(setup); + return; + } + + if (setup->metadata && setup->metadata->iov_len) + bt_bap_stream_metadata(setup->stream, setup->metadata, NULL, + NULL); + + bt_bap_stream_set_user_data(setup->stream, ep->path); +} + +static void bap_config(void *data, void *user_data) +{ + struct bap_ep *ep = data; + + queue_foreach(ep->setups, setup_config, NULL); +} + static void select_cb(struct bt_bap_pac *pac, int err, struct iovec *caps, struct iovec *metadata, struct bt_bap_qos *qos, void *user_data) { struct bap_ep *ep = user_data; + struct bap_setup *setup; if (err) { error("err %d", err); - return; + ep->data->selecting--; + goto done; } - ep->caps = caps; - ep->metadata = metadata; - ep->qos = *qos; + setup = setup_new(ep); + setup->caps = util_iov_dup(caps, 1); + setup->metadata = util_iov_dup(metadata, 1); + setup->qos = *qos; - /* TODO: Check if stream capabilities match add support for Latency - * and PHY. - */ - if (ep->stream) - ep->id = bt_bap_stream_config(ep->stream, &ep->qos, ep->caps, - config_cb, ep); - else - ep->stream = bt_bap_config(ep->data->bap, ep->lpac, ep->rpac, - &ep->qos, ep->caps, - config_cb, ep); + DBG("selecting %d", ep->data->selecting); + ep->data->selecting--; - if (!ep->stream) { - DBG("Unable to config stream"); - free(ep->caps); - ep->caps = NULL; - } +done: + if (ep->data->selecting) + return; - bt_bap_stream_set_user_data(ep->stream, ep->path); + queue_foreach(ep->data->srcs, bap_config, NULL); + queue_foreach(ep->data->snks, bap_config, NULL); + queue_foreach(ep->data->bcast, bap_config, NULL); } -static bool pac_found(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, +static bool pac_register(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, void *user_data) { struct btd_service *service = user_data; @@ -608,14 +1611,80 @@ static bool pac_found(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, DBG("lpac %p rpac %p", lpac, rpac); ep = ep_register(service, lpac, rpac); - if (!ep) { + if (!ep) error("Unable to register endpoint for pac %p", rpac); + + return true; +} + +static bool pac_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, + void *user_data) +{ + struct btd_service *service = user_data; + struct bap_data *data = btd_service_get_user_data(service); + struct match_ep match = { lpac, rpac }; + struct queue *queue; + struct bap_ep *ep; + + switch (bt_bap_pac_get_type(rpac)) { + case BT_BAP_SINK: + queue = data->snks; + break; + case BT_BAP_SOURCE: + queue = data->srcs; + break; + default: + return true; + } + + ep = queue_find(queue, match_ep, &match); + if (!ep) { + error("Unable to find endpoint for pac %p", rpac); return true; } /* TODO: Cache LRU? */ if (btd_service_is_initiator(service)) - bt_bap_select(lpac, rpac, select_cb, ep); + bt_bap_select(lpac, rpac, &ep->data->selecting, select_cb, ep); + + return true; +} + +static bool pac_cancel_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, + void *user_data) +{ + struct bap_ep *ep = user_data; + + bt_bap_cancel_select(lpac, select_cb, ep); + + return true; +} + +static void ep_cancel_select(struct bap_ep *ep) +{ + struct bt_bap *bap = ep->data->bap; + + bt_bap_foreach_pac(bap, BT_BAP_SOURCE, pac_cancel_select, ep); + bt_bap_foreach_pac(bap, BT_BAP_SINK, pac_cancel_select, ep); +} + +static bool pac_found_bcast(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, + void *user_data) +{ + struct bap_data *data = user_data; + struct bap_ep *ep; + + DBG("lpac %p rpac %p", lpac, rpac); + + ep = ep_register_bcast(user_data, lpac, rpac); + if (!ep) { + error("Unable to register endpoint for pac %p", rpac); + return true; + } + + /* Mark the device as connetable if an Endpoint is registered */ + if (data->device) + btd_device_set_connectable(data->device, true); return true; } @@ -626,28 +1695,82 @@ static void bap_ready(struct bt_bap *bap, void *user_data) DBG("bap %p", bap); - bt_bap_foreach_pac(bap, BT_BAP_SOURCE, pac_found, service); - bt_bap_foreach_pac(bap, BT_BAP_SINK, pac_found, service); + /* Register all ep before selecting, so that sound server + * knows all. + */ + bt_bap_foreach_pac(bap, BT_BAP_SOURCE, pac_register, service); + bt_bap_foreach_pac(bap, BT_BAP_SINK, pac_register, service); + + bt_bap_foreach_pac(bap, BT_BAP_SOURCE, pac_select, service); + bt_bap_foreach_pac(bap, BT_BAP_SINK, pac_select, service); +} + +static bool match_setup_stream(const void *data, const void *user_data) +{ + const struct bap_setup *setup = data; + const struct bt_bap_stream *stream = user_data; + + return setup->stream == stream; } -static bool match_ep_by_stream(const void *data, const void *user_data) +static bool match_ep_stream(const void *data, const void *user_data) { const struct bap_ep *ep = data; const struct bt_bap_stream *stream = user_data; - return ep->stream == stream; + return queue_find(ep->setups, match_setup_stream, stream); } -static struct bap_ep *bap_find_ep_by_stream(struct bap_data *data, +static struct bap_setup *bap_find_setup_by_stream(struct bap_data *data, struct bt_bap_stream *stream) { - struct bap_ep *ep; + struct bap_ep *ep = NULL; + struct queue *queue = NULL; + + switch (bt_bap_stream_get_type(stream)) { + case BT_BAP_STREAM_TYPE_UCAST: + ep = queue_find(data->snks, match_ep_stream, stream); + if (!ep) + ep = queue_find(data->srcs, match_ep_stream, stream); + + break; + case BT_BAP_STREAM_TYPE_BCAST: + ep = queue_find(data->bcast, match_ep_stream, stream); + break; + } - ep = queue_find(data->snks, match_ep_by_stream, stream); if (ep) - return ep; + queue = ep->setups; + else + queue = data->bcast_snks; - return queue_find(data->srcs, match_ep_by_stream, stream); + return queue_find(queue, match_setup_stream, stream); +} + +static void iso_connect_bcast_cb(GIOChannel *chan, GError *err, + gpointer user_data) +{ + struct bt_bap_stream *stream = user_data; + int fd; + + if (err) { + error("%s", err->message); + bt_bap_stream_set_io(stream, -1); + return; + } + + DBG("ISO connected"); + + fd = g_io_channel_unix_get_fd(chan); + + if (bt_bap_stream_set_io(stream, fd)) { + bt_bap_stream_start(stream, NULL, NULL); + g_io_channel_set_close_on_unref(chan, FALSE); + return; + } + + error("Unable to set IO"); + bt_bap_stream_set_io(stream, -1); } static void iso_connect_cb(GIOChannel *chan, GError *err, gpointer user_data) @@ -679,11 +1802,11 @@ static void bap_iso_qos(struct bt_bap_qos *qos, struct bt_iso_io_qos *io) if (!qos) return; - io->interval = qos->interval; - io->latency = qos->latency; - io->sdu = qos->sdu; - io->phy = qos->phy; - io->rtn = qos->rtn; + io->interval = qos->ucast.io_qos.interval; + io->latency = qos->ucast.io_qos.latency; + io->sdu = qos->ucast.io_qos.sdu; + io->phy = qos->ucast.io_qos.phy; + io->rtn = qos->ucast.io_qos.rtn; } static bool match_stream_qos(const void *data, const void *user_data) @@ -694,10 +1817,10 @@ static bool match_stream_qos(const void *data, const void *user_data) qos = bt_bap_stream_get_qos((void *)stream); - if (iso_qos->cig != qos->cig_id) + if (iso_qos->ucast.cig != qos->ucast.cig_id) return false; - return iso_qos->cis == qos->cis_id; + return iso_qos->ucast.cis == qos->ucast.cis_id; } static void iso_confirm_cb(GIOChannel *io, void *user_data) @@ -719,7 +1842,7 @@ static void iso_confirm_cb(GIOChannel *io, void *user_data) } DBG("ISO: incoming connect from %s (CIG 0x%02x CIS 0x%02x)", - address, qos.cig, qos.cis); + address, qos.ucast.cig, qos.ucast.cis); stream = queue_remove_if(data->streams, match_stream_qos, &qos); if (!stream) { @@ -739,8 +1862,9 @@ drop: g_io_channel_shutdown(io, TRUE, NULL); } -static void bap_accept_io(struct bap_data *data, struct bt_bap_stream *stream, - int fd, int defer) +static void setup_accept_io(struct bap_setup *setup, + struct bt_bap_stream *stream, + int fd, int defer) { char c; struct pollfd pfd; @@ -769,66 +1893,174 @@ static void bap_accept_io(struct bap_data *data, struct bt_bap_stream *stream, goto fail; } - if (!(pfd.revents & POLLOUT)) { - if (read(fd, &c, 1) < 0) { - error("read: %s (%d)", strerror(errno), errno); - goto fail; - } - } + if (!(pfd.revents & POLLOUT)) { + if (read(fd, &c, 1) < 0) { + error("read: %s (%d)", strerror(errno), errno); + goto fail; + } + } + + setup->cig_active = true; + + return; + +fail: + close(fd); +} + +struct cig_busy_data { + struct btd_adapter *adapter; + uint8_t cig; +}; + +static bool match_cig_active(const void *data, const void *match_data) +{ + const struct bap_setup *setup = data; + const struct cig_busy_data *info = match_data; + + return (setup->qos.ucast.cig_id == info->cig) && setup->cig_active; +} + +static bool cig_busy_ep(const void *data, const void *match_data) +{ + const struct bap_ep *ep = data; + const struct cig_busy_data *info = match_data; + + return queue_find(ep->setups, match_cig_active, info); +} + +static bool cig_busy_session(const void *data, const void *match_data) +{ + const struct bap_data *session = data; + const struct cig_busy_data *info = match_data; + + if (device_get_adapter(session->device) != info->adapter) + return false; + + return queue_find(session->snks, cig_busy_ep, match_data) || + queue_find(session->srcs, cig_busy_ep, match_data); +} + +static bool is_cig_busy(struct bap_data *data, uint8_t cig) +{ + struct cig_busy_data info; + + if (cig == BT_ISO_QOS_CIG_UNSET) + return false; + + info.adapter = device_get_adapter(data->device); + info.cig = cig; + + return queue_find(sessions, cig_busy_session, &info); +} + +static void setup_create_io(struct bap_data *data, struct bap_setup *setup, + struct bt_bap_stream *stream, int defer); + +static gboolean setup_io_recreate(void *user_data) +{ + struct bap_setup *setup = user_data; + + DBG("%p", setup); + + setup->io_id = 0; + + setup_create_io(setup->ep->data, setup, setup->stream, true); + + return FALSE; +} + +static void setup_recreate(void *data, void *match_data) +{ + struct bap_setup *setup = data; + struct cig_busy_data *info = match_data; + + if (setup->qos.ucast.cig_id != info->cig || !setup->recreate || + setup->io_id) + return; + + setup->recreate = false; + setup->io_id = g_idle_add(setup_io_recreate, setup); +} - return; +static void recreate_cig_ep(void *data, void *match_data) +{ + struct bap_ep *ep = data; -fail: - close(fd); + queue_foreach(ep->setups, setup_recreate, match_data); } -static void bap_create_io(struct bap_data *data, struct bap_ep *ep, - struct bt_bap_stream *stream, int defer); +static void recreate_cig_session(void *data, void *match_data) +{ + struct bap_data *session = data; + struct cig_busy_data *info = match_data; + + if (device_get_adapter(session->device) != info->adapter) + return; + + queue_foreach(session->snks, recreate_cig_ep, match_data); + queue_foreach(session->srcs, recreate_cig_ep, match_data); +} -static gboolean bap_io_recreate(void *user_data) +static void recreate_cig(struct bap_setup *setup) { - struct bap_ep *ep = user_data; + struct bap_data *data = setup->ep->data; + struct cig_busy_data info; - DBG("ep %p", ep); + info.adapter = device_get_adapter(data->device); + info.cig = setup->qos.ucast.cig_id; - ep->io_id = 0; + DBG("adapter %p setup %p recreate CIG %d", info.adapter, setup, + info.cig); - bap_create_io(ep->data, ep, ep->stream, true); + if (setup->qos.ucast.cig_id == BT_ISO_QOS_CIG_UNSET) { + recreate_cig_ep(setup->ep, &info); + return; + } - return FALSE; + queue_foreach(sessions, recreate_cig_session, &info); } -static gboolean bap_io_disconnected(GIOChannel *io, GIOCondition cond, +static gboolean setup_io_disconnected(GIOChannel *io, GIOCondition cond, gpointer user_data) { - struct bap_ep *ep = user_data; + struct bap_setup *setup = user_data; - DBG("ep %p recreate %s", ep, ep->recreate ? "true" : "false"); + DBG("%p recreate %s", setup, setup->recreate ? "true" : "false"); - ep->io_id = 0; + setup->io_id = 0; - bap_io_close(ep); + setup_io_close(setup, NULL); /* Check if connecting recreate IO */ - if (ep->recreate) { - ep->recreate = false; - ep->io_id = g_idle_add(bap_io_recreate, ep); - } + if (!is_cig_busy(setup->ep->data, setup->qos.ucast.cig_id)) + recreate_cig(setup); return FALSE; } +static void bap_connect_bcast_io_cb(GIOChannel *chan, GError *err, + gpointer user_data) +{ + struct bap_setup *setup = user_data; + + if (!setup->stream) + return; + + iso_connect_bcast_cb(chan, err, setup->stream); +} + static void bap_connect_io_cb(GIOChannel *chan, GError *err, gpointer user_data) { - struct bap_ep *ep = user_data; + struct bap_setup *setup = user_data; - if (!ep->stream) + if (!setup->stream) return; - iso_connect_cb(chan, err, ep->stream); + iso_connect_cb(chan, err, setup->stream); } -static void bap_connect_io(struct bap_data *data, struct bap_ep *ep, +static void setup_connect_io(struct bap_data *data, struct bap_setup *setup, struct bt_bap_stream *stream, struct bt_iso_qos *qos, int defer) { @@ -838,36 +2070,43 @@ static void bap_connect_io(struct bap_data *data, struct bap_ep *ep, int fd; /* If IO already set skip creating it again */ - if (bt_bap_stream_get_io(stream)) + if (bt_bap_stream_get_io(stream)) { + DBG("setup %p stream %p has existing io", setup, stream); return; + } if (bt_bap_stream_io_is_connecting(stream, &fd)) { - bap_accept_io(data, stream, fd, defer); + setup_accept_io(setup, stream, fd, defer); return; } - /* If IO channel still up wait for it to be disconnected and then - * recreate. + /* If IO channel still up or CIG is busy, wait for it to be + * disconnected and then recreate. */ - if (ep->io) { - ep->recreate = true; + if (setup->io || is_cig_busy(data, setup->qos.ucast.cig_id)) { + DBG("setup %p stream %p defer %s wait recreate", setup, stream, + defer ? "true" : "false"); + setup->recreate = true; return; } - if (ep->io_id) { - g_source_remove(ep->io_id); - ep->io_id = 0; + if (setup->io_id) { + g_source_remove(setup->io_id); + setup->io_id = 0; } - DBG("ep %p stream %p defer %s", ep, stream, defer ? "true" : "false"); + DBG("setup %p stream %p defer %s", setup, stream, + defer ? "true" : "false"); - io = bt_io_connect(bap_connect_io_cb, ep, NULL, &err, + io = bt_io_connect(bap_connect_io_cb, setup, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, btd_adapter_get_address(adapter), + BT_IO_OPT_SOURCE_TYPE, + btd_adapter_get_address_type(adapter), BT_IO_OPT_DEST_BDADDR, - device_get_address(ep->data->device), + device_get_address(data->device), BT_IO_OPT_DEST_TYPE, - device_get_le_address_type(ep->data->device), + device_get_le_address_type(data->device), BT_IO_OPT_MODE, BT_IO_MODE_ISO, BT_IO_OPT_QOS, qos, BT_IO_OPT_DEFER_TIMEOUT, defer, @@ -878,15 +2117,75 @@ static void bap_connect_io(struct bap_data *data, struct bap_ep *ep, return; } - ep->io_id = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL, - bap_io_disconnected, ep); + setup->io_id = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL, + setup_io_disconnected, setup); + + setup->io = io; + setup->cig_active = !defer; + + bt_bap_stream_io_connecting(stream, g_io_channel_unix_get_fd(io)); +} + +static void setup_connect_io_broadcast(struct bap_data *data, + struct bap_setup *setup, + struct bt_bap_stream *stream, + struct bt_iso_qos *qos, int defer) +{ + struct btd_adapter *adapter = data->user_data; + GIOChannel *io = NULL; + GError *err = NULL; + bdaddr_t dst_addr = {0}; + char addr[18]; + struct bt_iso_base base; + + /* If IO already set and we are in the creation step, + * skip creating it again + */ + if (bt_bap_stream_get_io(stream)) + return; + + if (setup->io_id) { + g_source_remove(setup->io_id); + setup->io_id = 0; + } + base.base_len = setup->base->iov_len; + + memset(base.base, 0, 248); + memcpy(base.base, setup->base->iov_base, setup->base->iov_len); + ba2str(btd_adapter_get_address(adapter), addr); + + DBG("setup %p stream %p", setup, stream); + + io = bt_io_connect(bap_connect_bcast_io_cb, setup, NULL, &err, + BT_IO_OPT_SOURCE_BDADDR, + btd_adapter_get_address(adapter), + BT_IO_OPT_SOURCE_TYPE, + btd_adapter_get_address_type(adapter), + BT_IO_OPT_DEST_BDADDR, + &dst_addr, + BT_IO_OPT_DEST_TYPE, + BDADDR_LE_PUBLIC, + BT_IO_OPT_MODE, BT_IO_MODE_ISO, + BT_IO_OPT_QOS, qos, + BT_IO_OPT_BASE, &base, + BT_IO_OPT_DEFER_TIMEOUT, defer, + BT_IO_OPT_INVALID); + + if (!io) { + error("%s", err->message); + g_error_free(err); + return; + } + + setup->io_id = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL, + setup_io_disconnected, setup); - ep->io = io; + setup->io = io; bt_bap_stream_io_connecting(stream, g_io_channel_unix_get_fd(io)); } -static void bap_listen_io(struct bap_data *data, struct bt_bap_stream *stream, +static void setup_listen_io(struct bap_data *data, struct bt_bap_stream *stream, struct bt_iso_qos *qos) { struct btd_adapter *adapter = device_get_adapter(data->device); @@ -902,10 +2201,12 @@ static void bap_listen_io(struct bap_data *data, struct bt_bap_stream *stream, io = bt_io_listen(NULL, iso_confirm_cb, data, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, btd_adapter_get_address(adapter), + BT_IO_OPT_SOURCE_TYPE, + btd_adapter_get_address_type(adapter), BT_IO_OPT_DEST_BDADDR, - device_get_address(data->device), + BDADDR_ANY, BT_IO_OPT_DEST_TYPE, - device_get_le_address_type(data->device), + BDADDR_LE_PUBLIC, BT_IO_OPT_MODE, BT_IO_MODE_ISO, BT_IO_OPT_QOS, qos, BT_IO_OPT_INVALID); @@ -918,19 +2219,104 @@ static void bap_listen_io(struct bap_data *data, struct bt_bap_stream *stream, data->listen_io = io; } -static void bap_create_io(struct bap_data *data, struct bap_ep *ep, - struct bt_bap_stream *stream, int defer) +static void check_pa_req_in_progress(void *data, void *user_data) { - struct bt_bap_qos *qos[2] = {}; - struct bt_iso_qos iso_qos; + struct bap_bcast_pa_req *req = data; + + if (req->in_progress == TRUE) + *((bool *)user_data) = TRUE; +} - DBG("ep %p stream %p defer %s", ep, stream, defer ? "true" : "false"); +static int pa_sync(struct bap_bcast_pa_req *req); +static void pa_and_big_sync(struct bap_bcast_pa_req *req); - if (!data->streams) - data->streams = queue_new(); +static gboolean pa_idle_timer(gpointer user_data) +{ + struct bap_adapter *adapter = user_data; + struct bap_bcast_pa_req *req; + bool in_progress = FALSE; + + /* Handle timer if no request is in progress */ + queue_foreach(adapter->bcast_pa_requests, check_pa_req_in_progress, + &in_progress); + if (in_progress == FALSE) { + req = queue_peek_head(adapter->bcast_pa_requests); + if (req != NULL) + switch (req->type) { + case BAP_PA_SHORT_REQ: + DBG("do short lived PA Sync"); + pa_sync(req); + break; + case BAP_PA_LONG_REQ: + DBG("do long lived PA Sync"); + pa_sync(req); + break; + case BAP_PA_BIG_SYNC_REQ: + DBG("do PA Sync and BIG Sync"); + pa_and_big_sync(req); + break; + } + else { + /* pa_req queue is empty, stop the timer by returning + * FALSE and set the pa_timer_id to 0. This will later + * be used to check if the timer is active. + */ + adapter->pa_timer_id = 0; + return FALSE; + } + } - if (!queue_find(data->streams, NULL, stream)) - queue_push_tail(data->streams, stream); + return TRUE; +} + +static void setup_accept_io_broadcast(struct bap_data *data, + struct bap_setup *setup) +{ + struct bap_bcast_pa_req *req = new0(struct bap_bcast_pa_req, 1); + struct bap_adapter *adapter = data->adapter; + struct queue *links = bt_bap_stream_io_get_links(setup->stream); + const struct queue_entry *entry; + + /* Timer could be stopped if all other requests were treated. + * Check the state of the timer and turn it on so that this request + * can also be treated. + */ + if (adapter->pa_timer_id == 0) + adapter->pa_timer_id = g_timeout_add_seconds(PA_IDLE_TIMEOUT, + pa_idle_timer, + adapter); + + /* Add this request to the PA queue. + * We don't need to check the queue here, as we cannot have + * BAP_PA_BIG_SYNC_REQ before a short PA (BAP_PA_SHORT_REQ) + */ + req->type = BAP_PA_BIG_SYNC_REQ; + req->in_progress = FALSE; + req->bap_data = data; + + req->data.setups = queue_new(); + + /* Enqueue all linked setups to the request */ + queue_push_tail(req->data.setups, setup); + + for (entry = queue_get_entries(links); entry; + entry = entry->next) { + struct bt_bap_stream *stream = entry->data; + + queue_push_tail(req->data.setups, + bap_find_setup_by_stream(data, stream)); + } + + queue_push_tail(adapter->bcast_pa_requests, req); +} + +static void setup_create_ucast_io(struct bap_data *data, + struct bap_setup *setup, + struct bt_bap_stream *stream, + int defer) +{ + struct bt_bap_qos *qos[2] = {}; + struct bt_iso_qos iso_qos; if (!bt_bap_stream_io_get_qos(stream, &qos[0], &qos[1])) { error("bt_bap_stream_get_qos_links: failed"); @@ -938,66 +2324,413 @@ static void bap_create_io(struct bap_data *data, struct bap_ep *ep, } memset(&iso_qos, 0, sizeof(iso_qos)); - iso_qos.cig = qos[0] ? qos[0]->cig_id : qos[1]->cig_id; - iso_qos.cis = qos[0] ? qos[0]->cis_id : qos[1]->cis_id; - bap_iso_qos(qos[0], &iso_qos.in); - bap_iso_qos(qos[1], &iso_qos.out); + iso_qos.ucast.cig = qos[0] ? qos[0]->ucast.cig_id : + qos[1]->ucast.cig_id; + iso_qos.ucast.cis = qos[0] ? qos[0]->ucast.cis_id : + qos[1]->ucast.cis_id; - if (ep) - bap_connect_io(data, ep, stream, &iso_qos, defer); + bap_iso_qos(qos[0], &iso_qos.ucast.in); + bap_iso_qos(qos[1], &iso_qos.ucast.out); + + if (setup) + setup_connect_io(data, setup, stream, &iso_qos, defer); + else + setup_listen_io(data, stream, &iso_qos); +} + +static void setup_create_bcast_io(struct bap_data *data, + struct bap_setup *setup, + struct bt_bap_stream *stream, int defer) +{ + struct bt_bap_qos *qos = &setup->qos; + struct iovec *bcode = qos->bcast.bcode; + struct bt_iso_qos iso_qos; + + memset(&iso_qos, 0, sizeof(iso_qos)); + + iso_qos.bcast.big = setup->qos.bcast.big; + iso_qos.bcast.bis = setup->qos.bcast.bis; + iso_qos.bcast.sync_factor = setup->qos.bcast.sync_factor; + iso_qos.bcast.packing = setup->qos.bcast.packing; + iso_qos.bcast.framing = setup->qos.bcast.framing; + iso_qos.bcast.encryption = setup->qos.bcast.encryption; + if (bcode && bcode->iov_base) + memcpy(iso_qos.bcast.bcode, bcode->iov_base, bcode->iov_len); + iso_qos.bcast.options = setup->qos.bcast.options; + iso_qos.bcast.skip = setup->qos.bcast.skip; + iso_qos.bcast.sync_timeout = setup->qos.bcast.sync_timeout; + iso_qos.bcast.sync_cte_type = setup->qos.bcast.sync_cte_type; + iso_qos.bcast.mse = setup->qos.bcast.mse; + iso_qos.bcast.timeout = setup->qos.bcast.timeout; + memcpy(&iso_qos.bcast.out, &setup->qos.bcast.io_qos, + sizeof(struct bt_iso_io_qos)); + + if (bt_bap_stream_get_dir(stream) == BT_BAP_BCAST_SINK) + setup_connect_io_broadcast(data, setup, stream, &iso_qos, + defer); else - bap_listen_io(data, stream, &iso_qos); + setup_accept_io_broadcast(data, setup); +} + +static void setup_create_io(struct bap_data *data, struct bap_setup *setup, + struct bt_bap_stream *stream, int defer) +{ + DBG("setup %p stream %p defer %s", setup, stream, + defer ? "true" : "false"); + + if (!data->streams) + data->streams = queue_new(); + + if (!queue_find(data->streams, NULL, stream)) + queue_push_tail(data->streams, stream); + + switch (bt_bap_stream_get_type(stream)) { + case BT_BAP_STREAM_TYPE_UCAST: + setup_create_ucast_io(data, setup, stream, defer); + break; + case BT_BAP_STREAM_TYPE_BCAST: + setup_create_bcast_io(data, setup, stream, defer); + break; + } } static void bap_state(struct bt_bap_stream *stream, uint8_t old_state, uint8_t new_state, void *user_data) { struct bap_data *data = user_data; - struct bap_ep *ep; + struct bap_setup *setup; DBG("stream %p: %s(%u) -> %s(%u)", stream, bt_bap_stream_statestr(old_state), old_state, bt_bap_stream_statestr(new_state), new_state); - if (new_state == old_state) + /* Ignore transitions back to same state (ASCS allows some of these). + * Of these we need to handle only the config->config case, which will + * occur when reconfiguring the codec from initial config state. + */ + if (new_state == old_state && new_state != BT_BAP_STREAM_STATE_CONFIG) return; - ep = bap_find_ep_by_stream(data, stream); + setup = bap_find_setup_by_stream(data, stream); switch (new_state) { case BT_BAP_STREAM_STATE_IDLE: /* Release stream if idle */ - if (ep) - bap_io_close(ep); + if (setup) + setup_free(setup); else queue_remove(data->streams, stream); break; case BT_BAP_STREAM_STATE_CONFIG: - if (ep && !ep->id) { - bap_create_io(data, ep, stream, true); - if (!ep->io) { + if (setup && !setup->id) { + setup_create_io(data, setup, stream, true); + if (!setup->io) { error("Unable to create io"); - bt_bap_stream_release(stream, NULL, NULL); + if (old_state != BT_BAP_STREAM_STATE_RELEASING) + bt_bap_stream_release(stream, NULL, + NULL); return; } - /* Wait QoS response to respond */ - ep->id = bt_bap_stream_qos(stream, &ep->qos, qos_cb, - ep); - if (!ep->id) { + setup->id = bt_bap_stream_qos(stream, + &setup->qos, + qos_cb, setup); + if (!setup->id) { error("Failed to Configure QoS"); - bt_bap_stream_release(stream, NULL, NULL); + bt_bap_stream_release(stream, + NULL, NULL); } } break; case BT_BAP_STREAM_STATE_QOS: - bap_create_io(data, ep, stream, true); + setup_create_io(data, setup, stream, true); + break; + case BT_BAP_STREAM_STATE_ENABLING: + if (setup) + setup_create_io(data, setup, stream, false); + break; + case BT_BAP_STREAM_STATE_STREAMING: + break; + } +} + +/* This function will call setup_create_io on all BISes from a BIG. + * The defer parameter will be set on true on all but the last one. + * This is done to inform the kernel when to when to start the BIG. + */ +static bool create_io_bises(struct bap_setup *setup, + uint8_t nb_bises, struct bap_data *data) +{ + const struct queue_entry *entry; + struct bap_setup *ent_setup; + bool defer = true; + uint8_t active_bis_cnt = 1; + + for (entry = queue_get_entries(setup->ep->setups); + entry; entry = entry->next) { + ent_setup = entry->data; + + if (bt_bap_stream_get_qos(ent_setup->stream)->bcast.big != + bt_bap_stream_get_qos(setup->stream)->bcast.big) + continue; + + if (active_bis_cnt == nb_bises) + defer = false; + + setup_create_io(data, ent_setup, ent_setup->stream, defer); + if (!ent_setup->io) { + error("Unable to create io"); + goto fail; + } + + active_bis_cnt++; + } + + return true; + +fail: + /* Clear the io of the created sockets if one + * socket creation fails. + */ + for (entry = queue_get_entries(setup->ep->setups); + entry; entry = entry->next) { + ent_setup = entry->data; + + if (bt_bap_stream_get_qos(ent_setup->stream)->bcast.big != + bt_bap_stream_get_qos(setup->stream)->bcast.big) + continue; + + if (setup->io) + g_io_channel_unref(setup->io); + } + return false; +} + +static void iterate_setup_update_base(void *data, void *user_data) +{ + struct bap_setup *setup = data; + struct bap_setup *data_setup = user_data; + + if ((setup->stream != data_setup->stream) && + (setup->qos.bcast.big == data_setup->qos.bcast.big)) { + + if (setup->base) + util_iov_free(setup->base, 1); + + setup->base = util_iov_dup(data_setup->base, 1); + } +} + +/* Function checks the state of all streams in the same BIG + * as the parameter stream, so it can decide if any sockets need + * to be created. Returns he number of streams that need a socket + * from that BIG. + */ +static uint8_t get_streams_nb_by_state(struct bap_setup *setup) +{ + const struct queue_entry *entry; + struct bap_setup *ent_setup; + uint8_t stream_cnt = 0; + + if (setup->qos.bcast.big == BT_ISO_QOS_BIG_UNSET) + /* If BIG ID is unset this is a single BIS BIG. + * return 1 as create one socket only for this BIS + */ + return 1; + + for (entry = queue_get_entries(setup->ep->setups); + entry; entry = entry->next) { + ent_setup = entry->data; + + /* Skip the curent stream form testing */ + if (ent_setup == setup) { + stream_cnt++; + continue; + } + + /* Test only BISes for the same BIG */ + if (bt_bap_stream_get_qos(ent_setup->stream)->bcast.big != + bt_bap_stream_get_qos(setup->stream)->bcast.big) + continue; + + if (bt_bap_stream_get_state(ent_setup->stream) == + BT_BAP_STREAM_STATE_STREAMING) + /* If one stream in a multiple BIS BIG is in + * streaming state this means that just the current + * stream must have is socket created so return 1. + */ + return 1; + else if (bt_bap_stream_get_state(ent_setup->stream) != + BT_BAP_STREAM_STATE_ENABLING) + /* Not all streams form a BIG have received transport + * acquire, so wait for the other streams to. + */ + return 0; + + stream_cnt++; + } + + /* Return the number of streams for the BIG + * as all are ready to create sockets + */ + return stream_cnt; +} + +static void bap_state_bcast_src(struct bt_bap_stream *stream, uint8_t old_state, + uint8_t new_state, void *user_data) +{ + struct bap_data *data = user_data; + struct bap_setup *setup; + bool defer = false; + uint8_t nb_bises = 0; + + DBG("stream %p: %s(%u) -> %s(%u)", stream, + bt_bap_stream_statestr(old_state), old_state, + bt_bap_stream_statestr(new_state), new_state); + + /* Ignore transitions back to same state */ + if (new_state == old_state) + return; + + setup = bap_find_setup_by_stream(data, stream); + + switch (new_state) { + case BT_BAP_STREAM_STATE_IDLE: + /* Release stream if idle */ + if (setup) + setup_free(setup); + else + queue_remove(data->streams, stream); + break; + case BT_BAP_STREAM_STATE_CONFIG: + // TO DO Reconfiguration + break; + /* Use the ENABLING state to know when a transport + * linked to a stream has been acquired by a process + * and in the case of a BIG with one BIS stream goes + * in the ENABLING state waiting for the response + * from the kernel that the BIG has been created + * so it can go to the streaming state. + * For the case of a BIG with multiple BISes, + * the BIG is created when all BISes are acquired. + * So we use the ENABLING state to verify that all + * transports attached to that streams form BIG have + * been acquired so we can create the BIG. + */ + case BT_BAP_STREAM_STATE_ENABLING: + /* If the stream attached to a broadcast + * source endpoint generate the base. + */ + if (setup->base == NULL) { + setup->base = bt_bap_stream_get_base( + setup->stream); + /* Set the generated BASE on all setups + * from the same BIG. + */ + queue_foreach(setup->ep->setups, + iterate_setup_update_base, setup); + } + /* The kernel has 2 requirements when handling + * multiple BIS connections for the same BIG: + * 1 - setup_create_io for all but the last BIS + * must be with defer true so we can inform the + * kernel when to start the BIG. + * 2 - The order in which the setup_create_io + * are called must be in the order of BIS + * indexes in BASE from first to last. + * To address this requirement we will call + * setup_create_io on all BISes only when all + * transport acquire have been received and will + * send it in the order of the BIS index + * from BASE. + */ + nb_bises = get_streams_nb_by_state(setup); + + if (nb_bises == 1) { + setup_create_io(data, setup, + stream, defer); + if (!setup->io) { + error("Unable to create io"); + if (old_state != + BT_BAP_STREAM_STATE_RELEASING) + bt_bap_stream_release(stream, + NULL, NULL); + } + break; + } else if (nb_bises == 0) + break; + + if (!create_io_bises(setup, nb_bises, data)) { + if (old_state != + BT_BAP_STREAM_STATE_RELEASING) + bt_bap_stream_release(stream, + NULL, NULL); + } + break; + } +} + +static bool link_enabled(const void *data, const void *match_data) +{ + struct bt_bap_stream *stream = (struct bt_bap_stream *)data; + uint8_t state = bt_bap_stream_get_state(stream); + + return ((state == BT_BAP_STREAM_STATE_ENABLING) || + bt_bap_stream_get_io(stream)); +} + +static void bap_state_bcast_sink(struct bt_bap_stream *stream, + uint8_t old_state, uint8_t new_state, + void *user_data) +{ + struct bap_data *data = user_data; + struct bap_setup *setup; + bool defer = false; + + DBG("stream %p: %s(%u) -> %s(%u)", stream, + bt_bap_stream_statestr(old_state), old_state, + bt_bap_stream_statestr(new_state), new_state); + + if (new_state == old_state && new_state != BT_BAP_STREAM_STATE_CONFIG) + return; + + setup = bap_find_setup_by_stream(data, stream); + + switch (new_state) { + case BT_BAP_STREAM_STATE_IDLE: + /* Release stream if idle */ + if (setup) + setup_free(setup); + else + queue_remove(data->streams, stream); + break; + case BT_BAP_STREAM_STATE_CONFIG: + if (!setup) + break; + if (old_state == + BT_BAP_STREAM_STATE_STREAMING) + setup_io_close(setup, NULL); break; case BT_BAP_STREAM_STATE_ENABLING: - if (ep) - bap_create_io(data, ep, stream, false); + /* For a Broadcast Sink, the ENABLING state suggests that + * the upper layer process requires the stream to start + * receiving audio. This state is used to differentiate + * between all configured streams and the ones that have + * been enabled by the upper layer. + * + * Create stream io if not already created and if no + * link has been enabled or started. + * + * The first enabled link will create and set fds for + * all links. + */ + if (!bt_bap_stream_get_io(stream) && + !queue_find(bt_bap_stream_io_get_links(stream), + link_enabled, NULL)) + setup_create_io(data, setup, stream, defer); + break; } } @@ -1014,32 +2747,79 @@ static void pac_added(struct bt_bap_pac *pac, void *user_data) data = btd_service_get_user_data(service); - bt_bap_foreach_pac(data->bap, BT_BAP_SOURCE, pac_found, service); - bt_bap_foreach_pac(data->bap, BT_BAP_SINK, pac_found, service); + bt_bap_foreach_pac(data->bap, BT_BAP_SOURCE, pac_register, service); + bt_bap_foreach_pac(data->bap, BT_BAP_SINK, pac_register, service); + + bt_bap_foreach_pac(data->bap, BT_BAP_SOURCE, pac_select, service); + bt_bap_foreach_pac(data->bap, BT_BAP_SINK, pac_select, service); +} + +static void pac_added_broadcast(struct bt_bap_pac *pac, void *user_data) +{ + struct bap_data *data = user_data; + + /* + * If pac type is BT_BAP_BCAST_SOURCE locally create an endpoint + * without a remote pac. + * If pac type is BT_BAP_BCAST_SOURCE and remote then look for a + * local broadcast sink pac locally before creating an endpoint. + */ + if (bt_bap_pac_bcast_is_local(data->bap, pac) && + (bt_bap_pac_get_type(pac) == BT_BAP_BCAST_SOURCE)) + pac_found_bcast(pac, NULL, user_data); + else + bt_bap_foreach_pac(data->bap, bt_bap_pac_get_type(pac), + pac_found_bcast, data); } -static bool ep_match_rpac(const void *data, const void *match_data) +static bool ep_match_pac(const void *data, const void *match_data) { const struct bap_ep *ep = data; const struct bt_bap_pac *pac = match_data; - return ep->rpac == pac; + return ep->rpac == pac || ep->lpac == pac; +} + +static void pac_removed(struct bt_bap_pac *pac, void *user_data) +{ + struct btd_service *service = user_data; + struct bap_data *data; + struct queue *queue; + struct bap_ep *ep; + + DBG("pac %p", pac); + + if (btd_service_get_state(service) != BTD_SERVICE_STATE_CONNECTED) + return; + + data = btd_service_get_user_data(service); + + switch (bt_bap_pac_get_type(pac)) { + case BT_BAP_SINK: + queue = data->srcs; + break; + case BT_BAP_SOURCE: + queue = data->snks; + break; + default: + return; + } + + ep = queue_remove_if(queue, ep_match_pac, pac); + if (!ep) + return; + + ep_unregister(ep); } -static void pac_removed(struct bt_bap_pac *pac, void *user_data) +static void pac_removed_broadcast(struct bt_bap_pac *pac, void *user_data) { - struct btd_service *service = user_data; - struct bap_data *data; + struct bap_data *data = user_data; struct queue *queue; struct bap_ep *ep; DBG("pac %p", pac); - if (btd_service_get_state(service) != BTD_SERVICE_STATE_CONNECTED) - return; - - data = btd_service_get_user_data(service); - switch (bt_bap_pac_get_type(pac)) { case BT_BAP_SINK: queue = data->srcs; @@ -1047,17 +2827,39 @@ static void pac_removed(struct bt_bap_pac *pac, void *user_data) case BT_BAP_SOURCE: queue = data->snks; break; + case BT_BAP_BCAST_SOURCE: + queue = data->bcast; + break; default: return; } - ep = queue_remove_if(queue, ep_match_rpac, pac); + ep = queue_remove_if(queue, ep_match_pac, pac); if (!ep) return; ep_unregister(ep); } +static bool match_device(const void *data, const void *match_data) +{ + const struct bap_data *bdata = data; + const struct btd_device *device = match_data; + + return bdata->device == device; +} + +struct bt_bap *bap_get_session(struct btd_device *device) +{ + struct bap_data *data; + + data = queue_find(sessions, match_device, device); + if (!data) + return NULL; + + return data->bap; +} + static struct bap_data *bap_data_new(struct btd_device *device) { struct bap_data *data; @@ -1066,6 +2868,7 @@ static struct bap_data *bap_data_new(struct btd_device *device) data->device = device; data->srcs = queue_new(); data->snks = queue_new(); + data->bcast = queue_new(); return data; } @@ -1098,50 +2901,111 @@ static bool match_data(const void *data, const void *match_data) return bdata->bap == bap; } +static bool io_get_qos(GIOChannel *io, struct bt_iso_qos *qos) +{ + GError *err = NULL; + bool ret; + + ret = bt_io_get(io, &err, BT_IO_OPT_QOS, qos, BT_IO_OPT_INVALID); + if (!ret) { + error("%s", err->message); + g_error_free(err); + } + + return ret; +} + static void bap_connecting(struct bt_bap_stream *stream, bool state, int fd, void *user_data) { struct bap_data *data = user_data; - struct bap_ep *ep; + struct bap_setup *setup; + struct bt_bap_qos *qos; GIOChannel *io; if (!state) return; - ep = bap_find_ep_by_stream(data, stream); - if (!ep) + setup = bap_find_setup_by_stream(data, stream); + if (!setup) return; - ep->recreate = false; + setup->recreate = false; + qos = &setup->qos; - if (!ep->io) { + if (!setup->io) { io = g_io_channel_unix_new(fd); - ep->io = io; + setup->io_id = g_io_add_watch(io, + G_IO_HUP | G_IO_ERR | G_IO_NVAL, + setup_io_disconnected, setup); + setup->io = io; } else - io = ep->io; + io = setup->io; g_io_channel_set_close_on_unref(io, FALSE); /* Attempt to get CIG/CIS if they have not been set */ - if (ep->qos.cig_id == BT_ISO_QOS_CIG_UNSET || - ep->qos.cis_id == BT_ISO_QOS_CIS_UNSET) { - struct bt_iso_qos qos; - GError *err = NULL; - - if (!bt_io_get(io, &err, BT_IO_OPT_QOS, &qos, - BT_IO_OPT_INVALID)) { - error("%s", err->message); - g_error_free(err); + if (qos->ucast.cig_id == BT_ISO_QOS_CIG_UNSET || + qos->ucast.cis_id == BT_ISO_QOS_CIS_UNSET) { + struct bt_iso_qos iso_qos; + + if (!io_get_qos(io, &iso_qos)) { g_io_channel_unref(io); return; } - ep->qos.cig_id = qos.cig; - ep->qos.cis_id = qos.cis; + qos->ucast.cig_id = iso_qos.ucast.cig; + qos->ucast.cis_id = iso_qos.ucast.cis; } DBG("stream %p fd %d: CIG 0x%02x CIS 0x%02x", stream, fd, - ep->qos.cig_id, ep->qos.cis_id); + qos->ucast.cig_id, qos->ucast.cis_id); +} + +static void bap_connecting_bcast(struct bt_bap_stream *stream, bool state, + int fd, void *user_data) +{ + struct bap_data *data = user_data; + struct bap_setup *setup; + GIOChannel *io; + + if (!state) + return; + + setup = bap_find_setup_by_stream(data, stream); + if (!setup) + return; + + setup->recreate = false; + + if (!setup->io) { + io = g_io_channel_unix_new(fd); + setup->io_id = g_io_add_watch(io, + G_IO_HUP | G_IO_ERR | G_IO_NVAL, + setup_io_disconnected, setup); + setup->io = io; + } else + io = setup->io; + + g_io_channel_set_close_on_unref(io, FALSE); + + /* Attempt to get BIG/BIS if they have not been set */ + if (setup->qos.bcast.big == BT_ISO_QOS_BIG_UNSET || + setup->qos.bcast.bis == BT_ISO_QOS_BIS_UNSET) { + struct bt_iso_qos iso_qos; + + if (!io_get_qos(io, &iso_qos)) { + g_io_channel_unref(io); + return; + } + + setup->qos.bcast.big = iso_qos.bcast.big; + setup->qos.bcast.bis = iso_qos.bcast.bis; + bt_bap_stream_qos(setup->stream, &setup->qos, NULL, NULL); + } + + DBG("stream %p fd %d: BIG 0x%02x BIS 0x%02x", stream, fd, + setup->qos.bcast.big, setup->qos.bcast.bis); } static void bap_attached(struct bt_bap *bap, void *user_data) @@ -1196,6 +3060,320 @@ static void bap_detached(struct bt_bap *bap, void *user_data) bap_data_remove(data); } +static int pa_sync(struct bap_bcast_pa_req *req) +{ + struct btd_service *service = req->data.service; + struct bap_data *data = btd_service_get_user_data(service); + GError *err = NULL; + + if (data->listen_io) { + DBG("Already probed"); + return -1; + } + + DBG("Create PA sync with this source"); + req->in_progress = TRUE; + data->listen_io = bt_io_listen(NULL, iso_pa_sync_confirm_cb, req, + NULL, &err, + BT_IO_OPT_SOURCE_BDADDR, + btd_adapter_get_address(data->adapter->adapter), + BT_IO_OPT_SOURCE_TYPE, + btd_adapter_get_address_type(data->adapter->adapter), + BT_IO_OPT_DEST_BDADDR, + device_get_address(data->device), + BT_IO_OPT_DEST_TYPE, + btd_device_get_bdaddr_type(data->device), + BT_IO_OPT_MODE, BT_IO_MODE_ISO, + BT_IO_OPT_QOS, &bap_sink_pa_qos, + BT_IO_OPT_INVALID); + if (!data->listen_io) { + error("%s", err->message); + g_error_free(err); + } + + return 0; +} + +static void append_setup(void *data, void *user_data) +{ + struct bap_setup *setup = data; + struct sockaddr_iso_bc *addr = user_data; + char *path = bt_bap_stream_get_user_data(setup->stream); + int bis = 1; + int s_err; + const char *strbis = NULL; + + strbis = strstr(path, "/bis"); + if (!strbis) { + DBG("bis index cannot be found"); + return; + } + + s_err = sscanf(strbis, "/bis%d", &bis); + if (s_err == -1) { + DBG("sscanf error"); + return; + } + + DBG("Do BIG Sync with BIS %d", bis); + + addr->bc_bis[addr->bc_num_bis] = bis; + addr->bc_num_bis++; +} + +static void setup_refresh_qos(void *data, void *user_data) +{ + struct bap_setup *setup = data; + + setup->qos = *bt_bap_stream_get_qos(setup->stream); +} + +static void iso_do_big_sync(GIOChannel *io, void *user_data) +{ + GError *err = NULL; + struct bap_bcast_pa_req *req = user_data; + struct queue *setups = req->data.setups; + struct bap_setup *setup = queue_peek_head(setups); + struct bap_data *data = req->bap_data; + struct sockaddr_iso_bc iso_bc_addr = {0}; + struct bt_iso_qos qos; + + DBG("PA Sync done"); + + if (req->io) { + g_io_channel_unref(req->io); + g_io_channel_shutdown(req->io, TRUE, NULL); + req->io = io; + g_io_channel_ref(req->io); + } + + iso_bc_addr.bc_bdaddr_type = btd_device_get_bdaddr_type(data->device); + memcpy(&iso_bc_addr.bc_bdaddr, device_get_address(data->device), + sizeof(bdaddr_t)); + + /* Append each linked BIS to the BIG sync request */ + queue_foreach(setups, append_setup, &iso_bc_addr); + + /* Refresh qos stored in setups */ + queue_foreach(setups, setup_refresh_qos, NULL); + + /* Set the user requested QOS */ + memset(&qos, 0, sizeof(qos)); + qos.bcast.big = setup->qos.bcast.big; + qos.bcast.bis = setup->qos.bcast.bis; + qos.bcast.sync_factor = setup->qos.bcast.sync_factor; + qos.bcast.packing = setup->qos.bcast.packing; + qos.bcast.framing = setup->qos.bcast.framing; + qos.bcast.encryption = setup->qos.bcast.encryption; + if (setup->qos.bcast.bcode && setup->qos.bcast.bcode->iov_base) + memcpy(qos.bcast.bcode, setup->qos.bcast.bcode->iov_base, + setup->qos.bcast.bcode->iov_len); + qos.bcast.options = setup->qos.bcast.options; + qos.bcast.skip = setup->qos.bcast.skip; + qos.bcast.sync_timeout = setup->qos.bcast.sync_timeout; + qos.bcast.sync_cte_type = setup->qos.bcast.sync_cte_type; + qos.bcast.mse = setup->qos.bcast.mse; + qos.bcast.timeout = setup->qos.bcast.timeout; + memcpy(&qos.bcast.out, &setup->qos.bcast.io_qos, + sizeof(struct bt_iso_io_qos)); + + if (!bt_io_set(io, &err, + BT_IO_OPT_QOS, &qos, + BT_IO_OPT_INVALID)) { + error("bt_io_set: %s", err->message); + g_error_free(err); + } + + if (!bt_io_bcast_accept(io, + iso_bcast_confirm_cb, + req, NULL, &err, + BT_IO_OPT_ISO_BC_NUM_BIS, + iso_bc_addr.bc_num_bis, BT_IO_OPT_ISO_BC_BIS, + iso_bc_addr.bc_bis, BT_IO_OPT_INVALID)) { + error("bt_io_bcast_accept: %s", err->message); + g_error_free(err); + } +} + +static void pa_and_big_sync(struct bap_bcast_pa_req *req) +{ + GError *err = NULL; + struct bap_data *bap_data = req->bap_data; + + req->in_progress = TRUE; + + if (bap_data->listen_io) { + /* If there is an active listen io for the BAP session + * with the Broadcast Source, it means that PA sync is + * already established. Go straight to establishing BIG + * sync. + */ + iso_do_big_sync(bap_data->listen_io, req); + return; + } + + DBG("Create PA sync with this source"); + req->io = bt_io_listen(NULL, iso_do_big_sync, req, + NULL, &err, + BT_IO_OPT_SOURCE_BDADDR, + btd_adapter_get_address(bap_data->adapter->adapter), + BT_IO_OPT_DEST_BDADDR, + device_get_address(bap_data->device), + BT_IO_OPT_DEST_TYPE, + btd_device_get_bdaddr_type(bap_data->device), + BT_IO_OPT_MODE, BT_IO_MODE_ISO, + BT_IO_OPT_QOS, &bap_sink_pa_qos, + BT_IO_OPT_INVALID); + if (!req->io) { + error("%s", err->message); + g_error_free(err); + } +} + +static bool match_bap_adapter(const void *data, const void *match_data) +{ + struct bap_adapter *adapter = (struct bap_adapter *)data; + + return adapter->adapter == match_data; +} + +void bap_scan_delegator_probe(struct btd_device *device) +{ + struct bap_data *data; + + /* Create BAP session for the Broadcaster device */ + data = bap_data_new(device); + data->device = device; + + bap_data_add(data); + + /* Add Broadcast Audio Announcement Service UUID + * to device and probe service. + */ + btd_device_add_uuid(device, BCAAS_UUID_STR); +} + +static int bap_bcast_probe(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + struct btd_adapter *adapter = device_get_adapter(device); + struct btd_gatt_database *database = btd_adapter_get_database(adapter); + struct bap_bcast_pa_req *req; + uint8_t type = BAP_PA_LONG_REQ; + struct bap_data *data; + + if (!btd_adapter_has_exp_feature(adapter, EXP_FEAT_ISO_SOCKET)) { + error("BAP requires ISO Socket which is not enabled"); + return -ENOTSUP; + } + + data = queue_find(sessions, match_device, device); + if (data && data->service) { + error("Profile probed twice for the same device!"); + return -EINVAL; + } + + if (!data) { + data = bap_data_new(device); + data->device = device; + bap_data_add(data); + + /* The Broadcaster was scanned autonomously, + * so it should be probed short-lived. + */ + type = BAP_PA_SHORT_REQ; + } + + data->service = service; + btd_service_set_user_data(service, data); + + data->adapter = queue_find(adapters, match_bap_adapter, adapter); + data->bap = bt_bap_new(btd_gatt_database_get_db(database), + btd_gatt_database_get_db(database)); + if (!data->bap) { + error("Unable to create BAP instance"); + free(data); + return -EINVAL; + } + + bt_bap_set_debug(data->bap, bap_debug, NULL, NULL); + + data->bcast_snks = queue_new(); + + if (!bt_bap_attach(data->bap, NULL)) { + error("BAP unable to attach"); + return -EINVAL; + } + + data->ready_id = bt_bap_ready_register(data->bap, bap_ready, service, + NULL); + data->state_id = bt_bap_state_register(data->bap, bap_state_bcast_sink, + bap_connecting_bcast, data, NULL); + data->pac_id = bt_bap_pac_register(data->bap, pac_added_broadcast, + pac_removed_broadcast, data, NULL); + + bt_bap_set_user_data(data->bap, service); + + /* Start the PA timer if it hasn't been started yet */ + if (data->adapter->pa_timer_id == 0) + data->adapter->pa_timer_id = g_timeout_add_seconds( + PA_IDLE_TIMEOUT, + pa_idle_timer, + data->adapter); + + /* Enqueue this device advertisement so that we can create PA sync. */ + DBG("enqueue service: %p", service); + req = new0(struct bap_bcast_pa_req, 1); + req->type = type; + req->in_progress = FALSE; + req->data.service = service; + queue_push_tail(data->adapter->bcast_pa_requests, req); + + return 0; +} + +static bool match_service(const void *data, const void *match_data) +{ + struct bap_bcast_pa_req *req = (struct bap_bcast_pa_req *)data; + + return req->data.service == match_data; +} + +static void bap_bcast_remove(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + struct bap_data *data; + struct bap_bcast_pa_req *req; + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("%s", addr); + + data = btd_service_get_user_data(service); + if (!data) { + error("BAP service not handled by profile"); + return; + } + /* Remove the corresponding entry from the pa_req queue. Any pa_req that + * are in progress will be stopped by bap_data_remove which calls + * bap_data_free. + */ + req = queue_remove_if(data->adapter->bcast_pa_requests, + match_service, service); + if (req && req->io_id) { + g_source_remove(req->io_id); + req->io_id = 0; + } + free(req); + + /* Notify the BASS plugin about the removed session. */ + bass_bcast_remove(device); + + bap_data_remove(data); + + bass_remove_stream(device); +} + static int bap_probe(struct btd_service *service) { struct btd_device *device = btd_service_get_device(service); @@ -1235,8 +3413,8 @@ static int bap_probe(struct btd_service *service) NULL); data->state_id = bt_bap_state_register(data->bap, bap_state, bap_connecting, data, NULL); - data->pac_id = bt_bap_pac_register(pac_added, pac_removed, service, - NULL); + data->pac_id = bt_bap_pac_register(data->bap, pac_added, pac_removed, + service, NULL); bt_bap_set_user_data(data->bap, service); @@ -1289,6 +3467,83 @@ static int bap_disconnect(struct btd_service *service) return 0; } +static int bap_adapter_probe(struct btd_profile *p, struct btd_adapter *adapter) +{ + struct btd_gatt_database *database = btd_adapter_get_database(adapter); + struct bap_data *data; + char addr[18]; + + ba2str(btd_adapter_get_address(adapter), addr); + DBG("%s", addr); + + if (!btd_kernel_experimental_enabled(ISO_SOCKET_UUID)) { + error("BAP requires ISO Socket which is not enabled"); + return -ENOTSUP; + } + + data = bap_data_new(NULL); + + data->bap = bt_bap_new(btd_gatt_database_get_db(database), + btd_gatt_database_get_db(database)); + if (!data->bap) { + error("Unable to create BAP instance"); + free(data); + return -EINVAL; + } + + bap_data_add(data); + + if (!bt_bap_attach_broadcast(data->bap)) { + error("BAP unable to attach"); + return -EINVAL; + } + + data->state_id = bt_bap_state_register(data->bap, bap_state_bcast_src, + bap_connecting_bcast, data, NULL); + data->pac_id = bt_bap_pac_register(data->bap, pac_added_broadcast, + pac_removed_broadcast, data, NULL); + + bt_bap_set_user_data(data->bap, adapter); + bap_data_set_user_data(data, adapter); + + data->adapter = new0(struct bap_adapter, 1); + data->adapter->adapter = adapter; + + if (adapters == NULL) + adapters = queue_new(); + data->adapter->bcast_pa_requests = queue_new(); + queue_push_tail(adapters, data->adapter); + + return 0; +} + +static void bap_adapter_remove(struct btd_profile *p, + struct btd_adapter *adapter) +{ + struct bap_data *data = queue_find(sessions, match_data_bap_data, + adapter); + char addr[18]; + + ba2str(btd_adapter_get_address(adapter), addr); + DBG("%s", addr); + + queue_destroy(data->adapter->bcast_pa_requests, free); + queue_remove(adapters, data->adapter); + free(data->adapter); + + if (queue_isempty(adapters)) { + queue_destroy(adapters, NULL); + adapters = NULL; + } + + if (!data) { + error("BAP service not handled by profile"); + return; + } + + bap_data_remove(data); +} + static struct btd_profile bap_profile = { .name = "bap", .priority = BTD_PROFILE_PRIORITY_MEDIUM, @@ -1297,18 +3552,37 @@ static struct btd_profile bap_profile = { .device_remove = bap_remove, .accept = bap_accept, .disconnect = bap_disconnect, + .adapter_probe = bap_adapter_probe, + .adapter_remove = bap_adapter_remove, + .auto_connect = true, + .experimental = true, +}; + +static struct btd_profile bap_bcast_profile = { + .name = "bcaa", + .priority = BTD_PROFILE_PRIORITY_MEDIUM, + .remote_uuid = BCAAS_UUID_STR, + .device_probe = bap_bcast_probe, + .device_remove = bap_bcast_remove, + .disconnect = bap_disconnect, + .auto_connect = false, + .experimental = true, }; static unsigned int bap_id = 0; static int bap_init(void) { - if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) { - warn("D-Bus experimental not enabled"); - return -ENOTSUP; - } + int err; + + err = btd_profile_register(&bap_profile); + if (err) + return err; + + err = btd_profile_register(&bap_bcast_profile); + if (err) + return err; - btd_profile_register(&bap_profile); bap_id = bt_bap_register(bap_attached, bap_detached, NULL); return 0; @@ -1316,10 +3590,8 @@ static int bap_init(void) static void bap_exit(void) { - if (g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL) { - btd_profile_unregister(&bap_profile); - bt_bap_unregister(bap_id); - } + btd_profile_unregister(&bap_profile); + bt_bap_unregister(bap_id); } BLUETOOTH_PLUGIN_DEFINE(bap, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, diff --git a/profiles/audio/bap.h b/profiles/audio/bap.h new file mode 100644 index 0000000000000000000000000000000000000000..cfe63331186df34a57f12c0bc4191d2092d5a964 --- /dev/null +++ b/profiles/audio/bap.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright 2024 NXP + * + */ + +struct bt_bap *bap_get_session(struct btd_device *device); +void bap_scan_delegator_probe(struct btd_device *device); diff --git a/profiles/audio/bass.c b/profiles/audio/bass.c new file mode 100644 index 0000000000000000000000000000000000000000..6237f5acc1c35c94305f44eca20ba86c8cc3cabe --- /dev/null +++ b/profiles/audio/bass.c @@ -0,0 +1,1241 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright 2023-2024 NXP + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE + +#include <ctype.h> +#include <stdbool.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#include <glib.h> + +#include "gdbus/gdbus.h" + +#include "lib/bluetooth.h" +#include "lib/uuid.h" + +#include "src/dbus-common.h" +#include "src/shared/util.h" +#include "src/shared/att.h" +#include "src/shared/queue.h" +#include "src/shared/gatt-db.h" +#include "src/shared/gatt-client.h" +#include "src/shared/gatt-server.h" +#include "src/adapter.h" +#include "src/shared/bass.h" +#include "src/shared/bap.h" +#include "src/shared/ad.h" + +#include "src/plugin.h" +#include "src/gatt-database.h" +#include "src/device.h" +#include "src/profile.h" +#include "src/service.h" +#include "src/log.h" +#include "src/error.h" + +#include "bass.h" +#include "bap.h" + +#define BASS_UUID_STR "0000184f-0000-1000-8000-00805f9b34fb" +#define BCAAS_UUID_STR "00001852-0000-1000-8000-00805f9b34fb" + +#define MEDIA_ASSISTANT_INTERFACE "org.bluez.MediaAssistant1" + +enum assistant_state { + ASSISTANT_STATE_IDLE, /* Assistant object was created for + * the stream + */ + ASSISTANT_STATE_PENDING, /* Assistant object was pushed */ + ASSISTANT_STATE_REQUESTING, /* Remote device requires + * Broadcast_Code + */ + ASSISTANT_STATE_ACTIVE, /* Remote device started receiving + * stream + */ +}; + +static const char *const str_state[] = { + "ASSISTANT_STATE_IDLE", + "ASSISTANT_STATE_PENDING", + "ASSISTANT_STATE_REQUESTING", + "ASSISTANT_STATE_ACTIVE", +}; + +struct bass_data { + struct btd_device *device; + struct btd_service *service; + struct bt_bass *bass; + unsigned int src_id; + unsigned int cp_id; +}; + +struct bass_assistant { + struct btd_device *device; /* Broadcast source device */ + struct bass_data *data; /* BASS session with peer device */ + uint8_t sgrp; + uint8_t bis; + uint32_t bid; + struct bt_iso_qos qos; + struct iovec *meta; + struct iovec *caps; + enum assistant_state state; + char *path; +}; + +struct bass_delegator { + struct btd_device *device; /* Broadcast source device */ + struct bt_bcast_src *src; + struct bt_bap *bap; + unsigned int state_id; + uint8_t *bcode; + unsigned int timeout; + struct queue *bcode_reqs; +}; + +struct bass_bcode_req { + struct bt_bap_stream *stream; + bt_bass_bcode_func_t cb; + void *user_data; +}; + +static struct queue *sessions; +static struct queue *assistants; +static struct queue *delegators; + +static const char *state2str(enum assistant_state state); + +static void bass_debug(const char *str, void *user_data) +{ + DBG_IDX(0xffff, "%s", str); +} + +static gboolean req_timeout(gpointer user_data) +{ + struct bass_delegator *dg = user_data; + struct bass_bcode_req *req; + + DBG("delegator %p", dg); + + dg->timeout = 0; + + while ((req = queue_pop_head(dg->bcode_reqs))) { + if (req->cb) + req->cb(req->user_data, -ETIMEDOUT); + + free(req); + } + + return FALSE; +} + +static bool delegator_match_bap(const void *data, const void *match_data) +{ + const struct bass_delegator *dg = data; + const struct bt_bap *bap = match_data; + + return dg->bap == bap; +} + +static void stream_set_bcode(uint8_t *bcode, struct bt_bap_stream *stream, + bt_bass_bcode_func_t cb, void *user_data) +{ + struct bt_bap_qos *qos = bt_bap_stream_get_qos(stream); + + /* Allocate Broadcast Code inside stream QoS */ + qos->bcast.bcode = util_iov_new(bcode, BT_BASS_BCAST_CODE_SIZE); + + if (cb) + cb(user_data, 0); +} + +void bass_req_bcode(struct bt_bap_stream *stream, + bt_bass_bcode_func_t cb, + void *user_data) +{ + struct bt_bap *bap = bt_bap_stream_get_session(stream); + struct bass_delegator *dg; + struct bass_bcode_req *req; + + dg = queue_find(delegators, delegator_match_bap, bap); + if (!dg) { + cb(user_data, -EINVAL); + return; + } + + if (dg->bcode) { + /* Broadcast Code has already been received before. */ + stream_set_bcode(dg->bcode, stream, cb, user_data); + return; + } + + /* Create a request for the Broadcast Code. The request + * will be considered handled when the Broadcast Code is + * received from a Broadcast Assistant. + */ + req = new0(struct bass_bcode_req, 1); + if (!req) + return; + + req->stream = stream; + req->cb = cb; + req->user_data = user_data; + + queue_push_tail(dg->bcode_reqs, req); + + /* Mark the encryption status as "Broadcast Code Required" + * in the Broadcast Receive State characteristic and notify + * Broadcast Assistants. + */ + bt_bass_set_enc(dg->src, BT_BASS_BIG_ENC_STATE_BCODE_REQ); + + /* Add timeout for Broadcast Assistants to provide the Code. */ + if (!dg->timeout) + dg->timeout = g_timeout_add_seconds(10, req_timeout, dg); +} + +static bool delegator_match_device(const void *data, const void *match_data) +{ + const struct bass_delegator *dg = data; + const struct btd_device *device = match_data; + + return dg->device == device; +} + +bool bass_check_bis(struct btd_device *device, uint8_t bis) +{ + struct bass_delegator *dg; + + dg = queue_find(delegators, delegator_match_device, device); + if (!dg) + return true; + + if (!bt_bass_check_bis(dg->src, bis)) + return false; + + return true; +} + +static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state, + uint8_t new_state, void *user_data) +{ + struct bass_delegator *dg = user_data; + int bis; + char *path = bt_bap_stream_get_user_data(stream); + struct bt_bap *bap = bt_bap_stream_get_session(stream); + const char *strbis; + int err; + + if (dg->bap != bap) + return; + + strbis = strstr(path, "/bis"); + if (strbis == NULL) { + DBG("bis index cannot be found"); + return; + } + + err = sscanf(strbis, "/bis%d", &bis); + if (err < 0) { + DBG("sscanf error"); + return; + } + + DBG("stream %p: %s(%u) -> %s(%u)", stream, + bt_bap_stream_statestr(old_state), old_state, + bt_bap_stream_statestr(new_state), new_state); + + switch (new_state) { + case BT_BAP_STREAM_STATE_STREAMING: + /* BAP stream was started. Mark BIS index as synced inside the + * Broadcast Receive State characteristic and notify peers about + * the update. + */ + bt_bass_set_bis_sync(dg->src, bis); + break; + case BT_BAP_STREAM_STATE_CONFIG: + if (old_state == BT_BAP_STREAM_STATE_STREAMING) + /* BAP stream was disabled. Clear BIS index from the + * bitmask inside the Broadcast Receive State + * characteristic and notify peers about the update. + */ + bt_bass_clear_bis_sync(dg->src, bis); + break; + } +} + +bool bass_bcast_probe(struct btd_device *device, struct bt_bap *bap) +{ + struct bass_delegator *dg; + + dg = queue_find(delegators, delegator_match_device, device); + if (!dg) + return false; + + DBG("%p", dg); + + dg->bap = bap; + + /* Update Broadcast Receive State characteristic value and notify + * peers. + */ + if (bt_bass_set_pa_sync(dg->src, BT_BASS_SYNCHRONIZED_TO_PA)) + DBG("Failed to update Broadcast Receive State characteristic"); + + /* Register BAP stream state changed callback, to keep up to + * date with BIG/PA sync state. + */ + dg->state_id = bt_bap_state_register(bap, bap_state_changed, + NULL, dg, NULL); + + return true; +} + +bool bass_bcast_remove(struct btd_device *device) +{ + struct bass_delegator *dg; + + dg = queue_remove_if(delegators, delegator_match_device, device); + if (!dg) + return false; + + DBG("%p", dg); + + /* Update Broadcast Receive State characteristic value and notify + * peers. + */ + if (bt_bass_set_pa_sync(dg->src, BT_BASS_NOT_SYNCHRONIZED_TO_PA)) + DBG("Failed to update Broadcast Receive State characteristic"); + + /* Unregister BAP stream state changed callback. */ + bt_bap_state_unregister(dg->bap, dg->state_id); + + if (dg->timeout) + g_source_remove(dg->timeout); + + queue_destroy(dg->bcode_reqs, free); + + free(dg->bcode); + + free(dg); + + return true; +} + +static void assistant_set_state(struct bass_assistant *assistant, + enum assistant_state state) +{ + enum assistant_state old_state = assistant->state; + const char *str; + + if (old_state == state) + return; + + assistant->state = state; + + DBG("State changed %s: %s -> %s", assistant->path, str_state[old_state], + str_state[state]); + + str = state2str(state); + + if (g_strcmp0(str, state2str(old_state)) != 0) + g_dbus_emit_property_changed(btd_get_dbus_connection(), + assistant->path, + MEDIA_ASSISTANT_INTERFACE, + "State"); +} + +static int assistant_parse_qos(struct bass_assistant *assistant, + DBusMessageIter *iter) +{ + DBusMessageIter dict; + const char *key; + + dbus_message_iter_recurse(iter, &dict); + + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter value, entry; + int var; + + dbus_message_iter_recurse(&dict, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &value); + + var = dbus_message_iter_get_arg_type(&value); + + if (!strcasecmp(key, "BCode")) { + DBusMessageIter array; + struct iovec iov = {0}; + + if (var != DBUS_TYPE_ARRAY) + return -EINVAL; + + dbus_message_iter_recurse(&value, &array); + dbus_message_iter_get_fixed_array(&array, + &iov.iov_base, + (int *)&iov.iov_len); + + if (iov.iov_len != BT_BASS_BCAST_CODE_SIZE) { + error("Invalid size for BCode: %zu != 16", + iov.iov_len); + return -EINVAL; + } + + memcpy(assistant->qos.bcast.bcode, iov.iov_base, + iov.iov_len); + + return 0; + } + + dbus_message_iter_next(&dict); + } + + return 0; +} + +static int assistant_parse_props(struct bass_assistant *assistant, + DBusMessageIter *props) +{ + DBusMessageIter value, entry, array; + const char *key; + + while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) { + dbus_message_iter_recurse(props, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &value); + + if (!strcasecmp(key, "Metadata")) { + struct iovec iov; + + if (dbus_message_iter_get_arg_type(&value) != + DBUS_TYPE_ARRAY) + goto fail; + + dbus_message_iter_recurse(&value, &array); + dbus_message_iter_get_fixed_array(&array, + &iov.iov_base, + (int *)&iov.iov_len); + + util_iov_free(assistant->meta, 1); + assistant->meta = util_iov_dup(&iov, 1); + DBG("Parsed Metadata"); + } else if (!strcasecmp(key, "QoS")) { + if (dbus_message_iter_get_arg_type(&value) != + DBUS_TYPE_ARRAY) + goto fail; + + if (assistant_parse_qos(assistant, &value)) + goto fail; + + DBG("Parsed QoS"); + } + + dbus_message_iter_next(props); + } + + return 0; + +fail: + DBG("Failed parsing %s", key); + + return -EINVAL; +} + +static DBusMessage *push(DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + struct bass_assistant *assistant = user_data; + struct bt_bass_bcast_audio_scan_cp_hdr hdr; + struct bt_bass_add_src_params params; + struct iovec iov = {0}; + uint32_t bis_sync = 0; + uint8_t meta_len = 0; + int err; + DBusMessageIter props, dict; + + DBG(""); + + dbus_message_iter_init(msg, &props); + + if (dbus_message_iter_get_arg_type(&props) != DBUS_TYPE_ARRAY) { + DBG("Unable to parse properties"); + return btd_error_invalid_args(msg); + } + + dbus_message_iter_recurse(&props, &dict); + + if (assistant_parse_props(assistant, &dict)) { + DBG("Unable to parse properties"); + return btd_error_invalid_args(msg); + } + + hdr.op = BT_BASS_ADD_SRC; + + if (device_get_le_address_type(assistant->device) == BDADDR_LE_PUBLIC) + params.addr_type = BT_BASS_ADDR_PUBLIC; + else + params.addr_type = BT_BASS_ADDR_RANDOM; + + bacpy(¶ms.addr, device_get_address(assistant->device)); + put_le24(assistant->bid, params.bid); + params.pa_sync = PA_SYNC_NO_PAST; + params.pa_interval = PA_INTERVAL_UNKNOWN; + params.num_subgroups = assistant->sgrp + 1; + + util_iov_append(&iov, ¶ms, sizeof(params)); + + /* Metadata and the BIS index associated with the MediaAssistant + * object will be set in the subgroup they belong to. For the other + * subgroups, no metadata and no BIS index will be provided. + */ + for (uint8_t sgrp = 0; sgrp < assistant->sgrp; sgrp++) { + util_iov_append(&iov, &bis_sync, sizeof(bis_sync)); + util_iov_append(&iov, &meta_len, sizeof(meta_len)); + } + + bis_sync = (1 << (assistant->bis - 1)); + meta_len = assistant->meta->iov_len; + + util_iov_append(&iov, &bis_sync, sizeof(bis_sync)); + util_iov_append(&iov, &meta_len, sizeof(meta_len)); + util_iov_append(&iov, assistant->meta->iov_base, + assistant->meta->iov_len); + + err = bt_bass_send(assistant->data->bass, &hdr, &iov); + if (err) { + DBG("Unable to send BASS Write Command"); + return btd_error_failed(msg, strerror(-err)); + } + + free(iov.iov_base); + + assistant_set_state(assistant, ASSISTANT_STATE_PENDING); + + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); +} + +static const GDBusMethodTable assistant_methods[] = { + {GDBUS_EXPERIMENTAL_ASYNC_METHOD("Push", + GDBUS_ARGS({ "Props", "a{sv}" }), + NULL, push)}, + {}, +}; + +static const char *state2str(enum assistant_state state) +{ + switch (state) { + case ASSISTANT_STATE_IDLE: + return "idle"; + case ASSISTANT_STATE_PENDING: + return "pending"; + case ASSISTANT_STATE_REQUESTING: + return "requesting"; + case ASSISTANT_STATE_ACTIVE: + return "active"; + } + + return NULL; +} + +static gboolean get_state(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct bass_assistant *assistant = data; + const char *state = state2str(assistant->state); + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &state); + + return TRUE; +} + +static gboolean get_metadata(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct bass_assistant *assistant = data; + DBusMessageIter array; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, &array); + + if (assistant->meta) + dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, + &assistant->meta->iov_base, + assistant->meta->iov_len); + + dbus_message_iter_close_container(iter, &array); + + return TRUE; +} + +static gboolean get_qos(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct bass_assistant *assistant = data; + DBusMessageIter dict; + uint8_t *bcode = assistant->qos.bcast.bcode; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &dict); + + dict_append_entry(&dict, "Encryption", DBUS_TYPE_BYTE, + &assistant->qos.bcast.encryption); + dict_append_array(&dict, "BCode", DBUS_TYPE_BYTE, + &bcode, BT_BASS_BCAST_CODE_SIZE); + + dbus_message_iter_close_container(iter, &dict); + + return TRUE; +} + +static const GDBusPropertyTable assistant_properties[] = { + { "State", "s", get_state }, + { "Metadata", "ay", get_metadata, NULL, NULL, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { "QoS", "a{sv}", get_qos, NULL, NULL, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { } +}; + +static void assistant_free(void *data) +{ + struct bass_assistant *assistant = data; + + g_free(assistant->path); + util_iov_free(assistant->meta, 1); + util_iov_free(assistant->caps, 1); + + free(assistant); +} + +static void src_ad_search_bid(void *data, void *user_data) +{ + struct bt_ad_service_data *sd = data; + struct bass_assistant *assistant = user_data; + struct iovec iov; + + if (sd->uuid.type != BT_UUID16 || sd->uuid.value.u16 != BCAA_SERVICE) + return; + + iov.iov_base = sd->data; + iov.iov_len = sd->len; + + util_iov_pull_le24(&iov, &assistant->bid); +} + +static struct bass_assistant *assistant_new(struct btd_adapter *adapter, + struct btd_device *device, struct bass_data *data, + uint8_t sgrp, uint8_t bis, struct bt_iso_qos *qos, + struct iovec *meta, struct iovec *caps) +{ + struct bass_assistant *assistant; + char src_addr[18]; + char dev_addr[18]; + + assistant = new0(struct bass_assistant, 1); + if (!assistant) + return NULL; + + DBG("assistant %p", assistant); + + assistant->device = device; + assistant->data = data; + assistant->sgrp = sgrp; + assistant->bis = bis; + assistant->qos = *qos; + assistant->meta = util_iov_dup(meta, 1); + assistant->caps = util_iov_dup(caps, 1); + + btd_device_foreach_service_data(assistant->device, src_ad_search_bid, + assistant); + + ba2str(device_get_address(device), src_addr); + ba2str(device_get_address(data->device), dev_addr); + + assistant->path = g_strdup_printf("%s/src_%s/dev_%s/bis%d", + adapter_get_path(adapter), src_addr, dev_addr, bis); + + g_strdelimit(assistant->path, ":", '_'); + + if (!assistants) + assistants = queue_new(); + + queue_push_tail(assistants, assistant); + + return assistant; +} + +void bass_add_stream(struct btd_device *device, struct iovec *meta, + struct iovec *caps, struct bt_iso_qos *qos, + uint8_t sgrp, uint8_t bis) +{ + const struct queue_entry *entry; + struct bt_bap *bap; + struct bt_bap_pac *pac; + struct bass_assistant *assistant; + char addr[18]; + + for (entry = queue_get_entries(sessions); entry; entry = entry->next) { + struct bass_data *data = entry->data; + struct btd_adapter *adapter = device_get_adapter(data->device); + + if (!bt_bass_get_client(data->bass)) + /* Only client sessions must be handled */ + continue; + + bap = bap_get_session(data->device); + if (!bap) + continue; + + /* Check stream capabilities against peer caps. */ + bt_bap_verify_bis(bap, bis, caps, &pac); + + if (!pac) + /* Capabilities did not match. */ + continue; + + ba2str(device_get_address(device), addr); + + DBG("%s data %p BIS %d", addr, data, bis); + + assistant = assistant_new(adapter, device, data, sgrp, + bis, qos, meta, caps); + + if (g_dbus_register_interface(btd_get_dbus_connection(), + assistant->path, + MEDIA_ASSISTANT_INTERFACE, + assistant_methods, NULL, + assistant_properties, + assistant, + assistant_free) == FALSE) + DBG("Could not register path %s", assistant->path); + } +} + +static bool assistant_match_device(const void *data, const void *match_data) +{ + const struct bass_assistant *assistant = data; + const struct btd_device *device = match_data; + + return (assistant->device == device); +} + +static void unregister_assistant(void *data) +{ + struct bass_assistant *assistant = data; + + DBG("%p", assistant); + + g_dbus_unregister_interface(btd_get_dbus_connection(), + assistant->path, MEDIA_ASSISTANT_INTERFACE); +} + +void bass_remove_stream(struct btd_device *device) +{ + queue_remove_all(assistants, assistant_match_device, + device, unregister_assistant); +} + +static struct bass_data *bass_data_new(struct btd_device *device) +{ + struct bass_data *data; + + data = new0(struct bass_data, 1); + data->device = device; + + return data; +} + +static void bass_data_add(struct bass_data *data) +{ + DBG("data %p", data); + + if (queue_find(sessions, NULL, data)) { + error("data %p already added", data); + return; + } + + bt_bass_set_debug(data->bass, bass_debug, NULL, NULL); + + if (!sessions) + sessions = queue_new(); + + queue_push_tail(sessions, data); + + if (data->service) + btd_service_set_user_data(data->service, data); +} + +static bool match_data(const void *data, const void *match_data) +{ + const struct bass_data *bdata = data; + const struct bt_bass *bass = match_data; + + return bdata->bass == bass; +} + +static bool assistant_match_data(const void *data, const void *match_data) +{ + const struct bass_assistant *assistant = data; + const struct bass_data *bdata = match_data; + + return (assistant->data == bdata); +} + +static void bass_data_free(struct bass_data *data) +{ + if (data->service) { + btd_service_set_user_data(data->service, NULL); + bt_bass_set_user_data(data->bass, NULL); + } + + bt_bass_src_unregister(data->bass, data->src_id); + bt_bass_cp_handler_unregister(data->bass, data->cp_id); + + bt_bass_unref(data->bass); + + queue_remove_all(assistants, assistant_match_data, + data, unregister_assistant); + + free(data); +} + +static void bass_data_remove(struct bass_data *data) +{ + DBG("data %p", data); + + if (!queue_remove(sessions, data)) + return; + + bass_data_free(data); + + if (queue_isempty(sessions)) { + queue_destroy(sessions, NULL); + sessions = NULL; + } +} + +static void bass_detached(struct bt_bass *bass, void *user_data) +{ + struct bass_data *data; + + DBG("%p", bass); + + data = queue_find(sessions, match_data, bass); + if (!data) { + error("Unable to find bass session"); + return; + } + + /* If there is a service it means there is BASS thus we can keep + * instance allocated. + */ + if (data->service) + return; + + bass_data_remove(data); +} + +static int handle_add_src_req(struct bt_bcast_src *bcast_src, + struct bt_bass_add_src_params *params, + struct bass_data *data) +{ + struct btd_adapter *adapter = device_get_adapter(data->device); + struct btd_device *device; + struct bass_delegator *dg; + + /* Create device for Broadcast Source using the parameters + * provided by Broadcast Assistant. + */ + device = btd_adapter_get_device(adapter, ¶ms->addr, + params->addr_type); + if (!device) { + DBG("Unable to get device"); + return -EINVAL; + } + + DBG("device %p", device); + + /* Probe Broadcast Source, if it has not already been + * autonomously probed inside BAP. + */ + if (!btd_device_get_service(device, BCAAS_UUID_STR)) + goto probe; + + return 0; + +probe: + dg = new0(struct bass_delegator, 1); + if (!dg) + return -ENOMEM; + + dg->device = device; + dg->src = bcast_src; + dg->bcode_reqs = queue_new(); + + if (!delegators) + delegators = queue_new(); + + queue_push_tail(delegators, dg); + + DBG("delegator %p", dg); + + /* Probe device with BAP. */ + bap_scan_delegator_probe(device); + + return 0; +} + +static bool delegator_match_src(const void *data, const void *match_data) +{ + const struct bass_delegator *dg = data; + const struct bt_bcast_src *src = match_data; + + return dg->src == src; +} + +static int handle_set_bcode_req(struct bt_bcast_src *bcast_src, + struct bt_bass_set_bcast_code_params *params, + struct bass_data *data) +{ + struct bass_delegator *dg; + struct bass_bcode_req *req; + + dg = queue_find(delegators, delegator_match_src, bcast_src); + if (!dg) + return -EINVAL; + + dg->bcode = new0(uint8_t, BT_BASS_BCAST_CODE_SIZE); + memcpy(dg->bcode, params->bcast_code, BT_BASS_BCAST_CODE_SIZE); + + if (dg->timeout) { + g_source_remove(dg->timeout); + dg->timeout = 0; + } + + /* Set the Broadcast Code for each stream that required it. */ + while ((req = queue_pop_head(dg->bcode_reqs))) { + stream_set_bcode(dg->bcode, req->stream, req->cb, + req->user_data); + free(req); + } + + return 0; +} + +static int cp_handler(struct bt_bcast_src *bcast_src, uint8_t op, void *params, + void *user_data) +{ + struct bass_data *data = user_data; + int err = 0; + + switch (op) { + case BT_BASS_ADD_SRC: + err = handle_add_src_req(bcast_src, params, data); + break; + case BT_BASS_SET_BCAST_CODE: + err = handle_set_bcode_req(bcast_src, params, data); + break; + } + + return err; +} + +static void bass_attached(struct bt_bass *bass, void *user_data) +{ + struct bass_data *data; + struct bt_att *att; + struct btd_device *device; + + DBG("%p", bass); + + data = queue_find(sessions, match_data, bass); + if (data) + return; + + att = bt_bass_get_att(bass); + if (!att) + return; + + device = btd_adapter_find_device_by_fd(bt_att_get_fd(att)); + if (!device) { + error("Unable to find device"); + return; + } + + data = bass_data_new(device); + data->bass = bass; + + data->cp_id = bt_bass_cp_handler_register(data->bass, + cp_handler, NULL, data); + + bass_data_add(data); +} + +static void bass_handle_bcode_req(struct bass_assistant *assistant, int id) +{ + struct bt_bass_bcast_audio_scan_cp_hdr hdr; + struct bt_bass_set_bcast_code_params params; + struct iovec iov = {0}; + int err; + + assistant_set_state(assistant, ASSISTANT_STATE_REQUESTING); + + hdr.op = BT_BASS_SET_BCAST_CODE; + + params.id = id; + memcpy(params.bcast_code, assistant->qos.bcast.bcode, + BT_BASS_BCAST_CODE_SIZE); + + iov.iov_base = malloc0(sizeof(params)); + if (!iov.iov_base) + return; + + util_iov_push_mem(&iov, sizeof(params), ¶ms); + + err = bt_bass_send(assistant->data->bass, &hdr, &iov); + if (err) { + DBG("Unable to send BASS Write Command"); + return; + } + + free(iov.iov_base); +} + +static void bass_src_changed(uint8_t id, uint32_t bid, uint8_t enc, + uint32_t bis_sync, void *user_data) +{ + const struct queue_entry *entry; + + for (entry = queue_get_entries(assistants); entry; + entry = entry->next) { + struct bass_assistant *assistant = entry->data; + uint32_t bis = 1 << (assistant->bis - 1); + + if (assistant->bid != bid) + /* Only handle assistant objects + * that match the source + */ + continue; + + switch (enc) { + case BT_BASS_BIG_ENC_STATE_BCODE_REQ: + if (assistant->state != ASSISTANT_STATE_PENDING) + /* Only handle assistant objects that + * have been pushed by the user + */ + break; + + /* Provide Broadcast Code to peer */ + bass_handle_bcode_req(assistant, id); + break; + case BT_BASS_BIG_ENC_STATE_NO_ENC: + if (assistant->state != ASSISTANT_STATE_PENDING) + /* Only handle assistant objects that + * have been pushed by the user + */ + break; + + /* Match BIS index */ + if (bis & bis_sync) + assistant_set_state(assistant, + ASSISTANT_STATE_ACTIVE); + break; + case BT_BASS_BIG_ENC_STATE_DEC: + /* Only handle assistant objects that + * have requested a Broadcast Code + */ + if (assistant->state != ASSISTANT_STATE_REQUESTING) + break; + + /* Match BIS index */ + if (bis & bis_sync) + assistant_set_state(assistant, + ASSISTANT_STATE_ACTIVE); + break; + default: + continue; + } + } +} + +static int bass_probe(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + struct btd_adapter *adapter = device_get_adapter(device); + struct btd_gatt_database *database = btd_adapter_get_database(adapter); + struct bass_data *data = btd_service_get_user_data(service); + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("%s", addr); + + /* Ignore, if we were probed for this device already */ + if (data) { + error("Profile probed twice for the same device!"); + return -EINVAL; + } + + data = bass_data_new(device); + data->service = service; + + data->bass = bt_bass_new(btd_gatt_database_get_db(database), + btd_device_get_gatt_db(device), + btd_adapter_get_address(adapter)); + if (!data->bass) { + error("Unable to create BASS instance"); + free(data); + return -EINVAL; + } + + bass_data_add(data); + bt_bass_set_user_data(data->bass, service); + + /* Register callback to be called when notifications for + * Broadcast Receive State characteristics are received. + */ + data->src_id = bt_bass_src_register(data->bass, bass_src_changed, + data, NULL); + + data->cp_id = bt_bass_cp_handler_register(data->bass, + cp_handler, NULL, data); + + return 0; +} + +static void bass_remove(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + struct bass_data *data; + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("%s", addr); + + data = btd_service_get_user_data(service); + if (!data) { + error("BASS service not handled by profile"); + return; + } + + bass_data_remove(data); +} +static int bass_accept(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + struct bt_gatt_client *client = btd_device_get_gatt_client(device); + struct bass_data *data = btd_service_get_user_data(service); + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("%s", addr); + + if (!data) { + error("BASS service not handled by profile"); + return -EINVAL; + } + + if (!bt_bass_attach(data->bass, client)) { + error("BASS unable to attach"); + return -EINVAL; + } + + btd_service_connecting_complete(service, 0); + + return 0; +} + +static int bass_disconnect(struct btd_service *service) +{ + struct bass_data *data = btd_service_get_user_data(service); + struct btd_device *device = btd_service_get_device(service); + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("%s", addr); + + bt_bass_detach(data->bass); + + btd_service_disconnecting_complete(service, 0); + + return 0; +} + +static int bass_server_probe(struct btd_profile *p, + struct btd_adapter *adapter) +{ + struct btd_gatt_database *database = btd_adapter_get_database(adapter); + + DBG("BASS path %s", adapter_get_path(adapter)); + + bt_bass_add_db(btd_gatt_database_get_db(database), + btd_adapter_get_address(adapter)); + + return 0; +} + +static void bass_server_remove(struct btd_profile *p, + struct btd_adapter *adapter) +{ + DBG("BASS remove Adapter"); +} + +static struct btd_profile bass_service = { + .name = "bass", + .priority = BTD_PROFILE_PRIORITY_MEDIUM, + .remote_uuid = BASS_UUID_STR, + .device_probe = bass_probe, + .device_remove = bass_remove, + .accept = bass_accept, + .disconnect = bass_disconnect, + .adapter_probe = bass_server_probe, + .adapter_remove = bass_server_remove, + .experimental = true, +}; + +static unsigned int bass_id; + +static int bass_init(void) +{ + int err; + + err = btd_profile_register(&bass_service); + if (err) + return err; + + bass_id = bt_bass_register(bass_attached, bass_detached, NULL); + + return 0; +} + +static void bass_exit(void) +{ + btd_profile_unregister(&bass_service); + bt_bass_unregister(bass_id); +} + +BLUETOOTH_PLUGIN_DEFINE(bass, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, + bass_init, bass_exit) diff --git a/profiles/audio/bass.h b/profiles/audio/bass.h new file mode 100644 index 0000000000000000000000000000000000000000..257346374ef179ca64b63631bd412897ff8b0909 --- /dev/null +++ b/profiles/audio/bass.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright 2024 NXP + * + */ + +void bass_add_stream(struct btd_device *device, struct iovec *meta, + struct iovec *caps, struct bt_iso_qos *qos, + uint8_t sgrp, uint8_t bis); +void bass_remove_stream(struct btd_device *device); + +bool bass_bcast_probe(struct btd_device *device, struct bt_bap *bap); +bool bass_bcast_remove(struct btd_device *device); + +bool bass_check_bis(struct btd_device *device, uint8_t bis); + +typedef void (*bt_bass_bcode_func_t)(void *user_data, int err); + +void bass_req_bcode(struct bt_bap_stream *stream, + bt_bass_bcode_func_t cb, + void *user_data); diff --git a/profiles/audio/ccp.c b/profiles/audio/ccp.c new file mode 100644 index 0000000000000000000000000000000000000000..ae17a31f7ed3190798a21be7de1d54ff82e387f6 --- /dev/null +++ b/profiles/audio/ccp.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2024 Intel Corporation. All rights reserved. + * + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE + +#include <ctype.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#include <glib.h> + +#include "gdbus/gdbus.h" + +#include "lib/bluetooth.h" +#include "lib/hci.h" +#include "lib/sdp.h" +#include "lib/uuid.h" + +#include "src/dbus-common.h" +#include "src/shared/util.h" +#include "src/shared/att.h" +#include "src/shared/queue.h" +#include "src/shared/gatt-db.h" +#include "src/shared/gatt-client.h" +#include "src/shared/gatt-server.h" +#include "src/shared/ccp.h" + +#include "btio/btio.h" +#include "src/plugin.h" +#include "src/adapter.h" +#include "src/gatt-database.h" +#include "src/device.h" +#include "src/profile.h" +#include "src/service.h" +#include "src/log.h" +#include "src/error.h" + +#define GTBS_UUID_STR "0000184C-0000-1000-8000-00805f9b34fb" + +struct ccp_data { + struct btd_device *device; + struct btd_service *service; + struct bt_ccp *ccp; + unsigned int state_id; +}; + +static void ccp_debug(const char *str, void *user_data) +{ + DBG_IDX(0xffff, "%s", str); +} + +static struct ccp_data *ccp_data_new(struct btd_device *device) +{ + struct ccp_data *data; + + data = new0(struct ccp_data, 1); + data->device = device; + + return data; +} + +static int ccp_probe(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + struct btd_adapter *adapter = device_get_adapter(device); + struct btd_gatt_database *database = btd_adapter_get_database(adapter); + struct ccp_data *data = btd_service_get_user_data(service); + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("%s", addr); + + if (data) { + error("Profile probed twice for the same device!"); + return -EINVAL; + } + + data = ccp_data_new(device); + data->service = service; + + data->ccp = bt_ccp_new(btd_gatt_database_get_db(database), + btd_device_get_gatt_db(device)); + + bt_ccp_set_debug(data->ccp, ccp_debug, NULL, NULL); + btd_service_set_user_data(service, data); + + return 0; +} + +static void ccp_data_free(struct ccp_data *data) +{ + if (data->service) { + btd_service_set_user_data(data->service, NULL); + bt_ccp_set_user_data(data->ccp, NULL); + } + + bt_ccp_unref(data->ccp); + free(data); +} + +static void ccp_data_remove(struct ccp_data *data) +{ + DBG("data %p", data); + + ccp_data_free(data); +} + +static void ccp_remove(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + struct ccp_data *data; + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("%s", addr); + + data = btd_service_get_user_data(service); + if (!data) { + error("CCP service not handled by profile"); + return; + } + + ccp_data_remove(data); +} + +static int ccp_accept(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + struct bt_gatt_client *client = btd_device_get_gatt_client(device); + struct ccp_data *data = btd_service_get_user_data(service); + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("%s", addr); + + if (!bt_ccp_attach(data->ccp, client)) { + error("CCP unable to attach"); + return -EINVAL; + } + + /* TODO: register telephony operations here */ + + btd_service_connecting_complete(service, 0); + + return 0; +} + +static int ccp_connect(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("%s", addr); + + return 0; +} + +static int ccp_disconnect(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + struct ccp_data *data = btd_service_get_user_data(service); + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("%s", addr); + + bt_ccp_detach(data->ccp); + + btd_service_disconnecting_complete(service, 0); + + return 0; +} + +static int ccp_server_probe(struct btd_profile *p, struct btd_adapter *adapter) +{ + struct btd_gatt_database *database = btd_adapter_get_database(adapter); + + bt_ccp_register(btd_gatt_database_get_db(database)); + + return 0; +} + +static void +ccp_server_remove(struct btd_profile *p, + struct btd_adapter *adapter) +{ + DBG("CCP remove adapter"); +} + +static struct btd_profile ccp_profile = { + .name = "ccp", + .priority = BTD_PROFILE_PRIORITY_MEDIUM, + .remote_uuid = GTBS_UUID_STR, + .device_probe = ccp_probe, + .device_remove = ccp_remove, + .accept = ccp_accept, + .connect = ccp_connect, + .disconnect = ccp_disconnect, + .adapter_probe = ccp_server_probe, + .adapter_remove = ccp_server_remove, + .testing = true, +}; + +static int ccp_init(void) +{ + return btd_profile_register(&ccp_profile); +} + +static void ccp_exit(void) +{ + btd_profile_unregister(&ccp_profile); +} + +BLUETOOTH_PLUGIN_DEFINE(ccp, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, + ccp_init, ccp_exit) diff --git a/profiles/audio/csip.c b/profiles/audio/csip.c new file mode 100644 index 0000000000000000000000000000000000000000..a697ebdfbda0917944789b515d5894463485b6b3 --- /dev/null +++ b/profiles/audio/csip.c @@ -0,0 +1,479 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2022 Intel Corporation. All rights reserved. + * + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE + +#include <ctype.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#include <glib.h> + +#include "gdbus/gdbus.h" + +#include "lib/bluetooth.h" +#include "lib/hci.h" +#include "lib/sdp.h" +#include "lib/uuid.h" + +#include "src/dbus-common.h" +#include "src/shared/util.h" +#include "src/shared/att.h" +#include "src/shared/queue.h" +#include "src/shared/gatt-db.h" +#include "src/shared/gatt-client.h" +#include "src/shared/gatt-server.h" +#include "src/shared/csip.h" +#include "src/shared/crypto.h" + +#include "btio/btio.h" +#include "src/plugin.h" +#include "src/adapter.h" +#include "src/gatt-database.h" +#include "src/device.h" +#include "src/profile.h" +#include "src/service.h" +#include "src/log.h" +#include "src/error.h" +#include "src/btd.h" + +#define CSIS_UUID_STR "00001846-0000-1000-8000-00805f9b34fb" + +struct csis_data { + struct btd_adapter *adapter; + struct bt_csip *csip; +}; + +struct csip_data { + struct btd_adapter *adapter; + struct btd_device *device; + struct btd_service *service; + struct bt_csip *csip; + unsigned int ready_id; +}; + +static struct queue *sessions; +static struct queue *servers; + +static void csip_debug(const char *str, void *user_data) +{ + DBG_IDX(0xffff, "%s", str); +} + +static struct csip_data *csip_data_new(struct btd_device *device) +{ + struct csip_data *data; + + data = new0(struct csip_data, 1); + data->device = device; + + return data; +} + +static void csip_data_add(struct csip_data *data) +{ + DBG("data %p", data); + + if (queue_find(sessions, NULL, data)) { + error("data %p already added", data); + return; + } + + bt_csip_set_debug(data->csip, csip_debug, NULL, NULL); + + if (!sessions) + sessions = queue_new(); + + queue_push_tail(sessions, data); + + if (data->service) + btd_service_set_user_data(data->service, data); +} + +static int csip_disconnect(struct btd_service *service) +{ + struct csip_data *data = btd_service_get_user_data(service); + + bt_csip_detach(data->csip); + + btd_service_disconnecting_complete(service, 0); + + return 0; +} + +static bool match_data(const void *data, const void *match_data) +{ + const struct csip_data *vdata = data; + const struct bt_csip *csip = match_data; + + return vdata->csip == csip; +} + +static void csip_data_free(struct csip_data *data) +{ + if (data->service) { + btd_service_set_user_data(data->service, NULL); + bt_csip_set_user_data(data->csip, NULL); + } + + bt_csip_ready_unregister(data->csip, data->ready_id); + bt_csip_unref(data->csip); + free(data); +} + +static void csip_data_remove(struct csip_data *data) +{ + DBG("data %p", data); + + if (!queue_remove(sessions, data)) + return; + + csip_data_free(data); + + if (queue_isempty(sessions)) { + queue_destroy(sessions, NULL); + sessions = NULL; + } +} + +static void csip_detached(struct bt_csip *csip, void *user_data) +{ + struct csip_data *data; + + DBG("%p", csip); + + data = queue_find(sessions, match_data, csip); + if (!data) { + error("Unable to find csip session"); + return; + } + + /* If there is a service it means there is CSIS thus we can keep + * instance allocated. + */ + if (data->service) + return; + + csip_data_remove(data); +} + +static void csip_attached(struct bt_csip *csip, void *user_data) +{ + struct csip_data *data; + struct bt_att *att; + struct btd_device *device; + + DBG("%p", csip); + + data = queue_find(sessions, match_data, csip); + if (data) + return; + + att = bt_csip_get_att(csip); + if (!att) + return; + + device = btd_adapter_find_device_by_fd(bt_att_get_fd(att)); + if (!device) { + error("Unable to find device"); + return; + } + + data = csip_data_new(device); + data->csip = csip; + + csip_data_add(data); +} + +static int csip_accept(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + struct bt_gatt_client *client = btd_device_get_gatt_client(device); + struct csip_data *data = btd_service_get_user_data(service); + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("%s", addr); + + if (!data) { + error("CSIP service not handled by profile"); + return -EINVAL; + } + + if (!bt_csip_attach(data->csip, client)) { + error("CSIP unable to attach"); + return -EINVAL; + } + + btd_service_connecting_complete(service, 0); + + return 0; +} + +static void csip_ready(struct bt_csip *csip, void *user_data) +{ + struct btd_service *service = user_data; + struct btd_device *device = btd_service_get_device(service); + uint8_t type, size, rank; + uint8_t k[16]; + + DBG("csip %p", csip); + + if (!bt_csip_get_sirk(csip, &type, k, &size, &rank)) { + error("Unable to read SIRK"); + return; + } + + btd_device_add_set(device, type == BT_CSIP_SIRK_ENCRYPT ? true : false, + k, size, rank); +} + +static int csip_probe(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + struct btd_adapter *adapter = device_get_adapter(device); + struct btd_gatt_database *database = btd_adapter_get_database(adapter); + struct csip_data *data = btd_service_get_user_data(service); + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("%s", addr); + + /* Ignore, if we were probed for this device already */ + if (data) { + error("Profile probed twice for the same device!"); + return -EINVAL; + } + + data = csip_data_new(device); + data->service = service; + + data->csip = bt_csip_new(btd_gatt_database_get_db(database), + btd_device_get_gatt_db(device)); + if (!data->csip) { + error("Unable to create CSIP instance"); + free(data); + return -EINVAL; + } + + csip_data_add(data); + + data->ready_id = bt_csip_ready_register(data->csip, csip_ready, service, + NULL); + + bt_csip_set_user_data(data->csip, service); + + return 0; +} + +static void csip_remove(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + struct csip_data *data; + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("%s", addr); + + data = btd_service_get_user_data(service); + if (!data) { + error("CSIP service not handled by profile"); + return; + } + + csip_data_remove(data); +} + +static struct btd_profile csip_profile = { + .name = "csip", + .priority = BTD_PROFILE_PRIORITY_MEDIUM, + .remote_uuid = CSIS_UUID_STR, + + .device_probe = csip_probe, + .device_remove = csip_remove, + + .accept = csip_accept, + .disconnect = csip_disconnect, + + .experimental = true, +}; + +static bool csis_encrypt(struct bt_att *att, uint8_t val[16]) +{ + struct btd_device *device; + struct bt_crypto *crypto; + uint8_t ltk[16]; + bool ret; + + device = btd_adapter_find_device_by_fd(bt_att_get_fd(att)); + if (!device) { + error("Unable to find device"); + return false; + } + + if (!btd_device_get_ltk(device, ltk, NULL, NULL)) { + error("Unable to get device LTK"); + return false; + } + + crypto = bt_crypto_new(); + if (!crypto) { + error("Failed to open crypto"); + return false; + } + + ret = bt_crypto_sef(crypto, ltk, val, val); + if (!ret) + error("Failed to encrypt SIRK using LTK"); + + bt_crypto_unref(crypto); + + return ret; +} + +static void csis_data_add(struct csis_data *data) +{ + DBG("data %p", data); + + if (queue_find(servers, NULL, data)) { + error("data %p already added", data); + return; + } + + bt_csip_set_debug(data->csip, csip_debug, NULL, NULL); + + bt_csip_set_sirk(data->csip, btd_opts.csis.encrypt, btd_opts.csis.sirk, + btd_opts.csis.size, btd_opts.csis.rank, + csis_encrypt); + + if (!servers) + servers = queue_new(); + + queue_push_tail(servers, data); +} + +static struct csis_data *csis_data_new(struct btd_adapter *adapter) +{ + struct csis_data *data; + + data = new0(struct csis_data, 1); + data->adapter = adapter; + + return data; +} + +static int csis_server_probe(struct btd_profile *p, struct btd_adapter *adapter) +{ + struct btd_gatt_database *database = btd_adapter_get_database(adapter); + struct csis_data *data; + + DBG("path %s", adapter_get_path(adapter)); + + data = csis_data_new(adapter); + + data->csip = bt_csip_new(btd_gatt_database_get_db(database), NULL); + if (!data->csip) { + error("Unable to create CSIP instance"); + free(data); + return -EINVAL; + } + + csis_data_add(data); + + return 0; +} + +static bool match_csis(const void *data, const void *match_data) +{ + const struct csis_data *csis = data; + const struct btd_adapter *adapter = match_data; + + return csis->adapter == adapter; +} + +static void csis_data_free(struct csis_data *data) +{ + bt_csip_unref(data->csip); + free(data); +} + +static void csis_data_remove(struct csis_data *data) +{ + DBG("data %p", data); + + csis_data_free(data); + + if (queue_isempty(servers)) { + queue_destroy(servers, NULL); + servers = NULL; + } +} + +static void csis_server_remove(struct btd_profile *p, + struct btd_adapter *adapter) +{ + struct csis_data *data; + + DBG("path %s", adapter_get_path(adapter)); + + data = queue_remove_if(servers, match_csis, adapter); + if (!data) + return; + + csis_data_remove(data); +} + +static struct btd_profile csis_profile = { + .name = "csis", + .priority = BTD_PROFILE_PRIORITY_MEDIUM, + .local_uuid = CSIS_UUID_STR, + + .adapter_probe = csis_server_probe, + .adapter_remove = csis_server_remove, + .experimental = true, +}; + +static unsigned int csip_id; + +static int csip_init(void) +{ + int err; + + err = btd_profile_register(&csis_profile); + if (err) + return err; + + err = btd_profile_register(&csip_profile); + if (err) + return err; + + csip_id = bt_csip_register(csip_attached, csip_detached, NULL); + + return 0; +} + +static void csip_exit(void) +{ + btd_profile_unregister(&csis_profile); + btd_profile_unregister(&csip_profile); + bt_csip_unregister(csip_id); +} + +BLUETOOTH_PLUGIN_DEFINE(csip, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, + csip_init, csip_exit) diff --git a/profiles/audio/mcp.c b/profiles/audio/mcp.c index f3ea330f9839b4eb2f1cf5a21360d50d060561fb..0a2991f2074ff9574b402fd37a5657e49f7466ec 100644 --- a/profiles/audio/mcp.c +++ b/profiles/audio/mcp.c @@ -169,7 +169,7 @@ static void cb_track_duration(struct bt_mcp *mcp, int32_t duration) unsigned char buf[10]; /* MCP defines duration is int32 but api takes it as uint32 */ - sprintf((char *)buf, "%d", duration); + snprintf((char *)buf, 10, "%d", duration); media_player_set_metadata(mp, NULL, "Duration", buf, sizeof(buf)); media_player_metadata_changed(mp); } @@ -224,13 +224,27 @@ static int ct_stop(struct media_player *mp, void *user_data) return bt_mcp_stop(mcp); } +static int ct_next(struct media_player *mp, void *user_data) +{ + struct bt_mcp *mcp = user_data; + + return bt_mcp_next_track(mcp); +} + +static int ct_previous(struct media_player *mp, void *user_data) +{ + struct bt_mcp *mcp = user_data; + + return bt_mcp_previous_track(mcp); +} + static const struct media_player_callback ct_cbs = { .set_setting = NULL, .play = &ct_play, .pause = &ct_pause, .stop = &ct_stop, - .next = NULL, - .previous = NULL, + .next = &ct_next, + .previous = &ct_previous, .fast_forward = NULL, .rewind = NULL, .press = NULL, @@ -403,27 +417,18 @@ static struct btd_profile mcp_profile = { .adapter_probe = media_control_server_probe, .adapter_remove = media_control_server_remove, + + .experimental = true, }; static int mcp_init(void) { - DBG(""); - - if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) { - warn("D-Bus experimental not enabled"); - return -ENOTSUP; - } - - btd_profile_register(&mcp_profile); - return 0; + return btd_profile_register(&mcp_profile); } static void mcp_exit(void) { - DBG(""); - - if (g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL) - btd_profile_unregister(&mcp_profile); + btd_profile_unregister(&mcp_profile); } BLUETOOTH_PLUGIN_DEFINE(mcp, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, diff --git a/profiles/audio/media.c b/profiles/audio/media.c index c9328ab9bd6e905858104972054d7474968d13fa..746e538fcacdfe221c31607bd09113bdfd0f0fbb 100644 --- a/profiles/audio/media.c +++ b/profiles/audio/media.c @@ -6,7 +6,7 @@ * Copyright (C) 2006-2007 Nokia Corporation * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org> * Copyright (C) 2011 BMW Car IT GmbH. All rights reserved. - * + * Copyright 2023 NXP * */ @@ -23,6 +23,7 @@ #include "lib/bluetooth.h" #include "lib/sdp.h" #include "lib/uuid.h" +#include "lib/mgmt.h" #include "gdbus/gdbus.h" @@ -37,10 +38,12 @@ #include "src/log.h" #include "src/error.h" #include "src/gatt-database.h" +#include "src/shared/asha.h" #include "src/shared/util.h" #include "src/shared/queue.h" #include "src/shared/att.h" #include "src/shared/bap.h" +#include "src/shared/bap-debug.h" #include "avdtp.h" #include "media.h" @@ -86,15 +89,19 @@ struct endpoint_request { struct media_endpoint { struct a2dp_sep *sep; struct bt_bap_pac *pac; - void *stream; + struct bt_asha_device *asha; char *sender; /* Endpoint DBus bus id */ char *path; /* Endpoint object path */ char *uuid; /* Endpoint property UUID */ uint8_t codec; /* Endpoint codec */ + uint16_t cid; /* Endpoint company ID */ + uint16_t vid; /* Endpoint vendor codec ID */ bool delay_reporting;/* Endpoint delay_reporting */ struct bt_bap_pac_qos qos; /* Endpoint qos */ uint8_t *capabilities; /* Endpoint property capabilities */ size_t size; /* Endpoint capabilities size */ + uint8_t *metadata; /* Endpoint property metadata */ + size_t metadata_size; /* Endpoint metadata size */ guint hs_watch; guint ag_watch; guint watch; @@ -144,6 +151,11 @@ static void media_endpoint_cancel(struct endpoint_request *request) { struct media_endpoint *endpoint = request->endpoint; + DBG("Canceling %s: name = %s path = %s", + dbus_message_get_member(request->msg), + dbus_message_get_destination(request->msg), + dbus_message_get_path(request->msg)); + if (request->call) dbus_pending_call_cancel(request->call); @@ -178,6 +190,7 @@ static void media_endpoint_destroy(struct media_endpoint *endpoint) g_dbus_remove_watch(btd_get_dbus_connection(), endpoint->watch); g_free(endpoint->capabilities); + g_free(endpoint->metadata); g_free(endpoint->sender); g_free(endpoint->path); g_free(endpoint->uuid); @@ -725,33 +738,33 @@ struct pac_select_data { void *user_data; }; -static int parse_array(DBusMessageIter *iter, struct iovec **iov) +static int parse_array(DBusMessageIter *iter, struct iovec *iov) { DBusMessageIter array; if (!iov) return 0; - if (!(*iov)) - *iov = new0(struct iovec, 1); - dbus_message_iter_recurse(iter, &array); - dbus_message_iter_get_fixed_array(&array, &(*iov)->iov_base, - (int *)&(*iov)->iov_len); + dbus_message_iter_get_fixed_array(&array, &iov->iov_base, + (int *)&iov->iov_len); return 0; } -static int parse_select_properties(DBusMessageIter *props, struct iovec **caps, - struct iovec **metadata, - struct bt_bap_qos *qos) +static int parse_ucast_qos(DBusMessageIter *iter, struct bt_bap_qos *qos) { + DBusMessageIter array; const char *key; + struct bt_bap_io_qos io_qos; - while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) { + dbus_message_iter_recurse(iter, &array); + + memset(&io_qos, 0, sizeof(io_qos)); + while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) { DBusMessageIter value, entry; int var; - dbus_message_iter_recurse(props, &entry); + dbus_message_iter_recurse(&array, &entry); dbus_message_iter_get_basic(&entry, &key); dbus_message_iter_next(&entry); @@ -759,97 +772,119 @@ static int parse_select_properties(DBusMessageIter *props, struct iovec **caps, var = dbus_message_iter_get_arg_type(&value); - if (!strcasecmp(key, "Capabilities")) { - if (var != DBUS_TYPE_ARRAY) - goto fail; - - if (parse_array(&value, caps)) - goto fail; - } else if (!strcasecmp(key, "Metadata")) { - if (var != DBUS_TYPE_ARRAY) - goto fail; - - if (parse_array(&value, metadata)) - goto fail; - } else if (!strcasecmp(key, "CIG")) { + if (!strcasecmp(key, "CIG")) { if (var != DBUS_TYPE_BYTE) goto fail; - dbus_message_iter_get_basic(&value, &qos->cig_id); + dbus_message_iter_get_basic(&value, &qos->ucast.cig_id); } else if (!strcasecmp(key, "CIS")) { if (var != DBUS_TYPE_BYTE) goto fail; - dbus_message_iter_get_basic(&value, &qos->cis_id); + dbus_message_iter_get_basic(&value, &qos->ucast.cis_id); } else if (!strcasecmp(key, "Interval")) { if (var != DBUS_TYPE_UINT32) goto fail; - dbus_message_iter_get_basic(&value, &qos->interval); + dbus_message_iter_get_basic(&value, &io_qos.interval); } else if (!strcasecmp(key, "Framing")) { - dbus_bool_t val; - - if (var != DBUS_TYPE_BOOLEAN) + if (var != DBUS_TYPE_BYTE) goto fail; - dbus_message_iter_get_basic(&value, &val); - - qos->framing = val; + dbus_message_iter_get_basic(&value, + &qos->ucast.framing); } else if (!strcasecmp(key, "PHY")) { - const char *str; - - if (var != DBUS_TYPE_STRING) + if (var != DBUS_TYPE_BYTE) goto fail; - dbus_message_iter_get_basic(&value, &str); - - if (!strcasecmp(str, "1M")) - qos->phy = 0x01; - else if (!strcasecmp(str, "2M")) - qos->phy = 0x02; - else - goto fail; + dbus_message_iter_get_basic(&value, &io_qos.phy); } else if (!strcasecmp(key, "SDU")) { if (var != DBUS_TYPE_UINT16) goto fail; - dbus_message_iter_get_basic(&value, &qos->sdu); + dbus_message_iter_get_basic(&value, &io_qos.sdu); } else if (!strcasecmp(key, "Retransmissions")) { if (var != DBUS_TYPE_BYTE) goto fail; - dbus_message_iter_get_basic(&value, &qos->rtn); + dbus_message_iter_get_basic(&value, &io_qos.rtn); } else if (!strcasecmp(key, "Latency")) { if (var != DBUS_TYPE_UINT16) goto fail; - dbus_message_iter_get_basic(&value, &qos->latency); - } else if (!strcasecmp(key, "Delay")) { + dbus_message_iter_get_basic(&value, &io_qos.latency); + } else if (!strcasecmp(key, "PresentationDelay")) { if (var != DBUS_TYPE_UINT32) goto fail; - dbus_message_iter_get_basic(&value, &qos->delay); + dbus_message_iter_get_basic(&value, &qos->ucast.delay); } else if (!strcasecmp(key, "TargetLatency")) { if (var != DBUS_TYPE_BYTE) goto fail; dbus_message_iter_get_basic(&value, - &qos->target_latency); + &qos->ucast.target_latency); } - dbus_message_iter_next(props); + dbus_message_iter_next(&array); } + memcpy(&qos->ucast.io_qos, &io_qos, sizeof(io_qos)); + return 0; fail: DBG("Failed parsing %s", key); - if (*caps) { - free(*caps); - *caps = NULL; + return -EINVAL; +} + +static int parse_select_properties(DBusMessageIter *props, struct iovec *caps, + struct iovec *metadata, + struct bt_bap_qos *qos) +{ + const char *key; + + while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter value, entry; + int var; + + dbus_message_iter_recurse(props, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &value); + + var = dbus_message_iter_get_arg_type(&value); + + if (!strcasecmp(key, "Capabilities")) { + if (var != DBUS_TYPE_ARRAY) + goto fail; + + if (parse_array(&value, caps)) + goto fail; + } else if (!strcasecmp(key, "Metadata")) { + if (var != DBUS_TYPE_ARRAY) + goto fail; + + if (parse_array(&value, metadata)) + goto fail; + } else if (!strcasecmp(key, "QoS")) { + if (var != DBUS_TYPE_ARRAY) + goto fail; + + if (parse_ucast_qos(&value, qos)) + goto fail; + } + + dbus_message_iter_next(props); } + return 0; + +fail: + DBG("Failed parsing %s", key); + return -EINVAL; } @@ -859,7 +894,7 @@ static void pac_select_cb(struct media_endpoint *endpoint, void *ret, int size, struct pac_select_data *data = user_data; DBusMessageIter *iter = ret; int err; - struct iovec *caps = NULL, *metadata = NULL; + struct iovec caps, meta; struct bt_bap_qos qos; if (!ret) { @@ -878,19 +913,22 @@ static void pac_select_cb(struct media_endpoint *endpoint, void *ret, int size, memset(&qos, 0, sizeof(qos)); /* Mark CIG and CIS to be auto assigned */ - qos.cig_id = BT_ISO_QOS_CIG_UNSET; - qos.cis_id = BT_ISO_QOS_CIS_UNSET; + qos.ucast.cig_id = BT_ISO_QOS_CIG_UNSET; + qos.ucast.cis_id = BT_ISO_QOS_CIS_UNSET; - err = parse_select_properties(iter, &caps, &metadata, &qos); + memset(&caps, 0, sizeof(caps)); + memset(&meta, 0, sizeof(meta)); + + err = parse_select_properties(iter, &caps, &meta, &qos); if (err < 0) DBG("Unable to parse properties"); done: - data->cb(data->pac, err, caps, metadata, &qos, data->user_data); + data->cb(data->pac, err, &caps, &meta, &qos, data->user_data); } static int pac_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, - struct bt_bap_pac_qos *qos, + uint32_t location, struct bt_bap_pac_qos *qos, bt_bap_pac_select_t cb, void *cb_data, void *user_data) { struct media_endpoint *endpoint = user_data; @@ -901,6 +939,7 @@ static int pac_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, DBusMessage *msg; DBusMessageIter iter, dict; const char *key = "Capabilities"; + uint32_t loc; bt_bap_pac_get_codec(rpac, NULL, &caps, &metadata); if (!caps) @@ -932,6 +971,15 @@ static int pac_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, DBUS_TYPE_BYTE, &caps->iov_base, caps->iov_len); + loc = bt_bap_pac_get_locations(rpac); + if (loc) + g_dbus_dict_append_entry(&dict, "Locations", DBUS_TYPE_UINT32, + &loc); + + if (location) + g_dbus_dict_append_entry(&dict, "ChannelAllocation", + DBUS_TYPE_UINT32, &location); + if (metadata) { key = "Metadata"; g_dbus_dict_append_basic_array(&dict, DBUS_TYPE_STRING, &key, @@ -941,26 +989,44 @@ static int pac_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, } if (qos && qos->phy) { - g_dbus_dict_append_entry(&dict, "Framing", DBUS_TYPE_BYTE, + DBusMessageIter entry, variant, qos_dict; + + key = "QoS"; + 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_open_container(&entry, DBUS_TYPE_VARIANT, + "a{sv}", &variant); + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, + "{sv}", &qos_dict); + + g_dbus_dict_append_entry(&qos_dict, "Framing", DBUS_TYPE_BYTE, &qos->framing); - g_dbus_dict_append_entry(&dict, "PHY", DBUS_TYPE_BYTE, + g_dbus_dict_append_entry(&qos_dict, "PHY", DBUS_TYPE_BYTE, &qos->phy); - g_dbus_dict_append_entry(&dict, "Latency", DBUS_TYPE_UINT16, - &qos->latency); + g_dbus_dict_append_entry(&qos_dict, "Retransmissions", + DBUS_TYPE_BYTE, &qos->rtn); + + g_dbus_dict_append_entry(&qos_dict, "MaximumLatency", + DBUS_TYPE_UINT16, &qos->latency); - g_dbus_dict_append_entry(&dict, "MinimumDelay", + g_dbus_dict_append_entry(&qos_dict, "MinimumDelay", DBUS_TYPE_UINT32, &qos->pd_min); - g_dbus_dict_append_entry(&dict, "MaximumDelay", + g_dbus_dict_append_entry(&qos_dict, "MaximumDelay", DBUS_TYPE_UINT32, &qos->pd_max); - g_dbus_dict_append_entry(&dict, "PreferredMinimumDelay", + g_dbus_dict_append_entry(&qos_dict, "PreferredMinimumDelay", DBUS_TYPE_UINT32, &qos->ppd_min); - g_dbus_dict_append_entry(&dict, "PreferredMaximumDelay", - DBUS_TYPE_UINT32, &qos->ppd_min); + g_dbus_dict_append_entry(&qos_dict, "PreferredMaximumDelay", + DBUS_TYPE_UINT32, &qos->ppd_max); + + dbus_message_iter_close_container(&variant, &qos_dict); + dbus_message_iter_close_container(&entry, &variant); + dbus_message_iter_close_container(&dict, &entry); } dbus_message_iter_close_container(&iter, &dict); @@ -969,6 +1035,33 @@ static int pac_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, data, free); } +static void pac_cancel_select(struct bt_bap_pac *lpac, bt_bap_pac_select_t cb, + void *cb_data, void *user_data) +{ + struct media_endpoint *endpoint = user_data; + GSList *l = endpoint->requests; + + while (l) { + struct endpoint_request *req = l->data; + struct pac_select_data *data; + + if (req->cb != pac_select_cb) { + l = g_slist_next(l); + continue; + } + + data = req->user_data; + if (data->pac != lpac || data->cb != cb || + data->user_data != cb_data) { + l = g_slist_next(l); + continue; + } + + media_endpoint_cancel(req); + l = endpoint->requests; + } +} + struct pac_config_data { struct bt_bap_stream *stream; bt_bap_pac_config_t cb; @@ -978,23 +1071,20 @@ struct pac_config_data { static int transport_cmp(gconstpointer data, gconstpointer user_data) { const struct media_transport *transport = data; - const char *path = user_data; - if (g_str_has_prefix(media_transport_get_path((void *)transport), path)) + if (media_transport_get_stream((void *)transport) == user_data) return 0; return -1; } static struct media_transport *find_transport(struct media_endpoint *endpoint, - const char *path) + void *stream) { GSList *match; - if (!path) - return NULL; - - match = g_slist_find_custom(endpoint->transports, path, transport_cmp); + match = g_slist_find_custom(endpoint->transports, stream, + transport_cmp); if (match == NULL) return NULL; @@ -1006,13 +1096,68 @@ static void pac_config_cb(struct media_endpoint *endpoint, void *ret, int size, { struct pac_config_data *data = user_data; gboolean *ret_value = ret; + struct media_transport *transport; - if (ret_value) - endpoint->stream = data->stream; + /* If transport was cleared, configuration was cancelled */ + transport = find_transport(endpoint, data->stream); + if (!transport) + return; data->cb(data->stream, ret_value ? 0 : -EINVAL); } +static struct media_transport *pac_ucast_config(struct bt_bap_stream *stream, + struct iovec *cfg, + struct media_endpoint *endpoint) +{ + struct bt_bap *bap = bt_bap_stream_get_session(stream); + struct btd_service *service = bt_bap_get_user_data(bap); + struct btd_device *device; + const char *path; + + if (service) + device = btd_service_get_device(service); + else { + struct bt_att *att = bt_bap_get_att(bap); + int fd = bt_att_get_fd(att); + + device = btd_adapter_find_device_by_fd(fd); + } + + if (!device) { + error("Unable to find device"); + return NULL; + } + + path = bt_bap_stream_get_user_data(stream); + + return media_transport_create(device, path, cfg->iov_base, cfg->iov_len, + endpoint, stream); +} + +static struct media_transport *pac_bcast_config(struct bt_bap_stream *stream, + struct iovec *cfg, + struct media_endpoint *endpoint) +{ + struct bt_bap *bap = bt_bap_stream_get_session(stream); + struct btd_adapter *adapter = endpoint->adapter->btd_adapter; + struct btd_device *device; + const char *path; + + if (!adapter) + return NULL; + + if (!strcmp(endpoint->uuid, BCAA_SERVICE_UUID)) + device = NULL; + else + device = btd_service_get_device(bt_bap_get_user_data(bap)); + + path = bt_bap_stream_get_user_data(stream); + + return media_transport_create(device, path, cfg->iov_base, cfg->iov_len, + endpoint, stream); +} + static int pac_config(struct bt_bap_stream *stream, struct iovec *cfg, struct bt_bap_qos *qos, bt_bap_pac_config_t cb, void *user_data) @@ -1025,38 +1170,24 @@ static int pac_config(struct bt_bap_stream *stream, struct iovec *cfg, DBusMessageIter iter; const char *path; - path = bt_bap_stream_get_user_data(stream); - - DBG("endpoint %p path %s", endpoint, path); + DBG("endpoint %p stream %p", endpoint, stream); - transport = find_transport(endpoint, path); + transport = find_transport(endpoint, stream); if (!transport) { - struct bt_bap *bap = bt_bap_stream_get_session(stream); - struct btd_service *service = bt_bap_get_user_data(bap); - struct btd_device *device; - - if (service) - device = btd_service_get_device(service); - else { - struct bt_att *att = bt_bap_get_att(bap); - int fd = bt_att_get_fd(att); - - device = btd_adapter_find_device_by_fd(fd); - } - - if (!device) { - error("Unable to find device"); - return -EINVAL; + switch (bt_bap_stream_get_type(stream)) { + case BT_BAP_STREAM_TYPE_UCAST: + transport = pac_ucast_config(stream, cfg, endpoint); + break; + case BT_BAP_STREAM_TYPE_BCAST: + transport = pac_bcast_config(stream, cfg, endpoint); + break; } - transport = media_transport_create(device, path, cfg->iov_base, - cfg->iov_len, endpoint, - stream); if (!transport) return -EINVAL; - path = media_transport_get_path(transport); - bt_bap_stream_set_user_data(stream, (void *)path); + endpoint->transports = g_slist_append(endpoint->transports, + transport); } msg = dbus_message_new_method_call(endpoint->sender, endpoint->path, @@ -1064,7 +1195,7 @@ static int pac_config(struct bt_bap_stream *stream, struct iovec *cfg, "SetConfiguration"); if (msg == NULL) { error("Couldn't allocate D-Bus message"); - media_transport_destroy(transport); + endpoint_remove_transport(endpoint, transport); return FALSE; } @@ -1073,8 +1204,6 @@ static int pac_config(struct bt_bap_stream *stream, struct iovec *cfg, data->cb = cb; data->user_data = user_data; - endpoint->transports = g_slist_append(endpoint->transports, transport); - dbus_message_iter_init_append(msg, &iter); path = media_transport_get_path(transport); @@ -1089,15 +1218,18 @@ static int pac_config(struct bt_bap_stream *stream, struct iovec *cfg, static void pac_clear(struct bt_bap_stream *stream, void *user_data) { struct media_endpoint *endpoint = user_data; + struct media_transport *transport; - endpoint->stream = NULL; + DBG("endpoint %p stream %p", endpoint, stream); - while (endpoint->transports != NULL) - clear_configuration(endpoint, endpoint->transports->data); + transport = find_transport(endpoint, stream); + if (transport) + clear_configuration(endpoint, transport); } static struct bt_bap_pac_ops pac_ops = { .select = pac_select, + .cancel_select = pac_cancel_select, .config = pac_config, .clear = pac_clear, }; @@ -1113,6 +1245,7 @@ static bool endpoint_init_pac(struct media_endpoint *endpoint, uint8_t type, struct btd_gatt_database *database; struct gatt_db *db; struct iovec data; + struct iovec *metadata = NULL; char *name; if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) { @@ -1127,29 +1260,44 @@ static bool endpoint_init_pac(struct media_endpoint *endpoint, uint8_t type, return false; } - if (!bap_print_cc(endpoint->capabilities, endpoint->size, bap_debug, - NULL)) { + if (!bt_bap_debug_caps(endpoint->capabilities, endpoint->size, + bap_debug, NULL)) { error("Unable to parse endpoint capabilities"); return false; } + if (!bt_bap_debug_metadata(endpoint->metadata, endpoint->metadata_size, + bap_debug, NULL)) { + error("Unable to parse endpoint metadata"); + return false; + } + db = btd_gatt_database_get_db(database); data.iov_base = endpoint->capabilities; data.iov_len = endpoint->size; - /* TODO: Add support for metadata */ - if (asprintf(&name, "%s:%s", endpoint->sender, endpoint->path) < 0) { error("Could not allocate name for pac %s:%s", endpoint->sender, endpoint->path); + free(name); return false; } - endpoint->pac = bt_bap_add_pac(db, name, type, endpoint->codec, - &endpoint->qos, &data, NULL); + /* TODO: Add support for metadata */ + if (endpoint->metadata_size) { + metadata = g_new0(struct iovec, 1); + metadata->iov_base = endpoint->metadata; + metadata->iov_len = endpoint->metadata_size; + } + + endpoint->pac = bt_bap_add_vendor_pac(db, name, type, endpoint->codec, + endpoint->cid, endpoint->vid, &endpoint->qos, + &data, metadata); if (!endpoint->pac) { error("Unable to create PAC"); + free(name); + free(metadata); return false; } @@ -1158,6 +1306,7 @@ static bool endpoint_init_pac(struct media_endpoint *endpoint, uint8_t type, DBG("PAC %s registered", name); free(name); + free(metadata); return true; } @@ -1172,6 +1321,24 @@ static bool endpoint_init_pac_source(struct media_endpoint *endpoint, int *err) return endpoint_init_pac(endpoint, BT_BAP_SOURCE, err); } +static bool endpoint_init_broadcast_source(struct media_endpoint *endpoint, + int *err) +{ + return endpoint_init_pac(endpoint, BT_BAP_BCAST_SOURCE, err); +} + +static bool endpoint_init_broadcast_sink(struct media_endpoint *endpoint, + int *err) +{ + return endpoint_init_pac(endpoint, BT_BAP_BCAST_SINK, err); +} + +static bool endpoint_init_asha(struct media_endpoint *endpoint, + int *err) +{ + return true; +} + static bool endpoint_properties_exists(const char *uuid, struct btd_device *dev, void *user_data) @@ -1254,8 +1421,11 @@ static bool endpoint_properties_get(const char *uuid, return true; } -static bool endpoint_supported(struct btd_adapter *adapter) +static bool a2dp_endpoint_supported(struct btd_adapter *adapter) { + if (!btd_adapter_has_settings(adapter, MGMT_SETTING_BREDR)) + return false; + return true; } @@ -1264,20 +1434,59 @@ static bool experimental_endpoint_supported(struct btd_adapter *adapter) if (!btd_adapter_has_exp_feature(adapter, EXP_FEAT_ISO_SOCKET)) return false; + if (!btd_adapter_has_settings(adapter, MGMT_SETTING_CIS_CENTRAL | + MGMT_SETTING_CIS_PERIPHERAL)) + return false; + return g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL; } -static struct media_endpoint_init { +static bool experimental_broadcaster_ep_supported(struct btd_adapter *adapter) +{ + if (!btd_adapter_has_exp_feature(adapter, EXP_FEAT_ISO_SOCKET)) + return false; + + if (!btd_adapter_has_settings(adapter, MGMT_SETTING_ISO_BROADCASTER)) + return false; + + return g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL; +} + +static bool experimental_bcast_sink_ep_supported(struct btd_adapter *adapter) +{ + if (!btd_adapter_has_exp_feature(adapter, EXP_FEAT_ISO_SOCKET)) + return false; + + if (!btd_adapter_has_settings(adapter, MGMT_SETTING_ISO_SYNC_RECEIVER)) + return false; + + return g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL; +} + +static bool experimental_asha_supported(struct btd_adapter *adapter) +{ + return g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL; +} + +static const struct media_endpoint_init { const char *uuid; bool (*func)(struct media_endpoint *endpoint, int *err); bool (*supported)(struct btd_adapter *adapter); } init_table[] = { - { A2DP_SOURCE_UUID, endpoint_init_a2dp_source, endpoint_supported }, - { A2DP_SINK_UUID, endpoint_init_a2dp_sink, endpoint_supported }, + { A2DP_SOURCE_UUID, endpoint_init_a2dp_source, + a2dp_endpoint_supported }, + { A2DP_SINK_UUID, endpoint_init_a2dp_sink, + a2dp_endpoint_supported }, { PAC_SINK_UUID, endpoint_init_pac_sink, experimental_endpoint_supported }, { PAC_SOURCE_UUID, endpoint_init_pac_source, experimental_endpoint_supported }, + { BCAA_SERVICE_UUID, endpoint_init_broadcast_source, + experimental_broadcaster_ep_supported }, + { BAA_SERVICE_UUID, endpoint_init_broadcast_sink, + experimental_bcast_sink_ep_supported }, + { ASHA_PROFILE_UUID, endpoint_init_asha, + experimental_asha_supported }, }; static struct media_endpoint * @@ -1287,13 +1496,17 @@ media_endpoint_create(struct media_adapter *adapter, const char *uuid, gboolean delay_reporting, uint8_t codec, + uint16_t cid, + uint16_t vid, struct bt_bap_pac_qos *qos, uint8_t *capabilities, int size, + uint8_t *metadata, + int metadata_size, int *err) { struct media_endpoint *endpoint; - struct media_endpoint_init *init; + const struct media_endpoint_init *init; size_t i; bool succeeded = false; @@ -1302,6 +1515,8 @@ media_endpoint_create(struct media_adapter *adapter, endpoint->path = g_strdup(path); endpoint->uuid = g_strdup(uuid); endpoint->codec = codec; + endpoint->cid = cid; + endpoint->vid = vid; endpoint->delay_reporting = delay_reporting; if (qos) @@ -1313,6 +1528,12 @@ media_endpoint_create(struct media_adapter *adapter, endpoint->size = size; } + if (metadata_size > 0) { + endpoint->metadata = g_new(uint8_t, metadata_size); + memcpy(endpoint->metadata, metadata, metadata_size); + endpoint->metadata_size = metadata_size; + } + endpoint->adapter = adapter; for (i = 0; i < ARRAY_SIZE(init_table); i++) { @@ -1352,13 +1573,21 @@ media_endpoint_create(struct media_adapter *adapter, return endpoint; } +struct vendor { + uint16_t cid; + uint16_t vid; +} __packed; + static int parse_properties(DBusMessageIter *props, const char **uuid, gboolean *delay_reporting, uint8_t *codec, + uint16_t *cid, uint16_t *vid, struct bt_bap_pac_qos *qos, - uint8_t **capabilities, int *size) + uint8_t **capabilities, int *size, + uint8_t **metadata, int *metadata_size) { gboolean has_uuid = FALSE; gboolean has_codec = FALSE; + struct vendor vendor; while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) { const char *key; @@ -1382,6 +1611,12 @@ static int parse_properties(DBusMessageIter *props, const char **uuid, return -EINVAL; dbus_message_iter_get_basic(&value, codec); has_codec = TRUE; + } else if (strcasecmp(key, "Vendor") == 0) { + if (var != DBUS_TYPE_UINT32) + return -EINVAL; + dbus_message_iter_get_basic(&value, &vendor); + *cid = vendor.cid; + *vid = vendor.vid; } else if (strcasecmp(key, "DelayReporting") == 0) { if (var != DBUS_TYPE_BOOLEAN) return -EINVAL; @@ -1395,6 +1630,15 @@ static int parse_properties(DBusMessageIter *props, const char **uuid, dbus_message_iter_recurse(&value, &array); dbus_message_iter_get_fixed_array(&array, capabilities, size); + } else if (strcasecmp(key, "Metadata") == 0) { + DBusMessageIter array; + + if (var != DBUS_TYPE_ARRAY) + return -EINVAL; + + dbus_message_iter_recurse(&value, &array); + dbus_message_iter_get_fixed_array(&array, metadata, + metadata_size); } else if (strcasecmp(key, "Framing") == 0) { if (var != DBUS_TYPE_BYTE) return -EINVAL; @@ -1403,7 +1647,7 @@ static int parse_properties(DBusMessageIter *props, const char **uuid, if (var != DBUS_TYPE_BYTE) return -EINVAL; dbus_message_iter_get_basic(&value, &qos->phy); - } else if (strcasecmp(key, "RTN") == 0) { + } else if (strcasecmp(key, "Retransmissions") == 0) { if (var != DBUS_TYPE_BYTE) return -EINVAL; dbus_message_iter_get_basic(&value, &qos->rtn); @@ -1418,11 +1662,24 @@ static int parse_properties(DBusMessageIter *props, const char **uuid, } else if (strcasecmp(key, "PreferredMinimumDelay") == 0) { if (var != DBUS_TYPE_UINT16) return -EINVAL; - dbus_message_iter_get_basic(&value, &qos->pd_min); + dbus_message_iter_get_basic(&value, &qos->ppd_min); } else if (strcasecmp(key, "PreferredMaximumDelay") == 0) { if (var != DBUS_TYPE_UINT16) return -EINVAL; - dbus_message_iter_get_basic(&value, &qos->pd_max); + dbus_message_iter_get_basic(&value, &qos->ppd_max); + } else if (strcasecmp(key, "Locations") == 0) { + if (var != DBUS_TYPE_UINT32) + return -EINVAL; + dbus_message_iter_get_basic(&value, &qos->location); + } else if (strcasecmp(key, "Context") == 0) { + if (var != DBUS_TYPE_UINT16) + return -EINVAL; + dbus_message_iter_get_basic(&value, &qos->context); + } else if (strcasecmp(key, "SupportedContext") == 0) { + if (var != DBUS_TYPE_UINT16) + return -EINVAL; + dbus_message_iter_get_basic(&value, + &qos->supported_context); } dbus_message_iter_next(props); @@ -1439,9 +1696,13 @@ static DBusMessage *register_endpoint(DBusConnection *conn, DBusMessage *msg, const char *sender, *path, *uuid; gboolean delay_reporting = FALSE; uint8_t codec = 0; + uint16_t cid = 0; + uint16_t vid = 0; struct bt_bap_pac_qos qos = {}; uint8_t *capabilities = NULL; + uint8_t *metadata = NULL; int size = 0; + int metadata_size = 0; int err; sender = dbus_message_get_sender(msg); @@ -1458,12 +1719,14 @@ static DBusMessage *register_endpoint(DBusConnection *conn, DBusMessage *msg, if (dbus_message_iter_get_arg_type(&props) != DBUS_TYPE_DICT_ENTRY) return btd_error_invalid_args(msg); - if (parse_properties(&props, &uuid, &delay_reporting, &codec, &qos, - &capabilities, &size) < 0) + if (parse_properties(&props, &uuid, &delay_reporting, &codec, &cid, + &vid, &qos, &capabilities, &size, &metadata, + &metadata_size) < 0) return btd_error_invalid_args(msg); if (media_endpoint_create(adapter, sender, path, uuid, delay_reporting, - codec, &qos, capabilities, size, + codec, cid, vid, &qos, capabilities, + size, metadata, metadata_size, &err) == NULL) { if (err == -EPROTONOSUPPORT) return btd_error_not_supported(msg); @@ -2490,9 +2753,12 @@ static void app_register_endpoint(void *data, void *user_data) const char *uuid; gboolean delay_reporting = FALSE; uint8_t codec; + struct vendor vendor; struct bt_bap_pac_qos qos; uint8_t *capabilities = NULL; int size = 0; + uint8_t *metadata = NULL; + int metadata_size = 0; DBusMessageIter iter, array; struct media_endpoint *endpoint; @@ -2519,6 +2785,15 @@ static void app_register_endpoint(void *data, void *user_data) dbus_message_iter_get_basic(&iter, &codec); + memset(&vendor, 0, sizeof(vendor)); + + if (g_dbus_proxy_get_property(proxy, "Vendor", &iter)) { + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) + goto fail; + + dbus_message_iter_get_basic(&iter, &vendor); + } + /* DelayReporting and Capabilities are considered optional */ if (g_dbus_proxy_get_property(proxy, "DelayReporting", &iter)) { if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) @@ -2535,6 +2810,15 @@ static void app_register_endpoint(void *data, void *user_data) dbus_message_iter_get_fixed_array(&array, &capabilities, &size); } + if (g_dbus_proxy_get_property(proxy, "Metadata", &iter)) { + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) + goto fail; + + dbus_message_iter_recurse(&iter, &array); + dbus_message_iter_get_fixed_array(&array, &metadata, + &metadata_size); + } + /* Parse QoS preferences */ memset(&qos, 0, sizeof(qos)); if (g_dbus_proxy_get_property(proxy, "Framing", &iter)) { @@ -2551,7 +2835,7 @@ static void app_register_endpoint(void *data, void *user_data) dbus_message_iter_get_basic(&iter, &qos.phy); } - if (g_dbus_proxy_get_property(proxy, "Latency", &iter)) { + if (g_dbus_proxy_get_property(proxy, "MaximumLatency", &iter)) { if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT16) goto fail; @@ -2586,9 +2870,33 @@ static void app_register_endpoint(void *data, void *user_data) dbus_message_iter_get_basic(&iter, &qos.ppd_min); } + if (g_dbus_proxy_get_property(proxy, "Locations", &iter)) { + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) + goto fail; + + dbus_message_iter_get_basic(&iter, &qos.location); + } + + if (g_dbus_proxy_get_property(proxy, "Context", &iter)) { + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT16) + goto fail; + + dbus_message_iter_get_basic(&iter, &qos.context); + } + + if (g_dbus_proxy_get_property(proxy, "SupportedContext", &iter)) { + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT16) + goto fail; + + dbus_message_iter_get_basic(&iter, &qos.supported_context); + } + endpoint = media_endpoint_create(app->adapter, app->sender, path, uuid, - delay_reporting, codec, &qos, - capabilities, size, &app->err); + delay_reporting, codec, + vendor.cid, vendor.vid, &qos, + capabilities, size, + metadata, metadata_size, + &app->err); if (!endpoint) { error("Unable to register endpoint %s:%s: %s", app->sender, path, strerror(-app->err)); @@ -2726,9 +3034,6 @@ static void client_ready_cb(GDBusClient *client, void *user_data) goto reply; } - queue_foreach(app->proxies, app_register_endpoint, app); - queue_foreach(app->proxies, app_register_player, app); - if (app->err) { if (app->err == -EPROTONOSUPPORT) reply = btd_error_not_supported(app->reg); @@ -2772,6 +3077,10 @@ static void proxy_added_cb(GDBusProxy *proxy, void *user_data) path = g_dbus_proxy_get_path(proxy); DBG("Proxy added: %s, iface: %s", path, iface); + + app_register_endpoint(proxy, app); + app_register_player(proxy, app); + } static bool match_endpoint_by_path(const void *a, const void *b) @@ -2985,7 +3294,7 @@ static gboolean supported_uuids(const GDBusPropertyTable *property, DBUS_TYPE_STRING_AS_STRING, &entry); for (i = 0; i < ARRAY_SIZE(init_table); i++) { - struct media_endpoint_init *init = &init_table[i]; + const struct media_endpoint_init *init = &init_table[i]; if (init->supported(adapter->btd_adapter)) dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, @@ -3085,3 +3394,33 @@ uint8_t media_endpoint_get_codec(struct media_endpoint *endpoint) { return endpoint->codec; } + +struct btd_adapter *media_endpoint_get_btd_adapter( + struct media_endpoint *endpoint) +{ + return endpoint->adapter->btd_adapter; +} + +bool media_endpoint_is_broadcast(struct media_endpoint *endpoint) +{ + if (!strcmp(endpoint->uuid, BCAA_SERVICE_UUID) + || !strcmp(endpoint->uuid, BAA_SERVICE_UUID)) + return true; + + return false; +} + +const struct media_endpoint *media_endpoint_get_asha(void) +{ + /* + * Because ASHA does not require the application to register an + * endpoint, we need a minimal media_endpoint for transport creation to + * work, so let's create one + */ + static struct media_endpoint asha_endpoint = { + .uuid = ASHA_PROFILE_UUID, + .codec = 0x2, /* Currently on G.722 is defined by the spec */ + }; + + return &asha_endpoint; +} diff --git a/profiles/audio/media.h b/profiles/audio/media.h index 96bea9db4c748b6b139b04bcb53b60fe8b963e24..2b2e8e1572874d5f71abb28fdd5b92fa2d9efe83 100644 --- a/profiles/audio/media.h +++ b/profiles/audio/media.h @@ -20,5 +20,9 @@ void media_unregister(struct btd_adapter *btd_adapter); struct a2dp_sep *media_endpoint_get_sep(struct media_endpoint *endpoint); const char *media_endpoint_get_uuid(struct media_endpoint *endpoint); uint8_t media_endpoint_get_codec(struct media_endpoint *endpoint); - +struct btd_adapter *media_endpoint_get_btd_adapter( + struct media_endpoint *endpoint); +bool media_endpoint_is_broadcast(struct media_endpoint *endpoint); int8_t media_player_get_device_volume(struct btd_device *device); + +const struct media_endpoint *media_endpoint_get_asha(void); diff --git a/profiles/audio/micp.c b/profiles/audio/micp.c new file mode 100644 index 0000000000000000000000000000000000000000..452027c75da25f8d73287733d1d3b959d5333402 --- /dev/null +++ b/profiles/audio/micp.c @@ -0,0 +1,340 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2023 NXP Semiconductors. All rights reserved. + * + * + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE + +#include <ctype.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#include <glib.h> + +#include "gdbus/gdbus.h" + +#include "lib/bluetooth.h" +#include "lib/hci.h" +#include "lib/sdp.h" +#include "lib/uuid.h" + +#include "src/dbus-common.h" +#include "src/shared/util.h" +#include "src/shared/att.h" +#include "src/shared/queue.h" +#include "src/shared/gatt-db.h" +#include "src/shared/gatt-server.h" +#include "src/shared/micp.h" + +#include "btio/btio.h" +#include "src/plugin.h" +#include "src/adapter.h" +#include "src/gatt-database.h" +#include "src/device.h" +#include "src/profile.h" +#include "src/service.h" +#include "src/log.h" +#include "src/error.h" + +#define MICS_UUID_STR "0000184D-0000-1000-8000-00805f9b34fb" + +struct micp_data { + struct btd_device *device; + struct btd_service *service; + struct bt_micp *micp; + unsigned int ready_id; +}; + +static struct queue *sessions; + +static void micp_debug(const char *str, void *user_data) +{ + DBG_IDX(0xffff, "%s", str); +} + +static int micp_disconnect(struct btd_service *service) +{ + return 0; +} + +static struct micp_data *micp_data_new(struct btd_device *device) +{ + struct micp_data *data; + + data = new0(struct micp_data, 1); + g_assert(data); + data->device = device; + + return data; +} + +static void micp_data_add(struct micp_data *data) +{ + DBG("data %p", data); + + if (queue_find(sessions, NULL, data)) { + error("data %p allready added", data); + return; + } + + bt_micp_set_debug(data->micp, micp_debug, NULL, NULL); + + if (!sessions) + sessions = queue_new(); + + queue_push_tail(sessions, data); + + if (data->service) + btd_service_set_user_data(data->service, data); +} + +static bool match_data(const void *data, const void *match_data) +{ + const struct micp_data *mdata = data; + const struct bt_micp *micp = match_data; + + return mdata->micp == micp; +} + +static void micp_data_free(struct micp_data *data) +{ + if (data->service) { + btd_service_set_user_data(data->service, NULL); + bt_micp_set_user_data(data->micp, NULL); + } + + bt_micp_ready_unregister(data->micp, data->ready_id); + bt_micp_unref(data->micp); + free(data); +} + +static void micp_data_remove(struct micp_data *data) +{ + DBG("data %p", data); + + if (!queue_remove(sessions, data)) + return; + + micp_data_free(data); + + if (queue_isempty(sessions)) { + queue_destroy(sessions, NULL); + sessions = NULL; + } +} + +static void micp_detached(struct bt_micp *micp, void *user_data) +{ + struct micp_data *data; + + DBG("%p", micp); + + data = queue_find(sessions, match_data, micp); + if (!data) { + error("unable to find sessio"); + return; + } + + micp_data_remove(data); +} + +static void micp_ready(struct bt_micp *micp, void *user_data) +{ + DBG("micp %p\n", micp); +} + +static void micp_attached(struct bt_micp *micp, void *user_data) +{ + struct micp_data *data; + struct bt_att *att; + struct btd_device *device; + + DBG("%p", micp); + + data = queue_find(sessions, match_data, micp); + if (data) + return; + + att = bt_micp_get_att(micp); + if (!att) + return; + + device = btd_adapter_find_device_by_fd(bt_att_get_fd(att)); + if (!device) { + error("unable to find device"); + return; + } + + data = micp_data_new(device); + g_assert(data); + data->micp = micp; + + micp_data_add(data); +} + +static int micp_probe(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + struct btd_adapter *adapter = device_get_adapter(device); + struct btd_gatt_database *database = btd_adapter_get_database(adapter); + struct micp_data *data = btd_service_get_user_data(service); + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("%s", addr); + + /*Ignore, if we probed for this device allready */ + if (data) { + error("Profile probed twice for this device"); + return -EINVAL; + } + + data = micp_data_new(device); + data->service = service; + + data->micp = bt_micp_new(btd_gatt_database_get_db(database), + btd_device_get_gatt_db(device)); + + if (!data->micp) { + error("unable to create MICP instance"); + free(data); + return -EINVAL; + } + + micp_data_add(data); + + data->ready_id = bt_micp_ready_register(data->micp, micp_ready, service, + NULL); + + bt_micp_set_user_data(data->micp, service); + + return 0; +} + +static void micp_remove(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + struct micp_data *data; + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("%s", addr); + + data = btd_service_get_user_data(service); + if (!data) { + error("MICP Service not handled by profile"); + return; + } + + micp_data_remove(data); +} + +static int micp_accept(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + struct bt_gatt_client *client = btd_device_get_gatt_client(device); + struct micp_data *data = btd_service_get_user_data(service); + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("%s", addr); + + if (!data) { + error("MICP Service not handled by profile"); + return -EINVAL; + } + + if (!bt_micp_attach(data->micp, client)) { + error("MICP unable to attach"); + return -EINVAL; + } + + btd_service_connecting_complete(service, 0); + + return 0; +} + +static int micp_connect(struct btd_service *service) +{ + struct btd_device *device = btd_service_get_device(service); + char addr[18]; + + ba2str(device_get_address(device), addr); + DBG("%s", addr); + + return 0; +} + +static int micp_server_probe(struct btd_profile *p, + struct btd_adapter *adapter) +{ + struct btd_gatt_database *database = btd_adapter_get_database(adapter); + + DBG("MICP path %s", adapter_get_path(adapter)); + + bt_micp_add_db(btd_gatt_database_get_db(database)); + + return 0; +} + +static void micp_server_remove(struct btd_profile *p, + struct btd_adapter *adapter) +{ + DBG("MICP remove adapter"); +} + +static struct btd_profile micp_profile = { + .name = "micp", + .priority = BTD_PROFILE_PRIORITY_MEDIUM, + .remote_uuid = MICS_UUID_STR, + + .device_probe = micp_probe, + .device_remove = micp_remove, + + .accept = micp_accept, + .connect = micp_connect, + .disconnect = micp_disconnect, + + .adapter_probe = micp_server_probe, + .adapter_remove = micp_server_remove, +}; + +static unsigned int micp_id; + +static int micp_init(void) +{ + if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) { + warn("D-Bus experimental not enabled"); + return -ENOTSUP; + } + + btd_profile_register(&micp_profile); + micp_id = bt_micp_register(micp_attached, micp_detached, NULL); + + return 0; +} + +static void micp_exit(void) +{ + if (g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL) { + btd_profile_unregister(&micp_profile); + bt_micp_unregister(micp_id); + } +} + +BLUETOOTH_PLUGIN_DEFINE(micp, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, + micp_init, micp_exit) diff --git a/profiles/audio/player.c b/profiles/audio/player.c index c995697fe0bf42b0c06a64ef0e68b84a0bd6f99c..0f72d760133385dd621922fb27e7d4e9965d1eec 100644 --- a/profiles/audio/player.c +++ b/profiles/audio/player.c @@ -88,6 +88,7 @@ struct media_player { struct player_callback *cb; GSList *pending; GSList *folders; + uint16_t obex_port; }; static void append_track(void *key, void *value, void *user_data) @@ -437,6 +438,28 @@ static gboolean get_playlist(const GDBusPropertyTable *property, return TRUE; } +static gboolean obexport_exists(const GDBusPropertyTable *property, + void *data) +{ + struct media_player *mp = data; + + return mp->obex_port != 0; +} + +static gboolean get_obexport(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct media_player *mp = data; + + if (mp->obex_port == 0) + return FALSE; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, + &mp->obex_port); + + return TRUE; +} + static DBusMessage *media_player_play(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -778,6 +801,8 @@ static const GDBusPropertyTable media_player_properties[] = { { "Browsable", "b", get_browsable, NULL, browsable_exists }, { "Searchable", "b", get_searchable, NULL, searchable_exists }, { "Playlist", "o", get_playlist, NULL, playlist_exists }, + { "ObexPort", "q", get_obexport, NULL, obexport_exists, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, { } }; @@ -1413,18 +1438,19 @@ void media_player_set_metadata(struct media_player *mp, void *data, size_t len) { char *value, *curval; + GHashTable *metadata = item ? item->metadata : mp->track; value = g_strndup(data, len); DBG("%s: %s", key, value); - curval = g_hash_table_lookup(mp->track, key); + curval = g_hash_table_lookup(metadata, key); if (g_strcmp0(curval, value) == 0) { g_free(value); return; } - g_hash_table_replace(mp->track, g_strdup(key), value); + g_hash_table_replace(metadata, g_strdup(key), value); } void media_player_metadata_changed(struct media_player *mp) @@ -1997,3 +2023,19 @@ struct media_item *media_player_set_playlist_item(struct media_player *mp, return item; } + +void media_player_clear_playlist(struct media_player *mp) +{ + if (mp->playlist) { + g_slist_free_full(mp->playlist->items, media_item_destroy); + mp->playlist->items = NULL; + } + + g_dbus_emit_property_changed(btd_get_dbus_connection(), mp->path, + MEDIA_PLAYER_INTERFACE, "Playlist"); +} + +void media_player_set_obex_port(struct media_player *mp, uint16_t port) +{ + mp->obex_port = port; +} diff --git a/profiles/audio/player.h b/profiles/audio/player.h index 74fb7d7717d69738f77114e5cd0e69c9a7e5c249..5e181591c0f4ebe7535a7cd9ec433ed0368d9b24 100644 --- a/profiles/audio/player.h +++ b/profiles/audio/player.h @@ -86,6 +86,8 @@ void media_player_set_folder(struct media_player *mp, const char *path, void media_player_set_playlist(struct media_player *mp, const char *name); struct media_item *media_player_set_playlist_item(struct media_player *mp, uint64_t uid); +void media_player_clear_playlist(struct media_player *mp); +void media_player_set_obex_port(struct media_player *mp, uint16_t port); struct media_item *media_player_create_folder(struct media_player *mp, const char *name, diff --git a/profiles/audio/sink.c b/profiles/audio/sink.c index 56c49177807704974bc72396d1b2d7bd6d72984c..77f1954360328b55ef7baca94d65aa585852f6d8 100644 --- a/profiles/audio/sink.c +++ b/profiles/audio/sink.c @@ -62,7 +62,7 @@ struct sink_state_callback { static GSList *sink_callbacks = NULL; -static char *str_state[] = { +static const char *str_state[] = { "SINK_STATE_DISCONNECTED", "SINK_STATE_CONNECTING", "SINK_STATE_CONNECTED", @@ -137,6 +137,11 @@ static void stream_state_changed(struct avdtp_stream *stream, case AVDTP_STATE_IDLE: btd_service_disconnecting_complete(sink->service, 0); + if (sink->connect_id > 0) { + a2dp_cancel(sink->connect_id); + sink->connect_id = 0; + } + if (sink->disconnect_id > 0) { a2dp_cancel(sink->disconnect_id); sink->disconnect_id = 0; diff --git a/profiles/audio/source.c b/profiles/audio/source.c index c6009d0ea24f089a23c42aa6da138a3d1a163c39..db777e86d54209eb06eae782f0dd1221b632731a 100644 --- a/profiles/audio/source.c +++ b/profiles/audio/source.c @@ -61,7 +61,7 @@ struct source_state_callback { static GSList *source_callbacks = NULL; -static char *str_state[] = { +static const char *str_state[] = { "SOURCE_STATE_DISCONNECTED", "SOURCE_STATE_CONNECTING", "SOURCE_STATE_CONNECTED", @@ -134,6 +134,11 @@ static void stream_state_changed(struct avdtp_stream *stream, case AVDTP_STATE_IDLE: btd_service_disconnecting_complete(source->service, 0); + if (source->connect_id > 0) { + a2dp_cancel(source->connect_id); + source->connect_id = 0; + } + if (source->disconnect_id > 0) { a2dp_cancel(source->disconnect_id); source->disconnect_id = 0; diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c index 41339da51e17d10235f8f30fd06c9743a4d0d4bc..c7a0eaec34f169b5b7db17acbebb6b8b756721a9 100644 --- a/profiles/audio/transport.c +++ b/profiles/audio/transport.c @@ -5,6 +5,7 @@ * * Copyright (C) 2006-2007 Nokia Corporation * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org> + * Copyright 2023-2024 NXP * * */ @@ -34,8 +35,10 @@ #include "src/shared/util.h" #include "src/shared/queue.h" #include "src/shared/bap.h" +#include "src/shared/bass.h" #include "src/shared/io.h" +#include "asha.h" #include "avdtp.h" #include "media.h" #include "transport.h" @@ -43,20 +46,26 @@ #include "sink.h" #include "source.h" #include "avrcp.h" +#include "bass.h" #define MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport1" typedef enum { TRANSPORT_STATE_IDLE, /* Not acquired and suspended */ TRANSPORT_STATE_PENDING, /* Playing but not acquired */ + /* Playing but not acquired, applicable only for transports + * created by a broadcast sink + */ + TRANSPORT_STATE_BROADCASTING, TRANSPORT_STATE_REQUESTING, /* Acquire in progress */ TRANSPORT_STATE_ACTIVE, /* Acquired and playing */ TRANSPORT_STATE_SUSPENDING, /* Release in progress */ } transport_state_t; -static char *str_state[] = { +static const char *str_state[] = { "TRANSPORT_STATE_IDLE", "TRANSPORT_STATE_PENDING", + "TRANSPORT_STATE_BROADCASTING", "TRANSPORT_STATE_REQUESTING", "TRANSPORT_STATE_ACTIVE", "TRANSPORT_STATE_SUSPENDING", @@ -78,25 +87,45 @@ struct a2dp_transport { struct avdtp *session; uint16_t delay; int8_t volume; + guint watch; }; struct bap_transport { struct bt_bap_stream *stream; unsigned int state_id; bool linked; - uint32_t interval; - uint8_t framing; - uint8_t phy; - uint16_t sdu; - uint8_t rtn; - uint16_t latency; - uint32_t delay; + struct bt_bap_qos qos; + guint resume_id; +}; + +struct media_transport_ops { + const char *uuid; + const GDBusPropertyTable *properties; + void (*set_owner)(struct media_transport *transport, + struct media_owner *owner); + void (*remove_owner)(struct media_transport *transport, + struct media_owner *owner); + void *(*init)(struct media_transport *transport, void *stream); + guint (*resume)(struct media_transport *transport, + struct media_owner *owner); + guint (*suspend)(struct media_transport *transport, + struct media_owner *owner); + void (*cancel)(struct media_transport *transport, guint id); + void (*set_state)(struct media_transport *transport, + transport_state_t state); + void *(*get_stream)(struct media_transport *transport); + int8_t (*get_volume)(struct media_transport *transport); + int (*set_volume)(struct media_transport *transport, int8_t level); + int (*set_delay)(struct media_transport *transport, uint16_t delay); + void (*update_links)(const struct media_transport *transport); + GDestroyNotify destroy; }; struct media_transport { char *path; /* Transport object path */ struct btd_device *device; /* Transport device */ - const char *remote_endpoint; /* Transport remote SEP */ + struct btd_adapter *adapter; /* Transport adapter bcast*/ + char *remote_endpoint; /* Transport remote SEP */ struct media_endpoint *endpoint; /* Transport endpoint */ struct media_owner *owner; /* Transport owner */ uint8_t *configuration; /* Transport configuration */ @@ -105,18 +134,7 @@ struct media_transport { uint16_t imtu; /* Transport input mtu */ uint16_t omtu; /* Transport output mtu */ transport_state_t state; - guint hs_watch; - guint source_watch; - guint sink_watch; - guint (*resume) (struct media_transport *transport, - struct media_owner *owner); - guint (*suspend) (struct media_transport *transport, - struct media_owner *owner); - void (*cancel) (struct media_transport *transport, - guint id); - void (*set_state) (struct media_transport *transport, - transport_state_t state); - GDestroyNotify destroy; + const struct media_transport_ops *ops; void *data; }; @@ -130,6 +148,8 @@ static const char *state2str(transport_state_t state) return "idle"; case TRANSPORT_STATE_PENDING: return "pending"; + case TRANSPORT_STATE_BROADCASTING: + return "broadcasting"; case TRANSPORT_STATE_ACTIVE: case TRANSPORT_STATE_SUSPENDING: return "active"; @@ -143,6 +163,7 @@ static gboolean state_in_use(transport_state_t state) switch (state) { case TRANSPORT_STATE_IDLE: case TRANSPORT_STATE_PENDING: + case TRANSPORT_STATE_BROADCASTING: return FALSE; case TRANSPORT_STATE_REQUESTING: case TRANSPORT_STATE_ACTIVE: @@ -164,7 +185,8 @@ find_transport_by_bap_stream(const struct bt_bap_stream *stream) struct bap_transport *bap; if (strcasecmp(uuid, PAC_SINK_UUID) && - strcasecmp(uuid, PAC_SOURCE_UUID)) + strcasecmp(uuid, PAC_SOURCE_UUID) && + strcasecmp(uuid, BAA_SERVICE_UUID)) continue; bap = transport->data; @@ -199,20 +221,14 @@ static void transport_set_state(struct media_transport *transport, "State"); /* Update transport specific data */ - if (transport->set_state) - transport->set_state(transport, state); + if (transport->ops && transport->ops->set_state) + transport->ops->set_state(transport, state); } void media_transport_destroy(struct media_transport *transport) { char *path; - if (transport->sink_watch) - sink_remove_state_cb(transport->sink_watch); - - if (transport->source_watch) - source_remove_state_cb(transport->source_watch); - path = g_strdup(transport->path); g_dbus_unregister_interface(btd_get_dbus_connection(), path, MEDIA_TRANSPORT_INTERFACE); @@ -262,8 +278,8 @@ static void media_owner_remove(struct media_owner *owner) DBG("Owner %s Request %s", owner->name, dbus_message_get_member(req->msg)); - if (req->id) - transport->cancel(transport, req->id); + if (req->id && transport->ops && transport->ops->cancel) + transport->ops->cancel(transport, req->id); owner->pending = NULL; if (req->msg) @@ -274,10 +290,15 @@ static void media_owner_remove(struct media_owner *owner) static void media_owner_free(struct media_owner *owner) { + struct media_transport *transport = owner->transport; + DBG("Owner %s", owner->name); media_owner_remove(owner); + if (transport) + transport->owner = NULL; + g_free(owner->name); g_free(owner); } @@ -298,10 +319,33 @@ static void linked_transport_remove_owner(void *data, void *user_data) transport->owner = NULL; } +static guint media_transport_suspend(struct media_transport *transport, + struct media_owner *owner) +{ + if (!state_in_use(transport->state)) + return 0; + + DBG("Transport %s Owner %s", transport->path, owner ? owner->name : ""); + + if (transport->ops && transport->ops->suspend) + return transport->ops->suspend(transport, owner); + + return 0; +} + +static void transport_bap_remove_owner(struct media_transport *transport, + struct media_owner *owner) +{ + struct bap_transport *bap = transport->data; + + if (bap && bap->linked) + queue_foreach(bt_bap_stream_io_get_links(bap->stream), + linked_transport_remove_owner, owner); +} + static void media_transport_remove_owner(struct media_transport *transport) { struct media_owner *owner = transport->owner; - struct bap_transport *bap = transport->data; if (!transport->owner) return; @@ -313,17 +357,16 @@ static void media_transport_remove_owner(struct media_transport *transport) media_request_reply(owner->pending, EIO); transport->owner = NULL; - if (bap->linked) - queue_foreach(bt_bap_stream_io_get_links(bap->stream), - linked_transport_remove_owner, owner); + + if (transport->ops && transport->ops->remove_owner) + transport->ops->remove_owner(transport, owner); if (owner->watch) g_dbus_remove_watch(btd_get_dbus_connection(), owner->watch); media_owner_free(owner); - if (state_in_use(transport->state)) - transport->suspend(transport, NULL); + media_transport_suspend(transport, NULL); } static gboolean media_transport_set_fd(struct media_transport *transport, @@ -341,13 +384,22 @@ static gboolean media_transport_set_fd(struct media_transport *transport, return TRUE; } +static void *transport_a2dp_get_stream(struct media_transport *transport) +{ + struct a2dp_sep *sep = media_endpoint_get_sep(transport->endpoint); + + if (!sep) + return NULL; + + return a2dp_sep_get_stream(sep); +} + static void a2dp_resume_complete(struct avdtp *session, int err, void *user_data) { struct media_owner *owner = user_data; struct media_request *req = owner->pending; struct media_transport *transport = owner->transport; - struct a2dp_sep *sep = media_endpoint_get_sep(transport->endpoint); struct avdtp_stream *stream; int fd; uint16_t imtu, omtu; @@ -358,7 +410,7 @@ static void a2dp_resume_complete(struct avdtp *session, int err, if (err) goto fail; - stream = a2dp_sep_get_stream(sep); + stream = transport_a2dp_get_stream(transport); if (stream == NULL) goto fail; @@ -386,7 +438,7 @@ fail: media_transport_remove_owner(transport); } -static guint resume_a2dp(struct media_transport *transport, +static guint transport_a2dp_resume(struct media_transport *transport, struct media_owner *owner) { struct a2dp_transport *a2dp = transport->data; @@ -440,7 +492,7 @@ static void a2dp_suspend_complete(struct avdtp *session, int err, media_transport_remove_owner(transport); } -static guint suspend_a2dp(struct media_transport *transport, +static guint transport_a2dp_suspend(struct media_transport *transport, struct media_owner *owner) { struct a2dp_transport *a2dp = transport->data; @@ -457,15 +509,85 @@ static guint suspend_a2dp(struct media_transport *transport, return 0; } -static void cancel_a2dp(struct media_transport *transport, guint id) +static void transport_a2dp_cancel(struct media_transport *transport, guint id) { a2dp_cancel(id); } +static int8_t transport_a2dp_get_volume(struct media_transport *transport) +{ + struct a2dp_transport *a2dp = transport->data; + return a2dp->volume; +} + +static int transport_a2dp_src_set_volume(struct media_transport *transport, + int8_t level) +{ + struct a2dp_transport *a2dp = transport->data; + + if (a2dp->volume == level) + return 0; + + return avrcp_set_volume(transport->device, level, false); +} + +static int transport_a2dp_snk_set_volume(struct media_transport *transport, + int8_t level) +{ + struct a2dp_transport *a2dp = transport->data; + bool notify; + + if (a2dp->volume == level) + return 0; + + notify = a2dp->watch ? true : false; + if (notify) { + a2dp->volume = level; + g_dbus_emit_property_changed(btd_get_dbus_connection(), + transport->path, + MEDIA_TRANSPORT_INTERFACE, + "Volume"); + } + + return avrcp_set_volume(transport->device, level, notify); +} + +static int transport_a2dp_snk_set_delay(struct media_transport *transport, + uint16_t delay) +{ + struct a2dp_transport *a2dp = transport->data; + struct avdtp_stream *stream; + + if (a2dp->delay == delay) + return 0; + + if (a2dp->session == NULL) { + a2dp->session = a2dp_avdtp_get(transport->device); + if (a2dp->session == NULL) + return -EIO; + } + + stream = media_transport_get_stream(transport); + if (stream == NULL) + return -EIO; + + if (a2dp->watch) { + a2dp->delay = delay; + g_dbus_emit_property_changed(btd_get_dbus_connection(), + transport->path, + MEDIA_TRANSPORT_INTERFACE, + "Delay"); + } + + return avdtp_delay_report(a2dp->session, stream, delay); +} + static void media_owner_exit(DBusConnection *connection, void *user_data) { struct media_owner *owner = user_data; + DBG("Owner %s", owner->name); + owner->watch = 0; media_owner_remove(owner); @@ -489,17 +611,24 @@ static void linked_transport_set_owner(void *data, void *user_data) transport->owner = owner; } -static void media_transport_set_owner(struct media_transport *transport, +static void transport_bap_set_owner(struct media_transport *transport, struct media_owner *owner) { struct bap_transport *bap = transport->data; + if (bap && bap->linked) + queue_foreach(bt_bap_stream_io_get_links(bap->stream), + linked_transport_set_owner, owner); +} + +static void media_transport_set_owner(struct media_transport *transport, + struct media_owner *owner) +{ DBG("Transport %s Owner %s", transport->path, owner->name); transport->owner = owner; - if (bap->linked) - queue_foreach(bt_bap_stream_io_get_links(bap->stream), - linked_transport_set_owner, owner); + if (transport->ops && transport->ops->set_owner) + transport->ops->set_owner(transport, owner); owner->transport = transport; owner->watch = g_dbus_add_disconnect_watch(btd_get_dbus_connection(), @@ -529,12 +658,30 @@ static void media_owner_add(struct media_owner *owner, owner->pending = req; } +static void *transport_bap_get_stream(struct media_transport *transport) +{ + struct bap_transport *bap = transport->data; + + return bap->stream; +} + +static guint media_transport_resume(struct media_transport *transport, + struct media_owner *owner) +{ + DBG("Transport %s Owner %s", transport->path, owner ? owner->name : ""); + + if (transport->ops && transport->ops->resume) + return transport->ops->resume(transport, owner); + + return 0; +} + static DBusMessage *acquire(DBusConnection *conn, DBusMessage *msg, void *data) { struct media_transport *transport = data; struct media_owner *owner; - struct media_request *req; + struct media_request *req = NULL; guint id; if (transport->owner != NULL) @@ -544,15 +691,27 @@ static DBusMessage *acquire(DBusConnection *conn, DBusMessage *msg, return btd_error_not_authorized(msg); owner = media_owner_create(msg); - id = transport->resume(transport, owner); + + if (!strcmp(media_endpoint_get_uuid(transport->endpoint), + BAA_SERVICE_UUID) + || !strcmp(media_endpoint_get_uuid(transport->endpoint), + BCAA_SERVICE_UUID)) { + req = media_request_create(msg, 0x00); + media_owner_add(owner, req); + media_transport_set_owner(transport, owner); + } + + id = media_transport_resume(transport, owner); if (id == 0) { media_owner_free(owner); return btd_error_not_authorized(msg); } - req = media_request_create(msg, id); - media_owner_add(owner, req); - media_transport_set_owner(transport, owner); + if (!req) { + req = media_request_create(msg, id); + media_owner_add(owner, req); + media_transport_set_owner(transport, owner); + } return NULL; } @@ -571,11 +730,12 @@ static DBusMessage *try_acquire(DBusConnection *conn, DBusMessage *msg, if (transport->state >= TRANSPORT_STATE_REQUESTING) return btd_error_not_authorized(msg); - if (transport->state != TRANSPORT_STATE_PENDING) + if ((transport->state != TRANSPORT_STATE_PENDING) && + (transport->state != TRANSPORT_STATE_BROADCASTING)) return btd_error_not_available(msg); owner = media_owner_create(msg); - id = transport->resume(transport, owner); + id = media_transport_resume(transport, owner); if (id == 0) { media_owner_free(owner); return btd_error_not_authorized(msg); @@ -588,6 +748,41 @@ static DBusMessage *try_acquire(DBusConnection *conn, DBusMessage *msg, return NULL; } +static void bap_stop_complete(struct bt_bap_stream *stream, + uint8_t code, uint8_t reason, + void *user_data) +{ + struct media_owner *owner = user_data; + struct media_request *req; + struct media_transport *transport; + + if (!owner) + return; + + req = owner->pending; + + /* Release always succeeds */ + if (req) { + req->id = 0; + media_request_reply(req, 0); + media_owner_remove(owner); + } + + transport = owner->transport; + + if (transport) { + transport_set_state(transport, TRANSPORT_STATE_IDLE); + media_transport_remove_owner(transport); + } +} + +static void bap_disable_complete(struct bt_bap_stream *stream, + uint8_t code, uint8_t reason, + void *user_data) +{ + bap_stop_complete(stream, code, reason, user_data); +} + static DBusMessage *release(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -602,6 +797,8 @@ static DBusMessage *release(DBusConnection *conn, DBusMessage *msg, if (owner == NULL || g_strcmp0(owner->name, sender) != 0) return btd_error_not_authorized(msg); + DBG("Owner %s", owner->name); + if (owner->pending) { const char *member; @@ -615,7 +812,7 @@ static DBusMessage *release(DBusConnection *conn, DBusMessage *msg, transport_set_state(transport, TRANSPORT_STATE_SUSPENDING); - id = transport->suspend(transport, owner); + id = media_transport_suspend(transport, owner); if (id == 0) { media_transport_remove_owner(transport); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); @@ -631,7 +828,12 @@ static gboolean get_device(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { struct media_transport *transport = data; - const char *path = device_get_path(transport->device); + const char *path; + + if (transport->device) + path = device_get_path(transport->device); + else + path = adapter_get_path(transport->adapter); dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path); @@ -693,12 +895,16 @@ static gboolean delay_reporting_exists(const GDBusPropertyTable *property, void *data) { struct media_transport *transport = data; - struct a2dp_transport *a2dp = transport->data; + struct avdtp_stream *stream; + + stream = media_transport_get_stream(transport); + if (stream == NULL) + return FALSE; - return a2dp->delay != 0; + return avdtp_stream_has_delay_reporting(stream); } -static gboolean get_delay_reporting(const GDBusPropertyTable *property, +static gboolean get_delay_report(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { struct media_transport *transport = data; @@ -709,64 +915,147 @@ static gboolean get_delay_reporting(const GDBusPropertyTable *property, return TRUE; } +static int media_transport_set_delay(struct media_transport *transport, + uint16_t delay) +{ + DBG("Transport %s delay %d", transport->path, delay); + + if (transport->ops && transport->ops->set_delay) + return transport->ops->set_delay(transport, delay); + + return 0; +} + +static void set_delay_report(const GDBusPropertyTable *property, + DBusMessageIter *iter, + GDBusPendingPropertySet id, + void *data) +{ + struct media_transport *transport = data; + struct media_owner *owner = transport->owner; + const char *sender; + uint16_t arg; + int err; + + if (owner != NULL) { + /* If the transport is acquired, do not allow to modify + * the delay anyone but the owner. + */ + sender = g_dbus_pending_property_get_sender(id); + if (g_strcmp0(owner->name, sender) != 0) { + g_dbus_pending_property_error(id, + ERROR_INTERFACE ".NotAuthorized", + "Operation Not Authorized"); + return; + } + } + + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16) { + g_dbus_pending_property_error(id, + ERROR_INTERFACE ".InvalidArguments", + "Expected UINT16"); + return; + } + + dbus_message_iter_get_basic(iter, &arg); + + err = media_transport_set_delay(transport, arg); + if (err) { + error("Unable to set delay: %s (%d)", strerror(-err), err); + g_dbus_pending_property_error(id, + ERROR_INTERFACE ".Failed", + "Internal error %s (%d)", + strerror(-err), err); + return; + } + + g_dbus_pending_property_success(id); +} + static gboolean volume_exists(const GDBusPropertyTable *property, void *data) { struct media_transport *transport = data; - struct a2dp_transport *a2dp = transport->data; + int8_t volume; + + if (media_transport_get_volume(transport, &volume)) + return FALSE; + + return volume >= 0; +} + +int media_transport_get_volume(struct media_transport *transport, + int8_t *volume) +{ + if (transport->ops && transport->ops->get_volume) { + *volume = transport->ops->get_volume(transport); + return 0; + } - return a2dp->volume >= 0; + return -EINVAL; } static gboolean get_volume(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { struct media_transport *transport = data; - struct a2dp_transport *a2dp = transport->data; - uint16_t volume = (uint16_t)a2dp->volume; + int8_t level; + uint16_t volume; + + if (media_transport_get_volume(transport, &level)) + return FALSE; + + volume = level; dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &volume); return TRUE; } +static int media_transport_set_volume(struct media_transport *transport, + int8_t level) +{ + DBG("Transport %s level %d", transport->path, level); + + if (transport->ops && transport->ops->set_volume) + return transport->ops->set_volume(transport, level); + + return 0; +} + static void set_volume(const GDBusPropertyTable *property, DBusMessageIter *iter, GDBusPendingPropertySet id, void *data) { struct media_transport *transport = data; - struct a2dp_transport *a2dp = transport->data; uint16_t arg; - int8_t volume; - bool notify; + int err; - if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16) - goto error; + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16) { + g_dbus_pending_property_error(id, + ERROR_INTERFACE ".InvalidArguments", + "Expected UINT16"); + return; + } dbus_message_iter_get_basic(iter, &arg); - if (arg > INT8_MAX) - goto error; - - g_dbus_pending_property_success(id); - - volume = (int8_t)arg; - if (a2dp->volume == volume) + if (arg > INT8_MAX) { + g_dbus_pending_property_error(id, + ERROR_INTERFACE ".InvalidArguments", + "Volume must not be larger than 127"); return; - - notify = transport->source_watch ? true : false; - if (notify) { - a2dp->volume = volume; - g_dbus_emit_property_changed(btd_get_dbus_connection(), - transport->path, - MEDIA_TRANSPORT_INTERFACE, - "Volume"); } - avrcp_set_volume(transport->device, volume, notify); - return; + err = media_transport_set_volume(transport, arg); + if (err) { + error("Unable to set volume: %s (%d)", strerror(-err), err); + g_dbus_pending_property_error(id, + ERROR_INTERFACE ".Failed", + "Internal error %s (%d)", + strerror(-err), err); + return; + } -error: - g_dbus_pending_property_error(id, ERROR_INTERFACE ".InvalidArguments", - "Invalid arguments in method call"); + g_dbus_pending_property_success(id); } static gboolean endpoint_exists(const GDBusPropertyTable *property, void *data) @@ -787,6 +1076,12 @@ static gboolean get_endpoint(const GDBusPropertyTable *property, return TRUE; } +static DBusMessage *select_transport(DBusConnection *conn, DBusMessage *msg, + void *data); + +static DBusMessage *unselect_transport(DBusConnection *conn, DBusMessage *msg, + void *data); + static const GDBusMethodTable transport_methods[] = { { GDBUS_ASYNC_METHOD("Acquire", NULL, @@ -799,192 +1094,414 @@ static const GDBusMethodTable transport_methods[] = { { "mtu_w", "q" }), try_acquire) }, { GDBUS_ASYNC_METHOD("Release", NULL, NULL, release) }, + { GDBUS_ASYNC_METHOD("Select", + NULL, NULL, select_transport) }, + { GDBUS_ASYNC_METHOD("Unselect", + NULL, NULL, unselect_transport) }, { }, }; -static const GDBusPropertyTable a2dp_properties[] = { +static const GDBusPropertyTable transport_a2dp_properties[] = { { "Device", "o", get_device }, { "UUID", "s", get_uuid }, { "Codec", "y", get_codec }, { "Configuration", "ay", get_configuration }, { "State", "s", get_state }, - { "Delay", "q", get_delay_reporting, NULL, delay_reporting_exists }, + { "Delay", "q", get_delay_report, set_delay_report, + delay_reporting_exists }, { "Volume", "q", get_volume, set_volume, volume_exists }, { "Endpoint", "o", get_endpoint, NULL, endpoint_exists, G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, { } }; -static gboolean get_interval(const GDBusPropertyTable *property, +static void append_io_qos(DBusMessageIter *dict, struct bt_bap_io_qos *qos) +{ + dict_append_entry(dict, "Interval", DBUS_TYPE_UINT32, &qos->interval); + dict_append_entry(dict, "Latency", DBUS_TYPE_UINT16, &qos->latency); + dict_append_entry(dict, "SDU", DBUS_TYPE_UINT16, &qos->sdu); + dict_append_entry(dict, "PHY", DBUS_TYPE_BYTE, &qos->phy); + dict_append_entry(dict, "Retransmissions", DBUS_TYPE_BYTE, &qos->rtn); +} + +static gboolean get_ucast_qos(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { struct media_transport *transport = data; struct bap_transport *bap = transport->data; + DBusMessageIter dict; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &dict); + + dict_append_entry(&dict, "CIG", DBUS_TYPE_BYTE, + &bap->qos.ucast.cig_id); + dict_append_entry(&dict, "CIS", DBUS_TYPE_BYTE, + &bap->qos.ucast.cis_id); + dict_append_entry(&dict, "Framing", DBUS_TYPE_BYTE, + &bap->qos.ucast.framing); + dict_append_entry(&dict, "PresentationDelay", DBUS_TYPE_UINT32, + &bap->qos.ucast.delay); - dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &bap->interval); + append_io_qos(&dict, &bap->qos.ucast.io_qos); + + dbus_message_iter_close_container(iter, &dict); return TRUE; } -static gboolean get_framing(const GDBusPropertyTable *property, +static gboolean get_location(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { struct media_transport *transport = data; struct bap_transport *bap = transport->data; - dbus_bool_t val = bap->framing; + uint32_t location = bt_bap_stream_get_location(bap->stream); - dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &val); + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &location); return TRUE; } -static gboolean get_sdu(const GDBusPropertyTable *property, +static gboolean get_metadata(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { struct media_transport *transport = data; struct bap_transport *bap = transport->data; + struct iovec *meta = bt_bap_stream_get_metadata(bap->stream); + DBusMessageIter array; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, &array); + + if (meta) + dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, + &meta->iov_base, + meta->iov_len); - dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &bap->sdu); + dbus_message_iter_close_container(iter, &array); return TRUE; } -static gboolean get_retransmissions(const GDBusPropertyTable *property, - DBusMessageIter *iter, void *data) +static gboolean links_exists(const GDBusPropertyTable *property, void *data) { struct media_transport *transport = data; struct bap_transport *bap = transport->data; - dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE, &bap->rtn); + return bap->linked; +} - return TRUE; +static void append_link(void *data, void *user_data) +{ + struct bt_bap_stream *stream = data; + DBusMessageIter *array = user_data; + struct media_transport *transport; + + if (!stream) + return; + + transport = find_transport_by_bap_stream(stream); + if (!transport) { + error("Unable to find transport"); + return; + } + + dbus_message_iter_append_basic(array, DBUS_TYPE_OBJECT_PATH, + &transport->path); } -static gboolean get_latency(const GDBusPropertyTable *property, +static gboolean get_links(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { struct media_transport *transport = data; struct bap_transport *bap = transport->data; + struct queue *links = bt_bap_stream_io_get_links(bap->stream); + DBusMessageIter array; - dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &bap->latency); + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_OBJECT_PATH_AS_STRING, + &array); + + queue_foreach(links, append_link, &array); + + dbus_message_iter_close_container(iter, &array); return TRUE; } -static gboolean get_delay(const GDBusPropertyTable *property, - DBusMessageIter *iter, void *data) +static struct media_transport *find_transport_by_path(const char *path) { - struct media_transport *transport = data; + GSList *l; + + for (l = transports; l; l = g_slist_next(l)) { + struct media_transport *transport = l->data; + + if (g_str_equal(path, transport->path)) + return transport; + } + + return NULL; +} + +static void set_links(const GDBusPropertyTable *property, + DBusMessageIter *iter, + GDBusPendingPropertySet id, void *user_data) +{ + struct media_transport *transport = user_data; struct bap_transport *bap = transport->data; + DBusMessageIter array; - dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &bap->delay); + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) { + g_dbus_pending_property_error(id, + ERROR_INTERFACE ".InvalidArguments", + "Invalid arguments in method call"); + return; + } - return TRUE; + dbus_message_iter_recurse(iter, &array); + + while (dbus_message_iter_get_arg_type(&array) == + DBUS_TYPE_OBJECT_PATH) { + struct media_transport *link; + struct bap_transport *bap_link; + const char *path; + + dbus_message_iter_get_basic(&array, &path); + + link = find_transport_by_path(path); + if (!link) { + g_dbus_pending_property_error(id, + ERROR_INTERFACE ".InvalidArguments", + "Invalid arguments in method call"); + return; + } + + bap_link = link->data; + + /* Link stream */ + bt_bap_stream_io_link(bap->stream, bap_link->stream); + + dbus_message_iter_next(&array); + } + + g_dbus_pending_property_success(id); } -static gboolean get_location(const GDBusPropertyTable *property, - DBusMessageIter *iter, void *data) +static gboolean qos_ucast_exists(const GDBusPropertyTable *property, void *data) { struct media_transport *transport = data; struct bap_transport *bap = transport->data; - uint32_t location = bt_bap_stream_get_location(bap->stream); - dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &location); - - return TRUE; + return bap->qos.ucast.io_qos.phy != 0x00; } -static gboolean get_metadata(const GDBusPropertyTable *property, +static const GDBusPropertyTable transport_bap_uc_properties[] = { + { "Device", "o", get_device }, + { "UUID", "s", get_uuid }, + { "Codec", "y", get_codec }, + { "Configuration", "ay", get_configuration }, + { "State", "s", get_state }, + { "QoS", "a{sv}", get_ucast_qos, NULL, qos_ucast_exists }, + { "Endpoint", "o", get_endpoint, NULL, endpoint_exists }, + { "Location", "u", get_location }, + { "Metadata", "ay", get_metadata }, + { "Links", "ao", get_links, NULL, links_exists }, + { } +}; + +static gboolean get_bcast_qos(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { struct media_transport *transport = data; struct bap_transport *bap = transport->data; - struct iovec *meta = bt_bap_stream_get_metadata(bap->stream); - DBusMessageIter array; + DBusMessageIter dict; dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_BYTE_AS_STRING, &array); - - if (meta) - dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, - &meta->iov_base, - meta->iov_len); - - dbus_message_iter_close_container(iter, &array); + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &dict); + + dict_append_entry(&dict, "BIG", DBUS_TYPE_BYTE, + &bap->qos.bcast.big); + dict_append_entry(&dict, "BIS", DBUS_TYPE_BYTE, + &bap->qos.bcast.bis); + dict_append_entry(&dict, "SyncFactor", DBUS_TYPE_BYTE, + &bap->qos.bcast.sync_factor); + dict_append_entry(&dict, "Packing", DBUS_TYPE_BYTE, + &bap->qos.bcast.packing); + dict_append_entry(&dict, "Framing", DBUS_TYPE_BYTE, + &bap->qos.bcast.framing); + dict_append_entry(&dict, "Encryption", DBUS_TYPE_BYTE, + &bap->qos.bcast.encryption); + if (bap->qos.bcast.bcode) + dict_append_array(&dict, "BCode", DBUS_TYPE_BYTE, + &bap->qos.bcast.bcode->iov_base, + bap->qos.bcast.bcode->iov_len); + dict_append_entry(&dict, "Options", DBUS_TYPE_BYTE, + &bap->qos.bcast.options); + dict_append_entry(&dict, "Skip", DBUS_TYPE_UINT16, + &bap->qos.bcast.skip); + dict_append_entry(&dict, "SyncTimeout", DBUS_TYPE_UINT16, + &bap->qos.bcast.sync_timeout); + dict_append_entry(&dict, "SyncType", DBUS_TYPE_BYTE, + &bap->qos.bcast.sync_cte_type); + dict_append_entry(&dict, "MSE", DBUS_TYPE_BYTE, + &bap->qos.bcast.mse); + dict_append_entry(&dict, "Timeout", DBUS_TYPE_UINT16, + &bap->qos.bcast.timeout); + + append_io_qos(&dict, &bap->qos.bcast.io_qos); + + dbus_message_iter_close_container(iter, &dict); return TRUE; } -static gboolean links_exists(const GDBusPropertyTable *property, void *data) +static gboolean qos_bcast_exists(const GDBusPropertyTable *property, void *data) { struct media_transport *transport = data; struct bap_transport *bap = transport->data; - return bap->linked; + return bap->qos.bcast.io_qos.phy != 0x00; } -static void append_links(void *data, void *user_data) +static void bcast_qos_set(void *user_data, int err) { - struct bt_bap_stream *stream = data; - DBusMessageIter *array = user_data; - struct media_transport *transport; - - transport = find_transport_by_bap_stream(stream); - if (!transport) { - error("Unable to find transport"); - return; - } + GDBusPendingPropertySet id = GPOINTER_TO_UINT(user_data); - dbus_message_iter_append_basic(array, DBUS_TYPE_OBJECT_PATH, - &transport->path); + if (!err) + g_dbus_pending_property_success(id); + else + g_dbus_pending_property_error(id, + ERROR_INTERFACE ".Failed", + "Failed to set Broadcast Code"); } -static gboolean get_links(const GDBusPropertyTable *property, - DBusMessageIter *iter, void *data) +static void set_bcast_qos(const GDBusPropertyTable *property, + DBusMessageIter *dict, GDBusPendingPropertySet id, + void *data) { + DBusMessageIter array, entry, value; struct media_transport *transport = data; struct bap_transport *bap = transport->data; - struct queue *links = bt_bap_stream_io_get_links(bap->stream); - DBusMessageIter array; + struct bt_bap_qos *bap_qos = bt_bap_stream_get_qos(bap->stream); + char *key; - dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_OBJECT_PATH_AS_STRING, - &array); + dbus_message_iter_recurse(dict, &array); - queue_foreach(links, append_links, &array); + dbus_message_iter_recurse(&array, &entry); + dbus_message_iter_get_basic(&entry, &key); - dbus_message_iter_close_container(iter, &array); + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &value); - return TRUE; + if (!strcasecmp(key, "BCode")) { + uint8_t *val; + int len; + DBusMessageIter array; + uint8_t empty_bcode[BT_BASS_BCAST_CODE_SIZE] = {0}; + + dbus_message_iter_recurse(&value, &array); + dbus_message_iter_get_fixed_array(&array, &val, &len); + + if (len > BT_BASS_BCAST_CODE_SIZE) { + g_dbus_pending_property_error(id, + ERROR_INTERFACE ".InvalidArguments", + "Invalid arguments in method call"); + return; + } + + if (!memcmp(val, empty_bcode, len)) { + /* If the user did not provide a Broadcast Code + * for the encrypted stream, request the code from + * Broadcast Assistants, if any are available. + */ + bass_req_bcode(bap->stream, bcast_qos_set, + GUINT_TO_POINTER(id)); + return; + } + + bap_qos->bcast.bcode = util_iov_new(val, len); + } + + bt_bap_stream_qos(bap->stream, bap_qos, NULL, NULL); + g_dbus_pending_property_success(id); } -static const GDBusPropertyTable bap_properties[] = { +static const GDBusPropertyTable transport_bap_bc_properties[] = { { "Device", "o", get_device }, { "UUID", "s", get_uuid }, { "Codec", "y", get_codec }, { "Configuration", "ay", get_configuration }, { "State", "s", get_state }, - { "Interval", "u", get_interval }, - { "Framing", "b", get_framing }, - { "SDU", "q", get_sdu }, - { "Retransmissions", "y", get_retransmissions }, - { "Latency", "q", get_latency }, - { "Delay", "u", get_delay }, + { "QoS", "a{sv}", get_bcast_qos, set_bcast_qos, qos_bcast_exists }, { "Endpoint", "o", get_endpoint, NULL, endpoint_exists }, { "Location", "u", get_location }, { "Metadata", "ay", get_metadata }, - { "Links", "ao", get_links, NULL, links_exists }, + { "Links", "ao", get_links, set_links, NULL }, + { } +}; + +static gboolean get_asha_delay(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct media_transport *transport = data; + struct bt_asha_device *asha_dev = transport->data; + uint16_t delay; + + // Delay property is in 1/10ths of ms, while ASHA RenderDelay is in ms + delay = bt_asha_device_get_render_delay(asha_dev) * 10; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &delay); + + return TRUE; +} + +static const GDBusPropertyTable transport_asha_properties[] = { + { "Device", "o", get_device }, + { "Endpoint", "o", get_endpoint, NULL, endpoint_exists }, + { "UUID", "s", get_uuid }, + { "Codec", "y", get_codec }, + { "State", "s", get_state }, + { "Delay", "q", get_asha_delay }, + { "Volume", "q", get_volume, set_volume, volume_exists }, { } }; -static void destroy_a2dp(void *data) +static void transport_a2dp_destroy(void *data) { struct a2dp_transport *a2dp = data; if (a2dp->session) avdtp_unref(a2dp->session); - g_free(a2dp); + free(a2dp); +} + +static void transport_a2dp_src_destroy(void *data) +{ + struct a2dp_transport *a2dp = data; + + if (a2dp->watch) + sink_remove_state_cb(a2dp->watch); + + transport_a2dp_destroy(data); +} + +static void transport_a2dp_snk_destroy(void *data) +{ + struct a2dp_transport *a2dp = data; + + if (a2dp->watch) + source_remove_state_cb(a2dp->watch); + + transport_a2dp_destroy(data); } static void media_transport_free(void *data) @@ -996,9 +1513,10 @@ static void media_transport_free(void *data) if (transport->owner) media_transport_remove_owner(transport); - if (transport->destroy != NULL) - transport->destroy(transport->data); + if (transport->ops && transport->ops->destroy) + transport->ops->destroy(transport->data); + g_free(transport->remote_endpoint); g_free(transport->configuration); g_free(transport->path); g_free(transport); @@ -1011,15 +1529,63 @@ static void transport_update_playing(struct media_transport *transport, str_state[transport->state], playing); if (playing == FALSE) { - if (transport->state == TRANSPORT_STATE_PENDING) - transport_set_state(transport, TRANSPORT_STATE_IDLE); - else if (transport->state == TRANSPORT_STATE_ACTIVE) { - /* Remove owner */ - if (transport->owner != NULL) - media_transport_remove_owner(transport); + if (!strcmp(media_endpoint_get_uuid(transport->endpoint), + BAA_SERVICE_UUID)) { + if ((transport->state == + TRANSPORT_STATE_BROADCASTING) || + (transport->state == TRANSPORT_STATE_ACTIVE)) + transport_set_state(transport, + TRANSPORT_STATE_IDLE); + } else { + if (transport->state == TRANSPORT_STATE_PENDING) + transport_set_state(transport, + TRANSPORT_STATE_IDLE); + else if (transport->state == TRANSPORT_STATE_ACTIVE) { + /* Remove owner */ + if (transport->owner != NULL) + media_transport_remove_owner(transport); + } } - } else if (transport->state == TRANSPORT_STATE_IDLE) - transport_set_state(transport, TRANSPORT_STATE_PENDING); + } else if (transport->state == TRANSPORT_STATE_IDLE) { + if (!strcmp(media_endpoint_get_uuid(transport->endpoint), + BAA_SERVICE_UUID)) + transport_set_state(transport, + TRANSPORT_STATE_BROADCASTING); + else + transport_set_state(transport, TRANSPORT_STATE_PENDING); + } +} + +static DBusMessage *select_transport(DBusConnection *conn, DBusMessage *msg, + void *data) +{ + struct media_transport *transport = data; + + if (transport->owner != NULL) + return btd_error_not_authorized(msg); + + if (transport->state >= TRANSPORT_STATE_REQUESTING) + return btd_error_not_authorized(msg); + + if (!strcmp(media_endpoint_get_uuid(transport->endpoint), + BAA_SERVICE_UUID)) { + transport_update_playing(transport, TRUE); + } + + return dbus_message_new_method_return(msg); +} + +static DBusMessage *unselect_transport(DBusConnection *conn, DBusMessage *msg, + void *data) +{ + struct media_transport *transport = data; + + if (!strcmp(media_endpoint_get_uuid(transport->endpoint), + BAA_SERVICE_UUID)) { + transport_update_playing(transport, FALSE); + } + + return dbus_message_new_method_return(msg); } static void sink_state_changed(struct btd_service *service, @@ -1048,53 +1614,39 @@ static void source_state_changed(struct btd_service *service, transport_update_playing(transport, FALSE); } -static int media_transport_init_source(struct media_transport *transport) +static void *transport_a2dp_src_init(struct media_transport *transport, + void *stream) { struct btd_service *service; struct a2dp_transport *a2dp; service = btd_device_get_service(transport->device, A2DP_SINK_UUID); - if (service == NULL) - return -EINVAL; - - a2dp = g_new0(struct a2dp_transport, 1); - - transport->resume = resume_a2dp; - transport->suspend = suspend_a2dp; - transport->cancel = cancel_a2dp; - transport->data = a2dp; - transport->destroy = destroy_a2dp; + if (!service) + return NULL; + a2dp = new0(struct a2dp_transport, 1); a2dp->volume = -1; - transport->sink_watch = sink_add_state_cb(service, sink_state_changed, - transport); + a2dp->watch = sink_add_state_cb(service, sink_state_changed, transport); - return 0; + return a2dp; } -static int media_transport_init_sink(struct media_transport *transport) +static void *transport_a2dp_snk_init(struct media_transport *transport, + void *stream) { struct btd_service *service; struct a2dp_transport *a2dp; service = btd_device_get_service(transport->device, A2DP_SOURCE_UUID); - if (service == NULL) - return -EINVAL; - - a2dp = g_new0(struct a2dp_transport, 1); - - transport->resume = resume_a2dp; - transport->suspend = suspend_a2dp; - transport->cancel = cancel_a2dp; - transport->data = a2dp; - transport->destroy = destroy_a2dp; + if (!service) + return NULL; + a2dp = new0(struct a2dp_transport, 1); a2dp->volume = 127; - transport->source_watch = source_add_state_cb(service, - source_state_changed, - transport); + a2dp->watch = source_add_state_cb(service, source_state_changed, + transport); - return 0; + return a2dp; } static void bap_enable_complete(struct bt_bap_stream *stream, @@ -1107,17 +1659,27 @@ static void bap_enable_complete(struct bt_bap_stream *stream, media_transport_remove_owner(owner->transport); } -static gboolean resume_complete(void *data) +static void bap_resume_complete(struct media_transport *transport) { - struct media_transport *transport = data; + struct bap_transport *bap = transport->data; struct media_owner *owner = transport->owner; + DBG("stream %p owner %p resume complete", bap->stream, owner); + + if (bap->resume_id) { + g_source_remove(bap->resume_id); + bap->resume_id = 0; + } + if (!owner) - return FALSE; + return; + + if (owner->pending) + owner->pending->id = 0; if (transport->fd < 0) { media_transport_remove_owner(transport); - return FALSE; + return; } if (owner->pending) { @@ -1131,15 +1693,13 @@ static gboolean resume_complete(void *data) DBUS_TYPE_INVALID); if (!ret) { media_transport_remove_owner(transport); - return FALSE; + return; } } media_owner_remove(owner); transport_set_state(transport, TRANSPORT_STATE_ACTIVE); - - return FALSE; } static void bap_update_links(const struct media_transport *transport); @@ -1158,7 +1718,8 @@ static bool match_link_transport(const void *data, const void *user_data) return true; } -static void bap_update_links(const struct media_transport *transport) +static void transport_bap_update_links_uc( + const struct media_transport *transport) { struct bap_transport *bap = transport->data; struct queue *links = bt_bap_stream_io_get_links(bap->stream); @@ -1181,28 +1742,122 @@ static void bap_update_links(const struct media_transport *transport) DBG("stream %p linked %s", bap->stream, bap->linked ? "true" : "false"); } -static guint resume_bap(struct media_transport *transport, +static void transport_bap_update_links_bc( + const struct media_transport *transport) +{ + struct bap_transport *bap = transport->data; + struct queue *links = bt_bap_stream_io_get_links(bap->stream); + + if (!queue_isempty(links)) + bap->linked = true; + else + bap->linked = false; + + g_dbus_emit_property_changed(btd_get_dbus_connection(), transport->path, + MEDIA_TRANSPORT_INTERFACE, + "Links"); + + DBG("stream %p linked %s", bap->stream, bap->linked ? "true" : "false"); +} + +static void bap_update_links(const struct media_transport *transport) +{ + if (transport->ops && transport->ops->update_links) + transport->ops->update_links(transport); +} + +static void bap_update_qos(const struct media_transport *transport) +{ + struct bap_transport *bap = transport->data; + struct bt_bap_qos *qos; + + qos = bt_bap_stream_get_qos(bap->stream); + + if (!memcmp(qos, &bap->qos, sizeof(struct bt_bap_qos))) + return; + + bap->qos = *qos; + + g_dbus_emit_property_changed(btd_get_dbus_connection(), + transport->path, MEDIA_TRANSPORT_INTERFACE, + "QoS"); +} + +static gboolean bap_resume_complete_cb(void *data) +{ + struct media_transport *transport = data; + struct bap_transport *bap = transport->data; + + bap->resume_id = 0; + bap_resume_complete(transport); + return FALSE; +} + +static gboolean bap_resume_wait_cb(void *data) +{ + struct media_transport *transport = data; + struct bap_transport *bap = transport->data; + struct media_owner *owner = transport->owner; + + /* bap_state_changed will call completion callback when ready */ + DBG("stream %p owner %p resume wait", bap->stream, owner); + + bap->resume_id = 0; + if (owner && owner->pending) + owner->pending->id = 0; + + return FALSE; +} + +static void bap_update_bcast_qos(const struct media_transport *transport) +{ + struct bap_transport *bap = transport->data; + struct bt_bap_qos *qos; + + qos = bt_bap_stream_get_qos(bap->stream); + + if (!memcmp(qos, &bap->qos, sizeof(struct bt_bap_qos))) + return; + + bap->qos = *qos; + + g_dbus_emit_property_changed(btd_get_dbus_connection(), + transport->path, MEDIA_TRANSPORT_INTERFACE, + "QoS"); + g_dbus_emit_property_changed(btd_get_dbus_connection(), + transport->path, MEDIA_TRANSPORT_INTERFACE, + "Codec"); + g_dbus_emit_property_changed(btd_get_dbus_connection(), + transport->path, MEDIA_TRANSPORT_INTERFACE, + "Configuration"); +} + +static guint transport_bap_resume(struct media_transport *transport, struct media_owner *owner) { struct bap_transport *bap = transport->data; + struct iovec *meta; guint id; if (!bap->stream) return 0; + if (bap->resume_id) + return 0; bap_update_links(transport); switch (bt_bap_stream_get_state(bap->stream)) { case BT_BAP_STREAM_STATE_ENABLING: bap_enable_complete(bap->stream, 0x00, 0x00, owner); - if (owner->pending) - return owner->pending->id; - return 0; + bap->resume_id = g_idle_add(bap_resume_wait_cb, transport); + return bap->resume_id; case BT_BAP_STREAM_STATE_STREAMING: - return g_idle_add(resume_complete, transport); + bap->resume_id = g_idle_add(bap_resume_complete_cb, transport); + return bap->resume_id; } - id = bt_bap_stream_enable(bap->stream, bap->linked, NULL, + meta = bt_bap_stream_get_metadata(bap->stream); + id = bt_bap_stream_enable(bap->stream, bap->linked, meta, bap_enable_complete, owner); if (!id) return 0; @@ -1213,37 +1868,47 @@ static guint resume_bap(struct media_transport *transport, return id; } -static void bap_stop_complete(struct bt_bap_stream *stream, - uint8_t code, uint8_t reason, - void *user_data) +static void update_links(void *data, void *user_data) { - struct media_owner *owner = user_data; - struct media_request *req = owner->pending; - struct media_transport *transport = owner->transport; + struct bt_bap_stream *link = data; + struct media_transport *transport; - /* Release always succeeds */ - if (req) { - req->id = 0; - media_request_reply(req, 0); - media_owner_remove(owner); + transport = find_transport_by_bap_stream(link); + if (!transport) { + error("Unable to find transport"); + return; } - transport_set_state(transport, TRANSPORT_STATE_IDLE); - media_transport_remove_owner(transport); + bap_update_links(transport); } -static void bap_disable_complete(struct bt_bap_stream *stream, - uint8_t code, uint8_t reason, - void *user_data) +static void transport_unlink(void *data, void *user_data) { - bap_stop_complete(stream, code, reason, user_data); + struct bt_bap_stream *link = data; + struct bt_bap_stream *stream = user_data; + struct media_transport *transport; + + transport = find_transport_by_bap_stream(link); + if (!transport) { + error("Unable to find transport"); + return; + } + + bt_bap_stream_io_unlink(link, stream); + + bap_update_links(transport); + + /* Emit property changed for all remaining links */ + queue_foreach(bt_bap_stream_io_get_links(link), update_links, NULL); } -static guint suspend_bap(struct media_transport *transport, +static guint transport_bap_suspend(struct media_transport *transport, struct media_owner *owner) { struct bap_transport *bap = transport->data; + struct queue *links = bt_bap_stream_io_get_links(bap->stream); bt_bap_stream_func_t func = NULL; + guint id; if (!bap->stream) return 0; @@ -1253,15 +1918,33 @@ static guint suspend_bap(struct media_transport *transport, else transport_set_state(transport, TRANSPORT_STATE_IDLE); + if (bt_bap_stream_get_type(bap->stream) == BT_BAP_STREAM_TYPE_BCAST) + /* Unlink stream from all its links */ + queue_foreach(links, transport_unlink, bap->stream); + bap_update_links(transport); - return bt_bap_stream_disable(bap->stream, bap->linked, func, owner); + id = bt_bap_stream_disable(bap->stream, bap->linked, func, owner); + + if (bt_bap_stream_get_type(bap->stream) == BT_BAP_STREAM_TYPE_BCAST) { + if (transport->owner == owner) + bap_disable_complete(bap->stream, 0x00, 0x00, owner); + return 0; + } + + return id; } -static void cancel_bap(struct media_transport *transport, guint id) +static void transport_bap_cancel(struct media_transport *transport, guint id) { struct bap_transport *bap = transport->data; + if (id == bap->resume_id && bap->resume_id) { + g_source_remove(bap->resume_id); + bap->resume_id = 0; + return; + } + if (!bap->stream) return; @@ -1283,7 +1966,7 @@ static void link_set_state(void *data, void *user_data) transport_set_state(transport, state); } -static void set_state_bap(struct media_transport *transport, +static void transport_bap_set_state(struct media_transport *transport, transport_state_t state) { struct bap_transport *bap = transport->data; @@ -1323,6 +2006,10 @@ static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state, if (owner && owner->pending) return; bap_update_links(transport); + if (!media_endpoint_is_broadcast(transport->endpoint)) + bap_update_qos(transport); + else if (bt_bap_stream_io_dir(stream) != BT_BAP_BCAST_SOURCE) + bap_update_bcast_qos(transport); transport_update_playing(transport, FALSE); return; case BT_BAP_STREAM_STATE_DISABLING: @@ -1332,6 +2019,13 @@ static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state, return; break; case BT_BAP_STREAM_STATE_STREAMING: + if ((bt_bap_stream_io_dir(stream) == BT_BAP_BCAST_SOURCE) || + (bt_bap_stream_io_dir(stream) == BT_BAP_BCAST_SINK)) + bap_update_bcast_qos(transport); + break; + case BT_BAP_STREAM_STATE_RELEASING: + if (bt_bap_stream_io_dir(stream) == BT_BAP_BCAST_SINK) + return; break; } @@ -1363,7 +2057,7 @@ static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state, transport_update_playing(transport, TRUE); done: - resume_complete(transport); + bap_resume_complete(transport); } static void bap_connecting(struct bt_bap_stream *stream, bool state, int fd, @@ -1378,7 +2072,7 @@ static void bap_connecting(struct bt_bap_stream *stream, bool state, int fd, bap_update_links(transport); } -static void free_bap(void *data) +static void transport_bap_destroy(void *data) { struct bap_transport *bap = data; @@ -1387,8 +2081,7 @@ static void free_bap(void *data) free(bap); } -static int media_transport_init_bap(struct media_transport *transport, - void *stream) +static void *transport_bap_init(struct media_transport *transport, void *stream) { struct bt_bap_qos *qos; struct bap_transport *bap; @@ -1397,25 +2090,257 @@ static int media_transport_init_bap(struct media_transport *transport, bap = new0(struct bap_transport, 1); bap->stream = stream; - bap->interval = qos->interval; - bap->framing = qos->framing; - bap->phy = qos->phy; - bap->rtn = qos->rtn; - bap->latency = qos->latency; - bap->delay = qos->delay; + bap->qos = *qos; bap->state_id = bt_bap_state_register(bt_bap_stream_get_session(stream), bap_state_changed, bap_connecting, transport, NULL); - transport->data = bap; - transport->resume = resume_bap; - transport->suspend = suspend_bap; - transport->cancel = cancel_bap; - transport->set_state = set_state_bap; - transport->destroy = free_bap; + return bap; +} - return 0; +static void asha_transport_sync_state(struct media_transport *transport, + struct bt_asha_device *asha_dev) +{ + switch (bt_asha_device_get_state(asha_dev)) { + case ASHA_STOPPED: + transport_set_state(transport, TRANSPORT_STATE_IDLE); + break; + case ASHA_STARTING: + transport_set_state(transport, TRANSPORT_STATE_REQUESTING); + break; + case ASHA_STARTED: + transport_set_state(transport, TRANSPORT_STATE_ACTIVE); + break; + case ASHA_STOPPING: + transport_set_state(transport, TRANSPORT_STATE_SUSPENDING); + break; + } +} + +static void asha_transport_state_cb(int status, void *user_data) +{ + struct media_owner *owner = user_data; + struct media_transport *transport = owner->transport; + struct bt_asha_device *asha_dev; + enum bt_asha_state_t state; + + if (!transport) { + DBG("Lost owner while connecting, bailing"); + return; + } + + asha_dev = transport->data; + state = bt_asha_device_get_state(asha_dev); + + if (state == ASHA_STARTED) { + int fd; + uint16_t imtu, omtu; + gboolean ret; + + fd = bt_asha_device_get_fd(asha_dev); + imtu = bt_asha_device_get_imtu(asha_dev); + omtu = bt_asha_device_get_omtu(asha_dev); + + media_transport_set_fd(transport, fd, imtu, omtu); + + owner->pending->id = 0; + ret = g_dbus_send_reply(btd_get_dbus_connection(), + owner->pending->msg, + DBUS_TYPE_UNIX_FD, &fd, + DBUS_TYPE_UINT16, &imtu, + DBUS_TYPE_UINT16, &omtu, + DBUS_TYPE_INVALID); + if (!ret) { + media_transport_remove_owner(transport); + return; + } + + media_owner_remove(owner); + } else if (state == ASHA_STOPPED) { + if (owner->pending) { + owner->pending->id = 0; + media_request_reply(owner->pending, 0); + media_owner_remove(owner); + } + + media_transport_remove_owner(transport); + } + + asha_transport_sync_state(transport, asha_dev); +} + +static guint transport_asha_resume(struct media_transport *transport, + struct media_owner *owner) +{ + struct bt_asha_device *asha_dev = transport->data; + guint ret; + + ret = bt_asha_device_start(asha_dev, asha_transport_state_cb, owner); + asha_transport_sync_state(transport, asha_dev); + + return ret > 0 ? ret : 0; +} + +static guint transport_asha_suspend(struct media_transport *transport, + struct media_owner *owner) +{ + struct bt_asha_device *asha_dev = transport->data; + guint ret = 0; + + if (owner) { + ret = bt_asha_device_stop(asha_dev, asha_transport_state_cb, + owner); + asha_transport_sync_state(transport, asha_dev); + } else { + ret = bt_asha_device_stop(asha_dev, NULL, NULL); + /* We won't have a callback to set the final state */ + transport_set_state(transport, TRANSPORT_STATE_IDLE); + } + + return ret; +} + +static void transport_asha_cancel(struct media_transport *transport, guint id) +{ + struct bt_asha_device *asha_dev = transport->data; + enum bt_asha_state_t state = bt_asha_device_get_state(asha_dev); + + if (id != bt_asha_device_device_get_resume_id(asha_dev)) { + /* Not current, ignore */ + DBG("Ignoring cancel request for id %d", id); + return; + } + + if (state == ASHA_STARTING || state == ASHA_STARTED) { + DBG("Cancel requested, stopping"); + bt_asha_device_stop(asha_dev, NULL, NULL); + /* We won't have a callback to set the final state */ + transport_set_state(transport, TRANSPORT_STATE_IDLE); + } else if (state == ASHA_STOPPING) { + DBG("Cancel requested, resetting transport state"); + /* We already dispatched a stop, just reset our state */ + bt_asha_device_state_reset(asha_dev); + transport_set_state(transport, TRANSPORT_STATE_IDLE); + } +} + +static int8_t transport_asha_get_volume(struct media_transport *transport) +{ + struct bt_asha_device *asha_dev = transport->data; + int8_t volume; + int scaled_volume; + + volume = bt_asha_device_get_volume(asha_dev); + + /* Convert -128-0 to 0-127 */ + scaled_volume = ((((int) volume) + 128) * 127) / 128; + + return scaled_volume; +} + +static int transport_asha_set_volume(struct media_transport *transport, + int8_t volume) +{ + struct bt_asha_device *asha_dev = transport->data; + int scaled_volume; + + /* Convert 0-127 to -128-0 */ + scaled_volume = ((((int) volume) * 128) / 127) - 128; + + return bt_asha_device_set_volume(asha_dev, scaled_volume) ? 0 : -EIO; +} + +static void *transport_asha_init(struct media_transport *transport, void *data) +{ + /* We just store the struct asha_device on the transport */ + return data; +} + +#define TRANSPORT_OPS(_uuid, _props, _set_owner, _remove_owner, _init, \ + _resume, _suspend, _cancel, _set_state, _get_stream, \ + _get_volume, _set_volume, _set_delay, _update_links, \ + _destroy) \ +{ \ + .uuid = _uuid, \ + .properties = _props, \ + .set_owner = _set_owner, \ + .remove_owner = _remove_owner, \ + .init = _init, \ + .resume = _resume, \ + .suspend = _suspend, \ + .cancel = _cancel, \ + .set_state = _set_state, \ + .get_stream = _get_stream, \ + .get_volume = _get_volume, \ + .set_volume = _set_volume, \ + .set_delay = _set_delay, \ + .update_links = _update_links, \ + .destroy = _destroy \ +} + +#define A2DP_OPS(_uuid, _init, _set_volume, _set_delay, _destroy) \ + TRANSPORT_OPS(_uuid, transport_a2dp_properties, NULL, NULL, _init, \ + transport_a2dp_resume, transport_a2dp_suspend, \ + transport_a2dp_cancel, NULL, \ + transport_a2dp_get_stream, transport_a2dp_get_volume, \ + _set_volume, _set_delay, NULL, _destroy) + +#define BAP_OPS(_uuid, _props, _set_owner, _remove_owner, _update_links, \ + _set_state) \ + TRANSPORT_OPS(_uuid, _props, _set_owner, _remove_owner,\ + transport_bap_init, \ + transport_bap_resume, transport_bap_suspend, \ + transport_bap_cancel, _set_state, \ + transport_bap_get_stream, NULL, NULL, NULL, \ + _update_links, transport_bap_destroy) + +#define BAP_UC_OPS(_uuid) \ + BAP_OPS(_uuid, transport_bap_uc_properties, \ + transport_bap_set_owner, transport_bap_remove_owner, \ + transport_bap_update_links_uc, transport_bap_set_state) + +#define BAP_BC_OPS(_uuid) \ + BAP_OPS(_uuid, transport_bap_bc_properties, NULL, NULL, \ + transport_bap_update_links_bc, NULL) + +#define ASHA_OPS(_uuid) \ + TRANSPORT_OPS(_uuid, transport_asha_properties, NULL, NULL, \ + transport_asha_init, \ + transport_asha_resume, transport_asha_suspend, \ + transport_asha_cancel, NULL, NULL, \ + transport_asha_get_volume, transport_asha_set_volume, \ + NULL, NULL, NULL) + +static const struct media_transport_ops transport_ops[] = { + A2DP_OPS(A2DP_SOURCE_UUID, transport_a2dp_src_init, + transport_a2dp_src_set_volume, + NULL, + transport_a2dp_src_destroy), + A2DP_OPS(A2DP_SINK_UUID, transport_a2dp_snk_init, + transport_a2dp_snk_set_volume, + transport_a2dp_snk_set_delay, + transport_a2dp_snk_destroy), + BAP_UC_OPS(PAC_SOURCE_UUID), + BAP_UC_OPS(PAC_SINK_UUID), + BAP_BC_OPS(BCAA_SERVICE_UUID), + BAP_BC_OPS(BAA_SERVICE_UUID), + ASHA_OPS(ASHA_PROFILE_UUID), +}; + +static const struct media_transport_ops * +media_transport_find_ops(const char *uuid) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(transport_ops); i++) { + const struct media_transport_ops *ops = &transport_ops[i]; + + if (!strcasecmp(uuid, ops->uuid)) + return ops; + } + + return NULL; } struct media_transport *media_transport_create(struct btd_device *device, @@ -1426,42 +2351,46 @@ struct media_transport *media_transport_create(struct btd_device *device, { struct media_endpoint *endpoint = data; struct media_transport *transport; - const char *uuid; + const struct media_transport_ops *ops; static int fd = 0; - const GDBusPropertyTable *properties; transport = g_new0(struct media_transport, 1); - transport->device = device; + if (device) + transport->device = device; + else + transport->adapter = media_endpoint_get_btd_adapter(endpoint); + transport->endpoint = endpoint; - transport->configuration = g_new(uint8_t, size); - memcpy(transport->configuration, configuration, size); + transport->configuration = util_memdup(configuration, size); transport->size = size; - transport->remote_endpoint = remote_endpoint; - transport->path = g_strdup_printf("%s/fd%d", - remote_endpoint ? remote_endpoint : - device_get_path(device), fd++); + transport->remote_endpoint = g_strdup(remote_endpoint); + + if (device) + transport->path = g_strdup_printf("%s/fd%d", + remote_endpoint ? remote_endpoint : + device_get_path(device), fd++); + else + transport->path = g_strdup_printf("%s/fd%d", + remote_endpoint ? remote_endpoint : + adapter_get_path(transport->adapter), + fd++); transport->fd = -1; - uuid = media_endpoint_get_uuid(endpoint); - if (strcasecmp(uuid, A2DP_SOURCE_UUID) == 0) { - if (media_transport_init_source(transport) < 0) - goto fail; - properties = a2dp_properties; - } else if (strcasecmp(uuid, A2DP_SINK_UUID) == 0) { - if (media_transport_init_sink(transport) < 0) - goto fail; - properties = a2dp_properties; - } else if (!strcasecmp(uuid, PAC_SINK_UUID) || - !strcasecmp(uuid, PAC_SOURCE_UUID)) { - if (media_transport_init_bap(transport, stream) < 0) - goto fail; - properties = bap_properties; - } else + ops = media_transport_find_ops(media_endpoint_get_uuid(endpoint)); + if (!ops) goto fail; + transport->ops = ops; + + if (ops->init) { + transport->data = ops->init(transport, stream); + if (!transport->data) + goto fail; + } + if (g_dbus_register_interface(btd_get_dbus_connection(), transport->path, MEDIA_TRANSPORT_INTERFACE, - transport_methods, NULL, properties, + transport_methods, NULL, ops->properties, transport, media_transport_free) == FALSE) { error("Could not register transport %s", transport->path); goto fail; @@ -1481,6 +2410,14 @@ const char *media_transport_get_path(struct media_transport *transport) return transport->path; } +void *media_transport_get_stream(struct media_transport *transport) +{ + if (transport->ops && transport->ops->get_stream) + return transport->ops->get_stream(transport); + + return NULL; +} + void media_transport_update_delay(struct media_transport *transport, uint16_t delay) { @@ -1502,12 +2439,6 @@ struct btd_device *media_transport_get_dev(struct media_transport *transport) return transport->device; } -int8_t media_transport_get_volume(struct media_transport *transport) -{ - struct a2dp_transport *a2dp = transport->data; - return a2dp->volume; -} - void media_transport_update_volume(struct media_transport *transport, int8_t volume) { @@ -1541,8 +2472,14 @@ int8_t media_transport_get_device_volume(struct btd_device *dev) continue; /* Volume is A2DP only */ - if (media_endpoint_get_sep(transport->endpoint)) - return media_transport_get_volume(transport); + if (media_endpoint_get_sep(transport->endpoint)) { + int8_t volume; + + if (!media_transport_get_volume(transport, &volume)) + return volume; + + return -1; + } } /* If transport volume doesn't exists use device_volume */ diff --git a/profiles/audio/transport.h b/profiles/audio/transport.h index 102fc3cf115339ae3da45d367ca2d21bf04ccbd0..b46bc80254187248f820441a1a33ece0b0de567d 100644 --- a/profiles/audio/transport.h +++ b/profiles/audio/transport.h @@ -19,8 +19,10 @@ struct media_transport *media_transport_create(struct btd_device *device, void media_transport_destroy(struct media_transport *transport); const char *media_transport_get_path(struct media_transport *transport); +void *media_transport_get_stream(struct media_transport *transport); struct btd_device *media_transport_get_dev(struct media_transport *transport); -int8_t media_transport_get_volume(struct media_transport *transport); +int media_transport_get_volume(struct media_transport *transport, + int8_t *volume); void media_transport_update_delay(struct media_transport *transport, uint16_t delay); void media_transport_update_volume(struct media_transport *transport, diff --git a/profiles/audio/vcp.c b/profiles/audio/vcp.c index b42b0a4f79dddc95eaec413abaa79597aa66bf7b..175275f2e97791d4e70c04bac2e9cc45380b055f 100644 --- a/profiles/audio/vcp.c +++ b/profiles/audio/vcp.c @@ -289,18 +289,20 @@ static struct btd_profile vcp_profile = { .adapter_probe = vcp_server_probe, .adapter_remove = vcp_server_remove, + + .experimental = true, }; static unsigned int vcp_id = 0; static int vcp_init(void) { - if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) { - warn("D-Bus experimental not enabled"); - return -ENOTSUP; - } + int err; + + err = btd_profile_register(&vcp_profile); + if (err) + return err; - btd_profile_register(&vcp_profile); vcp_id = bt_vcp_register(vcp_attached, vcp_detached, NULL); return 0; @@ -308,10 +310,8 @@ static int vcp_init(void) static void vcp_exit(void) { - if (g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL) { - btd_profile_unregister(&vcp_profile); - bt_vcp_unregister(vcp_id); - } + btd_profile_unregister(&vcp_profile); + bt_vcp_unregister(vcp_id); } BLUETOOTH_PLUGIN_DEFINE(vcp, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, diff --git a/profiles/gap/gas.c b/profiles/gap/gas.c index 400818d67591eaf640bb102988489860db62adf3..08aaf19cb3323373a1f56afcc7af0f4258a83b9b 100644 --- a/profiles/gap/gas.c +++ b/profiles/gap/gas.c @@ -50,10 +50,18 @@ struct gas { struct gatt_db_attribute *attr; }; -static void gas_free(struct gas *gas) +static void gas_reset(struct gas *gas) { + gas->attr = NULL; gatt_db_unref(gas->db); + gas->db = NULL; bt_gatt_client_unref(gas->client); + gas->client = NULL; +} + +static void gas_free(struct gas *gas) +{ + gas_reset(gas); btd_device_unref(gas->device); g_free(gas); } @@ -152,7 +160,76 @@ static void handle_appearance(struct gas *gas, uint16_t value_handle) DBG("Failed to send request to read appearance"); } -static bool uuid_cmp(uint16_t u16, const bt_uuid_t *uuid) +static void read_ppcp_cb(bool success, uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) +{ + struct gas *gas = user_data; + uint16_t min_interval, max_interval, latency, timeout, max_latency; + + if (!success) { + DBG("Reading PPCP failed with ATT error: %u", att_ecode); + return; + } + + if (length != 8) { + DBG("Malformed PPCP value"); + return; + } + + min_interval = get_le16(&value[0]); + max_interval = get_le16(&value[2]); + latency = get_le16(&value[4]); + timeout = get_le16(&value[6]); + + /* 0xffff indicates no specific min/max */ + if (min_interval == 0xffff) + min_interval = 0x0018; /* 30.0ms */ + + if (max_interval == 0xffff) + max_interval = 0x0028; /* 50.0ms */ + + DBG("GAP Peripheral Preferred Connection Parameters:"); + DBG("\tMinimum connection interval: %u", min_interval); + DBG("\tMaximum connection interval: %u", max_interval); + DBG("\tSlave latency: %u", latency); + DBG("\tConnection Supervision timeout multiplier: %u", timeout); + + /* avoid persisting connection parameters that are not valid */ + if (min_interval > max_interval || + min_interval < 6 || max_interval > 3200) { + warn("GAS PPCP: Invalid Connection Parameters values"); + return; + } + + if (timeout < 10 || timeout > 3200) { + warn("GAS PPCP: Invalid Connection Parameters values"); + return; + } + + if (max_interval >= timeout * 8) { + warn("GAS PPCP: Invalid Connection Parameters values"); + return; + } + + max_latency = (timeout * 4 / max_interval) - 1; + if (latency > 499 || latency > max_latency) { + warn("GAS PPCP: Invalid Connection Parameters values"); + return; + } + + btd_device_set_conn_param(gas->device, min_interval, max_interval, + latency, timeout); +} + +static void handle_ppcp(struct gas *gas, uint16_t value_handle) +{ + if (!bt_gatt_client_read_value(gas->client, value_handle, + read_ppcp_cb, gas, NULL)) + DBG("Failed to send request to read PPCP"); +} + +static inline bool uuid_cmp(uint16_t u16, const bt_uuid_t *uuid) { bt_uuid_t lhs; @@ -178,6 +255,8 @@ static void handle_characteristic(struct gatt_db_attribute *attr, handle_device_name(gas, value_handle); else if (uuid_cmp(GATT_CHARAC_APPEARANCE, &uuid)) handle_appearance(gas, value_handle); + else if (uuid_cmp(GATT_CHARAC_PERIPHERAL_PREF_CONN, &uuid)) + handle_ppcp(gas, value_handle); else { char uuid_str[MAX_LEN_UUID_STR]; @@ -188,11 +267,6 @@ static void handle_characteristic(struct gatt_db_attribute *attr, } } -static void handle_gap_service(struct gas *gas) -{ - gatt_db_service_foreach_char(gas->attr, handle_characteristic, gas); -} - static int gap_probe(struct btd_service *service) { struct btd_device *device = btd_service_get_device(service); @@ -246,16 +320,7 @@ static void foreach_gap_service(struct gatt_db_attribute *attr, void *user_data) } gas->attr = attr; - handle_gap_service(gas); -} - -static void gas_reset(struct gas *gas) -{ - gas->attr = NULL; - gatt_db_unref(gas->db); - gas->db = NULL; - bt_gatt_client_unref(gas->client); - gas->client = NULL; + gatt_db_service_foreach_char(gas->attr, handle_characteristic, gas); } static int gap_accept(struct btd_service *service) @@ -266,15 +331,21 @@ static int gap_accept(struct btd_service *service) struct gas *gas = btd_service_get_user_data(service); char addr[18]; bt_uuid_t gap_uuid; + int err = 0; ba2str(device_get_address(device), addr); DBG("GAP profile accept (%s)", addr); if (!gas) { error("GAP service not handled by profile"); - return -1; + err = -1; + goto _finish; } + /* Check if attribute already has been discovered */ + if (gas->attr) + goto _finish; + gas->db = gatt_db_ref(db); gas->client = bt_gatt_client_clone(client); @@ -285,20 +356,18 @@ static int gap_accept(struct btd_service *service) if (!gas->attr) { error("GAP attribute not found"); gas_reset(gas); - return -1; + err = -1; } - btd_service_connecting_complete(service, 0); +_finish: - return 0; + btd_service_connecting_complete(service, err); + + return err; } static int gap_disconnect(struct btd_service *service) { - struct gas *gas = btd_service_get_user_data(service); - - gas_reset(gas); - btd_service_disconnecting_complete(service, 0); return 0; diff --git a/profiles/health/hdp_util.c b/profiles/health/hdp_util.c index ab3b78f6a1c1a0ba48e5a71a027d7e9f8e667da5..ad3702f01f4503cc423f7b21bc6cde976e8b4ea8 100644 --- a/profiles/health/hdp_util.c +++ b/profiles/health/hdp_util.c @@ -42,7 +42,7 @@ typedef gboolean (*parse_item_f)(DBusMessageIter *iter, gpointer user_data, GError **err); struct dict_entry_func { - char *key; + const char *key; parse_item_f func; }; @@ -67,7 +67,7 @@ struct get_dcpsm_data { GDestroyNotify destroy; }; -static gboolean parse_dict_entry(struct dict_entry_func dict_context[], +static gboolean parse_dict_entry(const struct dict_entry_func dict_context[], DBusMessageIter *iter, GError **err, gpointer user_data) @@ -75,7 +75,6 @@ static gboolean parse_dict_entry(struct dict_entry_func dict_context[], DBusMessageIter entry; char *key; int ctype, i; - struct dict_entry_func df; dbus_message_iter_recurse(iter, &entry); ctype = dbus_message_iter_get_arg_type(&entry); @@ -88,9 +87,9 @@ static gboolean parse_dict_entry(struct dict_entry_func dict_context[], dbus_message_iter_get_basic(&entry, &key); dbus_message_iter_next(&entry); /* Find function and call it */ - for (i = 0, df = dict_context[0]; df.key; i++, df = dict_context[i]) { - if (g_ascii_strcasecmp(df.key, key) == 0) - return df.func(&entry, user_data, err); + for (i = 0; dict_context[i].key; i++) { + if (g_ascii_strcasecmp(dict_context[i].key, key) == 0) + return dict_context[i].func(&entry, user_data, err); } g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, @@ -98,7 +97,7 @@ static gboolean parse_dict_entry(struct dict_entry_func dict_context[], return FALSE; } -static gboolean parse_dict(struct dict_entry_func dict_context[], +static gboolean parse_dict(const struct dict_entry_func dict_context[], DBusMessageIter *iter, GError **err, gpointer user_data) @@ -273,7 +272,7 @@ static gboolean parse_chan_type(DBusMessageIter *iter, gpointer data, return TRUE; } -static struct dict_entry_func dict_parser[] = { +static const struct dict_entry_func dict_parser[] = { {"DataType", parse_data_type}, {"Role", parse_role}, {"Description", parse_desc}, diff --git a/profiles/health/mcap.c b/profiles/health/mcap.c index 5d2bac3d916b9bcc5e80d442b57f2ad32f39dff5..2e4214a6984ff7e26244161e58e0fde58ad65ac5 100644 --- a/profiles/health/mcap.c +++ b/profiles/health/mcap.c @@ -336,6 +336,9 @@ static void mcap_notify_error(struct mcap_mcl *mcl, GError *err) case MCAP_MD_CREATE_MDL_REQ: st = MDL_WAITING; l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state); + if (!l) + return; + mdl = l->data; mcl->mdls = g_slist_remove(mcl->mdls, mdl); mcap_mdl_unref(mdl); @@ -345,6 +348,9 @@ static void mcap_notify_error(struct mcap_mcl *mcl, GError *err) case MCAP_MD_ABORT_MDL_REQ: st = MDL_WAITING; l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state); + if (!l) + return; + shutdown_mdl(l->data); update_mcl_state(mcl); con->cb.notify(err, con->user_data); @@ -362,6 +368,9 @@ static void mcap_notify_error(struct mcap_mcl *mcl, GError *err) case MCAP_MD_RECONNECT_MDL_REQ: st = MDL_WAITING; l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state); + if (!l) + return; + shutdown_mdl(l->data); update_mcl_state(mcl); con->cb.op(NULL, err, con->user_data); @@ -1907,6 +1916,7 @@ gboolean mcap_create_mcl(struct mcap_instance *mi, set_default_cb(mcl); if (util_getrandom(&val, sizeof(val), 0) < 0) { mcap_instance_unref(mcl->mi); + g_free(mcl->cb); g_free(mcl); return FALSE; } @@ -2051,6 +2061,7 @@ static void connect_mcl_event_cb(GIOChannel *chan, GError *gerr, set_default_cb(mcl); if (util_getrandom(&val, sizeof(val), 0) < 0) { mcap_instance_unref(mcl->mi); + g_free(mcl->cb); g_free(mcl); goto drop; } diff --git a/profiles/iap/main.c b/profiles/iap/main.c index 9a04f5cc0e626f2fb45e8ab4b4a8ca1634094ba7..054ff600ea02943e0b9f2a625d044061dfc7e095 100644 --- a/profiles/iap/main.c +++ b/profiles/iap/main.c @@ -398,7 +398,7 @@ static guint setup_signalfd(void) static gboolean option_version = FALSE; -static GOptionEntry options[] = { +static const GOptionEntry options[] = { { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version, "Show version information and exit" }, { NULL }, diff --git a/profiles/input/device.c b/profiles/input/device.c index e2ac6ea603524e94af7365ccff362f2d285e0be3..8cf8e5ea78e1624cdc853af58112d7ab583b2141 100644 --- a/profiles/input/device.c +++ b/profiles/input/device.c @@ -20,6 +20,7 @@ #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> +#include <sys/uio.h> #include "lib/bluetooth.h" #include "lib/hidp.h" @@ -41,6 +42,8 @@ #include "src/sdp-client.h" #include "src/shared/timeout.h" #include "src/shared/uhid.h" +#include "src/shared/util.h" +#include "src/shared/queue.h" #include "device.h" #include "hidp_defs.h" @@ -54,13 +57,18 @@ enum reconnect_mode_t { RECONNECT_ANY }; +struct hidp_msg { + uint8_t hdr; + struct iovec *iov; +}; + struct input_device { struct btd_service *service; struct btd_device *device; char *path; bdaddr_t src; bdaddr_t dst; - uint32_t handle; + const sdp_record_t *rec; GIOChannel *ctrl_io; GIOChannel *intr_io; guint ctrl_watch; @@ -72,25 +80,40 @@ struct input_device { unsigned int reconnect_timer; uint32_t reconnect_attempt; struct bt_uhid *uhid; - bool uhid_created; uint8_t report_req_pending; unsigned int report_req_timer; uint32_t report_rsp_id; bool virtual_cable_unplug; + uint8_t type; + unsigned int idle_timer; }; static int idle_timeout = 0; -static bool uhid_enabled = false; -static bool classic_bonded_only = false; +static uhid_state_t uhid_state = UHID_ENABLED; +static bool classic_bonded_only = true; void input_set_idle_timeout(int timeout) { idle_timeout = timeout; } -void input_enable_userspace_hid(bool state) +void input_set_userspace_hid(char *state) +{ + if (!strcasecmp(state, "false") || !strcasecmp(state, "no") || + !strcasecmp(state, "off")) + uhid_state = UHID_DISABLED; + else if (!strcasecmp(state, "true") || !strcasecmp(state, "yes") || + !strcasecmp(state, "on")) + uhid_state = UHID_ENABLED; + else if (!strcasecmp(state, "persist")) + uhid_state = UHID_PERSIST; + else + error("Unknown value '%s'", state); +} + +uint8_t input_get_userspace_hid(void) { - uhid_enabled = state; + return uhid_state; } void input_set_classic_bonded_only(bool state) @@ -105,7 +128,6 @@ bool input_get_classic_bonded_only(void) static void input_device_enter_reconnect_mode(struct input_device *idev); static int connection_disconnect(struct input_device *idev, uint32_t flags); -static int uhid_disconnect(struct input_device *idev); static bool input_device_bonded(struct input_device *idev) { @@ -140,6 +162,9 @@ static void input_device_free(struct input_device *idev) g_free(idev->req); } + if (idev->idle_timer) + timeout_remove(idev->idle_timer); + if (idev->reconnect_timer > 0) timeout_remove(idev->reconnect_timer); @@ -157,40 +182,93 @@ static void virtual_cable_unplug(struct input_device *idev) idev->virtual_cable_unplug = false; } -static bool hidp_send_message(GIOChannel *chan, uint8_t hdr, - const uint8_t *data, size_t size) +static int uhid_disconnect(struct input_device *idev, bool force) +{ + int err; + + if (!bt_uhid_created(idev->uhid)) + return 0; + + /* Force destroy the node if virtual cable unplug flag has been set */ + if (idev->virtual_cable_unplug && !force) + force = true; + + if (!force && uhid_state != UHID_PERSIST) + force = true; + + err = bt_uhid_destroy(idev->uhid, force); + if (err < 0) { + error("bt_uhid_destroy: %s", strerror(-err)); + return err; + } + + if (!bt_uhid_created(idev->uhid)) + bt_uhid_unregister_all(idev->uhid); + + return err; +} + +static bool input_device_idle_timeout(gpointer user_data) +{ + struct input_device *idev = user_data; + + idev->idle_timer = 0; + + DBG("path=%s", idev->path); + + uhid_disconnect(idev, true); + connection_disconnect(idev, 0); + + return false; +} + +static void input_device_idle_reset(struct input_device *idev) +{ + timeout_remove(idev->idle_timer); + + if (idle_timeout) + idev->idle_timer = timeout_add_seconds(idle_timeout, + input_device_idle_timeout, idev, + NULL); +} + +static bool hidp_send_message(struct input_device *idev, GIOChannel *chan, + uint8_t hdr, const uint8_t *data, size_t size) { int fd; ssize_t len; - uint8_t msg[size + 1]; + struct iovec iov[2]; if (!chan) { error("BT socket not connected"); return false; } + iov[0].iov_base = &hdr; + iov[0].iov_len = sizeof(hdr); + if (data == NULL) size = 0; - msg[0] = hdr; - if (size > 0) - memcpy(&msg[1], data, size); - ++size; + iov[1].iov_base = (void *)data; + iov[1].iov_len = size; fd = g_io_channel_unix_get_fd(chan); - len = write(fd, msg, size); + len = writev(fd, iov, 2); if (len < 0) { error("BT socket write error: %s (%d)", strerror(errno), errno); return false; } - if ((size_t) len < size) { + if ((size_t) len < size + 1) { error("BT socket write error: partial write (%zd of %zu bytes)", - len, size); + len, size + 1); return false; } + input_device_idle_reset(idev); + return true; } @@ -200,45 +278,33 @@ static bool hidp_send_ctrl_message(struct input_device *idev, uint8_t hdr, if (hdr == (HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG)) idev->virtual_cable_unplug = true; - return hidp_send_message(idev->ctrl_io, hdr, data, size); + return hidp_send_message(idev, idev->ctrl_io, hdr, data, size); } static bool hidp_send_intr_message(struct input_device *idev, uint8_t hdr, const uint8_t *data, size_t size) { - return hidp_send_message(idev->intr_io, hdr, data, size); + return hidp_send_message(idev, idev->intr_io, hdr, data, size); } static bool uhid_send_get_report_reply(struct input_device *idev, const uint8_t *data, size_t size, uint32_t id, uint16_t err) { - struct uhid_event ev; int ret; if (data == NULL) size = 0; - if (size > sizeof(ev.u.get_report_reply.data)) - size = sizeof(ev.u.get_report_reply.data); - - if (!idev->uhid_created) { + if (!bt_uhid_created(idev->uhid)) { DBG("HID report (%zu bytes) dropped", size); return false; } - memset(&ev, 0, sizeof(ev)); - ev.type = UHID_GET_REPORT_REPLY; - ev.u.get_report_reply.id = id; - ev.u.get_report_reply.err = err; - ev.u.get_report_reply.size = size; - - if (size > 0) - memcpy(ev.u.get_report_reply.data, data, size); - - ret = bt_uhid_send(idev->uhid, &ev); + ret = bt_uhid_get_report_reply(idev->uhid, id, 0, err, data, size); if (ret < 0) { - error("bt_uhid_send: %s (%d)", strerror(-ret), -ret); + error("bt_uhid_get_report_reply: %s (%d)", strerror(-ret), + -ret); return false; } @@ -250,20 +316,15 @@ static bool uhid_send_get_report_reply(struct input_device *idev, static bool uhid_send_set_report_reply(struct input_device *idev, uint32_t id, uint16_t err) { - struct uhid_event ev; int ret; - if (!idev->uhid_created) + if (!bt_uhid_created(idev->uhid)) return false; - memset(&ev, 0, sizeof(ev)); - ev.type = UHID_SET_REPORT_REPLY; - ev.u.set_report_reply.id = id; - ev.u.set_report_reply.err = err; - - ret = bt_uhid_send(idev->uhid, &ev); + ret = bt_uhid_set_report_reply(idev->uhid, id, err); if (ret < 0) { - error("bt_uhid_send: %s (%d)", strerror(-ret), -ret); + error("bt_uhid_set_report_reply: %s (%d)", strerror(-ret), + -ret); return false; } @@ -273,30 +334,19 @@ static bool uhid_send_set_report_reply(struct input_device *idev, static bool uhid_send_input_report(struct input_device *idev, const uint8_t *data, size_t size) { - struct uhid_event ev; int err; if (data == NULL) size = 0; - if (size > sizeof(ev.u.input.data)) - size = sizeof(ev.u.input.data); - - if (!idev->uhid_created) { + if (!bt_uhid_created(idev->uhid)) { DBG("HID report (%zu bytes) dropped", size); return false; } - memset(&ev, 0, sizeof(ev)); - ev.type = UHID_INPUT; - ev.u.input.size = size; - - if (size > 0) - memcpy(ev.u.input.data, data, size); - - err = bt_uhid_send(idev->uhid, &ev); + err = bt_uhid_input(idev->uhid, 0, data, size); if (err < 0) { - error("bt_uhid_send: %s (%d)", strerror(-err), -err); + error("bt_uhid_input: %s (%d)", strerror(-err), -err); return false; } @@ -325,6 +375,8 @@ static bool hidp_recv_intr_data(GIOChannel *chan, struct input_device *idev) return true; } + input_device_idle_reset(idev); + hdr = data[0]; if (hdr != (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) { DBG("unsupported HIDP protocol header 0x%02x", hdr); @@ -383,8 +435,7 @@ static gboolean intr_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data virtual_cable_unplug(idev); /* If connection abruptly ended, uhid might be not yet disconnected */ - if (idev->uhid_created) - uhid_disconnect(idev); + uhid_disconnect(idev, false); return FALSE; } @@ -443,6 +494,7 @@ static void hidp_recv_ctrl_handshake(struct input_device *idev, uint8_t param) timeout_remove(idev->report_req_timer); idev->report_req_timer = 0; } + uhid_send_set_report_reply(idev, idev->report_rsp_id, 0); idev->report_rsp_id = 0; } } @@ -526,6 +578,8 @@ static bool hidp_recv_ctrl_message(GIOChannel *chan, struct input_device *idev) return true; } + input_device_idle_reset(idev); + hdr = data[0]; type = hdr & HIDP_HEADER_TRANS_MASK; param = hdr & HIDP_HEADER_PARAM_MASK; @@ -623,7 +677,7 @@ static bool hidp_report_req_timeout(gpointer data) break; } - DBG("Device %s HIDP %s request timed out", address, req_type_str); + error("Device %s HIDP %s request timed out", address, req_type_str); idev->report_req_pending = 0; idev->report_req_timer = 0; @@ -636,11 +690,14 @@ static void hidp_send_output(struct uhid_event *ev, void *user_data) { struct input_device *idev = user_data; uint8_t hdr = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUTPUT; + bool sent; DBG(""); - hidp_send_intr_message(idev, hdr, ev->u.output.data, + sent = hidp_send_intr_message(idev, hdr, ev->u.output.data, ev->u.output.size); + if (!sent) + uhid_disconnect(idev, true); } static void hidp_send_set_report(struct uhid_event *ev, void *user_data) @@ -680,8 +737,11 @@ static void hidp_send_set_report(struct uhid_event *ev, void *user_data) timeout_add_seconds(REPORT_REQ_TIMEOUT, hidp_report_req_timeout, idev, NULL); idev->report_rsp_id = ev->u.set_report.id; - } else + } else { uhid_send_set_report_reply(idev, ev->u.set_report.id, EIO); + /* Force UHID_DESTROY on error */ + uhid_disconnect(idev, true); + } } static void hidp_send_get_report(struct uhid_event *ev, void *user_data) @@ -724,9 +784,12 @@ static void hidp_send_get_report(struct uhid_event *ev, void *user_data) hidp_report_req_timeout, idev, NULL); idev->report_rsp_id = ev->u.get_report.id; - } else + } else { uhid_send_get_report_reply(idev, NULL, 0, ev->u.get_report.id, EIO); + /* Force UHID_DESTROY on error */ + uhid_disconnect(idev, true); + } } static void epox_endian_quirk(unsigned char *data, int size) @@ -754,7 +817,8 @@ static void epox_endian_quirk(unsigned char *data, int size) } } -static int create_hid_dev_name(sdp_record_t *rec, struct hidp_connadd_req *req) +static int create_hid_dev_name(const sdp_record_t *rec, + struct hidp_connadd_req *req) { char sdesc[sizeof(req->name) / 2]; @@ -776,7 +840,7 @@ static int create_hid_dev_name(sdp_record_t *rec, struct hidp_connadd_req *req) /* See HID profile specification v1.0, "7.11.6 HIDDescriptorList" for details * on the attribute format. */ -static int extract_hid_desc_data(sdp_record_t *rec, +static int extract_hid_desc_data(const sdp_record_t *rec, struct hidp_connadd_req *req) { sdp_data_t *d; @@ -817,36 +881,40 @@ invalid_desc: return -EINVAL; } -static int extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req) +static int extract_hid_record(struct input_device *idev, + struct hidp_connadd_req *req) { sdp_data_t *pdlist; uint8_t attr_val; int err; - err = create_hid_dev_name(rec, req); + if (!idev->rec) + return -ENOENT; + + err = create_hid_dev_name(idev->rec, req); if (err < 0) DBG("No valid Service Name or Service Description found"); - pdlist = sdp_data_get(rec, SDP_ATTR_HID_PARSER_VERSION); + pdlist = sdp_data_get(idev->rec, SDP_ATTR_HID_PARSER_VERSION); req->parser = pdlist ? pdlist->val.uint16 : 0x0100; - pdlist = sdp_data_get(rec, SDP_ATTR_HID_DEVICE_SUBCLASS); + pdlist = sdp_data_get(idev->rec, SDP_ATTR_HID_DEVICE_SUBCLASS); req->subclass = pdlist ? pdlist->val.uint8 : 0; - pdlist = sdp_data_get(rec, SDP_ATTR_HID_COUNTRY_CODE); + pdlist = sdp_data_get(idev->rec, SDP_ATTR_HID_COUNTRY_CODE); req->country = pdlist ? pdlist->val.uint8 : 0; - pdlist = sdp_data_get(rec, SDP_ATTR_HID_VIRTUAL_CABLE); + pdlist = sdp_data_get(idev->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); + pdlist = sdp_data_get(idev->rec, SDP_ATTR_HID_BOOT_DEVICE); attr_val = pdlist ? pdlist->val.uint8 : 0; if (attr_val) req->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE); - err = extract_hid_desc_data(rec, req); + err = extract_hid_desc_data(idev->rec, req); if (err < 0) return err; @@ -934,28 +1002,16 @@ static int ioctl_disconnect(struct input_device *idev, uint32_t flags) static int uhid_connadd(struct input_device *idev, struct hidp_connadd_req *req) { int err; - struct uhid_event ev; - if (idev->uhid_created) - return 0; + if (bt_uhid_created(idev->uhid)) + return bt_uhid_replay(idev->uhid); - /* create uHID device */ - memset(&ev, 0, sizeof(ev)); - ev.type = UHID_CREATE; - strncpy((char *) ev.u.create.name, req->name, sizeof(ev.u.create.name)); - ba2strlc(&idev->src, (char *) ev.u.create.phys); - ba2strlc(&idev->dst, (char *) ev.u.create.uniq); - ev.u.create.vendor = req->vendor; - ev.u.create.product = req->product; - ev.u.create.version = req->version; - ev.u.create.country = req->country; - ev.u.create.bus = BUS_BLUETOOTH; - ev.u.create.rd_data = req->rd_data; - ev.u.create.rd_size = req->rd_size; - - err = bt_uhid_send(idev->uhid, &ev); + err = bt_uhid_create(idev->uhid, req->name, &idev->src, &idev->dst, + req->vendor, req->product, req->version, + req->country, idev->type, + req->rd_data, req->rd_size); if (err < 0) { - error("bt_uhid_send: %s", strerror(-err)); + error("bt_uhid_create: %s", strerror(-err)); return err; } @@ -965,32 +1021,6 @@ static int uhid_connadd(struct input_device *idev, struct hidp_connadd_req *req) bt_uhid_register(idev->uhid, UHID_SET_REPORT, hidp_send_set_report, idev); - idev->uhid_created = true; - - return err; -} - -static int uhid_disconnect(struct input_device *idev) -{ - int err; - struct uhid_event ev; - - if (!idev->uhid_created) - return 0; - - bt_uhid_unregister_all(idev->uhid); - - memset(&ev, 0, sizeof(ev)); - ev.type = UHID_DESTROY; - - err = bt_uhid_send(idev->uhid, &ev); - if (err < 0) { - error("bt_uhid_send: %s", strerror(-err)); - return err; - } - - idev->uhid_created = false; - return err; } @@ -1035,11 +1065,6 @@ static gboolean encrypt_notify(GIOChannel *io, GIOCondition condition, static int hidp_add_connection(struct input_device *idev) { struct hidp_connadd_req *req; - sdp_record_t *rec; - char src_addr[18], dst_addr[18]; - char filename[PATH_MAX]; - GKeyFile *key_file; - char handle[11], *str; GError *gerr = NULL; int err; @@ -1049,33 +1074,7 @@ static int hidp_add_connection(struct input_device *idev) req->flags = 0; req->idle_to = idle_timeout; - ba2str(&idev->src, src_addr); - ba2str(&idev->dst, dst_addr); - - snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", src_addr, - dst_addr); - sprintf(handle, "0x%8.8X", idev->handle); - - key_file = g_key_file_new(); - if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { - error("Unable to load key file from %s: (%s)", filename, - gerr->message); - g_clear_error(&gerr); - } - str = g_key_file_get_string(key_file, "ServiceRecords", handle, NULL); - g_key_file_free(key_file); - - if (!str) { - error("Rejected connection from unknown device %s", dst_addr); - err = -EPERM; - goto cleanup; - } - - rec = record_from_string(str); - g_free(str); - - err = extract_hid_record(rec, req); - sdp_record_free(rec); + err = extract_hid_record(idev, req); if (err < 0) { error("Could not parse HID SDP record: %s (%d)", strerror(-err), -err); @@ -1091,7 +1090,7 @@ static int hidp_add_connection(struct input_device *idev) /* Make sure the device is bonded if required */ if (classic_bonded_only && !input_device_bonded(idev)) { - error("Rejected connection from !bonded device %s", dst_addr); + error("Rejected connection from !bonded device %s", idev->path); goto cleanup; } @@ -1099,7 +1098,7 @@ static int hidp_add_connection(struct input_device *idev) /* Some platforms may choose to require encryption for all devices */ /* Note that this only matters for pre 2.1 devices as otherwise the */ /* device is encrypted by default by the lower layers */ - if (classic_bonded_only || req->subclass & 0x40) { + if (classic_bonded_only || idev->type == BT_UHID_KEYBOARD) { if (!bt_io_set(idev->intr_io, &gerr, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_INVALID)) { @@ -1156,11 +1155,73 @@ static int connection_disconnect(struct input_device *idev, uint32_t flags) idev->virtual_cable_unplug = true; if (idev->uhid) - return uhid_disconnect(idev); + return uhid_disconnect(idev, false); else return ioctl_disconnect(idev, flags); } +static bool is_device_sdp_disable(const sdp_record_t *rec) +{ + sdp_data_t *data; + + data = sdp_data_get(rec, SDP_ATTR_HID_SDP_DISABLE); + + return data && data->val.uint8; +} + +static enum reconnect_mode_t hid_reconnection_mode(bool reconnect_initiate, + bool normally_connectable) +{ + if (!reconnect_initiate && !normally_connectable) + return RECONNECT_NONE; + else if (!reconnect_initiate && normally_connectable) + return RECONNECT_HOST; + else if (reconnect_initiate && !normally_connectable) + return RECONNECT_DEVICE; + else /* (reconnect_initiate && normally_connectable) */ + return RECONNECT_ANY; +} + +static void extract_hid_props(struct input_device *idev, + const sdp_record_t *rec) +{ + /* Extract HID connectability */ + bool reconnect_initiate, normally_connectable; + sdp_data_t *pdlist; + + /* HIDNormallyConnectable is optional and assumed FALSE if not + * present. + */ + pdlist = sdp_data_get(rec, SDP_ATTR_HID_RECONNECT_INITIATE); + reconnect_initiate = pdlist ? pdlist->val.uint8 : TRUE; + + pdlist = sdp_data_get(rec, SDP_ATTR_HID_NORMALLY_CONNECTABLE); + normally_connectable = pdlist ? pdlist->val.uint8 : FALSE; + + /* Update local values */ + idev->reconnect_mode = + hid_reconnection_mode(reconnect_initiate, normally_connectable); +} + +static void input_device_update_rec(struct input_device *idev) +{ + struct btd_profile *p = btd_service_get_profile(idev->service); + const sdp_record_t *rec; + + rec = btd_device_get_record(idev->device, p->remote_uuid); + if (!rec || idev->rec == rec) + return; + + idev->rec = rec; + idev->disable_sdp = is_device_sdp_disable(rec); + + /* Initialize device properties */ + extract_hid_props(idev, rec); + + if (idev->disable_sdp) + device_set_refresh_discovery(idev->device, false); +} + static int input_device_connected(struct input_device *idev) { int err; @@ -1168,6 +1229,9 @@ static int input_device_connected(struct input_device *idev) if (idev->intr_io == NULL || idev->ctrl_io == NULL) return -ENOTCONN; + /* Attempt to update SDP record if it had changed */ + input_device_update_rec(idev); + err = hidp_add_connection(idev); if (err < 0) return err; @@ -1411,74 +1475,22 @@ int input_device_disconnect(struct btd_service *service) return 0; } -static bool is_device_sdp_disable(const sdp_record_t *rec) -{ - sdp_data_t *data; - - data = sdp_data_get(rec, SDP_ATTR_HID_SDP_DISABLE); - - return data && data->val.uint8; -} - -static enum reconnect_mode_t hid_reconnection_mode(bool reconnect_initiate, - bool normally_connectable) -{ - if (!reconnect_initiate && !normally_connectable) - return RECONNECT_NONE; - else if (!reconnect_initiate && normally_connectable) - return RECONNECT_HOST; - else if (reconnect_initiate && !normally_connectable) - return RECONNECT_DEVICE; - else /* (reconnect_initiate && normally_connectable) */ - return RECONNECT_ANY; -} - -static void extract_hid_props(struct input_device *idev, - const sdp_record_t *rec) -{ - /* Extract HID connectability */ - bool reconnect_initiate, normally_connectable; - sdp_data_t *pdlist; - - /* HIDNormallyConnectable is optional and assumed FALSE - * if not present. */ - pdlist = sdp_data_get(rec, SDP_ATTR_HID_RECONNECT_INITIATE); - reconnect_initiate = pdlist ? pdlist->val.uint8 : TRUE; - - pdlist = sdp_data_get(rec, SDP_ATTR_HID_NORMALLY_CONNECTABLE); - normally_connectable = pdlist ? pdlist->val.uint8 : FALSE; - - /* Update local values */ - idev->reconnect_mode = - hid_reconnection_mode(reconnect_initiate, normally_connectable); -} - static struct input_device *input_device_new(struct btd_service *service) { struct btd_device *device = btd_service_get_device(service); - struct btd_profile *p = btd_service_get_profile(service); const char *path = device_get_path(device); - const sdp_record_t *rec = btd_device_get_record(device, p->remote_uuid); struct btd_adapter *adapter = device_get_adapter(device); struct input_device *idev; - if (!rec) - return NULL; - idev = g_new0(struct input_device, 1); bacpy(&idev->src, btd_adapter_get_address(adapter)); bacpy(&idev->dst, device_get_address(device)); idev->service = btd_service_ref(service); idev->device = btd_device_ref(device); idev->path = g_strdup(path); - idev->handle = rec->handle; - idev->disable_sdp = is_device_sdp_disable(rec); + idev->type = bt_uhid_icon_to_type(btd_device_get_icon(device)); - /* Initialize device properties */ - extract_hid_props(idev, rec); - - if (idev->disable_sdp) - device_set_refresh_discovery(device, false); + input_device_update_rec(idev); return idev; } @@ -1512,7 +1524,7 @@ int input_device_register(struct btd_service *service) if (!idev) return -EINVAL; - if (uhid_enabled) { + if (uhid_state) { idev->uhid = bt_uhid_new_default(); if (!idev->uhid) { error("bt_uhid_new_default: failed"); @@ -1610,7 +1622,7 @@ int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm, if (!idev) return -ENOENT; - if (uhid_enabled) + if (uhid_state) cond |= G_IO_IN; switch (psm) { diff --git a/profiles/input/device.h b/profiles/input/device.h index cf03894178f7bf00df11dc6003cc47ce8b243c1f..7b87ce5903374ea9285c0ce42fc7e63011f9e9ae 100644 --- a/profiles/input/device.h +++ b/profiles/input/device.h @@ -11,11 +11,18 @@ #define L2CAP_PSM_HIDP_CTRL 0x11 #define L2CAP_PSM_HIDP_INTR 0x13 +typedef enum { + UHID_DISABLED = 0, + UHID_ENABLED, + UHID_PERSIST +} uhid_state_t; + struct input_device; struct input_conn; void input_set_idle_timeout(int timeout); -void input_enable_userspace_hid(bool state); +void input_set_userspace_hid(char *state); +uint8_t input_get_userspace_hid(void); void input_set_classic_bonded_only(bool state); bool input_get_classic_bonded_only(void); void input_set_auto_sec(bool state); diff --git a/profiles/input/hog-lib.c b/profiles/input/hog-lib.c index 021db386f3b7dc7a33f67d84823e1590cc926d08..22599f71a394ae97570f90c7c05e5678f2c8ea40 100644 --- a/profiles/input/hog-lib.c +++ b/profiles/input/hog-lib.c @@ -73,14 +73,13 @@ struct bt_hog { uint16_t vendor; uint16_t product; uint16_t version; + uint8_t type; struct gatt_db_attribute *attr; struct gatt_primary *primary; GAttrib *attrib; GSList *reports; struct bt_uhid *uhid; int uhid_fd; - bool uhid_created; - bool uhid_start; uint64_t uhid_flags; uint16_t bcdhid; uint8_t bcountrycode; @@ -99,7 +98,6 @@ struct bt_hog { struct queue *gatt_op; struct gatt_db *gatt_db; struct gatt_db_attribute *report_map_attr; - struct queue *input; }; struct report { @@ -326,8 +324,6 @@ static void report_value_cb(const guint8 *pdu, guint16 len, gpointer user_data) { struct report *report = user_data; struct bt_hog *hog = report->hog; - struct uhid_event ev; - uint8_t *buf; int err; if (len < ATT_NOTIFICATION_HEADER_SIZE) { @@ -338,40 +334,19 @@ static void report_value_cb(const guint8 *pdu, guint16 len, gpointer user_data) pdu += ATT_NOTIFICATION_HEADER_SIZE; len -= ATT_NOTIFICATION_HEADER_SIZE; - memset(&ev, 0, sizeof(ev)); - ev.type = UHID_INPUT; - buf = ev.u.input.data; + err = bt_uhid_input(hog->uhid, report->numbered ? report->id : 0, pdu, + len); + if (err < 0) + error("bt_uhid_input: %s (%d)", strerror(-err), -err); +} - /* BLUETOOTH SPECIFICATION Page 16 of 26 - * HID Service Specification - * - * Report ID shall be nonzero in a Report Reference characteristic - * descriptor where there is more than one instance of the Report - * characteristic for any given Report Type. - */ - if (report->numbered && report->id) { - buf[0] = report->id; - len = MIN(len, sizeof(ev.u.input.data) - 1); - memcpy(buf + 1, pdu, len); - ev.u.input.size = ++len; - } else { - len = MIN(len, sizeof(ev.u.input.data)); - memcpy(buf, pdu, len); - ev.u.input.size = len; - } - - /* If uhid had not sent UHID_START yet queue up the input */ - if (!hog->uhid_created || !hog->uhid_start) { - if (!hog->input) - hog->input = queue_new(); - - queue_push_tail(hog->input, util_memdup(&ev, sizeof(ev))); - return; - } +static void report_notify_destroy(void *user_data) +{ + struct report *report = user_data; - err = bt_uhid_send(hog->uhid, &ev); - if (err < 0) - error("bt_uhid_send: %s (%d)", strerror(-err), -err); + DBG(""); + + report->notifyid = 0; } static void report_ccc_written_cb(guint8 status, const guint8 *pdu, @@ -393,7 +368,13 @@ static void report_ccc_written_cb(guint8 status, const guint8 *pdu, report->notifyid = g_attrib_register(hog->attrib, ATT_OP_HANDLE_NOTIFY, report->value_handle, - report_value_cb, report, NULL); + report_value_cb, report, + report_notify_destroy); + if (!report->notifyid) { + error("Unable to register report notification: handle 0x%04x", + report->value_handle); + goto remove; + } DBG("Report characteristic descriptor written: notifications enabled"); @@ -817,56 +798,48 @@ static void set_numbered(void *data, void *user_data) } } -static bool input_dequeue(const void *data, const void *match_data) -{ - const struct uhid_event *ev = data; - const struct bt_hog *hog = match_data; - int err; - - err = bt_uhid_send(hog->uhid, ev); - if (err < 0) { - error("bt_uhid_send: %s (%d)", strerror(-err), -err); - return false; - } - - return true; -} - static void start_flags(struct uhid_event *ev, void *user_data) { struct bt_hog *hog = user_data; - hog->uhid_start = true; hog->uhid_flags = ev->u.start.dev_flags; DBG("uHID device flags: 0x%16" PRIx64, hog->uhid_flags); if (hog->uhid_flags) g_slist_foreach(hog->reports, set_numbered, hog); - - queue_remove_all(hog->input, input_dequeue, hog, free); } static void set_report_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { struct bt_hog *hog = user_data; - struct uhid_event rsp; int err; hog->setrep_att = 0; - memset(&rsp, 0, sizeof(rsp)); - rsp.type = UHID_SET_REPORT_REPLY; - rsp.u.set_report_reply.id = hog->setrep_id; - rsp.u.set_report_reply.err = status; - if (status != 0) error("Error setting Report value: %s", att_ecode2str(status)); - err = bt_uhid_send(hog->uhid, &rsp); + err = bt_uhid_set_report_reply(hog->uhid, hog->setrep_id, status); if (err < 0) - error("bt_uhid_send: %s", strerror(-err)); + error("bt_uhid_set_report_reply: %s", strerror(-err)); +} + +static void uhid_destroy(struct bt_hog *hog, bool force) +{ + int err; + + if (!hog->uhid) + return; + + bt_uhid_unregister_all(hog->uhid); + + err = bt_uhid_destroy(hog->uhid, force); + if (err < 0) { + error("bt_uhid_destroy: %s", strerror(-err)); + return; + } } static void set_report(struct uhid_event *ev, void *user_data) @@ -877,6 +850,14 @@ static void set_report(struct uhid_event *ev, void *user_data) int size; int err; + /* Destroy input device if there is an attempt to communicate with it + * while disconnected. + */ + if (hog->attrib == NULL) { + uhid_destroy(hog, true); + return; + } + /* uhid never sends reqs in parallel; if there's a req, it timed out */ if (hog->setrep_att) { g_attrib_cancel(hog->attrib, hog->setrep_att); @@ -903,9 +884,6 @@ static void set_report(struct uhid_event *ev, void *user_data) DBG("Sending report type %d ID %d to handle 0x%X", report->type, report->id, report->value_handle); - if (hog->attrib == NULL) - return; - hog->setrep_att = gatt_write_char(hog->attrib, report->value_handle, data, size, set_report_cb, @@ -922,34 +900,16 @@ fail: } static void report_reply(struct bt_hog *hog, uint8_t status, uint8_t id, - bool numbered, uint16_t len, const uint8_t *data) + uint16_t len, const uint8_t *data) { - struct uhid_event rsp; int err; hog->getrep_att = 0; - memset(&rsp, 0, sizeof(rsp)); - rsp.type = UHID_GET_REPORT_REPLY; - rsp.u.get_report_reply.id = hog->getrep_id; - - if (status) - goto done; - - if (numbered && len > 0) { - rsp.u.get_report_reply.size = len + 1; - rsp.u.get_report_reply.data[0] = id; - memcpy(&rsp.u.get_report_reply.data[1], data, len); - } else { - rsp.u.get_report_reply.size = len; - memcpy(rsp.u.get_report_reply.data, data, len); - } - -done: - rsp.u.get_report_reply.err = status; - err = bt_uhid_send(hog->uhid, &rsp); + err = bt_uhid_get_report_reply(hog->uhid, hog->getrep_id, id, status, + data, len); if (err < 0) - error("bt_uhid_send: %s", strerror(-err)); + error("bt_uhid_get_report_reply: %s", strerror(-err)); } static void get_report_cb(guint8 status, const guint8 *pdu, guint16 len, @@ -979,7 +939,7 @@ static void get_report_cb(guint8 status, const guint8 *pdu, guint16 len, ++pdu; exit: - report_reply(hog, status, report->id, report->numbered, len, pdu); + report_reply(hog, status, report->numbered ? report->id : 0, len, pdu); } static void get_report(struct uhid_event *ev, void *user_data) @@ -988,6 +948,14 @@ static void get_report(struct uhid_event *ev, void *user_data) struct report *report; guint8 err; + /* Destroy input device if there is an attempt to communicate with it + * while disconnected. + */ + if (hog->attrib == NULL) { + uhid_destroy(hog, true); + return; + } + /* uhid never sends reqs in parallel; if there's a req, it timed out */ if (hog->getrep_att) { g_attrib_cancel(hog->attrib, hog->getrep_att); @@ -1015,61 +983,33 @@ static void get_report(struct uhid_event *ev, void *user_data) fail: /* reply with an error on failure */ - report_reply(hog, err, 0, false, 0, NULL); + report_reply(hog, err, 0, 0, NULL); } static void uhid_create(struct bt_hog *hog, uint8_t *report_map, size_t report_map_len) { uint8_t *value = report_map; - struct uhid_event ev; size_t vlen = report_map_len; - int i, err; + int err; GError *gerr = NULL; - - if (vlen > sizeof(ev.u.create2.rd_data)) { - error("Report MAP too big: %zu > %zu", vlen, - sizeof(ev.u.create2.rd_data)); - return; - } - - /* create uHID device */ - memset(&ev, 0, sizeof(ev)); - ev.type = UHID_CREATE2; + bdaddr_t src, dst; bt_io_get(g_attrib_get_channel(hog->attrib), &gerr, - BT_IO_OPT_SOURCE, ev.u.create2.phys, - BT_IO_OPT_DEST, ev.u.create2.uniq, + BT_IO_OPT_SOURCE_BDADDR, &src, + BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_INVALID); - if (gerr) { error("Failed to connection details: %s", gerr->message); g_error_free(gerr); return; } - /* Phys + uniq are the same size (hw address type) */ - for (i = 0; - i < (int)sizeof(ev.u.create2.phys) && ev.u.create2.phys[i] != 0; - ++i) { - ev.u.create2.phys[i] = tolower(ev.u.create2.phys[i]); - ev.u.create2.uniq[i] = tolower(ev.u.create2.uniq[i]); - } - - strncpy((char *) ev.u.create2.name, hog->name, - sizeof(ev.u.create2.name) - 1); - ev.u.create2.vendor = hog->vendor; - ev.u.create2.product = hog->product; - ev.u.create2.version = hog->version; - ev.u.create2.country = hog->bcountrycode; - ev.u.create2.bus = BUS_BLUETOOTH; - ev.u.create2.rd_size = vlen; - - memcpy(ev.u.create2.rd_data, value, vlen); - - err = bt_uhid_send(hog->uhid, &ev); + err = bt_uhid_create(hog->uhid, hog->name, &src, &dst, + hog->vendor, hog->product, hog->version, + hog->bcountrycode, hog->type, value, vlen); if (err < 0) { - error("bt_uhid_send: %s", strerror(-err)); + error("bt_uhid_create: %s", strerror(-err)); return; } @@ -1078,9 +1018,6 @@ static void uhid_create(struct bt_hog *hog, uint8_t *report_map, bt_uhid_register(hog->uhid, UHID_GET_REPORT, get_report, hog); bt_uhid_register(hog->uhid, UHID_SET_REPORT, set_report, hog); - hog->uhid_created = true; - hog->uhid_start = false; - DBG("HoG created uHID device"); } @@ -1131,7 +1068,8 @@ static void read_report_map(struct bt_hog *hog) { uint16_t handle; - if (!hog->report_map_attr || hog->uhid_created || hog->report_map_id) + if (!hog->report_map_attr || bt_uhid_created(hog->uhid) || + hog->report_map_id) return; handle = gatt_db_attribute_get_handle(hog->report_map_attr); @@ -1298,9 +1236,9 @@ static void hog_free(void *data) { struct bt_hog *hog = data; - bt_hog_detach(hog); + bt_hog_detach(hog, true); + uhid_destroy(hog, true); - queue_destroy(hog->input, free); queue_destroy(hog->bas, (void *) bt_bas_unref); g_slist_free_full(hog->instances, hog_free); @@ -1318,9 +1256,9 @@ static void hog_free(void *data) struct bt_hog *bt_hog_new_default(const char *name, uint16_t vendor, uint16_t product, uint16_t version, - struct gatt_db *db) + uint8_t type, struct gatt_db *db) { - return bt_hog_new(-1, name, vendor, product, version, db); + return bt_hog_new(-1, name, vendor, product, version, type, db); } static void foreach_hog_report(struct gatt_db_attribute *attr, void *user_data) @@ -1480,25 +1418,32 @@ static void foreach_hog_chrc(struct gatt_db_attribute *attr, void *user_data) static struct bt_hog *hog_new(int fd, const char *name, uint16_t vendor, uint16_t product, uint16_t version, + uint8_t type, struct gatt_db_attribute *attr) { + struct bt_uhid *uhid; struct bt_hog *hog; + if (fd < 0) + uhid = bt_uhid_new_default(); + else + uhid = bt_uhid_new(fd); + + if (!uhid) { + DBG("Unable to create UHID"); + return NULL; + } + hog = g_try_new0(struct bt_hog, 1); if (!hog) return NULL; hog->gatt_op = queue_new(); hog->bas = queue_new(); - - if (fd < 0) - hog->uhid = bt_uhid_new_default(); - else - hog->uhid = bt_uhid_new(fd); - hog->uhid_fd = fd; + hog->uhid = uhid; - if (!hog->gatt_op || !hog->bas || !hog->uhid) { + if (!hog->gatt_op || !hog->bas) { hog_free(hog); return NULL; } @@ -1507,6 +1452,7 @@ static struct bt_hog *hog_new(int fd, const char *name, uint16_t vendor, hog->vendor = vendor; hog->product = product; hog->version = version; + hog->type = type; hog->attr = attr; return hog; @@ -1522,8 +1468,8 @@ static void hog_attach_instance(struct bt_hog *hog, return; } - instance = hog_new(hog->uhid_fd, hog->name, hog->vendor, - hog->product, hog->version, attr); + instance = hog_new(hog->uhid_fd, hog->name, hog->vendor, hog->product, + hog->version, hog->type, attr); if (!instance) return; @@ -1559,11 +1505,11 @@ static void dis_notify(uint8_t source, uint16_t vendor, uint16_t product, struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor, uint16_t product, uint16_t version, - struct gatt_db *db) + uint8_t type, struct gatt_db *db) { struct bt_hog *hog; - hog = hog_new(fd, name, vendor, product, version, NULL); + hog = hog_new(fd, name, vendor, product, version, type, NULL); if (!hog) return NULL; @@ -1686,7 +1632,7 @@ static void hog_attach_hog(struct bt_hog *hog, struct gatt_primary *primary) instance = bt_hog_new(hog->uhid_fd, hog->name, hog->vendor, hog->product, hog->version, - hog->gatt_db); + hog->type, hog->gatt_db); if (!instance) return; @@ -1771,7 +1717,7 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt) bt_hog_attach(instance, gatt); } - if (!hog->uhid_created) { + if (!bt_uhid_created(hog->uhid)) { DBG("HoG discovering characteristics"); if (hog->attr) gatt_db_service_foreach_char(hog->attr, @@ -1783,7 +1729,7 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt) char_discovered_cb, hog); } - if (!hog->uhid_created) + if (!bt_uhid_created(hog->uhid)) return true; /* If UHID is already created, set up the report value handlers to @@ -1798,48 +1744,37 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt) r->notifyid = g_attrib_register(hog->attrib, ATT_OP_HANDLE_NOTIFY, r->value_handle, - report_value_cb, r, NULL); + report_value_cb, r, + report_notify_destroy); + if (!r->notifyid) + error("Unable to register report notification: " + "handle 0x%04x", r->value_handle); } + /* Attempt to replay get/set report messages since the driver might not + * be aware the device has been disconnected in the meantime. + */ + bt_uhid_replay(hog->uhid); + return true; } -static void uhid_destroy(struct bt_hog *hog) +void bt_hog_detach(struct bt_hog *hog, bool force) { - int err; - struct uhid_event ev; - - if (!hog->uhid_created) - return; - - bt_uhid_unregister_all(hog->uhid); - - memset(&ev, 0, sizeof(ev)); - ev.type = UHID_DESTROY; - - err = bt_uhid_send(hog->uhid, &ev); + GSList *l; - if (err < 0) { - error("bt_uhid_send: %s", strerror(-err)); + if (!hog) return; - } - - hog->uhid_created = false; -} - -void bt_hog_detach(struct bt_hog *hog) -{ - GSList *l; if (!hog->attrib) - return; + goto done; queue_foreach(hog->bas, (void *) bt_bas_detach, NULL); for (l = hog->instances; l; l = l->next) { struct bt_hog *instance = l->data; - bt_hog_detach(instance); + bt_hog_detach(instance, force); } for (l = hog->reports; l; l = l->next) { @@ -1860,7 +1795,9 @@ void bt_hog_detach(struct bt_hog *hog) queue_remove_all(hog->gatt_op, cancel_gatt_req, hog, destroy_gatt_req); g_attrib_unref(hog->attrib); hog->attrib = NULL; - uhid_destroy(hog); + +done: + uhid_destroy(hog, force); } int bt_hog_set_control_point(struct bt_hog *hog, bool suspend) diff --git a/profiles/input/hog-lib.h b/profiles/input/hog-lib.h index a79648976e797339b28f3886d70be890b0231514..41e4546427050c82f5be7dda3f4d66acc444d921 100644 --- a/profiles/input/hog-lib.h +++ b/profiles/input/hog-lib.h @@ -12,17 +12,17 @@ struct bt_hog; struct bt_hog *bt_hog_new_default(const char *name, uint16_t vendor, uint16_t product, uint16_t version, - struct gatt_db *db); + uint8_t type, struct gatt_db *db); struct bt_hog *bt_hog_new(int fd, const char *name, uint16_t vendor, uint16_t product, uint16_t version, - struct gatt_db *db); + uint8_t type, struct gatt_db *db); struct bt_hog *bt_hog_ref(struct bt_hog *hog); void bt_hog_unref(struct bt_hog *hog); bool bt_hog_attach(struct bt_hog *hog, void *gatt); -void bt_hog_detach(struct bt_hog *hog); +void bt_hog_detach(struct bt_hog *hog, bool force); int bt_hog_set_control_point(struct bt_hog *hog, bool suspend); int bt_hog_send_report(struct bt_hog *hog, void *data, size_t size, int type); diff --git a/profiles/input/hog.c b/profiles/input/hog.c index d50b823213b56f3c48f186396a9fb33c2a935276..017e320f0781835ddec52ecabb80da3bbb6d4d05 100644 --- a/profiles/input/hog.c +++ b/profiles/input/hog.c @@ -50,6 +50,7 @@ struct hog_device { struct btd_device *device; struct bt_hog *hog; + uint8_t type; }; static gboolean suspend_supported = FALSE; @@ -64,7 +65,7 @@ void input_set_auto_sec(bool state) static void hog_device_accept(struct hog_device *dev, struct gatt_db *db) { char name[248]; - uint16_t vendor, product, version; + uint16_t vendor, product, version, type; if (dev->hog) return; @@ -77,11 +78,12 @@ static void hog_device_accept(struct hog_device *dev, struct gatt_db *db) vendor = btd_device_get_vendor(dev->device); product = btd_device_get_product(dev->device); version = btd_device_get_version(dev->device); + type = bt_uhid_icon_to_type(btd_device_get_icon(dev->device)); DBG("name=%s vendor=0x%X, product=0x%X, version=0x%X", name, vendor, product, version); - dev->hog = bt_hog_new_default(name, vendor, product, version, db); + dev->hog = bt_hog_new_default(name, vendor, product, version, type, db); } static struct hog_device *hog_device_new(struct btd_device *device) @@ -206,7 +208,10 @@ static int hog_disconnect(struct btd_service *service) { struct hog_device *dev = btd_service_get_user_data(service); - bt_hog_detach(dev->hog); + if (input_get_userspace_hid() == UHID_PERSIST) + bt_hog_detach(dev->hog, false); + else + bt_hog_detach(dev->hog, true); btd_service_disconnecting_complete(service, 0); diff --git a/profiles/input/input.conf b/profiles/input/input.conf index 4c70bc561f05429442c6fe0a183584ad1536fa4b..d555d423e43c52272046ec7fcdb421c8453181c4 100644 --- a/profiles/input/input.conf +++ b/profiles/input/input.conf @@ -4,12 +4,17 @@ # particular interface [General] -# Set idle timeout (in minutes) before the connection will -# be disconnect (defaults to 0 for no timeout) -#IdleTimeout=30 +# Set idle timeout (in seconds) before the connection will be disconnect and +# the input device is removed. +# Defaults: 0 (disabled) +#IdleTimeout=0 # Enable HID protocol handling in userspace input profile -# Defaults to false (HIDP handled in HIDP kernel module) +# Possible values: +# - persist: Use UHID in persistent mode (keyboard only) +# - true: Use UHID instead +# - false: User kernel HIDP +# Defaults to true #UserspaceHID=true # Limit HID connections to bonded devices @@ -17,7 +22,7 @@ # platforms may want to make sure that input connections only come from bonded # device connections. Several older mice have been known for not supporting # pairing/encryption. -# Defaults to false to maximize device compatibility. +# Defaults to true for security. #ClassicBondedOnly=true # LE upgrade security diff --git a/profiles/input/manager.c b/profiles/input/manager.c index 92789a003c89a922b796329838441831aabebe0b..d1accc24f8f27d5d07832c46786822f3b9c12810 100644 --- a/profiles/input/manager.c +++ b/profiles/input/manager.c @@ -14,6 +14,7 @@ #include <errno.h> #include <stdbool.h> +#include <stdlib.h> #include "lib/bluetooth.h" #include "lib/sdp.h" @@ -83,22 +84,23 @@ static int input_init(void) config = load_config_file(CONFIGDIR "/input.conf"); if (config) { int idle_timeout; - gboolean uhid_enabled, classic_bonded_only, auto_sec; + gboolean classic_bonded_only, auto_sec; + char *uhid_enabled; idle_timeout = g_key_file_get_integer(config, "General", "IdleTimeout", &err); if (!err) { DBG("input.conf: IdleTimeout=%d", idle_timeout); - input_set_idle_timeout(idle_timeout * 60); + input_set_idle_timeout(idle_timeout); } else g_clear_error(&err); - uhid_enabled = g_key_file_get_boolean(config, "General", + uhid_enabled = g_key_file_get_string(config, "General", "UserspaceHID", &err); if (!err) { - DBG("input.conf: UserspaceHID=%s", uhid_enabled ? - "true" : "false"); - input_enable_userspace_hid(uhid_enabled); + DBG("input.conf: UserspaceHID=%s", uhid_enabled); + input_set_userspace_hid(uhid_enabled); + free(uhid_enabled); } else g_clear_error(&err); diff --git a/profiles/input/suspend-dummy.c b/profiles/input/suspend-dummy.c deleted file mode 100644 index ea1835e0f5d5c876c79bbc3a39449d4297a5c8dd..0000000000000000000000000000000000000000 --- a/profiles/input/suspend-dummy.c +++ /dev/null @@ -1,149 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * - * BlueZ - Bluetooth protocol stack for Linux - * - * Copyright (C) 2012 Nordic Semiconductor Inc. - * Copyright (C) 2012 Instituto Nokia de Tecnologia - INdT - * - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> - -#include <glib.h> - -#include "src/log.h" -#include "suspend.h" - -#define HOG_SUSPEND_FIFO "/tmp/hogsuspend" - -static suspend_event suspend_cb = NULL; -static resume_event resume_cb = NULL; -static guint watch = 0; - -static int fifo_open(void); - -static gboolean read_fifo(GIOChannel *io, GIOCondition cond, gpointer user_data) -{ - char buffer[12]; - gsize offset, left, bread; - GIOStatus iostatus; - - if (cond & (G_IO_ERR | G_IO_HUP)) { - /* - * Both ends needs to be open simultaneously before proceeding - * any input or output operation. When the remote closes the - * channel, hup signal is received on this end. - */ - fifo_open(); - return FALSE; - } - - offset = 0; - left = sizeof(buffer) - 1; - memset(buffer, 0, sizeof(buffer)); - - do { - iostatus = g_io_channel_read_chars(io, &buffer[offset], left, - &bread, NULL); - - offset += bread; - left -= bread; - if (left == 0) - break; - } while (iostatus == G_IO_STATUS_NORMAL); - - if (g_ascii_strncasecmp("suspend", buffer, 7) == 0) - suspend_cb(); - else if (g_ascii_strncasecmp("resume", buffer, 6) == 0) - resume_cb(); - - return TRUE; -} - -static int fifo_open(void) -{ - GIOCondition condition = G_IO_IN | G_IO_ERR | G_IO_HUP; - GIOChannel *fifoio; - int fd; - - fd = open(HOG_SUSPEND_FIFO, O_RDONLY | O_NONBLOCK); - if (fd < 0) { - int err = -errno; - error("Can't open FIFO (%s): %s(%d)", HOG_SUSPEND_FIFO, - strerror(-err), -err); - return err; - } - - fifoio = g_io_channel_unix_new(fd); - g_io_channel_set_close_on_unref(fifoio, TRUE); - - watch = g_io_add_watch(fifoio, condition, read_fifo, NULL); - - g_io_channel_unref(fifoio); - - return 0; -} - -int suspend_init(suspend_event suspend, resume_event resume) -{ - struct stat st; - int ret; - - DBG(""); - - suspend_cb = suspend; - resume_cb = resume; - - if (stat(HOG_SUSPEND_FIFO, &st) == 0) { - if (!S_ISFIFO(st.st_mode)) { - error("Unexpected non-FIFO %s file", HOG_SUSPEND_FIFO); - return -EIO; - } - - if (unlink(HOG_SUSPEND_FIFO) < 0) { - int err = -errno; - error("Failed to remove FIFO (%s): %s (%d)", - HOG_SUSPEND_FIFO, strerror(-err), -err); - return err; - } - } - - if (mkfifo(HOG_SUSPEND_FIFO, 0600) < 0) { - int err = -errno; - - error("Can't create FIFO (%s): %s (%d)", HOG_SUSPEND_FIFO, - strerror(-err), -err); - return err; - } - - DBG("Created suspend-dummy FIFO on %s", HOG_SUSPEND_FIFO); - - ret = fifo_open(); - if (ret < 0) - unlink(HOG_SUSPEND_FIFO); - - return ret; -} - -void suspend_exit(void) -{ - if (watch > 0) { - g_source_remove(watch); - watch = 0; - } - - unlink(HOG_SUSPEND_FIFO); -} diff --git a/profiles/midi/midi.c b/profiles/midi/midi.c index 40064df3aea3c6cdde15e544271e1cc87cf70bd9..bab309bca7c3341677cf48e0f9be364edecfd0e1 100644 --- a/profiles/midi/midi.c +++ b/profiles/midi/midi.c @@ -53,20 +53,21 @@ struct midi { struct midi_write_parser midi_out; }; +static void foreach_cb(const struct midi_write_parser *parser, void *user_data) +{ + struct midi *midi = user_data; + + bt_gatt_client_write_without_response(midi->client, + midi->midi_io_handle, false, + midi_write_data(parser), + midi_write_data_size(parser)); +} + static bool midi_write_cb(struct io *io, void *user_data) { struct midi *midi = user_data; int err; - void foreach_cb(const struct midi_write_parser *parser, void *user_data) { - struct midi *midi = user_data; - bt_gatt_client_write_without_response(midi->client, - midi->midi_io_handle, - false, - midi_write_data(parser), - midi_write_data_size(parser)); - }; - do { snd_seq_event_t *event = NULL; @@ -81,10 +82,10 @@ static bool midi_write_cb(struct io *io, void *user_data) if (midi_write_has_data(&midi->midi_out)) bt_gatt_client_write_without_response(midi->client, - midi->midi_io_handle, - false, - midi_write_data(&midi->midi_out), - midi_write_data_size(&midi->midi_out)); + midi->midi_io_handle, + false, + midi_write_data(&midi->midi_out), + midi_write_data_size(&midi->midi_out)); midi_write_reset(&midi->midi_out); diff --git a/src/adapter.c b/src/adapter.c index 8fb2acdc8aa1b43c9f3f0b7c68d963616021ed69..2bb94cf1673e85710abf1e619fdeee9c9fa0f087 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -24,6 +24,7 @@ #include <sys/file.h> #include <sys/stat.h> #include <dirent.h> +#include <limits.h> #include <glib.h> #include <dbus/dbus.h> @@ -170,6 +171,7 @@ static GSList *conn_fail_list = NULL; struct link_key_info { bdaddr_t bdaddr; + uint8_t bdaddr_type; unsigned char key[16]; uint8_t type; uint8_t pin_len; @@ -239,6 +241,11 @@ struct btd_adapter_pin_cb_iter { /* When the iterator reaches the end, it is NULL and attempt is 0 */ }; +struct exp_pending { + struct btd_adapter *adapter; + unsigned int id; +}; + enum { ADAPTER_POWER_STATE_OFF, ADAPTER_POWER_STATE_ON, @@ -255,6 +262,7 @@ struct btd_adapter { bdaddr_t bdaddr; /* controller Bluetooth address */ uint8_t bdaddr_type; /* address type */ + uint8_t version; /* controller core spec version */ uint32_t dev_class; /* controller class of device */ char *name; /* controller device name */ char *short_name; /* controller short name */ @@ -331,6 +339,7 @@ struct btd_adapter { bool is_default; /* true if adapter is default one */ + struct queue *exp_pending; struct queue *exps; }; @@ -1340,6 +1349,10 @@ int adapter_service_add(struct btd_adapter *adapter, sdp_record_t *rec) void adapter_service_remove(struct btd_adapter *adapter, uint32_t handle) { sdp_record_t *rec; + + if (!adapter) + return; + /* * If the controller does not support BR/EDR operation, * there is no point in trying to remote SDP records. @@ -1407,8 +1420,6 @@ static void adapter_remove_device(struct btd_adapter *adapter, void btd_adapter_remove_device(struct btd_adapter *adapter, struct btd_device *dev) { - GList *l; - adapter->connect_list = g_slist_remove(adapter->connect_list, dev); adapter_remove_device(adapter, dev); @@ -1422,22 +1433,7 @@ void btd_adapter_remove_device(struct btd_adapter *adapter, if (adapter->connect_le == dev) adapter->connect_le = NULL; - l = adapter->auths->head; - while (l != NULL) { - struct service_auth *auth = l->data; - GList *next = g_list_next(l); - - if (auth->device != dev) { - l = next; - continue; - } - - g_queue_delete_link(adapter->auths, l); - l = next; - - service_auth_cancel(auth); - } - + btd_adapter_cancel_service_auth(adapter, dev); device_remove(dev, TRUE); } @@ -1721,7 +1717,8 @@ static void discovery_cleanup(struct btd_adapter *adapter, int timeout) next = g_slist_next(l); - if (device_is_temporary(dev) && !device_is_connectable(dev)) + if (device_is_temporary(dev) && !device_is_connectable(dev) + && !btd_device_is_connected(dev)) btd_adapter_remove_device(adapter, dev); } } @@ -2192,6 +2189,7 @@ static int merge_discovery_filters(struct btd_adapter *adapter, int *rssi, bool empty_uuid = false; bool has_regular_discovery = false; bool has_filtered_discovery = false; + uint8_t adapter_scan_type = get_scan_type(adapter); for (l = adapter->discovery_list; l != NULL; l = g_slist_next(l)) { struct discovery_client *client = l->data; @@ -2202,6 +2200,20 @@ static int merge_discovery_filters(struct btd_adapter *adapter, int *rssi, continue; } + /* + * Detect empty filter with only discoverable + * (which does not require a kernel filter) set. + */ + if (item->uuids == NULL && + item->pathloss == DISTANCE_VAL_INVALID && + item->rssi == DISTANCE_VAL_INVALID && + item->type == adapter_scan_type && + item->duplicate == false && + item->pattern == NULL) { + has_regular_discovery = true; + continue; + } + has_filtered_discovery = true; *transport |= item->type; @@ -2251,7 +2263,7 @@ static int merge_discovery_filters(struct btd_adapter *adapter, int *rssi, * It there is both regular and filtered scan running, then * clear whole fitler to report all devices. */ - *transport = get_scan_type(adapter); + *transport = adapter_scan_type; *rssi = HCI_RSSI_INVALID; g_slist_free(*uuids); *uuids = NULL; @@ -2382,7 +2394,7 @@ static int update_discovery_filter(struct btd_adapter *adapter) * starting discovery. */ if (filters_equal(adapter->current_discovery_filter, sd_cp) && - adapter->discovering != 0) { + adapter->discovering != false) { DBG("filters were equal, deciding to not restart the scan."); g_free(sd_cp); return 0; @@ -2624,10 +2636,13 @@ static bool parse_transport(DBusMessageIter *value, static bool parse_duplicate_data(DBusMessageIter *value, struct discovery_filter *filter) { + dbus_bool_t duplicate = false; + if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN) return false; - dbus_message_iter_get_basic(value, &filter->duplicate); + dbus_message_iter_get_basic(value, &duplicate); + filter->duplicate = duplicate; return true; } @@ -2635,10 +2650,13 @@ static bool parse_duplicate_data(DBusMessageIter *value, static bool parse_discoverable(DBusMessageIter *value, struct discovery_filter *filter) { + dbus_bool_t discoverable = false; + if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN) return false; - dbus_message_iter_get_basic(value, &filter->discoverable); + dbus_message_iter_get_basic(value, &discoverable); + filter->discoverable = discoverable; return true; } @@ -3146,6 +3164,11 @@ static void property_set_mode(struct btd_adapter *adapter, uint32_t setting, param = &mode; len = sizeof(mode); break; + case MGMT_SETTING_CONNECTABLE: + opcode = MGMT_OP_SET_CONNECTABLE; + param = &mode; + len = sizeof(mode); + break; default: goto failed; } @@ -3519,6 +3542,47 @@ static gboolean property_experimental_exists(const GDBusPropertyTable *property, return !queue_isempty(adapter->exps); } +static gboolean property_get_manufacturer(const GDBusPropertyTable *property, + DBusMessageIter *iter, + void *user_data) +{ + struct btd_adapter *adapter = user_data; + dbus_uint16_t val = adapter->manufacturer; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &val); + + return TRUE; +} + +static gboolean property_get_version(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *user_data) +{ + struct btd_adapter *adapter = user_data; + uint8_t val = adapter->version; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE, &val); + + return TRUE; +} + +static gboolean property_get_connectable(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *user_data) +{ + struct btd_adapter *adapter = user_data; + + return property_get_mode(adapter, MGMT_SETTING_CONNECTABLE, iter); +} + +static void property_set_connectable(const GDBusPropertyTable *property, + DBusMessageIter *iter, + GDBusPendingPropertySet id, + void *user_data) +{ + struct btd_adapter *adapter = user_data; + + property_set_mode(adapter, MGMT_SETTING_CONNECTABLE, iter, id); +} + static DBusMessage *remove_device(DBusConnection *conn, DBusMessage *msg, void *user_data) { @@ -3748,9 +3812,6 @@ static DBusMessage *connect_device(DBusConnection *conn, if (!bacmp(&addr, BDADDR_ANY)) return btd_error_invalid_args(msg); - if (btd_adapter_find_device(adapter, &addr, addr_type)) - return btd_error_already_exists(msg); - device_connect(adapter, &addr, addr_type, msg); return NULL; } @@ -3863,9 +3924,10 @@ static const GDBusPropertyTable adapter_properties[] = { { "Name", "s", property_get_name }, { "Alias", "s", property_get_alias, property_set_alias }, { "Class", "u", property_get_class }, + { "Connectable", "b", property_get_connectable, + property_set_connectable }, { "Powered", "b", property_get_powered, property_set_powered }, - { "PowerState", "s", property_get_power_state, NULL, NULL, - G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { "PowerState", "s", property_get_power_state }, { "Discoverable", "b", property_get_discoverable, property_set_discoverable }, { "DiscoverableTimeout", "u", property_get_discoverable_timeout, @@ -3880,6 +3942,8 @@ static const GDBusPropertyTable adapter_properties[] = { { "Roles", "as", property_get_roles }, { "ExperimentalFeatures", "as", property_get_experimental, NULL, property_experimental_exists }, + { "Manufacturer", "q", property_get_manufacturer }, + { "Version", "y", property_get_version }, { } }; @@ -3914,7 +3978,9 @@ static bool is_blocked_key(uint8_t key_type, uint8_t *key_value) return false; } -static struct link_key_info *get_key_info(GKeyFile *key_file, const char *peer) +static struct link_key_info *get_key_info(GKeyFile *key_file, const char *peer, + uint8_t bdaddr_type) + { struct link_key_info *info = NULL; char *str; @@ -3926,6 +3992,7 @@ static struct link_key_info *get_key_info(GKeyFile *key_file, const char *peer) info = g_new0(struct link_key_info, 1); str2ba(peer, &info->bdaddr); + info->bdaddr_type = bdaddr_type; if (!strncmp(str, "0x", 2)) str2buf(&str[2], info->key, sizeof(info->key)); @@ -4133,6 +4200,7 @@ static int generate_and_write_irk(uint8_t *irk, GKeyFile *key_file, g_key_file_set_string(key_file, "General", "IdentityResolvingKey", str_irk_out); + create_file(filename, S_IRUSR | S_IWUSR); str = g_key_file_to_data(key_file, &length, NULL); if (!g_file_set_contents(filename, str, length, &gerr)) { error("Unable set contents for %s: (%s)", filename, @@ -4292,7 +4360,7 @@ static void load_link_keys(struct btd_adapter *adapter, GSList *keys, struct link_key_info *info = l->data; bacpy(&key->addr.bdaddr, &info->bdaddr); - key->addr.type = BDADDR_BREDR; + key->addr.type = info->bdaddr_type; key->type = info->type; memcpy(key->val, info->key, 16); key->pin_len = info->pin_len; @@ -4387,8 +4455,8 @@ static void load_ltks(struct btd_adapter *adapter, GSList *keys) if (dev) { device_set_paired(dev, info->bdaddr_type); device_set_bonded(dev, info->bdaddr_type); - device_set_ltk_enc_size(dev, info->enc_size); - device_set_ltk_enc_size(dev, info->enc_size); + device_set_ltk(dev, info->val, info->central, + info->enc_size); } } @@ -4547,14 +4615,42 @@ static void load_conn_params(struct btd_adapter *adapter, GSList *params) btd_error(adapter->dev_id, "Load connection parameters failed"); } -static uint8_t get_le_addr_type(GKeyFile *keyfile) +void btd_adapter_load_conn_param(struct btd_adapter *adapter, + const bdaddr_t *peer, uint8_t bdaddr_type, + uint16_t min_interval, uint16_t max_interval, + uint16_t latency, uint16_t timeout) +{ + GSList *params = NULL; + struct conn_param param; + + /* Only versions >= 1.23 support updating connection parameters */ + if (MGMT_VERSION(mgmt_version, mgmt_revision) < MGMT_VERSION(1, 23)) + return; + + bacpy(¶m.bdaddr, peer); + param.bdaddr_type = bdaddr_type; + param.max_interval = max_interval; + param.min_interval = min_interval; + param.latency = latency; + param.timeout = timeout; + + params = g_slist_append(params, ¶m); + load_conn_params(adapter, params); + g_slist_free(params); +} + +static uint8_t get_addr_type(GKeyFile *keyfile) { uint8_t addr_type; char *type; + /* The AddressType is written to file only When dev->le is + * set to true, as referenced in the update_technologies(). + * Therefore, When type is NULL, it default to BDADDR_BREDR. + */ type = g_key_file_get_string(keyfile, "General", "AddressType", NULL); if (!type) - return BDADDR_LE_PUBLIC; + return BDADDR_BREDR; if (g_str_equal(type, "public")) addr_type = BDADDR_LE_PUBLIC; @@ -4863,9 +4959,9 @@ static void load_devices(struct btd_adapter *adapter) g_clear_error(&gerr); } - key_info = get_key_info(key_file, entry->d_name); + bdaddr_type = get_addr_type(key_file); - bdaddr_type = get_le_addr_type(key_file); + key_info = get_key_info(key_file, entry->d_name, bdaddr_type); ltk_info = get_ltk_info(key_file, entry->d_name, bdaddr_type); @@ -4904,11 +5000,27 @@ static void load_devices(struct btd_adapter *adapter) goto free; } - if (key_info) + if (key_info) { + /* Fix up address type if it was stored with the wrong + * address type since Load Link Keys are only meant to + * work with BR/EDR addresses as per MGMT documentation. + */ + if (key_info->bdaddr_type != BDADDR_BREDR) + key_info->bdaddr_type = BDADDR_BREDR; + keys = g_slist_append(keys, key_info); + } + + if (ltk_info) { + /* Fix up address type if it was stored with the wrong + * address type since Load Long Term Keys are only meant + * to work with LE addresses as per MGMT documentation. + */ + if (ltk_info->bdaddr_type == BDADDR_BREDR) + ltk_info->bdaddr_type = BDADDR_LE_PUBLIC; - if (ltk_info) ltks = g_slist_append(ltks, ltk_info); + } if (peripheral_ltk_info) ltks = g_slist_append(ltks, peripheral_ltk_info); @@ -5144,9 +5256,10 @@ static void adapter_remove_device(struct btd_adapter *adapter, static void adapter_add_connection(struct btd_adapter *adapter, struct btd_device *device, - uint8_t bdaddr_type) + uint8_t bdaddr_type, + uint32_t flags) { - device_add_connection(device, bdaddr_type); + device_add_connection(device, bdaddr_type, flags); if (g_slist_find(adapter->connections, device)) { btd_error(adapter->dev_id, @@ -5199,7 +5312,7 @@ static void get_connections_complete(uint8_t status, uint16_t length, device = btd_adapter_get_device(adapter, &addr->bdaddr, addr->type); if (device) - adapter_add_connection(adapter, device, addr->type); + adapter_add_connection(adapter, device, addr->type, 0); } } @@ -5455,6 +5568,7 @@ void adapter_accept_list_remove(struct btd_adapter *adapter, static void set_device_privacy_complete(uint8_t status, uint16_t length, const void *param, void *user_data) { + struct btd_device *dev = user_data; const struct mgmt_rp_set_device_flags *rp = param; if (status != MGMT_STATUS_SUCCESS) { @@ -5467,6 +5581,9 @@ static void set_device_privacy_complete(uint8_t status, uint16_t length, error("Too small Set Device Flags complete event: %d", length); return; } + + btd_device_flags_changed(dev, btd_device_get_supported_flags(dev), + btd_device_get_pending_flags(dev)); } static void add_device_complete(uint8_t status, uint16_t length, @@ -5512,7 +5629,7 @@ static void add_device_complete(uint8_t status, uint16_t length, adapter_set_device_flags(adapter, dev, flags | DEVICE_FLAG_DEVICE_PRIVACY, set_device_privacy_complete, - NULL); + dev); } } } @@ -5562,6 +5679,7 @@ void adapter_set_device_flags(struct btd_adapter *adapter, { struct mgmt_cp_set_device_flags cp; uint32_t supported = btd_device_get_supported_flags(device); + uint32_t pending = btd_device_get_pending_flags(device); const bdaddr_t *bdaddr; uint8_t bdaddr_type; @@ -5569,6 +5687,14 @@ void adapter_set_device_flags(struct btd_adapter *adapter, (supported | flags) != supported) return; + /* Check if changing flags are pending */ + if (flags == (flags & pending)) + return; + + /* Set Device Privacy Mode if it has not set the flag yet. */ + if (btd_opts.device_privacy && !(flags & DEVICE_FLAG_DEVICE_PRIVACY)) + flags |= DEVICE_FLAG_DEVICE_PRIVACY & supported & ~pending; + bdaddr = device_get_address(device); bdaddr_type = btd_device_get_bdaddr_type(device); @@ -5577,8 +5703,9 @@ void adapter_set_device_flags(struct btd_adapter *adapter, cp.addr.type = bdaddr_type; cp.current_flags = cpu_to_le32(flags); - mgmt_send(adapter->mgmt, MGMT_OP_SET_DEVICE_FLAGS, adapter->dev_id, - sizeof(cp), &cp, func, user_data, NULL); + if (mgmt_send(adapter->mgmt, MGMT_OP_SET_DEVICE_FLAGS, adapter->dev_id, + sizeof(cp), &cp, func, user_data, NULL)) + btd_device_set_pending_flags(device, flags); } static void device_flags_changed_callback(uint16_t index, uint16_t length, @@ -5741,6 +5868,16 @@ static void remove_discovery_list(struct btd_adapter *adapter) adapter->discovery_list = NULL; } +static void cancel_exp_pending(void *data) +{ + struct exp_pending *pending = data; + struct btd_adapter *adapter = pending->adapter; + + pending->adapter = NULL; + mgmt_cancel(adapter->mgmt, pending->id); + g_free(pending); +} + static void adapter_free(gpointer user_data) { struct btd_adapter *adapter = user_data; @@ -5769,6 +5906,8 @@ static void adapter_free(gpointer user_data) g_queue_free(adapter->auths); queue_destroy(adapter->exps, NULL); + queue_destroy(adapter->exp_pending, cancel_exp_pending); + /* * Unregister all handlers for this specific index since * the adapter bound to them is no longer valid. @@ -6835,6 +6974,7 @@ static struct btd_adapter *btd_adapter_new(uint16_t index) adapter->auths = g_queue_new(); adapter->exps = queue_new(); + adapter->exp_pending = queue_new(); return btd_adapter_ref(adapter); } @@ -6882,6 +7022,8 @@ static void adapter_remove(struct btd_adapter *adapter) g_slist_free(adapter->msd_callbacks); adapter->msd_callbacks = NULL; + + queue_remove_all(adapter->exp_pending, NULL, NULL, cancel_exp_pending); } const char *adapter_get_path(struct btd_adapter *adapter) @@ -7073,12 +7215,10 @@ static bool device_is_discoverable(struct btd_adapter *adapter, return discoverable; } -void btd_adapter_update_found_device(struct btd_adapter *adapter, +void btd_adapter_device_found(struct btd_adapter *adapter, const bdaddr_t *bdaddr, uint8_t bdaddr_type, int8_t rssi, - bool confirm, bool legacy, - bool not_connectable, - bool name_resolve_failed, + uint32_t flags, const uint8_t *data, uint8_t data_len, bool monitoring) { @@ -7087,9 +7227,20 @@ void btd_adapter_update_found_device(struct btd_adapter *adapter, struct eir_data eir_data; bool name_known, discoverable; char addr[18]; + bool confirm; + bool legacy; + bool not_connectable; + bool name_resolve_failed; + bool scan_rsp; bool duplicate = false; struct queue *matched_monitors = NULL; + confirm = (flags & MGMT_DEV_FOUND_CONFIRM_NAME); + legacy = (flags & MGMT_DEV_FOUND_LEGACY_PAIRING); + not_connectable = (flags & MGMT_DEV_FOUND_NOT_CONNECTABLE); + name_resolve_failed = (flags & MGMT_DEV_FOUND_NAME_REQUEST_FAILED); + scan_rsp = (flags & MGMT_DEV_FOUND_SCAN_RSP); + if (!btd_adv_monitor_offload_enabled(adapter->adv_monitor_manager) || (MGMT_VERSION(mgmt_version, mgmt_revision) < MGMT_VERSION(1, 22))) { @@ -7122,7 +7273,23 @@ void btd_adapter_update_found_device(struct btd_adapter *adapter, dev = btd_adapter_find_device(adapter, bdaddr, bdaddr_type); if (!dev) { - if (!discoverable && !monitoring) { + /* In case of being just a scan response don't attempt to create + * the device. + */ + if (scan_rsp) { + eir_data_free(&eir_data); + return; + } + + /* Monitor Devices advertising Broadcast Announcements if the + * adapter is capable of synchronizing to it. + */ + if (eir_get_service_data(&eir_data, BCAA_SERVICE_UUID) && + btd_adapter_has_settings(adapter, + MGMT_SETTING_ISO_SYNC_RECEIVER)) + monitoring = true; + + if (!discoverable && !monitoring && not_connectable) { eir_data_free(&eir_data); return; } @@ -7169,7 +7336,7 @@ void btd_adapter_update_found_device(struct btd_adapter *adapter, /* If there is no matched Adv monitors, don't continue if not * discoverable or if active discovery filter don't match. */ - if (!monitoring && (!discoverable || + if (!eir_data.rsi && !monitoring && (!discoverable || (adapter->filtered_discovery && !is_filter_match( adapter->discovery_list, &eir_data, rssi)))) { eir_data_free(&eir_data); @@ -7302,10 +7469,6 @@ static void device_found_callback(uint16_t index, uint16_t length, const uint8_t *eir; uint16_t eir_len; uint32_t flags; - bool confirm_name; - bool legacy; - bool not_connectable; - bool name_resolve_failed; char addr[18]; if (length < sizeof(*ev)) { @@ -7327,22 +7490,15 @@ static void device_found_callback(uint16_t index, uint16_t length, else eir = ev->eir; - flags = btohl(ev->flags); + flags = le32_to_cpu(ev->flags); ba2str(&ev->addr.bdaddr, addr); DBG("hci%u addr %s, rssi %d flags 0x%04x eir_len %u", index, addr, ev->rssi, flags, eir_len); - confirm_name = (flags & MGMT_DEV_FOUND_CONFIRM_NAME); - legacy = (flags & MGMT_DEV_FOUND_LEGACY_PAIRING); - not_connectable = (flags & MGMT_DEV_FOUND_NOT_CONNECTABLE); - name_resolve_failed = (flags & MGMT_DEV_FOUND_NAME_REQUEST_FAILED); - - btd_adapter_update_found_device(adapter, &ev->addr.bdaddr, - ev->addr.type, ev->rssi, confirm_name, - legacy, not_connectable, - name_resolve_failed, eir, eir_len, - false); + btd_adapter_device_found(adapter, &ev->addr.bdaddr, + ev->addr.type, ev->rssi, flags, + eir, eir_len, false); } struct agent *adapter_get_agent(struct btd_adapter *adapter) @@ -7365,11 +7521,10 @@ static void adapter_remove_connection(struct btd_adapter *adapter, device_remove_connection(device, bdaddr_type, &remove_device); - if (device_is_authenticating(device)) - device_cancel_authentication(device, TRUE); + device_cancel_authentication(device, TRUE); /* If another bearer is still connected */ - if (btd_device_is_connected(device)) + if (btd_device_bearer_is_connected(device)) return; adapter->connections = g_slist_remove(adapter->connections, device); @@ -7432,6 +7587,12 @@ static void adapter_stop(struct btd_adapter *adapter) int btd_register_adapter_driver(struct btd_adapter_driver *driver) { + if (driver->experimental && !(g_dbus_get_flags() & + G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) { + DBG("D-Bus experimental not enabled"); + return -ENOTSUP; + } + adapter_drivers = g_slist_append(adapter_drivers, driver); if (driver->probe == NULL) @@ -8657,80 +8818,11 @@ static void new_long_term_key_callback(uint16_t index, uint16_t length, device_set_bonded(device, addr->type); } - device_set_ltk_enc_size(device, ev->key.enc_size); + device_set_ltk(device, ev->key.val, ev->key.central, ev->key.enc_size); bonding_complete(adapter, &addr->bdaddr, addr->type, 0); } -static void store_csrk(struct btd_adapter *adapter, const bdaddr_t *peer, - uint8_t bdaddr_type, const unsigned char *key, - uint32_t counter, uint8_t type) -{ - const char *group; - char device_addr[18]; - char filename[PATH_MAX]; - GKeyFile *key_file; - GError *gerr = NULL; - char key_str[33]; - gsize length = 0; - gboolean auth; - char *str; - int i; - - switch (type) { - case 0x00: - group = "LocalSignatureKey"; - auth = FALSE; - break; - case 0x01: - group = "RemoteSignatureKey"; - auth = FALSE; - break; - case 0x02: - group = "LocalSignatureKey"; - auth = TRUE; - break; - case 0x03: - group = "RemoteSignatureKey"; - auth = TRUE; - break; - default: - warn("Unsupported CSRK type %u", type); - return; - } - - ba2str(peer, device_addr); - - create_filename(filename, PATH_MAX, "/%s/%s/info", - btd_adapter_get_storage_dir(adapter), device_addr); - - key_file = g_key_file_new(); - if (!g_key_file_load_from_file(key_file, filename, 0, &gerr)) { - error("Unable to load key file from %s: (%s)", filename, - gerr->message); - g_clear_error(&gerr); - } - - for (i = 0; i < 16; i++) - sprintf(key_str + (i * 2), "%2.2X", key[i]); - - g_key_file_set_string(key_file, group, "Key", key_str); - g_key_file_set_integer(key_file, group, "Counter", counter); - g_key_file_set_boolean(key_file, group, "Authenticated", auth); - - create_file(filename, 0600); - - str = g_key_file_to_data(key_file, &length, NULL); - if (!g_file_set_contents(filename, str, length, &gerr)) { - error("Unable set contents for %s: (%s)", filename, - gerr->message); - g_error_free(gerr); - } - g_free(str); - - g_key_file_free(key_file); -} - static void new_csrk_callback(uint16_t index, uint16_t length, const void *param, void *user_data) { @@ -8758,13 +8850,7 @@ static void new_csrk_callback(uint16_t index, uint16_t length, return; } - if (!ev->store_hint) - return; - - store_csrk(adapter, &key->addr.bdaddr, key->addr.type, key->val, 0, - key->type); - - btd_device_set_temporary(device, false); + device_set_csrk(device, key->val, 0, key->type, ev->store_hint); } static void store_irk(struct btd_adapter *adapter, const bdaddr_t *peer, @@ -8864,10 +8950,10 @@ static void new_irk_callback(uint16_t index, uint16_t length, btd_device_set_temporary(device, false); } -static void store_conn_param(struct btd_adapter *adapter, const bdaddr_t *peer, - uint8_t bdaddr_type, uint16_t min_interval, - uint16_t max_interval, uint16_t latency, - uint16_t timeout) +void btd_adapter_store_conn_param(struct btd_adapter *adapter, + const bdaddr_t *peer, uint8_t bdaddr_type, + uint16_t min_interval, uint16_t max_interval, + uint16_t latency, uint16_t timeout) { char device_addr[18]; char filename[PATH_MAX]; @@ -8947,7 +9033,7 @@ static void new_conn_param(uint16_t index, uint16_t length, if (!ev->store_hint) return; - store_conn_param(adapter, &ev->addr.bdaddr, ev->addr.type, + btd_adapter_store_conn_param(adapter, &ev->addr.bdaddr, ev->addr.type, ev->min_interval, ev->max_interval, ev->latency, ev->timeout); } @@ -9205,10 +9291,8 @@ static int adapter_register(struct btd_adapter *adapter) agent_unref(agent); } - if (g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL) { - adapter->battery_provider_manager = - btd_battery_provider_manager_create(adapter); - } + adapter->battery_provider_manager = + btd_battery_provider_manager_create(adapter); /* Don't start GATT database and advertising managers on * non-LE controllers. @@ -9372,7 +9456,8 @@ static void connected_callback(uint16_t index, uint16_t length, if (eir_data.class != 0) device_set_class(device, eir_data.class); - adapter_add_connection(adapter, device, ev->addr.type); + adapter_add_connection(adapter, device, ev->addr.type, + le32_to_cpu(ev->flags)); name_known = device_name_known(device); @@ -9791,10 +9876,38 @@ static bool set_blocked_keys(struct btd_adapter *adapter) .func = _func, \ } +static void exp_complete(void *user_data); + +static bool exp_mgmt_send(struct btd_adapter *adapter, uint16_t opcode, + uint16_t index, uint16_t length, const void *param, + mgmt_request_func_t callback) +{ + struct exp_pending *pending; + + pending = g_new0(struct exp_pending, 1); + pending->adapter = adapter; + + if (!queue_push_tail(adapter->exp_pending, pending)) { + g_free(pending); + return false; + } + + pending->id = mgmt_send(adapter->mgmt, opcode, index, length, param, + callback, pending, exp_complete); + if (!pending->id) { + queue_remove(adapter->exp_pending, pending); + g_free(pending); + return false; + } + + return true; +} + static void set_exp_debug_complete(uint8_t status, uint16_t len, const void *param, void *user_data) { - struct btd_adapter *adapter = user_data; + struct exp_pending *pending = user_data; + struct btd_adapter *adapter = pending->adapter; uint8_t action; if (status != 0) { @@ -9819,9 +9932,9 @@ static void exp_debug_func(struct btd_adapter *adapter, uint8_t action) memcpy(cp.uuid, debug_uuid.val, 16); cp.action = action; - if (mgmt_send(adapter->mgmt, MGMT_OP_SET_EXP_FEATURE, + if (exp_mgmt_send(adapter, MGMT_OP_SET_EXP_FEATURE, adapter->dev_id, sizeof(cp), &cp, - set_exp_debug_complete, adapter, NULL) > 0) + set_exp_debug_complete)) return; btd_error(adapter->dev_id, "Failed to set exp debug"); @@ -9844,7 +9957,8 @@ static void quality_report_func(struct btd_adapter *adapter, uint8_t action) static void set_rpa_resolution_complete(uint8_t status, uint16_t len, const void *param, void *user_data) { - struct btd_adapter *adapter = user_data; + struct exp_pending *pending = user_data; + struct btd_adapter *adapter = pending->adapter; uint8_t action; if (status != 0) { @@ -9869,9 +9983,9 @@ static void rpa_resolution_func(struct btd_adapter *adapter, uint8_t action) memcpy(cp.uuid, rpa_resolution_uuid.val, 16); cp.action = action; - if (mgmt_send(adapter->mgmt, MGMT_OP_SET_EXP_FEATURE, + if (exp_mgmt_send(adapter, MGMT_OP_SET_EXP_FEATURE, adapter->dev_id, sizeof(cp), &cp, - set_rpa_resolution_complete, adapter, NULL) > 0) + set_rpa_resolution_complete)) return; btd_error(adapter->dev_id, "Failed to set RPA Resolution"); @@ -9880,7 +9994,8 @@ static void rpa_resolution_func(struct btd_adapter *adapter, uint8_t action) static void codec_offload_complete(uint8_t status, uint16_t len, const void *param, void *user_data) { - struct btd_adapter *adapter = user_data; + struct exp_pending *pending = user_data; + struct btd_adapter *adapter = pending->adapter; uint8_t action; if (status != 0) { @@ -9905,9 +10020,9 @@ static void codec_offload_func(struct btd_adapter *adapter, uint8_t action) memcpy(cp.uuid, codec_offload_uuid.val, 16); cp.action = action; - if (mgmt_send(adapter->mgmt, MGMT_OP_SET_EXP_FEATURE, + if (exp_mgmt_send(adapter, MGMT_OP_SET_EXP_FEATURE, adapter->dev_id, sizeof(cp), &cp, - codec_offload_complete, adapter, NULL) > 0) + codec_offload_complete)) return; btd_error(adapter->dev_id, "Failed to set Codec Offload"); @@ -9916,7 +10031,8 @@ static void codec_offload_func(struct btd_adapter *adapter, uint8_t action) static void iso_socket_complete(uint8_t status, uint16_t len, const void *param, void *user_data) { - struct btd_adapter *adapter = user_data; + struct exp_pending *pending = user_data; + struct btd_adapter *adapter = pending->adapter; uint8_t action; if (status != 0) { @@ -9941,9 +10057,9 @@ static void iso_socket_func(struct btd_adapter *adapter, uint8_t action) memcpy(cp.uuid, iso_socket_uuid.val, 16); cp.action = action; - if (mgmt_send(adapter->mgmt, MGMT_OP_SET_EXP_FEATURE, + if (exp_mgmt_send(adapter, MGMT_OP_SET_EXP_FEATURE, MGMT_INDEX_NONE, sizeof(cp), &cp, - iso_socket_complete, adapter, NULL) > 0) + iso_socket_complete)) return; btd_error(adapter->dev_id, "Failed to set ISO Socket"); @@ -9968,7 +10084,8 @@ static const struct exp_feat { static void read_exp_features_complete(uint8_t status, uint16_t length, const void *param, void *user_data) { - struct btd_adapter *adapter = user_data; + struct exp_pending *pending = user_data; + struct btd_adapter *adapter = pending->adapter; const struct mgmt_rp_read_exp_features_info *rp = param; size_t feature_count = 0; size_t i = 0; @@ -10028,9 +10145,8 @@ static void read_exp_features_complete(uint8_t status, uint16_t length, static void read_exp_features(struct btd_adapter *adapter) { - if (mgmt_send(adapter->mgmt, MGMT_OP_READ_EXP_FEATURES_INFO, - adapter->dev_id, 0, NULL, read_exp_features_complete, - adapter, NULL) > 0) + if (exp_mgmt_send(adapter, MGMT_OP_READ_EXP_FEATURES_INFO, + adapter->dev_id, 0, NULL, read_exp_features_complete)) return; btd_error(adapter->dev_id, "Failed to read exp features info"); @@ -10077,6 +10193,8 @@ static void read_info_complete(uint8_t status, uint16_t length, adapter->supported_settings = btohl(rp->supported_settings); adapter->current_settings = btohl(rp->current_settings); + adapter->version = rp->version; + clear_uuids(adapter); clear_devices(adapter); @@ -10110,12 +10228,12 @@ static void read_info_complete(uint8_t status, uint16_t length, switch (btd_opts.mode) { case BT_MODE_DUAL: - if (missing_settings & MGMT_SETTING_SSP) - set_mode(adapter, MGMT_OP_SET_SSP, 0x01); if (missing_settings & MGMT_SETTING_LE) set_mode(adapter, MGMT_OP_SET_LE, 0x01); if (missing_settings & MGMT_SETTING_BREDR) set_mode(adapter, MGMT_OP_SET_BREDR, 0x01); + if (missing_settings & MGMT_SETTING_SSP) + set_mode(adapter, MGMT_OP_SET_SSP, 0x01); break; case BT_MODE_BREDR: if (!(adapter->supported_settings & MGMT_SETTING_BREDR)) { @@ -10124,10 +10242,10 @@ static void read_info_complete(uint8_t status, uint16_t length, goto failed; } - if (missing_settings & MGMT_SETTING_SSP) - set_mode(adapter, MGMT_OP_SET_SSP, 0x01); if (missing_settings & MGMT_SETTING_BREDR) set_mode(adapter, MGMT_OP_SET_BREDR, 0x01); + if (missing_settings & MGMT_SETTING_SSP) + set_mode(adapter, MGMT_OP_SET_SSP, 0x01); if (adapter->current_settings & MGMT_SETTING_LE) set_mode(adapter, MGMT_OP_SET_LE, 0x00); break; @@ -10146,7 +10264,11 @@ static void read_info_complete(uint8_t status, uint16_t length, } if (missing_settings & MGMT_SETTING_SECURE_CONN) - set_mode(adapter, MGMT_OP_SET_SECURE_CONN, 0x01); + set_mode(adapter, MGMT_OP_SET_SECURE_CONN, + btd_opts.secure_conn); + + if (missing_settings & MGMT_SETTING_WIDEBAND_SPEECH) + set_mode(adapter, MGMT_OP_SET_WIDEBAND_SPEECH, 0x01); if (adapter->supported_settings & MGMT_SETTING_PRIVACY) set_privacy(adapter, btd_opts.privacy); @@ -10355,6 +10477,43 @@ static void reset_adv_monitors(uint16_t index) error("Failed to reset Adv Monitors"); } +static void read_info(struct btd_adapter *adapter) +{ + DBG("sending read info command for index %u", adapter->dev_id); + + if (mgmt_send(mgmt_primary, MGMT_OP_READ_INFO, adapter->dev_id, 0, NULL, + read_info_complete, adapter, NULL) > 0) + return; + + btd_error(adapter->dev_id, + "Failed to read controller info for index %u", + adapter->dev_id); + + adapter_list = g_list_remove(adapter_list, adapter); + + btd_adapter_unref(adapter); +} + +static void exp_complete(void *user_data) +{ + struct exp_pending *pending = user_data; + struct btd_adapter *adapter = pending->adapter; + + if (!adapter) + return; /* canceled */ + + queue_remove(adapter->exp_pending, pending); + g_free(pending); + + if (queue_isempty(adapter->exp_pending)) { + read_info(adapter); + return; + } + + DBG("index %u has %u pending MGMT EXP requests", adapter->dev_id, + queue_length(adapter->exp_pending)); +} + static void index_added(uint16_t index, uint16_t length, const void *param, void *user_data) { @@ -10401,18 +10560,8 @@ static void index_added(uint16_t index, uint16_t length, const void *param, */ adapter_list = g_list_append(adapter_list, adapter); - DBG("sending read info command for index %u", index); - - if (mgmt_send(mgmt_primary, MGMT_OP_READ_INFO, index, 0, NULL, - read_info_complete, adapter, NULL) > 0) - return; - - btd_error(adapter->dev_id, - "Failed to read controller info for index %u", index); - - adapter_list = g_list_remove(adapter_list, adapter); - - btd_adapter_unref(adapter); + if (queue_isempty(adapter->exp_pending)) + read_info(adapter); } static void index_removed(uint16_t index, uint16_t length, const void *param, @@ -10711,6 +10860,14 @@ bool btd_le_connect_before_pairing(void) return false; } +bool btd_adapter_has_settings(struct btd_adapter *adapter, uint32_t settings) +{ + if (!adapter) + return false; + + return (adapter->current_settings & settings) ? true : false; +} + bool btd_has_kernel_features(uint32_t features) { return (kernel_features & features) ? true : false; @@ -10730,3 +10887,25 @@ bool btd_adapter_has_exp_feature(struct btd_adapter *adapter, uint32_t feature) return false; } + +void btd_adapter_cancel_service_auth(struct btd_adapter *adapter, + struct btd_device *device) +{ + GList *l; + + l = adapter->auths->head; + while (l != NULL) { + struct service_auth *auth = l->data; + GList *next = g_list_next(l); + + if (auth->device != device) { + l = next; + continue; + } + + g_queue_delete_link(adapter->auths, l); + l = next; + + service_auth_cancel(auth); + } +} diff --git a/src/adapter.h b/src/adapter.h index 78eb069ae8de57a3525efa1530cb591a82fc0da6..8dfbe762ef01068de2acf213e91010727d671c21 100644 --- a/src/adapter.h +++ b/src/adapter.h @@ -88,14 +88,12 @@ struct btd_device *btd_adapter_find_device_by_path(struct btd_adapter *adapter, const char *path); struct btd_device *btd_adapter_find_device_by_fd(int fd); -void btd_adapter_update_found_device(struct btd_adapter *adapter, +void btd_adapter_device_found(struct btd_adapter *adapter, const bdaddr_t *bdaddr, uint8_t bdaddr_type, int8_t rssi, - bool confirm, bool legacy, - bool not_connectable, - bool name_resolve_failed, + uint32_t flags, const uint8_t *data, uint8_t data_len, - bool monitored); + bool monitoring); const char *adapter_get_path(struct btd_adapter *adapter); const bdaddr_t *btd_adapter_get_address(struct btd_adapter *adapter); @@ -127,6 +125,11 @@ struct btd_adapter_driver { struct btd_device *device); void (*device_resolved)(struct btd_adapter *adapter, struct btd_device *device); + + /* Indicates the driver is experimental and shall only be registered + * when experimental has been enabled (see: main.conf:Experimental). + */ + bool experimental; }; void device_resolved_drivers(struct btd_adapter *adapter, @@ -256,6 +259,8 @@ void btd_adapter_for_each_device(struct btd_adapter *adapter, bool btd_le_connect_before_pairing(void); +bool btd_adapter_has_settings(struct btd_adapter *adapter, uint32_t settings); + enum experimental_features { EXP_FEAT_DEBUG = 1 << 0, EXP_FEAT_LE_SIMULT_ROLES = 1 << 1, @@ -283,3 +288,15 @@ bool btd_adapter_set_allowed_uuids(struct btd_adapter *adapter, struct queue *uuids); bool btd_adapter_is_uuid_allowed(struct btd_adapter *adapter, const char *uuid_str); + +void btd_adapter_load_conn_param(struct btd_adapter *adapter, + const bdaddr_t *peer, uint8_t bdaddr_type, + uint16_t min_interval, uint16_t max_interval, + uint16_t latency, uint16_t timeout); + +void btd_adapter_store_conn_param(struct btd_adapter *adapter, + const bdaddr_t *peer, uint8_t bdaddr_type, + uint16_t min_interval, uint16_t max_interval, + uint16_t latency, uint16_t timeout); +void btd_adapter_cancel_service_auth(struct btd_adapter *adapter, + struct btd_device *device); diff --git a/src/adv_monitor.c b/src/adv_monitor.c index 33f4d9619c1cc9f6f43d728998f824759066d263..cb38916fc28b74fa9b2747ab530830fc776b6ab8 100644 --- a/src/adv_monitor.c +++ b/src/adv_monitor.c @@ -1583,10 +1583,6 @@ static void adv_monitor_device_found_callback(uint16_t index, uint16_t length, const uint8_t *ad_data = NULL; uint16_t ad_data_len; uint32_t flags; - bool confirm_name; - bool legacy; - bool not_connectable; - bool name_resolve_failed; char addr[18]; if (length < sizeof(*ev)) { @@ -1605,21 +1601,14 @@ static void adv_monitor_device_found_callback(uint16_t index, uint16_t length, if (ad_data_len > 0) ad_data = ev->ad_data; - flags = btohl(ev->flags); + flags = le32_to_cpu(ev->flags); ba2str(&ev->addr.bdaddr, addr); DBG("hci%u addr %s, rssi %d flags 0x%04x ad_data_len %u", index, addr, ev->rssi, flags, ad_data_len); - confirm_name = (flags & MGMT_DEV_FOUND_CONFIRM_NAME); - legacy = (flags & MGMT_DEV_FOUND_LEGACY_PAIRING); - not_connectable = (flags & MGMT_DEV_FOUND_NOT_CONNECTABLE); - name_resolve_failed = (flags & MGMT_DEV_FOUND_NAME_REQUEST_FAILED); - - btd_adapter_update_found_device(adapter, &ev->addr.bdaddr, - ev->addr.type, ev->rssi, confirm_name, - legacy, not_connectable, - name_resolve_failed, ad_data, + btd_adapter_device_found(adapter, &ev->addr.bdaddr, + ev->addr.type, ev->rssi, flags, ad_data, ad_data_len, true); if (handle) { diff --git a/src/advertising.c b/src/advertising.c index f9748b1328bc1f7e7071f3bd551f04499febb1e5..bd121e5250337ab56df8c9f01d316b6b8ffb5322 100644 --- a/src/advertising.c +++ b/src/advertising.c @@ -29,11 +29,13 @@ #include "error.h" #include "log.h" #include "eir.h" +#include "btd.h" #include "src/shared/ad.h" #include "src/shared/mgmt.h" #include "src/shared/queue.h" #include "src/shared/timeout.h" #include "src/shared/util.h" +#include "src/shared/crypto.h" #include "advertising.h" #define LE_ADVERTISING_MGR_IFACE "org.bluez.LEAdvertisingManager1" @@ -459,13 +461,50 @@ fail: return false; } +static bool set_rsi(struct btd_adv_client *client) +{ + struct bt_crypto *crypto; + uint8_t zero[16] = {}; + struct bt_ad_data rsi = { .type = BT_AD_CSIP_RSI }; + uint8_t data[6]; + bool ret; + + /* Check if a valid SIRK has been set */ + if (!memcmp(btd_opts.csis.sirk, zero, sizeof(zero))) + return false; + + /* Check if RSI needs to be set or data already contains RSI data */ + if (!client || bt_ad_has_data(client->data, &rsi)) + return true; + + crypto = bt_crypto_new(); + if (!crypto) + return false; + + ret = bt_crypto_random_bytes(crypto, data + 3, sizeof(data) - 3); + if (!ret) + goto done; + + ret = bt_crypto_sih(crypto, btd_opts.csis.sirk, data + 3, data); + if (!ret) + goto done; + + ret = bt_ad_add_data(client->data, BT_AD_CSIP_RSI, data, sizeof(data)); + +done: + bt_crypto_unref(crypto); + return ret; +} + static struct adv_include { uint8_t flag; const char *name; + bool (*set)(struct btd_adv_client *client); } includes[] = { { MGMT_ADV_FLAG_TX_POWER, "tx-power" }, { MGMT_ADV_FLAG_APPEARANCE, "appearance" }, { MGMT_ADV_FLAG_LOCAL_NAME, "local-name" }, + { 0 , "rsi", set_rsi }, { }, }; @@ -497,6 +536,11 @@ static bool parse_includes(DBusMessageIter *iter, if (strcmp(str, inc->name)) continue; + if (inc->set && inc->set(client)) { + DBG("Including Feature: %s", str); + continue; + } + if (!(client->manager->supported_flags & inc->flag)) continue; @@ -683,11 +727,6 @@ fail: static bool set_flags(struct btd_adv_client *client, uint8_t flags) { - if (!flags) { - bt_ad_clear_flags(client->data); - return true; - } - /* Set BR/EDR Not Supported for LE only */ if (!btd_adapter_get_bredr(client->manager->adapter)) flags |= BT_AD_FLAG_NO_BREDR; @@ -695,8 +734,7 @@ static bool set_flags(struct btd_adv_client *client, uint8_t flags) /* Set BR/EDR Not Supported if adapter is not discoverable but the * instance is. */ - if ((flags & (BT_AD_FLAG_GENERAL | BT_AD_FLAG_LIMITED)) && - !btd_adapter_get_discoverable(client->manager->adapter)) + if (!btd_adapter_get_discoverable(client->manager->adapter)) flags |= BT_AD_FLAG_NO_BREDR; if (!bt_ad_add_flags(client->data, &flags, 1)) @@ -845,12 +883,18 @@ static int get_adv_flags(struct btd_adv_client *client) flags |= client->flags; + /* Detect if the length is bigger that legacy and secondary is not set + * then force it to be set to ensure the kernel uses EA. + */ + if (bt_ad_length(client->data) > BT_AD_MAX_DATA_LEN && + !(flags & MGMT_ADV_FLAG_SEC_MASK)) + flags |= MGMT_ADV_FLAG_SEC_1M; + return flags; } static int refresh_legacy_adv(struct btd_adv_client *client, - mgmt_request_func_t func, - unsigned int *mgmt_id) + mgmt_request_func_t func) { struct mgmt_cp_add_advertising *cp; uint8_t param_len; @@ -895,7 +939,9 @@ static int refresh_legacy_adv(struct btd_adv_client *client, cp->adv_data_len = adv_data_len; cp->scan_rsp_len = scan_rsp_len; memcpy(cp->data, adv_data, adv_data_len); - memcpy(cp->data + adv_data_len, scan_rsp, scan_rsp_len); + + if (scan_rsp) + memcpy(cp->data + adv_data_len, scan_rsp, scan_rsp_len); free(adv_data); free(scan_rsp); @@ -909,8 +955,8 @@ static int refresh_legacy_adv(struct btd_adv_client *client, free(cp); return -EINVAL; } - if (mgmt_id) - *mgmt_id = mgmt_ret; + if (func) + client->add_adv_id = mgmt_ret; free(cp); @@ -921,7 +967,7 @@ static void add_adv_params_callback(uint8_t status, uint16_t length, const void *param, void *user_data); static int refresh_extended_adv(struct btd_adv_client *client, - mgmt_request_func_t func, unsigned int *mgmt_id) + mgmt_request_func_t func) { struct mgmt_cp_add_ext_adv_params cp; uint32_t flags = 0; @@ -974,21 +1020,18 @@ static int refresh_extended_adv(struct btd_adv_client *client, /* Store callback, called after we set advertising data */ client->refresh_done_func = func; - - if (mgmt_id) - *mgmt_id = mgmt_ret; - + client->add_adv_id = mgmt_ret; return 0; } static int refresh_advertisement(struct btd_adv_client *client, - mgmt_request_func_t func, unsigned int *mgmt_id) + mgmt_request_func_t func) { if (client->manager->extended_add_cmds) - return refresh_extended_adv(client, func, mgmt_id); + return refresh_extended_adv(client, func); - return refresh_legacy_adv(client, func, mgmt_id); + return refresh_legacy_adv(client, func); } static bool client_discoverable_timeout(void *user_data) @@ -1001,7 +1044,7 @@ static bool client_discoverable_timeout(void *user_data) bt_ad_clear_flags(client->data); - refresh_advertisement(client, NULL, NULL); + refresh_advertisement(client, NULL); return FALSE; } @@ -1024,7 +1067,9 @@ static bool parse_discoverable_timeout(DBusMessageIter *iter, if (client->disc_to_id) timeout_remove(client->disc_to_id); - client->disc_to_id = timeout_add_seconds(client->discoverable_to, + if (client->discoverable_to > 0) + client->disc_to_id = timeout_add_seconds( + client->discoverable_to, client_discoverable_timeout, client, NULL); @@ -1083,10 +1128,6 @@ static bool parse_min_interval(DBusMessageIter *iter, { uint32_t min_interval_ms; - /* Only consider this property if experimental setting is applied */ - if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) - return true; - if (!iter) { client->min_interval = 0; return false; @@ -1116,10 +1157,6 @@ static bool parse_max_interval(DBusMessageIter *iter, { uint32_t max_interval_ms; - /* Only consider this property if experimental setting is applied */ - if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) - return true; - if (!iter) { client->max_interval = 0; return false; @@ -1149,10 +1186,6 @@ static bool parse_tx_power(DBusMessageIter *iter, { int16_t val; - /* Only consider this property if experimental setting is applied */ - if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) - return true; - if (!iter) { client->tx_power = ADV_TX_POWER_NO_PREFERENCE; return false; @@ -1209,7 +1242,7 @@ static void properties_changed(GDBusProxy *proxy, const char *name, continue; if (parser->func(iter, client)) { - refresh_advertisement(client, NULL, NULL); + refresh_advertisement(client, NULL); break; } @@ -1220,9 +1253,18 @@ static void add_client_complete(struct btd_adv_client *client, uint8_t status) { DBusMessage *reply; - if (status) { + if (status) error("Failed to add advertisement: %s (0x%02x)", mgmt_errstr(status), status); + + /* If the advertising request was not started by a direct call from + * the client, but rather by a refresh due to properties update or + * our internal timer, there is nothing to reply to. + */ + if (!client->reg) + return; + + if (status) { reply = btd_error_failed(client->reg, "Failed to register advertisement"); queue_remove(client->manager->clients, client); @@ -1288,6 +1330,8 @@ static void add_adv_params_callback(uint8_t status, uint16_t length, unsigned int mgmt_ret; dbus_int16_t tx_power; + client->add_adv_id = 0; + if (status) goto fail; @@ -1350,6 +1394,9 @@ static void add_adv_params_callback(uint8_t status, uint16_t length, client->manager->mgmt_index, param_len, cp, client->refresh_done_func, client, NULL); + if (mgmt_ret && client->refresh_done_func) + client->add_adv_id = mgmt_ret; + /* Clear the callback */ client->refresh_done_func = NULL; @@ -1358,9 +1405,6 @@ static void add_adv_params_callback(uint8_t status, uint16_t length, goto fail; } - if (client->add_adv_id) - client->add_adv_id = mgmt_ret; - free(cp); cp = NULL; @@ -1401,7 +1445,8 @@ static DBusMessage *parse_advertisement(struct btd_adv_client *client) } } - if (bt_ad_has_flags(client->data)) { + if (bt_ad_get_flags(client->data) & + (BT_AD_FLAG_GENERAL | BT_AD_FLAG_LIMITED)) { /* BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part C * page 2042: * A device in the broadcast mode shall not set the @@ -1441,8 +1486,7 @@ static DBusMessage *parse_advertisement(struct btd_adv_client *client) goto fail; } - err = refresh_advertisement(client, add_adv_callback, - &client->add_adv_id); + err = refresh_advertisement(client, add_adv_callback); if (!err) return NULL; @@ -1512,10 +1556,14 @@ static struct btd_adv_client *client_create(struct btd_adv_manager *manager, if (!client->data) goto fail; + bt_ad_set_max_len(client->data, manager->max_adv_len); + client->scan = bt_ad_new(); if (!client->scan) goto fail; + bt_ad_set_max_len(client->scan, manager->max_scan_rsp_len); + client->manager = manager; client->appearance = UINT16_MAX; client->tx_power = ADV_TX_POWER_NO_PREFERENCE; @@ -1644,7 +1692,8 @@ static void append_include(struct btd_adv_manager *manager, struct adv_include *inc; for (inc = includes; inc && inc->name; inc++) { - if (manager->supported_flags & inc->flag) + if ((inc->set && inc->set(NULL)) || + (manager->supported_flags & inc->flag)) dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &inc->name); } @@ -1779,10 +1828,8 @@ static const GDBusPropertyTable properties[] = { { "SupportedIncludes", "as", get_supported_includes, NULL, NULL }, { "SupportedSecondaryChannels", "as", get_supported_secondary, NULL, secondary_exists }, - { "SupportedFeatures", "as", get_supported_features, NULL, NULL, - G_DBUS_PROPERTY_FLAG_EXPERIMENTAL}, - { "SupportedCapabilities", "a{sv}", get_supported_cap, NULL, NULL, - G_DBUS_PROPERTY_FLAG_EXPERIMENTAL}, + { "SupportedFeatures", "as", get_supported_features, NULL, NULL }, + { "SupportedCapabilities", "a{sv}", get_supported_cap, NULL, NULL }, { } }; @@ -1844,6 +1891,19 @@ static void read_adv_features_callback(uint8_t status, uint16_t length, /* Reset existing instances */ if (feat->num_instances) remove_advertising(manager, 0); + + /* Emit property update */ + g_dbus_emit_property_changed(btd_get_dbus_connection(), + adapter_get_path(manager->adapter), + LE_ADVERTISING_MGR_IFACE, "SupportedFeatures"); + + g_dbus_emit_property_changed(btd_get_dbus_connection(), + adapter_get_path(manager->adapter), + LE_ADVERTISING_MGR_IFACE, "SupportedIncludes"); + + g_dbus_emit_property_changed(btd_get_dbus_connection(), + adapter_get_path(manager->adapter), + LE_ADVERTISING_MGR_IFACE, "SupportedSecondaryChannels"); } static void read_controller_cap_complete(uint8_t status, uint16_t length, @@ -1923,8 +1983,7 @@ static struct btd_adv_manager *manager_create(struct btd_adapter *adapter, /* Query controller capabilities. This will be used to display valid * advertising tx power range to the client. */ - if (g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL && - btd_has_kernel_features(KERNEL_HAS_CONTROLLER_CAP_CMD)) + if (btd_has_kernel_features(KERNEL_HAS_CONTROLLER_CAP_CMD)) mgmt_send(manager->mgmt, MGMT_OP_READ_CONTROLLER_CAP, manager->mgmt_index, 0, NULL, read_controller_cap_complete, manager, NULL); @@ -1970,7 +2029,7 @@ static void manager_refresh(void *data, void *user_data) { struct btd_adv_client *client = data; - refresh_advertisement(client, user_data, NULL); + refresh_advertisement(client, NULL); } void btd_adv_manager_refresh(struct btd_adv_manager *manager) diff --git a/src/battery.c b/src/battery.c index 88a53e80e8906edd66035b7cc6a18c33a5e5ff74..59e4fc570278e4d4b7da2f7a73e1e86831eb8924 100644 --- a/src/battery.c +++ b/src/battery.c @@ -152,8 +152,7 @@ static gboolean property_source_exists(const GDBusPropertyTable *property, static const GDBusPropertyTable battery_properties[] = { { "Percentage", "y", property_percentage_get, NULL, property_percentage_exists }, - { "Source", "s", property_source_get, NULL, property_source_exists, - G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { "Source", "s", property_source_get, NULL, property_source_exists }, {} }; @@ -288,6 +287,10 @@ static void provided_battery_added_cb(GDBusProxy *proxy, void *user_data) uint8_t percentage; DBusMessageIter iter; + if (strcmp(g_dbus_proxy_get_interface(proxy), + BATTERY_PROVIDER_INTERFACE) != 0) + return; + if (g_dbus_proxy_get_property(proxy, "Device", &iter) == FALSE) { warn("Battery object %s does not specify device path", path); return; @@ -295,10 +298,6 @@ static void provided_battery_added_cb(GDBusProxy *proxy, void *user_data) dbus_message_iter_get_basic(&iter, &export_path); - if (strcmp(g_dbus_proxy_get_interface(proxy), - BATTERY_PROVIDER_INTERFACE) != 0) - return; - device = btd_adapter_find_device_by_path(provider->manager->adapter, export_path); if (!device || device_is_temporary(device)) { @@ -341,15 +340,15 @@ static void provided_battery_removed_cb(GDBusProxy *proxy, void *user_data) const char *export_path; DBusMessageIter iter; + if (strcmp(g_dbus_proxy_get_interface(proxy), + BATTERY_PROVIDER_INTERFACE) != 0) + return; + if (g_dbus_proxy_get_property(proxy, "Device", &iter) == FALSE) return; dbus_message_iter_get_basic(&iter, &export_path); - if (strcmp(g_dbus_proxy_get_interface(proxy), - BATTERY_PROVIDER_INTERFACE) != 0) - return; - DBG("provided battery removed %s", g_dbus_proxy_get_path(proxy)); battery = find_battery_by_path(export_path); @@ -523,10 +522,10 @@ static DBusMessage *unregister_battery_provider(DBusConnection *conn, } static const GDBusMethodTable methods[] = { - { GDBUS_EXPERIMENTAL_METHOD("RegisterBatteryProvider", + { GDBUS_METHOD("RegisterBatteryProvider", GDBUS_ARGS({ "provider", "o" }), NULL, register_battery_provider) }, - { GDBUS_EXPERIMENTAL_METHOD("UnregisterBatteryProvider", + { GDBUS_METHOD("UnregisterBatteryProvider", GDBUS_ARGS({ "provider", "o" }), NULL, unregister_battery_provider) }, {} diff --git a/src/bluetooth.service.in b/src/bluetooth.service.in index beb98ce0c88784038c7ba336dd2809510fd29f51..8ebe89bec682f6941f12f1f76f0f35e4d1c565fe 100644 --- a/src/bluetooth.service.in +++ b/src/bluetooth.service.in @@ -6,7 +6,7 @@ ConditionPathIsDirectory=/sys/class/bluetooth [Service] Type=dbus BusName=org.bluez -ExecStart=@pkglibexecdir@/bluetoothd +ExecStart=@PKGLIBEXECDIR@/bluetoothd NotifyAccess=main #WatchdogSec=10 #Restart=on-failure diff --git a/src/bluetooth.ver b/src/bluetooth.ver index 214fa8a611e72e8947f5a0f274014c5963eb4aa9..a96fda2a15631af7f4b7c97452f75da96f08e90a 100644 --- a/src/bluetooth.ver +++ b/src/bluetooth.ver @@ -7,6 +7,14 @@ debug; baswap; ba2str; + /* Don't break LLVM sanitizers */ + __asan*; + __dfsan*; + __lsan*; + __msan*; + __sanitizer*; + __tsan*; + __ubsan*; local: *; }; diff --git a/src/bluetoothd.8 b/src/bluetoothd.8 new file mode 100644 index 0000000000000000000000000000000000000000..2b37a8dc9429adccb47b06b1888b5d2da86b01a5 --- /dev/null +++ b/src/bluetoothd.8 @@ -0,0 +1,120 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BLUETOOTHD" "8" "March, 2004" "BlueZ" "System management commands" +.SH NAME +bluetoothd \- Bluetooth daemon +.SH SYNOPSIS +.sp +\fBbluetoothd\fP [\-\-version] | [\-\-help] +.sp +\fBbluetoothd\fP [\-\-nodetach] [\-\-compat] [\-\-experimental] [\-\-debug=<\fIfiles\fP>] +[\-\-plugin=<\fIplugins\fP>] [\-\-noplugin=<\fIplugins\fP>] +.SH DESCRIPTION +.sp +This manual page documents briefly the \fBbluetoothd\fP daemon, which manages +all the Bluetooth devices. \fBbluetoothd\fP can also provide a number of services +via the D\-Bus message bus system. +.SH OPTIONS +.INDENT 0.0 +.TP +.B \-v\fP,\fB \-\-version +Print bluetoothd version and exit. +.TP +.B \-h\fP,\fB \-\-help +Print bluetoothd options and exit. +.TP +.B \-n\fP,\fB \-\-nodetach +Enable logging in foreground. Directs log output to the +controlling terminal in addition to syslog. +.TP +.B \-f\fP,\fB \-\-configfile +Specifies an explicit config file path instead of relying +on the default path(\fI/usr/local/etc/bluetooth/main.conf\fP) +for the config file. +.UNINDENT +.INDENT 0.0 +.TP +.B \-d, \-\-debug=<file1>:<file2>:... +Sets how much information bluetoothd sends to the log destination (usually +syslog\(aqs \(dqdaemon\(dq facility). If the file options are omitted, then +debugging information from all the source files are printed. If file +options are present, then only debug prints from that source file are +printed. The option can be a pattern containing \(dq*\(dq and \(dq?\(dq characters. +.sp +Example: \-\-debug=src/adapter.c:src/agent.c +.TP +.B \-p, \-\-plugin=<plugin1>,<plugin2>,.. +Load these plugins only. The option can be a pattern containing \(dq*\(dq and +\(dq?\(dq characters. +.TP +.B \-P, \-\-noplugin=<plugin1>,<plugin2>,.. +Never load these plugins. The option can be a pattern containing \(dq*\(dq and +\(dq?\(dq characters. +.UNINDENT +.INDENT 0.0 +.TP +.B \-C\fP,\fB \-\-compat +Provide deprecated command line interfaces. +.TP +.B \-E\fP,\fB \-\-experimental +Enable D\-Bus experimental interfaces. +These interfaces are not guaranteed to be compatible or present in future +releases. +.TP +.B \-T\fP,\fB \-\-testing +Enable D\-Bus testing interfaces. +These interfaces are only meant for test validation of the internals of +bluetoothd and shall not never be used by anything other than that. +.UNINDENT +.INDENT 0.0 +.TP +.B \-K, \-\-kernel=<uuid1>,<uuid2>,... +Enable Kernel experimental features. Kernel experimental features are +considered unstable and may be removed from future kernel releases. +.UNINDENT +.SH FILES +.INDENT 0.0 +.TP +.B \fI/usr/local/etc/bluetooth/main.conf\fP +Location of the global configuration file. +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH AUTHOR +Marcel Holtmann, Philipp Matthias Hahn, Fredrik Noring +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/src/bluetoothd.rst b/src/bluetoothd.rst new file mode 100644 index 0000000000000000000000000000000000000000..d507cfa475280979e801302e8aecd3e618f6ff7f --- /dev/null +++ b/src/bluetoothd.rst @@ -0,0 +1,93 @@ +========== +bluetoothd +========== + +---------------- +Bluetooth daemon +---------------- + +:Authors: - Marcel Holtmann + - Philipp Matthias Hahn + - Fredrik Noring +:Version: BlueZ +:Copyright: Free use of this software is granted under ther terms of the GNU + Lesser General Public Licenses (LGPL). +:Date: March, 2004 +:Manual section: 8 +:Manual group: System management commands + +SYNOPSIS +======== + +**bluetoothd** [--version] | [--help] + +**bluetoothd** [--nodetach] [--compat] [--experimental] [--debug=<*files*>] +[--plugin=<*plugins*>] [--noplugin=<*plugins*>] + +DESCRIPTION +=========== + +This manual page documents briefly the **bluetoothd** daemon, which manages +all the Bluetooth devices. **bluetoothd** can also provide a number of services +via the D-Bus message bus system. + +OPTIONS +======= + +-v, --version Print bluetoothd version and exit. + +-h, --help Print bluetoothd options and exit. + +-n, --nodetach Enable logging in foreground. Directs log output to the + controlling terminal in addition to syslog. + +-f, --configfile Specifies an explicit config file path instead of relying + on the default path(*/usr/local/etc/bluetooth/main.conf*) + for the config file. + +-d, --debug=<file1>:<file2>:... + Sets how much information bluetoothd sends to the log destination (usually + syslog's "daemon" facility). If the file options are omitted, then + debugging information from all the source files are printed. If file + options are present, then only debug prints from that source file are + printed. The option can be a pattern containing "*" and "?" characters. + + Example: --debug=src/adapter.c:src/agent.c + +-p, --plugin=<plugin1>,<plugin2>,.. + Load these plugins only. The option can be a pattern containing "*" and + "?" characters. + +-P, --noplugin=<plugin1>,<plugin2>,.. + Never load these plugins. The option can be a pattern containing "*" and + "?" characters. + +-C, --compat Provide deprecated command line interfaces. + +-E, --experimental Enable D-Bus experimental interfaces. + These interfaces are not guaranteed to be compatible or present in future + releases. + +-T, --testing Enable D-Bus testing interfaces. + These interfaces are only meant for test validation of the internals of + bluetoothd and shall not never be used by anything other than that. + +-K, --kernel=<uuid1>,<uuid2>,... + Enable Kernel experimental features. Kernel experimental features are + considered unstable and may be removed from future kernel releases. + +FILES +===== + +*/usr/local/etc/bluetooth/main.conf* + Location of the global configuration file. + +RESOURCES +========= + +http://www.bluez.org + +REPORTING BUGS +============== + +linux-bluetooth@vger.kernel.org diff --git a/src/bluetoothd.rst.in b/src/bluetoothd.rst.in index 7a0fa1b244698b09c78d05337031810e8c67065f..0b998f6215953dc0b570b3d6f5a675d5e2ab0756 100644 --- a/src/bluetoothd.rst.in +++ b/src/bluetoothd.rst.in @@ -64,8 +64,13 @@ OPTIONS -C, --compat Provide deprecated command line interfaces. --E, --experimental Enable experimental interfaces. Those interfaces are not - guaranteed to be compatible or present in future releases. +-E, --experimental Enable D-Bus experimental interfaces. + These interfaces are not guaranteed to be compatible or present in future + releases. + +-T, --testing Enable D-Bus testing interfaces. + These interfaces are only meant for test validation of the internals of + bluetoothd and shall not never be used by anything other than that. -K, --kernel=<uuid1>,<uuid2>,... Enable Kernel experimental features. Kernel experimental features are diff --git a/src/btd.h b/src/btd.h index 63be6d8d4b3f54019d86a9a3d888b11190651b5a..07205aa6948643639d3e3354cc0279d26b427264 100644 --- a/src/btd.h +++ b/src/btd.h @@ -36,6 +36,12 @@ enum mps_mode_t { MPS_MULTIPLE, }; +enum sc_mode_t { + SC_OFF, + SC_ON, + SC_ONLY, +}; + struct btd_br_defaults { uint16_t page_scan_type; uint16_t page_scan_interval; @@ -86,11 +92,23 @@ struct btd_defaults { struct btd_le_defaults le; }; +struct btd_csis { + bool encrypt; + uint8_t sirk[16]; + uint8_t size; + uint8_t rank; +}; + struct btd_avdtp_opts { uint8_t session_mode; uint8_t stream_mode; }; +struct btd_avrcp_opts { + bool volume_without_target; + bool volume_category; +}; + struct btd_advmon_opts { uint8_t rssi_sampling_period; }; @@ -98,22 +116,24 @@ struct btd_advmon_opts { struct btd_opts { char *name; uint32_t class; - gboolean pairable; + bool pairable; uint32_t pairto; uint32_t discovto; uint32_t tmpto; uint8_t privacy; bool device_privacy; uint32_t name_request_retry_delay; + uint8_t secure_conn; struct btd_defaults defaults; - gboolean reverse_discovery; - gboolean name_resolv; - gboolean debug_keys; - gboolean fast_conn; - gboolean refresh_discovery; - gboolean experimental; + bool reverse_discovery; + bool name_resolv; + bool debug_keys; + bool fast_conn; + bool refresh_discovery; + bool experimental; + bool testing; struct queue *kernel; uint16_t did_source; @@ -126,20 +146,24 @@ struct btd_opts { bt_gatt_cache_t gatt_cache; uint16_t gatt_mtu; uint8_t gatt_channels; + bool gatt_client; enum mps_mode_t mps; struct btd_avdtp_opts avdtp; + struct btd_avrcp_opts avrcp; uint8_t key_size; enum jw_repairing_t jw_repairing; struct btd_advmon_opts advmon; + + struct btd_csis csis; }; extern struct btd_opts btd_opts; -gboolean plugin_init(const char *enable, const char *disable); +void plugin_init(const char *enable, const char *disable); void plugin_cleanup(void); void rfkill_init(void); diff --git a/src/device.c b/src/device.c index 995d39f2ccee325cdc2206d52ed2adf3867af144..2b3d19f552fa9cec575ba35505552567942aaa90 100644 --- a/src/device.c +++ b/src/device.c @@ -5,7 +5,7 @@ * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org> - * + * Copyright 2024 NXP * */ @@ -22,6 +22,7 @@ #include <errno.h> #include <dirent.h> #include <time.h> +#include <limits.h> #include <sys/stat.h> #include <glib.h> @@ -64,6 +65,7 @@ #include "storage.h" #include "eir.h" #include "settings.h" +#include "set.h" #define DISCONNECT_TIMER 2 #define DISCOVERY_TIMER 1 @@ -159,9 +161,24 @@ struct bearer_state { time_t last_seen; }; +struct ltk_info { + uint8_t key[16]; + bool central; + uint8_t enc_size; +}; + struct csrk_info { uint8_t key[16]; uint32_t counter; + bool auth; +}; + +struct sirk_info { + struct btd_device_set *set; + uint8_t encrypted; + uint8_t key[16]; + uint8_t size; + uint8_t rank; }; enum { @@ -198,6 +215,7 @@ struct btd_device { GDBusPendingPropertySet wake_id; uint32_t supported_flags; + uint32_t pending_flags; uint32_t current_flags; GSList *svc_callbacks; GSList *eir_uuids; @@ -253,7 +271,8 @@ struct btd_device { struct csrk_info *local_csrk; struct csrk_info *remote_csrk; - uint8_t ltk_enc_size; + struct ltk_info *ltk; + struct queue *sirks; sdp_list_t *tmp_records; @@ -294,11 +313,11 @@ static struct bearer_state *get_state(struct btd_device *dev, return &dev->le_state; } -static bool get_initiator(struct btd_device *dev) +bool btd_device_is_initiator(struct btd_device *dev) { if (dev->le_state.connected) return dev->le_state.initiator; - if (dev->bredr_state.connected) + else if (dev->bredr_state.connected) return dev->bredr_state.initiator; return dev->att_io ? true : false; @@ -384,6 +403,25 @@ static void store_csrk(struct csrk_info *csrk, GKeyFile *key_file, g_key_file_set_string(key_file, group, "Key", key); g_key_file_set_integer(key_file, group, "Counter", csrk->counter); + g_key_file_set_boolean(key_file, group, "Authenticated", csrk->auth); +} + +static void store_sirk(struct sirk_info *sirk, GKeyFile *key_file, + uint8_t index) +{ + char group[28]; + char key[33]; + int i; + + sprintf(group, "SetIdentityResolvingKey#%u", index); + + for (i = 0; i < 16; i++) + sprintf(key + (i * 2), "%2.2X", sirk->key[i]); + + g_key_file_set_boolean(key_file, group, "Encrypted", sirk->encrypted); + g_key_file_set_string(key_file, group, "Key", key); + g_key_file_set_integer(key_file, group, "Size", sirk->size); + g_key_file_set_integer(key_file, group, "Rank", sirk->rank); } static gboolean store_device_info_cb(gpointer user_data) @@ -483,6 +521,18 @@ static gboolean store_device_info_cb(gpointer user_data) if (device->remote_csrk) store_csrk(device->remote_csrk, key_file, "RemoteSignatureKey"); + if (!queue_isempty(device->sirks)) { + const struct queue_entry *entry; + int i; + + for (entry = queue_get_entries(device->sirks), i = 0; entry; + entry = entry->next, i++) { + struct sirk_info *sirk = entry->data; + + store_sirk(sirk, key_file, i); + } + } + str = g_key_file_to_data(key_file, &length, NULL); if (!g_file_set_contents(filename, str, length, &gerr)) { error("Unable set contents for %s: (%s)", filename, @@ -804,8 +854,11 @@ static void device_free(gpointer user_data) if (device->eir_uuids) g_slist_free_full(device->eir_uuids, g_free); + queue_destroy(device->sirks, free); + g_free(device->local_csrk); g_free(device->remote_csrk); + free(device->ltk); g_free(device->path); g_free(device->alias); free(device->modalias); @@ -1001,16 +1054,14 @@ static gboolean dev_property_get_appearance(const GDBusPropertyTable *property, return TRUE; } -static const char *get_icon(const GDBusPropertyTable *property, void *data) +const char *btd_device_get_icon(struct btd_device *device) { - struct btd_device *device = data; const char *icon = NULL; - uint16_t appearance; if (device->class != 0) icon = class_to_icon(device->class); - else if (get_appearance(property, data, &appearance)) - icon = gap_appearance_to_icon(appearance); + else if (device->appearance != 0) + icon = gap_appearance_to_icon(device->appearance); return icon; } @@ -1018,7 +1069,7 @@ static const char *get_icon(const GDBusPropertyTable *property, void *data) static gboolean dev_property_exists_icon( const GDBusPropertyTable *property, void *data) { - return get_icon(property, data) != NULL; + return btd_device_get_icon(data) != NULL; } static gboolean dev_property_get_icon(const GDBusPropertyTable *property, @@ -1026,7 +1077,7 @@ static gboolean dev_property_get_icon(const GDBusPropertyTable *property, { const char *icon; - icon = get_icon(property, data); + icon = btd_device_get_icon(data); if (icon == NULL) return FALSE; @@ -1520,7 +1571,7 @@ static void set_wake_allowed_complete(uint8_t status, uint16_t length, return; } - device_set_wake_allowed_complete(dev); + btd_device_flags_changed(dev, dev->supported_flags, dev->pending_flags); } void device_set_wake_allowed(struct btd_device *device, bool wake_allowed, @@ -1607,6 +1658,67 @@ static gboolean dev_property_wake_allowed_exist( return device_get_wake_support(device); } +static void append_set(void *data, void *user_data) +{ + struct sirk_info *info = data; + const char *path; + DBusMessageIter *iter = user_data; + DBusMessageIter entry, dict; + + if (!info->set) + return; + + path = btd_set_get_path(info->set); + + dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL, + &entry); + + dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH, &path); + + dbus_message_iter_open_container(&entry, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); + + g_dbus_dict_append_entry(&dict, "Rank", DBUS_TYPE_BYTE, &info->rank); + + dbus_message_iter_close_container(&entry, &dict); + dbus_message_iter_close_container(iter, &entry); +} + +static gboolean dev_property_get_set(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct btd_device *device = data; + DBusMessageIter array; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_OBJECT_PATH_AS_STRING + DBUS_TYPE_ARRAY_AS_STRING + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &array); + + queue_foreach(device->sirks, append_set, &array); + + dbus_message_iter_close_container(iter, &array); + + return TRUE; +} + +static gboolean dev_property_set_exists(const GDBusPropertyTable *property, + void *data) +{ + struct btd_device *device = data; + + return !queue_isempty(device->sirks); +} + static bool disconnect_all(gpointer user_data) { struct btd_device *device = user_data; @@ -1792,17 +1904,167 @@ bool device_is_disconnecting(struct btd_device *device) return device->disconn_timer > 0; } -void device_set_ltk_enc_size(struct btd_device *device, uint8_t enc_size) +static void add_set(void *data, void *user_data) { - device->ltk_enc_size = enc_size; - bt_att_set_enc_key_size(device->att, device->ltk_enc_size); + struct sirk_info *sirk = data; + struct btd_device *device = user_data; + struct btd_device_set *set; + + if (!sirk->encrypted) + return; + + set = btd_set_add_device(device, device->ltk->key, sirk->key, + sirk->size); + if (!set) + return; + + if (sirk->set != set) { + sirk->set = set; + g_dbus_emit_property_changed(dbus_conn, device->path, + DEVICE_INTERFACE, "Sets"); + } +} + +void device_set_ltk(struct btd_device *device, const uint8_t val[16], + bool central, uint8_t enc_size) +{ + if (!device->ltk) + device->ltk = new0(struct ltk_info, 1); + + memcpy(device->ltk->key, val, sizeof(device->ltk->key)); + device->ltk->central = central; + device->ltk->enc_size = enc_size; + bt_att_set_enc_key_size(device->att, enc_size); + + /* Check if there is any set/sirk that needs decryption */ + queue_foreach(device->sirks, add_set, device); +} + +bool btd_device_get_ltk(struct btd_device *device, uint8_t key[16], + bool *central, uint8_t *enc_size) +{ + if (!device || !device->ltk || !key) + return false; + + memcpy(key, device->ltk->key, sizeof(device->ltk->key)); + + if (central) + *central = device->ltk->central; + + if (enc_size) + *enc_size = device->ltk->enc_size; + + return true; +} + +void device_set_csrk(struct btd_device *device, const uint8_t val[16], + uint32_t counter, uint8_t type, + bool store_hint) +{ + struct csrk_info **handle; + struct csrk_info *csrk; + bool auth; + + switch (type) { + case 0x00: + handle = &device->local_csrk; + auth = FALSE; + break; + case 0x01: + handle = &device->remote_csrk; + auth = FALSE; + break; + case 0x02: + handle = &device->local_csrk; + auth = TRUE; + break; + case 0x03: + handle = &device->remote_csrk; + auth = TRUE; + break; + default: + warn("Unsupported CSRK type %u", type); + return; + } + + if (!*handle) + *handle = g_new0(struct csrk_info, 1); + + csrk = *handle; + memcpy(csrk->key, val, sizeof(csrk->key)); + csrk->counter = counter; + csrk->auth = auth; + + if (!store_hint) + return; + + store_device_info(device); + + btd_device_set_temporary(device, false); +} + +static bool match_sirk(const void *data, const void *match_data) +{ + const struct sirk_info *sirk = data; + const uint8_t *key = match_data; + + return !memcmp(sirk->key, key, sizeof(sirk->key)); +} + +static struct sirk_info *device_add_sirk_info(struct btd_device *device, + bool encrypted, uint8_t key[16], + uint8_t size, uint8_t rank) +{ + struct sirk_info *sirk; + + sirk = queue_find(device->sirks, match_sirk, key); + if (sirk) + return sirk; + + sirk = new0(struct sirk_info, 1); + sirk->encrypted = encrypted; + memcpy(sirk->key, key, sizeof(sirk->key)); + sirk->size = size; + sirk->rank = rank; + + queue_push_tail(device->sirks, sirk); + store_device_info(device); + + return sirk; +} + +bool btd_device_add_set(struct btd_device *device, bool encrypted, + uint8_t key[16], uint8_t size, uint8_t rank) +{ + struct btd_device_set *set; + struct sirk_info *sirk; + + if (encrypted && !device->ltk) + return false; + + sirk = device_add_sirk_info(device, encrypted, key, size, rank); + if (!sirk) + return false; + + set = btd_set_add_device(device, encrypted ? device->ltk->key : NULL, + key, size); + if (!set) + return false; + + if (sirk->set != set) { + sirk->set = set; + g_dbus_emit_property_changed(dbus_conn, device->path, + DEVICE_INTERFACE, "Sets"); + } + + return true; } static void device_set_auto_connect(struct btd_device *device, gboolean enable) { char addr[18]; - if (!device || !device->le) + if (!device || !device->le || device_address_is_private(device)) return; ba2str(&device->bdaddr, addr); @@ -1952,7 +2214,7 @@ done: void device_add_eir_uuids(struct btd_device *dev, GSList *uuids) { GSList *l; - bool added = false; + GSList *added = NULL; if (dev->bredr_state.svc_resolved || dev->le_state.svc_resolved) return; @@ -1961,13 +2223,11 @@ void device_add_eir_uuids(struct btd_device *dev, GSList *uuids) const char *str = l->data; if (g_slist_find_custom(dev->eir_uuids, str, bt_uuid_strcmp)) continue; - added = true; + added = g_slist_append(added, (void *)str); dev->eir_uuids = g_slist_append(dev->eir_uuids, g_strdup(str)); } - if (added) - g_dbus_emit_property_changed(dbus_conn, dev->path, - DEVICE_INTERFACE, "UUIDs"); + device_probe_profiles(dev, added); } static void add_manufacturer_data(void *data, void *user_data) @@ -1997,6 +2257,7 @@ static void add_service_data(void *data, void *user_data) struct eir_sd *sd = data; struct btd_device *dev = user_data; bt_uuid_t uuid; + GSList *l; if (bt_string_to_uuid(&uuid, sd->uuid) < 0) return; @@ -2004,6 +2265,10 @@ static void add_service_data(void *data, void *user_data) if (!bt_ad_add_service_data(dev->ad, &uuid, sd->data, sd->data_len)) return; + l = g_slist_append(NULL, sd->uuid); + device_add_eir_uuids(dev, l); + g_slist_free(l); + g_dbus_emit_property_changed(dbus_conn, dev->path, DEVICE_INTERFACE, "ServiceData"); } @@ -2272,13 +2537,13 @@ static uint8_t select_conn_bearer(struct btd_device *dev) if (dev->bdaddr_type == BDADDR_LE_RANDOM) return dev->bdaddr_type; - if (dev->bredr_state.last_seen) { + if (dev->bredr_state.connectable && dev->bredr_state.last_seen) { bredr_last = current - dev->bredr_state.last_seen; if (bredr_last > SEEN_TRESHHOLD) bredr_last = NVAL_TIME; } - if (dev->le_state.last_seen) { + if (dev->le_state.connectable && dev->le_state.last_seen) { le_last = current - dev->le_state.last_seen; if (le_last > SEEN_TRESHHOLD) le_last = NVAL_TIME; @@ -2812,12 +3077,25 @@ static DBusMessage *pair_device(DBusConnection *conn, DBusMessage *msg, if (device->bonding) return btd_error_in_progress(msg); - if (device->bredr_state.bonded) + /* Only use this selection algorithms when device is combo + * chip. Ohterwise, it will use the wrong bearer to establish + * a connection if the device is already paired, which will + * stall the pairing procedure. For example, for a BLE only + * device, if the device is already paired, and upper layer + * issue the pair device again, it will set bdaddr_type to + * BDADDR_BREDR since LE is bonded, then it goes with BR/EDR + * bearer. + */ + if (device->bredr && device->le) { + if (device->bredr_state.bonded) + bdaddr_type = device->bdaddr_type; + else if (device->le_state.bonded) + bdaddr_type = BDADDR_BREDR; + else + bdaddr_type = select_conn_bearer(device); + } else { bdaddr_type = device->bdaddr_type; - else if (device->le_state.bonded) - bdaddr_type = BDADDR_BREDR; - else - bdaddr_type = select_conn_bearer(device); + } state = get_state(device, bdaddr_type); @@ -2850,6 +3128,11 @@ static DBusMessage *pair_device(DBusConnection *conn, DBusMessage *msg, * this in the ATT connect callback) */ if (bdaddr_type != BDADDR_BREDR) { + if (device->disable_auto_connect) { + device->disable_auto_connect = FALSE; + device_set_auto_connect(device, TRUE); + } + if (!state->connected && btd_le_connect_before_pairing()) err = device_connect_le(device); else @@ -2946,6 +3229,86 @@ static DBusMessage *cancel_pairing(DBusConnection *conn, DBusMessage *msg, return dbus_message_new_method_return(msg); } +static sdp_list_t *read_device_records(struct btd_device *device); + +static DBusMessage *get_service_records(DBusConnection *conn, DBusMessage *msg, + void *data) +{ + DBusMessage *reply; + DBusMessageIter records_arr, record; + struct btd_device *device = data; + sdp_list_t *cur; + + if (!btd_adapter_get_powered(device->adapter)) + return btd_error_not_ready(msg); + + if (!btd_device_is_connected(device)) + return btd_error_not_connected(msg); + + if (!device->bredr_state.svc_resolved) + return btd_error_not_ready(msg); + + if (!device->tmp_records) { + device->tmp_records = read_device_records(device); + if (!device->tmp_records) + return btd_error_does_not_exist(msg); + } + + reply = dbus_message_new_method_return(msg); + if (!reply) + return btd_error_failed(msg, "Could not create method reply"); + + dbus_message_iter_init_append(reply, &records_arr); + if (!dbus_message_iter_open_container(&records_arr, DBUS_TYPE_ARRAY, + "ay", &record)) { + dbus_message_unref(reply); + return btd_error_failed(msg, "Could not initialize iterator"); + } + + for (cur = device->tmp_records; cur; cur = cur->next) { + DBusMessageIter record_bytes; + sdp_record_t *rec = cur->data; + sdp_buf_t buf; + int result; + + result = sdp_gen_record_pdu(rec, &buf); + if (result) { + dbus_message_iter_abandon_container(&records_arr, + &record); + dbus_message_unref(reply); + return btd_error_failed( + msg, "Could not marshal service record"); + } + if (!dbus_message_iter_open_container(&record, DBUS_TYPE_ARRAY, + "y", &record_bytes)) { + bt_free(buf.data); + dbus_message_iter_abandon_container(&records_arr, + &record); + dbus_message_unref(reply); + return btd_error_failed( + msg, "Could not initialize iterator"); + } + if (!dbus_message_iter_append_fixed_array( + &record_bytes, DBUS_TYPE_BYTE, &buf.data, + buf.data_size)) { + bt_free(buf.data); + dbus_message_iter_abandon_container(&record, + &record_bytes); + dbus_message_iter_abandon_container(&records_arr, + &record); + dbus_message_unref(reply); + return btd_error_failed( + msg, "Could not append record data to reply"); + } + dbus_message_iter_close_container(&record, &record_bytes); + bt_free(buf.data); + } + + dbus_message_iter_close_container(&records_arr, &record); + + return reply; +} + static const GDBusMethodTable device_methods[] = { { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, dev_disconnect) }, { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, dev_connect) }, @@ -2955,6 +3318,9 @@ static const GDBusMethodTable device_methods[] = { NULL, disconnect_profile) }, { GDBUS_ASYNC_METHOD("Pair", NULL, NULL, pair_device) }, { GDBUS_METHOD("CancelPairing", NULL, NULL, cancel_pairing) }, + { GDBUS_EXPERIMENTAL_METHOD("GetServiceRecords", NULL, + GDBUS_ARGS({ "Records", "aay" }), + get_service_records) }, { } }; @@ -2988,14 +3354,14 @@ static const GDBusPropertyTable device_properties[] = { dev_property_exists_tx_power }, { "ServicesResolved", "b", dev_property_get_svc_resolved, NULL, NULL }, { "AdvertisingFlags", "ay", dev_property_get_flags, NULL, - dev_property_flags_exist, - G_DBUS_PROPERTY_FLAG_EXPERIMENTAL}, + dev_property_flags_exist }, { "AdvertisingData", "a{yv}", dev_property_get_advertising_data, - NULL, dev_property_advertising_data_exist, - G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + NULL, dev_property_advertising_data_exist }, { "WakeAllowed", "b", dev_property_get_wake_allowed, dev_property_set_wake_allowed, dev_property_wake_allowed_exist }, + { "Sets", "a{oa{sv}}", dev_property_get_set, NULL, + dev_property_set_exists }, { } }; @@ -3005,6 +3371,15 @@ uint8_t btd_device_get_bdaddr_type(struct btd_device *dev) } bool btd_device_is_connected(struct btd_device *dev) +{ + if (btd_device_bearer_is_connected(dev)) + return true; + + return find_service_with_state(dev->services, + BTD_SERVICE_STATE_CONNECTED); +} + +bool btd_device_bearer_is_connected(struct btd_device *dev) { return dev->bredr_state.connected || dev->le_state.connected; } @@ -3017,7 +3392,8 @@ static void clear_temporary_timer(struct btd_device *dev) } } -void device_add_connection(struct btd_device *dev, uint8_t bdaddr_type) +void device_add_connection(struct btd_device *dev, uint8_t bdaddr_type, + uint32_t flags) { struct bearer_state *state = get_state(dev, bdaddr_type); @@ -3040,6 +3416,7 @@ void device_add_connection(struct btd_device *dev, uint8_t bdaddr_type) device_set_le_support(dev, bdaddr_type); state->connected = true; + state->initiator = flags & BIT(3); if (dev->le_state.connected && dev->bredr_state.connected) return; @@ -3051,10 +3428,26 @@ void device_add_connection(struct btd_device *dev, uint8_t bdaddr_type) "Connected"); } +static bool device_service_connected(struct btd_device *dev) +{ + if (find_service_with_state(dev->services, + BTD_SERVICE_STATE_CONNECTING)) + return true; + + return find_service_with_state(dev->services, + BTD_SERVICE_STATE_CONNECTED); +} + static bool device_disappeared(gpointer user_data) { struct btd_device *dev = user_data; + /* If there are services connected restart the timer to give more time + * for the service to either complete the connection or disconnect. + */ + if (device_service_connected(dev)) + return TRUE; + dev->temporary_timer = 0; btd_adapter_remove_device(dev->adapter, dev); @@ -3108,18 +3501,6 @@ void device_remove_connection(struct btd_device *device, uint8_t bdaddr_type, device->connect = NULL; } - while (device->disconnects) { - DBusMessage *msg = device->disconnects->data; - - if (dbus_message_is_method_call(msg, ADAPTER_INTERFACE, - "RemoveDevice")) - remove_device = true; - - g_dbus_send_reply(dbus_conn, msg, DBUS_TYPE_INVALID); - device->disconnects = g_slist_remove(device->disconnects, msg); - dbus_message_unref(msg); - } - /* Check paired status of both bearers since it's possible to be * paired but not connected via link key to LTK conversion. */ @@ -3159,6 +3540,19 @@ void device_remove_connection(struct btd_device *device, uint8_t bdaddr_type, g_dbus_emit_property_changed(dbus_conn, device->path, DEVICE_INTERFACE, "Connected"); + /* remove device only if both bearers are disconnected */ + while (device->disconnects) { + DBusMessage *msg = device->disconnects->data; + + if (dbus_message_is_method_call(msg, ADAPTER_INTERFACE, + "RemoveDevice")) + remove_device = true; + + g_dbus_send_reply(dbus_conn, msg, DBUS_TYPE_INVALID); + device->disconnects = g_slist_remove(device->disconnects, msg); + dbus_message_unref(msg); + } + if (remove_device) *remove = remove_device; } @@ -3290,6 +3684,63 @@ fail: return NULL; } +static struct sirk_info *load_sirk(GKeyFile *key_file, uint8_t index) +{ + char group[28]; + struct sirk_info *sirk; + char *str; + int i; + + sprintf(group, "SetIdentityResolvingKey#%u", index); + + str = g_key_file_get_string(key_file, group, "Key", NULL); + if (!str) + return NULL; + + sirk = g_new0(struct sirk_info, 1); + + for (i = 0; i < 16; i++) { + if (sscanf(str + (i * 2), "%2hhx", &sirk->key[i]) != 1) + goto fail; + } + + + sirk->encrypted = g_key_file_get_boolean(key_file, group, "Encrypted", + NULL); + sirk->size = g_key_file_get_integer(key_file, group, "Size", NULL); + sirk->rank = g_key_file_get_integer(key_file, group, "Rank", NULL); + g_free(str); + + return sirk; + +fail: + g_free(str); + g_free(sirk); + return NULL; +} + +static void load_sirks(struct btd_device *device, GKeyFile *key_file) +{ + struct sirk_info *sirk; + uint8_t i; + + for (i = 0; i < UINT8_MAX; i++) { + sirk = load_sirk(key_file, i); + if (!sirk) + break; + + queue_push_tail(device->sirks, sirk); + + /* Only add DeviceSet object if sirk does need + * decryption otherwise it has to wait for the LTK in + * order to decrypt. + */ + if (!sirk->encrypted) + btd_set_add_device(device, NULL, sirk->key, + sirk->size); + } +} + static void load_services(struct btd_device *device, char **uuids) { char **uuid; @@ -3430,6 +3881,8 @@ static void load_info(struct btd_device *device, const char *local, device->local_csrk = load_csrk(key_file, "LocalSignatureKey"); device->remote_csrk = load_csrk(key_file, "RemoteSignatureKey"); + + load_sirks(device, key_file); } g_strfreev(techno); @@ -3662,11 +4115,13 @@ static bool device_match_profile(struct btd_device *device, struct btd_profile *profile, GSList *uuids) { + GSList *l; + if (profile->remote_uuid == NULL) return false; - if (g_slist_find_custom(uuids, profile->remote_uuid, - bt_uuid_strcmp) == NULL) + l = g_slist_find_custom(uuids, profile->remote_uuid, bt_uuid_strcmp); + if (!l) return false; return true; @@ -3711,7 +4166,7 @@ done: } /* Notify driver about the new connection */ - service_accept(service, get_initiator(device)); + service_accept(service, btd_device_is_initiator(device)); } static void device_add_gatt_services(struct btd_device *device) @@ -3731,7 +4186,7 @@ static void device_add_gatt_services(struct btd_device *device) static void device_accept_gatt_profiles(struct btd_device *device) { GSList *l; - bool initiator = get_initiator(device); + bool initiator = btd_device_is_initiator(device); DBG("initiator %s", initiator ? "true" : "false"); @@ -3945,6 +4400,7 @@ static struct btd_device *device_new(struct btd_adapter *adapter, } device->adapter = adapter; + device->sirks = queue_new(); device->temporary = true; device->db_id = gatt_db_register(device->db, gatt_service_added, @@ -4158,7 +4614,10 @@ void device_update_addr(struct btd_device *device, const bdaddr_t *bdaddr, bacpy(&device->bdaddr, bdaddr); device->bdaddr_type = bdaddr_type; - store_device_info(device); + if (device->temporary) + btd_device_set_temporary(device, false); + else + store_device_info(device); g_dbus_emit_property_changed(dbus_conn, device->path, DEVICE_INTERFACE, "Address"); @@ -4186,6 +4645,9 @@ void device_set_le_support(struct btd_device *device, uint8_t bdaddr_type) device->le = true; device->bdaddr_type = bdaddr_type; + g_dbus_emit_property_changed(dbus_conn, device->path, + DEVICE_INTERFACE, "AddressType"); + store_device_info(device); } @@ -4206,6 +4668,11 @@ void device_update_last_seen(struct btd_device *device, uint8_t bdaddr_type, set_temporary_timer(device, btd_opts.tmpto); } +void btd_device_set_connectable(struct btd_device *device, bool connectable) +{ + device_update_last_seen(device, device->bdaddr_type, connectable); +} + /* It is possible that we have two device objects for the same device in * case it has first been discovered over BR/EDR and has a private * address when discovered over LE for the first time. In such a case we @@ -4553,8 +5020,15 @@ static struct btd_service *probe_service(struct btd_device *device, /* Only set auto connect if profile has set the flag and can really * accept connections. */ - if (profile->auto_connect && profile->accept) - device_set_auto_connect(device, TRUE); + if (profile->auto_connect && profile->accept) { + /* If temporary mark auto_connect as disabled so when the + * device is connected it attempts to enable it. + */ + if (device->temporary) + device->disable_auto_connect = TRUE; + else + device_set_auto_connect(device, TRUE); + } return service; } @@ -4615,6 +5089,9 @@ void device_probe_profiles(struct btd_device *device, GSList *uuids) struct probe_data d = { device, uuids }; char addr[18]; + if (!uuids) + return; + ba2str(&device->bdaddr, addr); if (device->blocked) { @@ -4622,8 +5099,6 @@ void device_probe_profiles(struct btd_device *device, GSList *uuids) goto add_uuids; } - DBG("Probing profiles for device %s", addr); - btd_profile_foreach(dev_probe, &d); add_uuids: @@ -5143,6 +5618,10 @@ static void gatt_client_init(struct btd_device *device) DBG("Reverse service discovery disabled: skipping GATT client"); return; } + if (!device->connect && !btd_opts.gatt_client) { + DBG("GATT client disabled: skipping GATT client"); + return; + } device->client = bt_gatt_client_new(device->db, device->att, device->att_mtu, 0); @@ -5152,12 +5631,14 @@ static void gatt_client_init(struct btd_device *device) } bt_gatt_client_set_debug(device->client, gatt_debug, NULL, NULL); + g_attrib_attach_client(device->attrib, device->client); /* - * Notify notify existing service about the new connection so they can - * react to notifications while discovering services + * If we have cache, notify existing service about the new connection + * so they can react to notifications while discovering services */ - device_accept_gatt_profiles(device); + if (!gatt_db_isempty(device->db)) + device_accept_gatt_profiles(device); device->gatt_ready_id = bt_gatt_client_ready_register(device->client, gatt_client_ready_cb, @@ -5205,7 +5686,9 @@ static void gatt_server_init(struct btd_device *device, return; } - bt_att_set_enc_key_size(device->att, device->ltk_enc_size); + if (device->ltk) + bt_att_set_enc_key_size(device->att, device->ltk->enc_size); + bt_gatt_server_set_debug(device->server, gatt_debug, NULL, NULL); btd_gatt_database_server_connected(database, device->server); @@ -5420,7 +5903,7 @@ int device_connect_le(struct btd_device *dev) char addr[18]; /* There is one connection attempt going on */ - if (dev->att_io) + if (dev->att_io || dev->att) return -EALREADY; ba2str(&dev->bdaddr, addr); @@ -5468,6 +5951,10 @@ int device_connect_le(struct btd_device *dev) /* Keep this, so we can cancel the connection */ dev->att_io = io; + /* Restart temporary timer to give it time to connect/pair, etc. */ + if (dev->temporary) + set_temporary_timer(dev, btd_opts.tmpto); + return 0; } @@ -6043,7 +6530,8 @@ void device_bonding_complete(struct btd_device *device, uint8_t bdaddr_type, /* Put the device back to the temporary state so that it will be * treated as a newly discovered device. */ - if (!device_is_paired(device, bdaddr_type) && + if (!btd_device_bearer_is_connected(device) && + !device_is_paired(device, bdaddr_type) && !btd_device_is_trusted(device)) btd_device_set_temporary(device, true); @@ -6564,6 +7052,9 @@ void device_cancel_authentication(struct btd_device *device, gboolean aborted) struct authentication_req *auth = device->authr; char addr[18]; + if (device->adapter) + btd_adapter_cancel_service_auth(device->adapter, device); + if (!auth) return; @@ -6609,6 +7100,27 @@ struct gatt_db *btd_device_get_gatt_db(struct btd_device *device) return device->db; } +bool btd_device_set_gatt_db(struct btd_device *device, struct gatt_db *db) +{ + struct gatt_db *clone; + + if (!device) + return false; + + clone = gatt_db_clone(db); + if (clone) + return false; + + gatt_db_unregister(device->db, device->db_id); + gatt_db_unref(device->db); + + device->db = clone; + device->db_id = gatt_db_register(device->db, gatt_service_added, + gatt_service_removed, device, NULL); + + return true; +} + struct bt_gatt_client *btd_device_get_gatt_client(struct btd_device *device) { if (!device) @@ -6647,9 +7159,6 @@ void btd_device_add_uuid(struct btd_device *device, const char *uuid) GSList *uuid_list; char *new_uuid; - if (g_slist_find_custom(device->uuids, uuid, bt_uuid_strcmp)) - return; - new_uuid = g_strdup(uuid); uuid_list = g_slist_append(NULL, new_uuid); @@ -6657,11 +7166,6 @@ void btd_device_add_uuid(struct btd_device *device, const char *uuid) g_free(new_uuid); g_slist_free(uuid_list); - - store_device_info(device); - - g_dbus_emit_property_changed(dbus_conn, device->path, - DEVICE_INTERFACE, "UUIDs"); } static sdp_list_t *read_device_records(struct btd_device *device) @@ -6758,6 +7262,14 @@ struct btd_device *btd_device_ref(struct btd_device *device) return device; } +static void remove_sirk_info(void *data, void *user_data) +{ + struct sirk_info *info = data; + struct btd_device *device = user_data; + + btd_set_remove_device(info->set, device); +} + void btd_device_unref(struct btd_device *device) { if (__sync_sub_and_fetch(&device->ref_count, 1)) @@ -6768,6 +7280,9 @@ void btd_device_unref(struct btd_device *device) return; } + if (!queue_isempty(device->sirks)) + queue_foreach(device->sirks, remove_sirk_info, device); + DBG("Freeing device %s", device->path); g_dbus_unregister_interface(dbus_conn, device->path, DEVICE_INTERFACE); @@ -6833,6 +7348,22 @@ uint32_t btd_device_get_supported_flags(struct btd_device *dev) return dev->supported_flags; } +void btd_device_set_pending_flags(struct btd_device *dev, uint32_t flags) +{ + if (!dev) + return; + + dev->pending_flags = flags; +} + +uint32_t btd_device_get_pending_flags(struct btd_device *dev) +{ + if (!dev) + return 0; + + return dev->pending_flags; +} + /* This event is sent immediately after add device on all mgmt sockets. * Afterwards, it is only sent to mgmt sockets other than the one which called * set_device_flags. @@ -6845,11 +7376,12 @@ void btd_device_flags_changed(struct btd_device *dev, uint32_t supported_flags, dev->supported_flags = supported_flags; dev->current_flags = current_flags; + dev->pending_flags = 0; if (!changed_flags) return; - if (changed_flags & DEVICE_FLAG_REMOTE_WAKEUP) { + if (changed_flags & DEVICE_FLAG_REMOTE_WAKEUP && dev->wake_support) { flag_value = !!(current_flags & DEVICE_FLAG_REMOTE_WAKEUP); dev->pending_wake_allowed = flag_value; @@ -6926,3 +7458,29 @@ int8_t btd_device_get_volume(struct btd_device *device) { return device->volume; } + +void btd_device_foreach_ad(struct btd_device *dev, bt_ad_func_t func, + void *data) +{ + bt_ad_foreach_data(dev->ad, func, data); +} + +void btd_device_set_conn_param(struct btd_device *device, uint16_t min_interval, + uint16_t max_interval, uint16_t latency, + uint16_t timeout) +{ + /* Attempt to load the new connection parameters, in case it is + * successful the MGMT_EV_NEW_CONN_PARAM will be generated which will + * then trigger btd_adapter_store_conn_param. + */ + btd_adapter_load_conn_param(device->adapter, &device->bdaddr, + device->bdaddr_type, min_interval, + max_interval, latency, + timeout); +} + +void btd_device_foreach_service_data(struct btd_device *dev, bt_ad_func_t func, + void *data) +{ + bt_ad_foreach_service_data(dev->ad, func, data); +} diff --git a/src/device.h b/src/device.h index 9e81fda9e9486e12e2c89beeffacd21ac031b11c..97536774ed5f4d9fe4cb6bb08745ac215de68722 100644 --- a/src/device.h +++ b/src/device.h @@ -5,7 +5,7 @@ * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org> - * + * Copyright 2024 NXP * */ @@ -41,6 +41,7 @@ uint16_t btd_device_get_vendor(struct btd_device *device); uint16_t btd_device_get_vendor_src(struct btd_device *device); uint16_t btd_device_get_product(struct btd_device *device); uint16_t btd_device_get_version(struct btd_device *device); +const char *btd_device_get_icon(struct btd_device *device); void device_remove_bonding(struct btd_device *device, uint8_t bdaddr_type); void device_remove(struct btd_device *device, gboolean remove_stored); int device_address_cmp(gconstpointer a, gconstpointer b); @@ -65,8 +66,10 @@ struct gatt_primary *btd_device_get_primary(struct btd_device *device, const char *uuid); GSList *btd_device_get_primaries(struct btd_device *device); struct gatt_db *btd_device_get_gatt_db(struct btd_device *device); +bool btd_device_set_gatt_db(struct btd_device *device, struct gatt_db *db); struct bt_gatt_client *btd_device_get_gatt_client(struct btd_device *device); struct bt_gatt_server *btd_device_get_gatt_server(struct btd_device *device); +bool btd_device_is_initiator(struct btd_device *device); void *btd_device_get_attrib(struct btd_device *device); void btd_device_gatt_set_service_changed(struct btd_device *device, uint16_t start, uint16_t end); @@ -94,6 +97,7 @@ void device_set_paired(struct btd_device *dev, uint8_t bdaddr_type); void device_set_unpaired(struct btd_device *dev, uint8_t bdaddr_type); void btd_device_set_temporary(struct btd_device *device, bool temporary); void btd_device_set_trusted(struct btd_device *device, gboolean trusted); +void btd_device_set_connectable(struct btd_device *device, bool connectable); void device_set_bonded(struct btd_device *device, uint8_t bdaddr_type); void device_set_legacy(struct btd_device *device, bool legacy); void device_set_rssi_with_delta(struct btd_device *device, int8_t rssi, @@ -102,6 +106,7 @@ void device_set_rssi(struct btd_device *device, int8_t rssi); void device_set_tx_power(struct btd_device *device, int8_t tx_power); void device_set_flags(struct btd_device *device, uint8_t flags); bool btd_device_is_connected(struct btd_device *dev); +bool btd_device_bearer_is_connected(struct btd_device *dev); uint8_t btd_device_get_bdaddr_type(struct btd_device *dev); bool device_is_retrying(struct btd_device *device); void device_bonding_complete(struct btd_device *device, uint8_t bdaddr_type, @@ -123,13 +128,21 @@ int device_notify_pincode(struct btd_device *device, gboolean secure, const char *pincode); void device_cancel_authentication(struct btd_device *device, gboolean aborted); gboolean device_is_authenticating(struct btd_device *device); -void device_add_connection(struct btd_device *dev, uint8_t bdaddr_type); +void device_add_connection(struct btd_device *dev, uint8_t bdaddr_type, + uint32_t flags); void device_remove_connection(struct btd_device *device, uint8_t bdaddr_type, bool *remove); void device_request_disconnect(struct btd_device *device, DBusMessage *msg); bool device_is_disconnecting(struct btd_device *device); -void device_set_ltk_enc_size(struct btd_device *device, uint8_t enc_size); - +void device_set_ltk(struct btd_device *device, const uint8_t val[16], + bool central, uint8_t enc_size); +bool btd_device_get_ltk(struct btd_device *device, uint8_t val[16], + bool *central, uint8_t *enc_size); +void device_set_csrk(struct btd_device *device, const uint8_t val[16], + uint32_t counter, uint8_t type, + bool store_hint); +bool btd_device_add_set(struct btd_device *device, bool encrypted, + uint8_t sirk[16], uint8_t size, uint8_t rank); void device_store_svc_chng_ccc(struct btd_device *device, uint8_t bdaddr_type, uint16_t value); void device_load_svc_chng_ccc(struct btd_device *device, uint16_t *ccc_le, @@ -178,6 +191,8 @@ int btd_device_connect_services(struct btd_device *dev, GSList *services); uint32_t btd_device_get_current_flags(struct btd_device *dev); uint32_t btd_device_get_supported_flags(struct btd_device *dev); +uint32_t btd_device_get_pending_flags(struct btd_device *dev); +void btd_device_set_pending_flags(struct btd_device *dev, uint32_t flags); void btd_device_flags_changed(struct btd_device *dev, uint32_t supported_flags, uint32_t current_flags); @@ -188,3 +203,14 @@ void btd_device_cleanup(void); void btd_device_set_volume(struct btd_device *dev, int8_t volume); int8_t btd_device_get_volume(struct btd_device *dev); + +typedef void (*bt_device_ad_func_t)(void *data, void *user_data); + +void btd_device_foreach_ad(struct btd_device *dev, bt_device_ad_func_t func, + void *data); +void btd_device_set_conn_param(struct btd_device *device, uint16_t min_interval, + uint16_t max_interval, uint16_t latency, + uint16_t timeout); +void btd_device_foreach_service_data(struct btd_device *dev, + bt_device_ad_func_t func, + void *data); diff --git a/src/eir.c b/src/eir.c index 2f9ee036ffd5c11ed413ba6d21b420fdb4147b78..3e3ee2863058def3827d5fb7f8710b0d0e747271 100644 --- a/src/eir.c +++ b/src/eir.c @@ -236,6 +236,9 @@ static void eir_parse_data(struct eir_data *eir, uint8_t type, memcpy(ad->data, data, len); eir->data_list = g_slist_append(eir->data_list, ad); + + if (type == EIR_CSIP_RSI) + eir->rsi = true; } void eir_parse(struct eir_data *eir, const uint8_t *eir_data, uint8_t eir_len) @@ -599,3 +602,25 @@ int eir_create_oob(const bdaddr_t *addr, const char *name, uint32_t cod, return eir_total_len; } + +static int match_sd_uuid(const void *data, const void *user_data) +{ + const struct eir_sd *sd = data; + const char *uuid = user_data; + + return strcmp(sd->uuid, uuid); +} + +struct eir_sd *eir_get_service_data(struct eir_data *eir, const char *uuid) +{ + GSList *l; + + if (!eir || !uuid) + return NULL; + + l = g_slist_find_custom(eir->sd_list, uuid, match_sd_uuid); + if (!l) + return NULL; + + return l->data; +} diff --git a/src/eir.h b/src/eir.h index 6154e23ec266ad3409df06ddb6096e5ea421f3be..f342919528236dfa9f336d6912bebd3d06e6b337 100644 --- a/src/eir.h +++ b/src/eir.h @@ -12,6 +12,7 @@ #include <glib.h> #include "lib/sdp.h" +#include "lib/uuid.h" #define EIR_FLAGS 0x01 /* flags */ #define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ @@ -37,6 +38,7 @@ #define EIR_SVC_DATA32 0x20 /* LE: Service data, 32-bit UUID */ #define EIR_SVC_DATA128 0x21 /* LE: Service data, 128-bit UUID */ #define EIR_TRANSPORT_DISCOVERY 0x26 /* Transport Discovery Service */ +#define EIR_CSIP_RSI 0x2e /* Resolvable Set Identifier */ #define EIR_MANUFACTURER_DATA 0xFF /* Manufacturer Specific Data */ /* Flags Descriptions */ @@ -76,6 +78,7 @@ struct eir_data { uint32_t class; uint16_t appearance; bool name_complete; + bool rsi; int8_t tx_power; uint8_t *hash; uint8_t *randomizer; @@ -97,3 +100,4 @@ int eir_create_oob(const bdaddr_t *addr, const char *name, uint32_t cod, uint16_t did_vendor, uint16_t did_product, uint16_t did_version, uint16_t did_source, sdp_list_t *uuids, uint8_t *data); +struct eir_sd *eir_get_service_data(struct eir_data *eir, const char *uuid); diff --git a/src/error.c b/src/error.c index 29c071067f2b1b9118497ca8742276566f6312ca..f179e6cda0e8619764b6cacf54b1921fd24517ca 100644 --- a/src/error.c +++ b/src/error.c @@ -171,6 +171,8 @@ const char *btd_error_bredr_conn_from_errno(int errno_code) return ERR_BREDR_CONN_ABORT_BY_LOCAL; case EPROTO: return ERR_BREDR_CONN_LMP_PROTO_ERROR; + case EBADE: + return ERR_BREDR_CONN_KEY_MISSING; default: return ERR_BREDR_CONN_UNKNOWN; } @@ -209,6 +211,8 @@ const char *btd_error_le_conn_from_errno(int errno_code) return ERR_LE_CONN_ABORT_BY_LOCAL; case EPROTO: return ERR_LE_CONN_LL_PROTO_ERROR; + case EBADE: + return ERR_LE_CONN_KEY_MISSING; default: return ERR_LE_CONN_UNKNOWN; } diff --git a/src/error.h b/src/error.h index cc7790a2321a45e85ef13210c3eac418636edc62..83206cb48a66644eb0f555be78fea59ecc6d23cd 100644 --- a/src/error.h +++ b/src/error.h @@ -43,6 +43,7 @@ #define ERR_BREDR_CONN_LMP_PROTO_ERROR "br-connection-lmp-protocol-"\ "error" #define ERR_BREDR_CONN_CANCELED "br-connection-canceled" +#define ERR_BREDR_CONN_KEY_MISSING "br-connection-key-missing" #define ERR_BREDR_CONN_UNKNOWN "br-connection-unknown" /* LE connection failure reasons */ @@ -63,6 +64,7 @@ #define ERR_LE_CONN_LL_PROTO_ERROR "le-connection-link-layer-protocol-"\ "error" #define ERR_LE_CONN_GATT_BROWSE "le-connection-gatt-browsing" +#define ERR_LE_CONN_KEY_MISSING "le-connection-key-missing" #define ERR_LE_CONN_UNKNOWN "le-connection-unknown" DBusMessage *btd_error_invalid_args(DBusMessage *msg); diff --git a/src/gatt-client.c b/src/gatt-client.c index b2fc16b90fae911289357396000bb8cb8b273bb0..8d83a95772acf63fcb3556eadfb76bbd6e9e7607 100644 --- a/src/gatt-client.c +++ b/src/gatt-client.c @@ -137,6 +137,17 @@ static bool uuid_cmp(const bt_uuid_t *uuid, uint16_t u16) return bt_uuid_cmp(uuid, &uuid16) == 0; } +static gboolean descriptor_get_handle(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct service *desc = data; + uint16_t handle = desc->start_handle; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &handle); + + return TRUE; +} + static gboolean descriptor_get_uuid(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { @@ -635,6 +646,7 @@ static DBusMessage *descriptor_write_value(DBusConnection *conn, } static const GDBusPropertyTable descriptor_properties[] = { + { "Handle", "q", descriptor_get_handle }, { "UUID", "s", descriptor_get_uuid }, { "Characteristic", "o", descriptor_get_characteristic, }, { "Value", "ay", descriptor_get_value, NULL, descriptor_value_exists }, @@ -713,6 +725,17 @@ static void unregister_descriptor(void *data) GATT_DESCRIPTOR_IFACE); } +static gboolean characteristic_get_handle(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct characteristic *chrc = data; + uint16_t handle = chrc->handle; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &handle); + + return TRUE; +} + static gboolean characteristic_get_uuid(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { @@ -1104,6 +1127,11 @@ static bool sock_read(struct io *io, void *user_data) msg.msg_iov = &iov; msg.msg_iovlen = 1; + if (fd < 0) { + error("io_get_fd() returned %d\n", fd); + return false; + } + bytes_read = recvmsg(fd, &msg, MSG_DONTWAIT); if (bytes_read < 0) { error("recvmsg: %s", strerror(errno)); @@ -1660,6 +1688,7 @@ static DBusMessage *characteristic_stop_notify(DBusConnection *conn, } static const GDBusPropertyTable characteristic_properties[] = { + { "Handle", "q", characteristic_get_handle }, { "UUID", "s", characteristic_get_uuid, NULL, NULL }, { "Service", "o", characteristic_get_service, NULL, NULL }, { "Value", "ay", characteristic_get_value, NULL, @@ -1821,6 +1850,17 @@ static void unregister_characteristic(void *data) GATT_CHARACTERISTIC_IFACE); } +static gboolean service_get_handle(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct service *service = data; + uint16_t handle = service->start_handle; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &handle); + + return TRUE; +} + static gboolean service_get_uuid(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { @@ -1884,6 +1924,7 @@ static gboolean service_get_includes(const GDBusPropertyTable *property, } static const GDBusPropertyTable service_properties[] = { + { "Handle", "q", service_get_handle }, { "UUID", "s", service_get_uuid }, { "Device", "o", service_get_device }, { "Primary", "b", service_get_primary }, @@ -2255,7 +2296,8 @@ void btd_gatt_client_eatt_connect(struct btd_gatt_client *client) char addr[18]; int i; - if (!(client->features & BT_GATT_CHRC_CLI_FEAT_EATT)) + if (!(client->features & BT_GATT_CHRC_CLI_FEAT_EATT) || + !btd_device_is_initiator(dev)) return; if (bt_att_get_channels(att) == btd_opts.gatt_channels) diff --git a/src/gatt-database.c b/src/gatt-database.c index ea282d4bc193bf73751133760e7fc2f943b03085..a86e528fd0e2e62404808d29618b6d5b1b0e75fb 100644 --- a/src/gatt-database.c +++ b/src/gatt-database.c @@ -16,6 +16,7 @@ #include <stdlib.h> #include <errno.h> #include <unistd.h> +#include <limits.h> #include "lib/bluetooth.h" #include "lib/sdp.h" @@ -110,6 +111,13 @@ struct external_profile { struct queue *profiles; /* btd_profile list */ }; +struct client_io { + struct bt_att *att; + struct external_chrc *chrc; + unsigned int disconn_id; + struct io *io; +}; + struct external_chrc { struct external_service *service; char *path; @@ -119,8 +127,8 @@ struct external_chrc { uint32_t perm; uint32_t ccc_perm; uint16_t mtu; - struct io *write_io; - struct io *notify_io; + struct queue *write_ios; + struct queue *notify_ios; struct gatt_db_attribute *attrib; struct gatt_db_attribute *ccc; struct queue *pending_reads; @@ -463,12 +471,22 @@ static void cancel_pending_write(void *data) op->owner_queue = NULL; } +static void client_io_free(void *data) +{ + struct client_io *client = data; + + bt_att_unregister_disconnect(client->att, client->disconn_id); + bt_att_unref(client->att); + io_destroy(client->io); + free(client); +} + static void chrc_free(void *data) { struct external_chrc *chrc = data; - io_destroy(chrc->write_io); - io_destroy(chrc->notify_io); + queue_destroy(chrc->write_ios, client_io_free); + queue_destroy(chrc->notify_ios, client_io_free); queue_destroy(chrc->pending_reads, cancel_pending_read); queue_destroy(chrc->pending_writes, cancel_pending_write); @@ -2231,6 +2249,9 @@ static uint8_t dbus_error_to_att_ecode(const char *name, const char *msg, if (strcmp(name, ERROR_INTERFACE ".InProgress") == 0) return BT_ERROR_ALREADY_IN_PROGRESS; + if (!strcmp(name, ERROR_INTERFACE ".ImproperlyConfigured")) + return BT_ERROR_CCC_IMPROPERLY_CONFIGURED; + if (strcmp(name, ERROR_INTERFACE ".NotPermitted") == 0) return perm_err; @@ -2543,39 +2564,52 @@ static void flush_pending_writes(GDBusProxy *proxy, queue_remove_all(owner_queue, NULL, NULL, NULL); } +static bool match_client_io(const void *data, const void *user_data) +{ + const struct client_io *client = data; + const struct io *io = user_data; + + return client->io == io; +} + static bool sock_hup(struct io *io, void *user_data) { struct external_chrc *chrc = user_data; + struct client_io *client; DBG("%p closed\n", io); - if (io == chrc->write_io) - chrc->write_io = NULL; - else - chrc->notify_io = NULL; + client = queue_remove_if(chrc->write_ios, match_client_io, io); + if (!client) { + client = queue_remove_if(chrc->notify_ios, match_client_io, io); + if (!client) + return false; + } - io_destroy(io); + client_io_free(client); return false; } static bool sock_io_read(struct io *io, void *user_data) { - struct external_chrc *chrc = user_data; + struct client_io *client = user_data; + struct external_chrc *chrc = client->chrc; uint8_t buf[512]; int fd = io_get_fd(io); ssize_t bytes_read; + if (fd < 0) { + error("io_get_fd() returned %d\n", fd); + return false; + } + bytes_read = read(fd, buf, sizeof(buf)); if (bytes_read <= 0) return false; - send_notification_to_devices(chrc->service->app->database, - gatt_db_attribute_get_handle(chrc->attrib), - buf, bytes_read, - gatt_db_attribute_get_handle(chrc->ccc), - conf_cb, - chrc->proxy); + gatt_notify_cb(chrc->attrib, chrc->ccc, buf, bytes_read, client->att, + client->chrc->service->app->database); return true; } @@ -2597,6 +2631,7 @@ static int sock_io_send(struct io *io, const void *data, size_t len) { struct msghdr msg; struct iovec iov; + int fd; iov.iov_base = (void *) data; iov.iov_len = len; @@ -2605,13 +2640,78 @@ static int sock_io_send(struct io *io, const void *data, size_t len) msg.msg_iov = &iov; msg.msg_iovlen = 1; - return sendmsg(io_get_fd(io), &msg, MSG_NOSIGNAL); + fd = io_get_fd(io); + if (fd < 0) { + error("io_get_fd() returned %d\n", fd); + return fd; + } + + return sendmsg(fd, &msg, MSG_NOSIGNAL); +} + +static void att_disconnect_cb(int err, void *user_data) +{ + struct client_io *client = user_data; + + /* If ATT is disconnected shutdown correspondent client IO so sock_hup + * is triggered and the server socket is closed. + */ + io_shutdown(client->io); +} + +static struct client_io * +client_io_new(struct external_chrc *chrc, int fd, struct bt_att *att) +{ + struct client_io *client; + + client = new0(struct client_io, 1); + client->att = bt_att_ref(att); + client->chrc = chrc; + client->disconn_id = bt_att_register_disconnect(att, att_disconnect_cb, + client, NULL); + client->io = sock_io_new(fd, chrc); + + return client; +} + +static bool match_client_att(const void *data, const void *user_data) +{ + const struct client_io *client = data; + const struct bt_att *att = user_data; + + /* Always match if ATT instance is not set since that is used by + * clear_cc_state to clear all instances. + */ + if (!att) + return true; + + return client->att == att; +} + +static struct client_io * +client_write_io_get(struct external_chrc *chrc, int fd, struct bt_att *att) +{ + struct client_io *client; + + client = queue_find(chrc->write_ios, match_client_att, att); + if (client) + return client; + + client = client_io_new(chrc, fd, att); + + if (!chrc->write_ios) + chrc->write_ios = queue_new(); + + queue_push_tail(chrc->write_ios, client); + + return client; } static void acquire_write_reply(DBusMessage *message, void *user_data) { struct pending_op *op = user_data; struct external_chrc *chrc; + struct client_io *client; DBusError err; int fd; uint16_t mtu; @@ -2636,6 +2736,7 @@ static void acquire_write_reply(DBusMessage *message, void *user_data) if (ecode != BT_ATT_ERROR_UNLIKELY) { gatt_db_attribute_write_result(op->attrib, op->id, ecode); + pending_op_free(op); return; } @@ -2651,10 +2752,12 @@ static void acquire_write_reply(DBusMessage *message, void *user_data) DBG("AcquireWrite success: fd %d MTU %u\n", fd, mtu); - chrc->write_io = sock_io_new(fd, chrc); + client = client_write_io_get(chrc, fd, op->att); + if (!client) + goto retry; while ((op = queue_peek_head(chrc->pending_writes)) != NULL) { - if (sock_io_send(chrc->write_io, op->data.iov_base, + if (sock_io_send(client->io, op->data.iov_base, op->data.iov_len) < 0) goto retry; @@ -2711,10 +2814,32 @@ static struct pending_op *acquire_write(struct external_chrc *chrc, return NULL; } +static struct client_io * +client_notify_io_get(struct external_chrc *chrc, int fd, struct bt_att *att) +{ + struct client_io *client; + + client = queue_find(chrc->notify_ios, match_client_att, att); + if (client) + return client; + + client = client_io_new(chrc, fd, att); + + io_set_read_handler(client->io, sock_io_read, client, NULL); + + if (!chrc->notify_ios) + chrc->notify_ios = queue_new(); + + queue_push_tail(chrc->notify_ios, client); + + return client; +} + static void acquire_notify_reply(DBusMessage *message, void *user_data) { struct pending_op *op = user_data; struct external_chrc *chrc = (void *) op->data.iov_base; + struct client_io *client; DBusError err; int fd; uint16_t mtu; @@ -2748,8 +2873,9 @@ static void acquire_notify_reply(DBusMessage *message, void *user_data) DBG("AcquireNotify success: fd %d MTU %u\n", fd, mtu); - chrc->notify_io = sock_io_new(fd, chrc); - io_set_read_handler(chrc->notify_io, sock_io_read, chrc, NULL); + client = client_notify_io_get(chrc, fd, op->att); + if (!client) + goto retry; __sync_fetch_and_add(&chrc->ntfy_cnt, 1); @@ -2782,6 +2908,7 @@ static void acquire_notify_setup(DBusMessageIter *iter, void *user_data) static uint8_t ccc_write_cb(struct pending_op *op, void *user_data) { struct external_chrc *chrc = user_data; + struct client_io *client; DBusMessageIter iter; uint16_t value; @@ -2794,14 +2921,16 @@ static uint8_t ccc_write_cb(struct pending_op *op, void *user_data) if (!chrc->ntfy_cnt) goto done; - if (__sync_sub_and_fetch(&chrc->ntfy_cnt, 1)) + client = queue_remove_if(chrc->notify_ios, match_client_att, + op ? op->att : NULL); + if (client) { + client_io_free(client); + __sync_sub_and_fetch(&chrc->ntfy_cnt, 1); goto done; + } - if (chrc->notify_io) { - io_destroy(chrc->notify_io); - chrc->notify_io = NULL; + if (__sync_sub_and_fetch(&chrc->ntfy_cnt, 1)) goto done; - } /* * Send request to stop notifying. This is best-effort @@ -2822,7 +2951,8 @@ static uint8_t ccc_write_cb(struct pending_op *op, void *user_data) (value == 2 && !(chrc->props & BT_GATT_CHRC_PROP_INDICATE))) return BT_ERROR_CCC_IMPROPERLY_CONFIGURED; - if (chrc->notify_io) { + client = queue_find(chrc->notify_ios, match_client_att, op->att); + if (client) { __sync_fetch_and_add(&chrc->ntfy_cnt, 1); goto done; } @@ -3123,6 +3253,7 @@ static void chrc_write_cb(struct gatt_db_attribute *attrib, void *user_data) { struct external_chrc *chrc = user_data; + struct client_io *client; struct btd_device *device; struct queue *queue; DBusMessageIter iter; @@ -3158,8 +3289,9 @@ static void chrc_write_cb(struct gatt_db_attribute *attrib, if (opcode == BT_ATT_OP_EXEC_WRITE_REQ) chrc->prep_authorized = false; - if (chrc->write_io) { - if (sock_io_send(chrc->write_io, value, len) < 0) { + client = queue_find(chrc->write_ios, match_client_att, att); + if (client) { + if (sock_io_send(client->io, value, len) < 0) { error("Unable to write: %s", strerror(errno)); goto fail; } @@ -3215,12 +3347,12 @@ static void database_add_includes(struct external_service *service) static bool database_add_chrc(struct external_service *service, struct external_chrc *chrc) { - uint16_t handle; + uint16_t handle = 0, value_handle; bt_uuid_t uuid; char str[MAX_LEN_UUID_STR]; const struct queue_entry *entry; - if (!parse_handle(chrc->proxy, &handle)) { + if (!parse_handle(chrc->proxy, &value_handle)) { error("Failed to read \"Handle\" property of characteristic"); return false; } @@ -3235,10 +3367,14 @@ static bool database_add_chrc(struct external_service *service, return false; } + if (value_handle) + handle = value_handle - 1; + chrc->attrib = gatt_db_service_insert_characteristic(service->attrib, - handle, &uuid, chrc->perm, - chrc->props, chrc_read_cb, - chrc_write_cb, chrc); + handle, value_handle, &uuid, + chrc->perm, chrc->props, + chrc_read_cb, chrc_write_cb, + chrc); if (!chrc->attrib) { error("Failed to create characteristic entry in database"); return false; @@ -3788,6 +3924,70 @@ static uint8_t server_authorize(struct bt_att *att, uint8_t opcode, return BT_ATT_ERROR_DB_OUT_OF_SYNC; } +static void eatt_confirm_cb(GIOChannel *io, gpointer data) +{ + char address[18]; + uint8_t dst_type; + bdaddr_t src, dst; + GError *gerr = NULL; + struct btd_device *device; + struct bt_gatt_server *server; + struct bt_att *att; + + bt_io_get(io, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src, + BT_IO_OPT_DEST_BDADDR, &dst, + BT_IO_OPT_DEST_TYPE, &dst_type, + BT_IO_OPT_DEST, address, + BT_IO_OPT_INVALID); + if (gerr) { + error("bt_io_get: %s", gerr->message); + g_error_free(gerr); + goto drop; + } + + DBG("New incoming EATT connection"); + + /* Confirm the device exists before accepting the connection, if the + * device is using an RPA it could be that the MGMT event has not been + * processed yet which would lead to create a second copy of the same + * device using its identity address. + */ + device = btd_adapter_find_device(adapter_find(&src), &dst, dst_type); + if (!device) { + error("Unable to find device: %s", address); + goto drop; + } + + /* Only allow EATT connection from central */ + if (btd_device_is_initiator(device)) { + warn("EATT connection from peripheral may cause collisions"); + goto drop; + } + + server = btd_device_get_gatt_server(device); + if (!server) { + error("Unable to resolve bt_server"); + goto drop; + } + + att = bt_gatt_server_get_att(server); + if (bt_att_get_channels(att) == btd_opts.gatt_channels) { + DBG("EATT channel limit reached"); + goto drop; + } + + if (!bt_io_accept(io, connect_cb, NULL, NULL, &gerr)) { + error("bt_io_accept: %s", gerr->message); + g_error_free(gerr); + goto drop; + } + + return; + +drop: + g_io_channel_shutdown(io, TRUE, NULL); +} + struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter) { struct btd_gatt_database *database; @@ -3824,14 +4024,14 @@ struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter) if (btd_opts.gatt_channels == 1) goto bredr; - /* EATT socket */ - database->eatt_io = bt_io_listen(connect_cb, NULL, NULL, NULL, + /* EATT socket, encryption is required */ + database->eatt_io = bt_io_listen(NULL, eatt_confirm_cb, NULL, NULL, &gerr, BT_IO_OPT_SOURCE_BDADDR, addr, BT_IO_OPT_SOURCE_TYPE, btd_adapter_get_address_type(adapter), BT_IO_OPT_PSM, BT_ATT_EATT_PSM, - BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, + BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_MTU, btd_opts.gatt_mtu, BT_IO_OPT_INVALID); if (!database->eatt_io) { diff --git a/src/genbuiltin b/src/genbuiltin index 8b6f047612ec62b9d9a38d62d1a29650be12315b..010e4ed2f0a069b3b5dfd36fed3121f0e48f6486 100755 --- a/src/genbuiltin +++ b/src/genbuiltin @@ -2,11 +2,11 @@ for i in $* do - echo "extern struct bluetooth_plugin_desc __bluetooth_builtin_$i;" + echo "extern const struct bluetooth_plugin_desc __bluetooth_builtin_$i;" done echo -echo "static struct bluetooth_plugin_desc *__bluetooth_builtin[] = {" +echo "static const struct bluetooth_plugin_desc *__bluetooth_builtin[] = {" for i in $* do diff --git a/src/log.c b/src/log.c index 0155a6bbafc87f26282ed2c70959d6f1a6b1c346..ca8ae2d0e8fdb679ad9d1041270d1c48f146cf33 100644 --- a/src/log.c +++ b/src/log.c @@ -123,7 +123,7 @@ extern struct btd_debug_desc __stop___debug[]; static char **enabled = NULL; -static gboolean is_enabled(struct btd_debug_desc *desc) +static gboolean is_enabled(const struct btd_debug_desc *desc) { int i; diff --git a/src/main.c b/src/main.c index 1d357161feec305694ba5cfd6609d9b549bcf640..41c3271a745753f3e5a705c7172ebb2645f02a28 100644 --- a/src/main.c +++ b/src/main.c @@ -22,6 +22,7 @@ #include <string.h> #include <signal.h> #include <stdbool.h> +#include <limits.h> #include <sys/signalfd.h> #include <sys/types.h> #include <sys/stat.h> @@ -43,6 +44,7 @@ #include "shared/mainloop.h" #include "shared/timeout.h" #include "shared/queue.h" +#include "shared/crypto.h" #include "lib/uuid.h" #include "shared/util.h" #include "btd.h" @@ -77,13 +79,16 @@ static const char *supported_options[] = { "NameResolving", "DebugKeys", "ControllerMode", - "MaxControllers" + "MaxControllers", "MultiProfile", "FastConnectable", + "SecureConnections", "Privacy", "JustWorksRepairing", "TemporaryTimeout", + "RefreshDiscovery", "Experimental", + "Testing", "KernelExperimental", "RemoteNameRequestRetryDelay", NULL @@ -142,6 +147,15 @@ static const char *gatt_options[] = { "KeySize", "ExchangeMTU", "Channels", + "Client", + NULL +}; + +static const char *csip_options[] = { + "SIRK", + "Encryption", + "Size", + "Rank", NULL }; @@ -151,6 +165,12 @@ static const char *avdtp_options[] = { NULL }; +static const char *avrcp_options[] = { + "VolumeWithoutTarget", + "VolumeCategory", + NULL +}; + static const char *advmon_options[] = { "RSSISamplingPeriod", NULL @@ -165,11 +185,56 @@ static const struct group_table { { "LE", le_options }, { "Policy", policy_options }, { "GATT", gatt_options }, + { "CSIS", csip_options }, { "AVDTP", avdtp_options }, + { "AVRCP", avrcp_options }, { "AdvMon", advmon_options }, { } }; +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#endif + +static int8_t check_sirk_alpha_numeric(char *str) +{ + int8_t val = 0; + char *s = str; + + if (strlen(s) != 32) /* 32 Bytes of Alpha numeric string */ + return 0; + + for ( ; *s; s++) { + if (((*s >= '0') & (*s <= '9')) + || ((*s >= 'a') && (*s <= 'z')) + || ((*s >= 'A') && (*s <= 'Z'))) { + val = 1; + } else { + val = 0; + break; + } + } + + return val; +} + +static size_t hex2bin(const char *hexstr, uint8_t *buf, size_t buflen) +{ + size_t i, len; + + if (!hexstr) + return 0; + + len = MIN((strlen(hexstr) / 2), buflen); + memset(buf, 0, len); + + for (i = 0; i < len; i++) { + if (sscanf(hexstr + (i * 2), "%02hhX", &buf[i]) != 1) + continue; + } + + return len; +} GKeyFile *btd_get_main_conf(void) { @@ -257,7 +322,7 @@ done: btd_opts.did_version = version; } -static bt_gatt_cache_t parse_gatt_cache(const char *cache) +static bt_gatt_cache_t parse_gatt_cache_str(const char *cache) { if (!strcmp(cache, "always")) { return BT_GATT_CACHE_ALWAYS; @@ -359,6 +424,69 @@ static int get_mode(const char *str) return BT_MODE_DUAL; } +static bool parse_config_string(GKeyFile *config, const char *group, + const char *key, char **val) +{ + GError *err = NULL; + char *tmp; + + tmp = g_key_file_get_string(config, group, key, &err); + if (err) { + if (err->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) + DBG("%s", err->message); + g_error_free(err); + return false; + } + + DBG("%s.%s = %s", group, key, tmp); + + if (val) { + g_free(*val); + *val = tmp; + } + + return true; +} + +static bool parse_config_int(GKeyFile *config, const char *group, + const char *key, int *val, + size_t min, size_t max) +{ + size_t tmp; + char *str = NULL; + char *endptr = NULL; + + if (!parse_config_string(config, group, key, &str)) + return false; + + tmp = strtol(str, &endptr, 0); + if (!endptr || *endptr != '\0') { + error("%s.%s = %s is not integer", group, key, str); + g_free(str); + return false; + } + + if (tmp < min) { + g_free(str); + warn("%s.%s = %zu is out of range (< %zu)", group, key, tmp, + min); + return false; + } + + if (tmp > max) { + g_free(str); + warn("%s.%s = %zu is out of range (> %zu)", group, key, tmp, + max); + return false; + } + + g_free(str); + if (val) + *val = tmp; + + return true; +} + struct config_param { const char * const val_name; void * const val; @@ -377,31 +505,15 @@ static void parse_mode_config(GKeyFile *config, const char *group, return; for (i = 0; i < params_len; ++i) { - GError *err = NULL; - char *str; - - str = g_key_file_get_string(config, group, params[i].val_name, - &err); - if (err) { - DBG("%s", err->message); - g_clear_error(&err); - } else { - char *endptr = NULL; - int val; - - val = strtol(str, &endptr, 0); - if (!endptr || *endptr != '\0') - continue; - - info("%s=%s(%d)", params[i].val_name, str, val); - - val = MAX(val, params[i].min); - val = MIN(val, params[i].max); + int val; + if (parse_config_int(config, group, params[i].val_name, + &val, params[i].min, params[i].max)) { val = htobl(val); memcpy(params[i].val, &val, params[i].size); - ++btd_opts.defaults.num_entries; } + + ++btd_opts.defaults.num_entries; } } @@ -651,330 +763,425 @@ static void btd_parse_kernel_experimental(char **list) } } -static void parse_config(GKeyFile *config) +static bool gen_sirk(const char *str) { - GError *err = NULL; - char *str, **strlist; - int val; - gboolean boolean; + struct bt_crypto *crypto; + int ret; - if (!config) - return; + crypto = bt_crypto_new(); + if (!crypto) { + error("Failed to open crypto"); + return false; + } - check_config(config); + ret = bt_crypto_sirk(crypto, str, btd_opts.did_vendor, + btd_opts.did_product, btd_opts.did_version, + btd_opts.did_source, btd_opts.csis.sirk); + if (!ret) + error("Failed to generate SIRK"); - DBG("parsing %s", main_conf_file_path); + bt_crypto_unref(crypto); + return ret; +} - val = g_key_file_get_integer(config, "General", - "DiscoverableTimeout", &err); - if (err) { - DBG("%s", err->message); - g_clear_error(&err); - } else { - DBG("discovto=%d", val); - btd_opts.discovto = val; - } +static bool parse_config_u32(GKeyFile *config, const char *group, + const char *key, uint32_t *val, + uint32_t min, uint32_t max) +{ + int tmp; - boolean = g_key_file_get_boolean(config, "General", - "AlwaysPairable", &err); - if (err) { - DBG("%s", err->message); - g_clear_error(&err); - } else { - DBG("pairable=%s", boolean ? "true" : "false"); - btd_opts.pairable = boolean; - } + if (!parse_config_int(config, group, key, &tmp, min, max)) + return false; + + if (val) + *val = tmp; + + return true; +} + +static bool parse_config_u16(GKeyFile *config, const char *group, + const char *key, uint16_t *val, + uint16_t min, uint16_t max) +{ + int tmp; + + if (!parse_config_int(config, group, key, &tmp, min, max)) + return false; + + if (val) + *val = tmp; + + return true; +} + +static bool parse_config_u8(GKeyFile *config, const char *group, + const char *key, uint8_t *val, + uint8_t min, uint8_t max) +{ + int tmp; + + if (!parse_config_int(config, group, key, &tmp, min, max)) + return false; + + if (val) + *val = tmp; + + return true; +} + +static bool parse_config_bool(GKeyFile *config, const char *group, + const char *key, bool *val) +{ + GError *err = NULL; + gboolean tmp; - val = g_key_file_get_integer(config, "General", - "PairableTimeout", &err); + tmp = g_key_file_get_boolean(config, group, key, &err); if (err) { - DBG("%s", err->message); - g_clear_error(&err); - } else { - DBG("pairto=%d", val); - btd_opts.pairto = val; + if (err->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) + DBG("%s", err->message); + g_error_free(err); + return false; } - str = g_key_file_get_string(config, "General", "Privacy", &err); - if (err) { - DBG("%s", err->message); - g_clear_error(&err); + DBG("%s.%s = %s", group, key, tmp ? "true" : "false"); + + if (val) + *val = tmp; + + return true; +} + +static void parse_privacy(GKeyFile *config) +{ + char *str = NULL; + + if (!parse_config_string(config, "General", "Privacy", &str)) { btd_opts.privacy = 0x00; btd_opts.device_privacy = true; - } else { - DBG("privacy=%s", str); - - if (!strcmp(str, "network") || !strcmp(str, "on")) { - btd_opts.privacy = 0x01; - } else if (!strcmp(str, "device")) { - btd_opts.privacy = 0x01; - btd_opts.device_privacy = true; - } else if (!strcmp(str, "limited-network")) { - if (btd_opts.mode != BT_MODE_DUAL) { - DBG("Invalid privacy option: %s", str); - btd_opts.privacy = 0x00; - } - btd_opts.privacy = 0x01; - } else if (!strcmp(str, "limited-device")) { - if (btd_opts.mode != BT_MODE_DUAL) { - DBG("Invalid privacy option: %s", str); - btd_opts.privacy = 0x00; - } - btd_opts.privacy = 0x02; - btd_opts.device_privacy = true; - } else if (!strcmp(str, "off")) { + return; + } + + if (!strcmp(str, "network") || !strcmp(str, "on")) { + btd_opts.privacy = 0x01; + } else if (!strcmp(str, "device")) { + btd_opts.privacy = 0x01; + btd_opts.device_privacy = true; + } else if (!strcmp(str, "limited-network")) { + if (btd_opts.mode != BT_MODE_DUAL) { + DBG("Invalid privacy option: %s", str); btd_opts.privacy = 0x00; - btd_opts.device_privacy = true; - } else { + } + btd_opts.privacy = 0x01; + } else if (!strcmp(str, "limited-device")) { + if (btd_opts.mode != BT_MODE_DUAL) { DBG("Invalid privacy option: %s", str); btd_opts.privacy = 0x00; } - - g_free(str); + btd_opts.privacy = 0x02; + btd_opts.device_privacy = true; + } else if (!strcmp(str, "off")) { + btd_opts.privacy = 0x00; + btd_opts.device_privacy = true; + } else { + DBG("Invalid privacy option: %s", str); + btd_opts.privacy = 0x00; } - str = g_key_file_get_string(config, "General", - "JustWorksRepairing", &err); - if (err) { - DBG("%s", err->message); - g_clear_error(&err); + g_free(str); +} + +static void parse_repairing(GKeyFile *config) +{ + char *str = NULL; + + if (!parse_config_string(config, "General", "JustWorksRepairing", + &str)) { btd_opts.jw_repairing = JW_REPAIRING_NEVER; - } else { - DBG("just_works_repairing=%s", str); - btd_opts.jw_repairing = parse_jw_repairing(str); - g_free(str); + return; } - val = g_key_file_get_integer(config, "General", - "TemporaryTimeout", &err); - if (err) { - DBG("%s", err->message); - g_clear_error(&err); - } else { - DBG("tmpto=%d", val); - btd_opts.tmpto = val; - } + btd_opts.jw_repairing = parse_jw_repairing(str); + g_free(str); +} - str = g_key_file_get_string(config, "General", "Name", &err); - if (err) { - DBG("%s", err->message); - g_clear_error(&err); - } else { - DBG("name=%s", str); - g_free(btd_opts.name); - btd_opts.name = str; - } +static bool parse_config_hex(GKeyFile *config, char *group, + const char *key, uint32_t *val) +{ + char *str = NULL; - str = g_key_file_get_string(config, "General", "Class", &err); - if (err) { - DBG("%s", err->message); - g_clear_error(&err); - } else { - DBG("class=%s", str); - btd_opts.class = strtol(str, NULL, 16); - g_free(str); - } + if (!parse_config_string(config, group, key, &str)) + return false; - str = g_key_file_get_string(config, "General", "DeviceID", &err); - if (err) { - DBG("%s", err->message); - g_clear_error(&err); - } else { - DBG("deviceid=%s", str); - parse_did(str); - g_free(str); - } + if (val) + *val = strtol(str, NULL, 16); - boolean = g_key_file_get_boolean(config, "General", - "ReverseServiceDiscovery", &err); - if (err) { - DBG("%s", err->message); - g_clear_error(&err); - } else - btd_opts.reverse_discovery = boolean; - - boolean = g_key_file_get_boolean(config, "General", - "NameResolving", &err); - if (err) - g_clear_error(&err); - else - btd_opts.name_resolv = boolean; + g_free(str); + return true; +} - boolean = g_key_file_get_boolean(config, "General", - "DebugKeys", &err); - if (err) - g_clear_error(&err); - else - btd_opts.debug_keys = boolean; +static void parse_device_id(GKeyFile *config) +{ + char *str = NULL; - str = g_key_file_get_string(config, "General", "ControllerMode", &err); - if (err) { - g_clear_error(&err); - } else { - DBG("ControllerMode=%s", str); - btd_opts.mode = get_mode(str); - g_free(str); - } + parse_config_string(config, "General", "DeviceID", &str); + if (!str) + return; - val = g_key_file_get_integer(config, "General", "MaxControllers", &err); - if (err) { - g_clear_error(&err); - } else { - DBG("MaxControllers=%d", val); - btd_opts.max_adapters = val; - } + parse_did(str); + g_free(str); +} - str = g_key_file_get_string(config, "General", "MultiProfile", &err); - if (err) { - g_clear_error(&err); - } else { - DBG("MultiProfile=%s", str); +static void parse_ctrl_mode(GKeyFile *config) +{ + char *str = NULL; - if (!strcmp(str, "single")) - btd_opts.mps = MPS_SINGLE; - else if (!strcmp(str, "multiple")) - btd_opts.mps = MPS_MULTIPLE; - else - btd_opts.mps = MPS_OFF; + parse_config_string(config, "General", "ControllerMode", &str); + if (!str) + return; - g_free(str); - } + btd_opts.mode = get_mode(str); + g_free(str); +} - boolean = g_key_file_get_boolean(config, "General", - "FastConnectable", &err); - if (err) - g_clear_error(&err); - else - btd_opts.fast_conn = boolean; +static void parse_multi_profile(GKeyFile *config) +{ + char *str = NULL; - boolean = g_key_file_get_boolean(config, "General", - "RefreshDiscovery", &err); - if (err) - g_clear_error(&err); - else - btd_opts.refresh_discovery = boolean; + parse_config_string(config, "General", "MultiProfile", &str); + if (!str) + return; - boolean = g_key_file_get_boolean(config, "General", "Experimental", - &err); - if (err) - g_clear_error(&err); + if (!strcmp(str, "single")) + btd_opts.mps = MPS_SINGLE; + else if (!strcmp(str, "multiple")) + btd_opts.mps = MPS_MULTIPLE; else - btd_opts.experimental = boolean; + btd_opts.mps = MPS_OFF; - strlist = g_key_file_get_string_list(config, "General", - "KernelExperimental", - NULL, &err); - if (err) - g_clear_error(&err); - else { + g_free(str); +} + +static gboolean parse_kernel_experimental(const char *key, const char *value, + gpointer user_data, GError **error) +{ + char **strlist; + + if (value && value[0] != '*') { + strlist = g_strsplit(value, ",", -1); btd_parse_kernel_experimental(strlist); g_strfreev(strlist); - } - - val = g_key_file_get_integer(config, "General", - "RemoteNameRequestRetryDelay", &err); - if (err) { - DBG("%s", err->message); - g_clear_error(&err); } else { - DBG("RemoteNameRequestRetryDelay=%d", val); - btd_opts.name_request_retry_delay = val; + if (!btd_opts.kernel) + btd_opts.kernel = queue_new(); + queue_push_head(btd_opts.kernel, strdup("*")); } - str = g_key_file_get_string(config, "GATT", "Cache", &err); - if (err) { - DBG("%s", err->message); - g_clear_error(&err); - } else { - btd_opts.gatt_cache = parse_gatt_cache(str); - g_free(str); - } + return TRUE; +} - val = g_key_file_get_integer(config, "GATT", "KeySize", &err); - if (err) { - DBG("%s", err->message); - g_clear_error(&err); - } else { - DBG("KeySize=%d", val); +static void parse_kernel_exp(GKeyFile *config) +{ + char *str = NULL; - if (val >=7 && val <= 16) - btd_opts.key_size = val; - } + if (!parse_config_string(config, "General", "KernelExperimental", + &str)) + return; - val = g_key_file_get_integer(config, "GATT", "ExchangeMTU", &err); - if (err) { - DBG("%s", err->message); - g_clear_error(&err); - } else { - /* Ensure the mtu is within a valid range. */ - val = MIN(val, BT_ATT_MAX_LE_MTU); - val = MAX(val, BT_ATT_DEFAULT_LE_MTU); - DBG("ExchangeMTU=%d", val); - btd_opts.gatt_mtu = val; - } + parse_kernel_experimental(NULL, str, NULL, NULL); - val = g_key_file_get_integer(config, "GATT", "Channels", &err); - if (err) { - DBG("%s", err->message); - g_clear_error(&err); - } else { - DBG("Channels=%d", val); - /* Ensure the channels is within a valid range. */ - val = MIN(val, 5); - val = MAX(val, 1); - btd_opts.gatt_channels = val; - } + g_free(str); +} - str = g_key_file_get_string(config, "AVDTP", "SessionMode", &err); - if (err) { - DBG("%s", err->message); - g_clear_error(&err); - } else { - DBG("SessionMode=%s", str); - - if (!strcmp(str, "basic")) - btd_opts.avdtp.session_mode = BT_IO_MODE_BASIC; - else if (!strcmp(str, "ertm")) - btd_opts.avdtp.session_mode = BT_IO_MODE_ERTM; - else { - DBG("Invalid mode option: %s", str); - btd_opts.avdtp.session_mode = BT_IO_MODE_BASIC; - } - g_free(str); - } +static void parse_secure_conns(GKeyFile *config) +{ + char *str = NULL; - str = g_key_file_get_string(config, "AVDTP", "StreamMode", &err); - if (err) { - DBG("%s", err->message); - g_clear_error(&err); - } else { - DBG("StreamMode=%s", str); - - if (!strcmp(str, "basic")) - btd_opts.avdtp.stream_mode = BT_IO_MODE_BASIC; - else if (!strcmp(str, "streaming")) - btd_opts.avdtp.stream_mode = BT_IO_MODE_STREAMING; - else { - DBG("Invalid mode option: %s", str); - btd_opts.avdtp.stream_mode = BT_IO_MODE_BASIC; - } - g_free(str); + if (!parse_config_string(config, "General", "SecureConnections", + &str)) + return; + + if (!strcmp(str, "off")) + btd_opts.secure_conn = SC_OFF; + else if (!strcmp(str, "on")) + btd_opts.secure_conn = SC_ON; + else if (!strcmp(str, "only")) + btd_opts.secure_conn = SC_ONLY; + + g_free(str); +} + +static void parse_general(GKeyFile *config) +{ + parse_config_string(config, "General", "Name", &btd_opts.name); + parse_config_hex(config, "General", "Class", &btd_opts.class); + parse_config_u32(config, "General", "DiscoverableTimeout", + &btd_opts.discovto, + 0, UINT32_MAX); + parse_config_bool(config, "General", "AlwaysPairable", + &btd_opts.pairable); + parse_config_u32(config, "General", "PairableTimeout", + &btd_opts.pairto, + 0, UINT32_MAX); + parse_device_id(config); + parse_config_bool(config, "General", "ReverseServiceDiscovery", + &btd_opts.reverse_discovery); + parse_config_bool(config, "General", "NameResolving", + &btd_opts.name_resolv); + parse_config_bool(config, "General", "DebugKeys", + &btd_opts.debug_keys); + parse_ctrl_mode(config); + parse_config_u16(config, "General", "MaxControllers", + &btd_opts.max_adapters, + 0, UINT16_MAX); + parse_multi_profile(config); + parse_config_bool(config, "General", "FastConnectable", + &btd_opts.fast_conn); + parse_privacy(config); + parse_repairing(config); + parse_config_u32(config, "General", "TemporaryTimeout", + &btd_opts.tmpto, + 0, UINT32_MAX); + parse_config_bool(config, "General", "RefreshDiscovery", + &btd_opts.refresh_discovery); + parse_secure_conns(config); + parse_config_bool(config, "General", "Experimental", + &btd_opts.experimental); + parse_config_bool(config, "General", "Testing", + &btd_opts.testing); + parse_kernel_exp(config); + parse_config_u32(config, "General", "RemoteNameRequestRetryDelay", + &btd_opts.name_request_retry_delay, + 0, UINT32_MAX); +} + +static void parse_gatt_cache(GKeyFile *config) +{ + char *str = NULL; + + parse_config_string(config, "GATT", "Cache", &str); + if (!str) + return; + + btd_opts.gatt_cache = parse_gatt_cache_str(str); + g_free(str); +} + +static void parse_gatt(GKeyFile *config) +{ + parse_gatt_cache(config); + parse_config_u8(config, "GATT", "KeySize", &btd_opts.key_size, 7, 16); + parse_config_u16(config, "GATT", "ExchangeMTU", &btd_opts.gatt_mtu, + BT_ATT_DEFAULT_LE_MTU, BT_ATT_MAX_LE_MTU); + parse_config_u8(config, "GATT", "Channels", &btd_opts.gatt_channels, + 1, 5); + parse_config_bool(config, "GATT", "Client", &btd_opts.gatt_client); +} + +static void parse_csis_sirk(GKeyFile *config) +{ + char *str = NULL; + + if (!parse_config_string(config, "CSIS", "SIRK", &str)) + return; + + if (strlen(str) == 32 && check_sirk_alpha_numeric(str)) + hex2bin(str, btd_opts.csis.sirk, sizeof(btd_opts.csis.sirk)); + else if (!gen_sirk(str)) + DBG("Unable to generate SIRK from string"); + + g_free(str); +} + +static void parse_csis(GKeyFile *config) +{ + parse_csis_sirk(config); + parse_config_bool(config, "CSIS", "Encryption", + &btd_opts.csis.encrypt); + parse_config_u8(config, "CSIS", "Size", &btd_opts.csis.size, + 0, UINT8_MAX); + parse_config_u8(config, "CSIS", "Rank", &btd_opts.csis.rank, + 0, UINT8_MAX); +} + +static void parse_avdtp_session_mode(GKeyFile *config) +{ + char *str = NULL; + + if (!parse_config_string(config, "AVDTP", "SessionMode", &str)) + return; + + if (!strcmp(str, "basic")) + btd_opts.avdtp.session_mode = BT_IO_MODE_BASIC; + else if (!strcmp(str, "ertm")) + btd_opts.avdtp.session_mode = BT_IO_MODE_ERTM; + else { + DBG("Invalid mode option: %s", str); + btd_opts.avdtp.session_mode = BT_IO_MODE_BASIC; } - val = g_key_file_get_integer(config, "AdvMon", "RSSISamplingPeriod", - &err); - if (err) { - DBG("%s", err->message); - g_clear_error(&err); - } else { - val = MIN(val, 0xFF); - val = MAX(val, 0); - DBG("RSSISamplingPeriod=%d", val); - btd_opts.advmon.rssi_sampling_period = val; + g_free(str); +} + +static void parse_avdtp_stream_mode(GKeyFile *config) +{ + char *str = NULL; + + if (!parse_config_string(config, "AVDTP", "StreamMode", &str)) + return; + + if (!strcmp(str, "basic")) + btd_opts.avdtp.stream_mode = BT_IO_MODE_BASIC; + else if (!strcmp(str, "streaming")) + btd_opts.avdtp.stream_mode = BT_IO_MODE_STREAMING; + else { + DBG("Invalid mode option: %s", str); + btd_opts.avdtp.stream_mode = BT_IO_MODE_BASIC; } + g_free(str); +} + +static void parse_avdtp(GKeyFile *config) +{ + parse_avdtp_session_mode(config); + parse_avdtp_stream_mode(config); +} + +static void parse_avrcp(GKeyFile *config) +{ + parse_config_bool(config, "AVRCP", + "VolumeWithoutTarget", + &btd_opts.avrcp.volume_without_target); + parse_config_bool(config, "AVRCP", + "VolumeCategory", + &btd_opts.avrcp.volume_category); +} + +static void parse_advmon(GKeyFile *config) +{ + parse_config_u8(config, "AdvMon", "RSSISamplingPeriod", + &btd_opts.advmon.rssi_sampling_period, + 0, UINT8_MAX); +} + +static void parse_config(GKeyFile *config) +{ + if (!config) + return; + + check_config(config); + + DBG("parsing %s", main_conf_file_path); + + /* Parse Groups */ + parse_general(config); parse_br_config(config); parse_le_config(config); + parse_gatt(config); + parse_csis(config); + parse_avdtp(config); + parse_avrcp(config); + parse_advmon(config); } static void init_defaults(void) @@ -993,6 +1200,7 @@ static void init_defaults(void) btd_opts.debug_keys = FALSE; btd_opts.refresh_discovery = TRUE; btd_opts.name_request_retry_delay = DEFAULT_NAME_REQUEST_RETRY_DELAY; + btd_opts.secure_conn = SC_ON; btd_opts.defaults.num_entries = 0; btd_opts.defaults.br.page_scan_type = 0xFFFF; @@ -1009,12 +1217,17 @@ static void init_defaults(void) btd_opts.gatt_cache = BT_GATT_CACHE_ALWAYS; btd_opts.gatt_mtu = BT_ATT_MAX_LE_MTU; - btd_opts.gatt_channels = 3; + btd_opts.gatt_channels = 1; + btd_opts.gatt_client = true; btd_opts.avdtp.session_mode = BT_IO_MODE_BASIC; btd_opts.avdtp.stream_mode = BT_IO_MODE_BASIC; + btd_opts.avrcp.volume_without_target = false; + btd_opts.avrcp.volume_category = true; + btd_opts.advmon.rssi_sampling_period = 0xFF; + btd_opts.csis.encrypt = true; } static void log_handler(const gchar *log_domain, GLogLevelFlags log_level, @@ -1109,6 +1322,11 @@ static void disconnected_dbus(DBusConnection *conn, void *data) mainloop_quit(); } +static void dbus_debug(const char *str, void *data) +{ + DBG_IDX(0xffff, "%s", str); +} + static int connect_dbus(void) { DBusConnection *conn; @@ -1130,6 +1348,7 @@ static int connect_dbus(void) g_dbus_set_disconnect_function(conn, disconnected_dbus, NULL, NULL); g_dbus_attach_object_manager(conn); + g_dbus_set_debug(dbus_debug, NULL, NULL); return 0; } @@ -1145,24 +1364,6 @@ static gboolean parse_debug(const char *key, const char *value, return TRUE; } -static gboolean parse_kernel_experimental(const char *key, const char *value, - gpointer user_data, GError **error) -{ - char **strlist; - - if (value) { - strlist = g_strsplit(value, ",", -1); - btd_parse_kernel_experimental(strlist); - g_strfreev(strlist); - } else { - if (!btd_opts.kernel) - btd_opts.kernel = queue_new(); - queue_push_head(btd_opts.kernel, strdup("*")); - } - - return TRUE; -} - static GOptionEntry options[] = { { "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, parse_debug, @@ -1177,6 +1378,8 @@ static GOptionEntry options[] = { "Provide deprecated command line interfaces" }, { "experimental", 'E', 0, G_OPTION_ARG_NONE, &btd_opts.experimental, "Enable experimental D-Bus interfaces" }, + { "testing", 'T', 0, G_OPTION_ARG_NONE, &btd_opts.testing, + "Enable testing D-Bus interfaces" }, { "kernel", 'K', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, parse_kernel_experimental, "Enable kernel experimental features" }, @@ -1243,6 +1446,9 @@ int main(int argc, char *argv[]) if (btd_opts.experimental) gdbus_flags = G_DBUS_FLAG_ENABLE_EXPERIMENTAL; + if (btd_opts.testing) + gdbus_flags |= G_DBUS_FLAG_ENABLE_TESTING; + g_dbus_set_flags(gdbus_flags); if (adapter_init() < 0) { diff --git a/src/main.conf b/src/main.conf index 2796f155ebaab60fb491573eee6374074f60efe2..fff13ed2ff3124547a001649c384b525f528f164 100644 --- a/src/main.conf +++ b/src/main.conf @@ -33,7 +33,7 @@ # us. For BR/EDR this option is really only needed for qualification since the # BITE tester doesn't like us doing reverse SDP for some test cases, for LE # this disables the GATT client functionally so it can be used in system which -# can only operate as peripheral. +# can only operate as peripheral (see also GATT Client option). # Defaults to 'true'. #ReverseServiceDiscovery = true @@ -111,10 +111,25 @@ # profile is connected. Defaults to true. #RefreshDiscovery = true +# Default Secure Connections setting. +# Enables the Secure Connections setting for adapters that support it. It +# provides better crypto algorithms for BT links and also enables CTKD (cross +# transport key derivation) during pairing on any link. +# Possible values: "off", "on", "only" +# - "off": Secure Connections are disabled +# - "on": Secure Connections are enabled when peer device supports them +# - "only": we allow only Secure Connections +# Defaults to "on" +#SecureConnections = on + # Enables D-Bus experimental interfaces # Possible values: true or false #Experimental = false +# Enables D-Bus testing interfaces +# Possible values: true or false +#Testing = false + # Enables kernel experimental features, alternatively a list of UUIDs # can be given. # Possible values: true,false,<UUID List> @@ -244,8 +259,38 @@ # Number of ATT channels # Possible values: 1-5 (1 disables EATT) -# Default to 3 -#Channels = 3 +# Default to 1 +#Channels = 1 + +[CSIS] +# SIRK - Set Identification Resolution Key which is common for all the +# sets. They SIRK key is used to identify its sets. This can be any +# 128 bit value or a string value (e.g. product name) which is then hashed. +# Possible Values: +# 16 byte hexadecimal value: 861FAE703ED681F0C50B34155B6434FB +# String value: "My Product Name" +# Defaults to none +#SIRK = + +# SIRK Encryption +# Possible values: +# true: Encrypt SIRK when read +# false: Do not encrypt SIRK when read. (plaintext) +# Defaults to true +#Encryption = true + +# Total no of sets belongs to this Profile +# Defaults to 0 +#Size = 0 + +# Rank for the device +# Defaults to 0 +#Rank = 0 + +# This enables the GATT client functionally, so it can be disabled in system +# which can only operate as a peripheral. +# Defaults to 'true'. +#Client = true [AVDTP] # AVDTP L2CAP Signalling Channel Mode. @@ -260,6 +305,17 @@ # streaming: Use L2CAP Streaming Mode #StreamMode = basic +[AVRCP] +# Allow SetAbsoluteVolume calls to a peer device that does not advertise the +# AVRCP remote control target profile. If it does advertise this profile, the +# version is ignored. +#VolumeWithoutTarget = false + +# Validate that remote AVRCP profiles advertise the category-2 bit before +# allowing SetAbsoluteVolume calls or registering for EVENT_VOLUME_CHANGED +# notifications. +#VolumeCategory = true + [Policy] # # The ReconnectUUIDs defines the set of remote services that should try diff --git a/src/oui.c b/src/oui.c index c434f416f0547661a777995472b234c009cc27d6..7b3040fb07bd30b899db437611c21f69c361376f 100644 --- a/src/oui.c +++ b/src/oui.c @@ -16,7 +16,7 @@ #include "lib/bluetooth.h" #include "oui.h" -#ifdef HAVE_UDEV_HWDB_NEW +#ifdef HAVE_UDEV #include <libudev.h> char *batocomp(const bdaddr_t *ba) diff --git a/src/plugin.c b/src/plugin.c index dd7b406c857bc12670e83c8ab7310a952dc18efb..e6d05be4ce0858b53b22205ab8901851f0e5eff0 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -26,12 +26,13 @@ #include "src/log.h" #include "src/btd.h" +#define IS_ENABLED(x) (x) + static GSList *plugins = NULL; struct bluetooth_plugin { void *handle; - gboolean active; - struct bluetooth_plugin_desc *desc; + const struct bluetooth_plugin_desc *desc; }; static int compare_priority(gconstpointer a, gconstpointer b) @@ -42,7 +43,24 @@ static int compare_priority(gconstpointer a, gconstpointer b) return plugin2->desc->priority - plugin1->desc->priority; } -static gboolean add_plugin(void *handle, struct bluetooth_plugin_desc *desc) +static int init_plugin(const struct bluetooth_plugin_desc *desc) +{ + int err; + + err = desc->init(); + if (err < 0) { + if (err == -ENOSYS || err == -ENOTSUP) + warn("System does not support %s plugin", + desc->name); + else + error("Failed to init %s plugin", + desc->name); + } + return err; +} + +static gboolean add_external_plugin(void *handle, + const struct bluetooth_plugin_desc *desc) { struct bluetooth_plugin *plugin; @@ -54,23 +72,47 @@ static gboolean add_plugin(void *handle, struct bluetooth_plugin_desc *desc) return FALSE; } - DBG("Loading %s plugin", desc->name); - plugin = g_try_new0(struct bluetooth_plugin, 1); if (plugin == NULL) return FALSE; plugin->handle = handle; - plugin->active = FALSE; plugin->desc = desc; + if (init_plugin(desc) < 0) { + g_free(plugin); + return FALSE; + } + __btd_enable_debug(desc->debug_start, desc->debug_stop); plugins = g_slist_insert_sorted(plugins, plugin, compare_priority); + DBG("Plugin %s loaded", desc->name); return TRUE; } +static void add_plugin(const struct bluetooth_plugin_desc *desc) +{ + struct bluetooth_plugin *plugin; + + DBG("Loading %s plugin", desc->name); + + plugin = g_try_new0(struct bluetooth_plugin, 1); + if (plugin == NULL) + return; + + plugin->desc = desc; + + if (init_plugin(desc) < 0) { + g_free(plugin); + return; + } + + plugins = g_slist_insert_sorted(plugins, plugin, compare_priority); + DBG("Plugin %s loaded", desc->name); +} + static gboolean enable_plugin(const char *name, char **cli_enable, char **cli_disable) { @@ -97,51 +139,26 @@ static gboolean enable_plugin(const char *name, char **cli_enable, return TRUE; } -#include "src/builtin.h" -gboolean plugin_init(const char *enable, const char *disable) +static void external_plugin_init(char **cli_disabled, char **cli_enabled) { - GSList *list; GDir *dir; const char *file; - char **cli_disabled, **cli_enabled; - unsigned int i; - /* Make a call to BtIO API so its symbols got resolved before the - * plugins are loaded. */ - bt_io_error_quark(); - - if (enable) - cli_enabled = g_strsplit_set(enable, ", ", -1); - else - cli_enabled = NULL; - - if (disable) - cli_disabled = g_strsplit_set(disable, ", ", -1); - else - cli_disabled = NULL; - - DBG("Loading builtin plugins"); - - for (i = 0; __bluetooth_builtin[i]; i++) { - if (!enable_plugin(__bluetooth_builtin[i]->name, cli_enabled, - cli_disabled)) - continue; - - add_plugin(NULL, __bluetooth_builtin[i]); - } + info("Using external plugins is not officially supported.\n"); + info("Consider upstreaming your plugins into the BlueZ project."); if (strlen(PLUGINDIR) == 0) - goto start; + return; DBG("Loading plugins %s", PLUGINDIR); dir = g_dir_open(PLUGINDIR, 0, NULL); if (!dir) - goto start; + return; while ((file = g_dir_read_name(dir)) != NULL) { - struct bluetooth_plugin_desc *desc; + const struct bluetooth_plugin_desc *desc; void *handle; char *filename; @@ -173,35 +190,46 @@ gboolean plugin_init(const char *enable, const char *disable) continue; } - if (add_plugin(handle, desc) == FALSE) + if (add_external_plugin(handle, desc) == FALSE) dlclose(handle); } g_dir_close(dir); +} -start: - for (list = plugins; list; list = list->next) { - struct bluetooth_plugin *plugin = list->data; - int err; - - err = plugin->desc->init(); - if (err < 0) { - if (err == -ENOSYS) - warn("System does not support %s plugin", - plugin->desc->name); - else - error("Failed to init %s plugin", - plugin->desc->name); +#include "src/builtin.h" + +void plugin_init(const char *enable, const char *disable) +{ + char **cli_disabled = NULL; + char **cli_enabled = NULL; + unsigned int i; + + /* Make a call to BtIO API so its symbols got resolved before the + * plugins are loaded. */ + bt_io_error_quark(); + + if (enable) + cli_enabled = g_strsplit_set(enable, ", ", -1); + + if (disable) + cli_disabled = g_strsplit_set(disable, ", ", -1); + + DBG("Loading builtin plugins"); + + for (i = 0; __bluetooth_builtin[i]; i++) { + if (!enable_plugin(__bluetooth_builtin[i]->name, cli_enabled, + cli_disabled)) continue; - } - plugin->active = TRUE; + add_plugin(__bluetooth_builtin[i]); } + if IS_ENABLED(EXTERNAL_PLUGINS) + external_plugin_init(cli_enabled, cli_disabled); + g_strfreev(cli_enabled); g_strfreev(cli_disabled); - - return TRUE; } void plugin_cleanup(void) @@ -213,7 +241,7 @@ void plugin_cleanup(void) for (list = plugins; list; list = list->next) { struct bluetooth_plugin *plugin = list->data; - if (plugin->active == TRUE && plugin->desc->exit) + if (plugin->desc->exit) plugin->desc->exit(); if (plugin->handle != NULL) diff --git a/src/plugin.h b/src/plugin.h index a5f92a557f6ea7e826c705d425938af38365252f..b484ed37874ee317b6ded672ed0e0346da7fd944 100644 --- a/src/plugin.h +++ b/src/plugin.h @@ -23,19 +23,25 @@ struct bluetooth_plugin_desc { #ifdef BLUETOOTH_PLUGIN_BUILTIN #define BLUETOOTH_PLUGIN_DEFINE(name, version, priority, init, exit) \ - struct bluetooth_plugin_desc __bluetooth_builtin_ ## name = { \ + const struct bluetooth_plugin_desc \ + __bluetooth_builtin_ ## name = { \ #name, version, priority, init, exit \ }; #else +#if EXTERNAL_PLUGINS #define BLUETOOTH_PLUGIN_DEFINE(name, version, priority, init, exit) \ extern struct btd_debug_desc __start___debug[] \ __attribute__ ((weak, visibility("hidden"))); \ extern struct btd_debug_desc __stop___debug[] \ __attribute__ ((weak, visibility("hidden"))); \ - extern struct bluetooth_plugin_desc bluetooth_plugin_desc \ + extern const struct bluetooth_plugin_desc \ + bluetooth_plugin_desc \ __attribute__ ((visibility("default"))); \ - struct bluetooth_plugin_desc bluetooth_plugin_desc = { \ + const struct bluetooth_plugin_desc bluetooth_plugin_desc = { \ #name, version, priority, init, exit, \ __start___debug, __stop___debug \ }; +#else +#error "Requested non built-in plugin, while external plugins is disabled" +#endif #endif diff --git a/src/profile.c b/src/profile.c index e1bebf1ee19c5e646a88e198426e7e6adf9e5dee..c62224af9dd84796662a255c869805bc0065075f 100644 --- a/src/profile.c +++ b/src/profile.c @@ -775,6 +775,18 @@ static struct btd_profile *btd_profile_find_uuid(const char *uuid) int btd_profile_register(struct btd_profile *profile) { + if (profile->experimental && !(g_dbus_get_flags() & + G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) { + DBG("D-Bus experimental not enabled"); + return -ENOTSUP; + } + + if (profile->testing && !(g_dbus_get_flags() & + G_DBUS_FLAG_ENABLE_TESTING)) { + DBG("D-Bus testing not enabled"); + return -ENOTSUP; + } + profiles = g_slist_append(profiles, profile); return 0; } diff --git a/src/profile.h b/src/profile.h index 6827f848148c153e77d5f4c3c67cf5234c824235..424ce55ad65748ead13b1a38d67fbad6beb2b828 100644 --- a/src/profile.h +++ b/src/profile.h @@ -28,6 +28,16 @@ struct btd_profile { */ bool external; + /* Indicates the profile is experimental and shall only be registered + * when experimental has been enabled (see: main.conf:Experimental). + */ + bool experimental; + + /* Indicates the profile for testing only and shall only be registered + * when testing has been enabled (see: main.conf:Testing). + */ + bool testing; + int (*device_probe) (struct btd_service *service); void (*device_remove) (struct btd_service *service); diff --git a/src/rfkill.c b/src/rfkill.c index a0a50d9e45d94887645640729ad0d76741c347c5..88cad1c9e19dc4d9cc04a01a4fa91b55e4042088 100644 --- a/src/rfkill.c +++ b/src/rfkill.c @@ -20,6 +20,7 @@ #include <stdint.h> #include <stdlib.h> #include <string.h> +#include <limits.h> #include <glib.h> @@ -55,7 +56,7 @@ struct rfkill_event { }; #define RFKILL_EVENT_SIZE_V1 8 -static int get_adapter_id_for_rfkill(int rfkill_id) +static int get_adapter_id_for_rfkill(uint32_t rfkill_id) { char sysname[PATH_MAX]; int namefd; diff --git a/src/set.c b/src/set.c new file mode 100644 index 0000000000000000000000000000000000000000..4ca2f78c37020fcf5192f38780240b70a91099f5 --- /dev/null +++ b/src/set.c @@ -0,0 +1,393 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2023 Intel Corporation + * + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdbool.h> +#include <errno.h> + +#include <glib.h> +#include <dbus/dbus.h> + +#include "gdbus/gdbus.h" +#include "src/shared/util.h" +#include "src/shared/queue.h" +#include "src/shared/ad.h" +#include "src/shared/crypto.h" +#include "src/shared/att.h" +#include "src/shared/gatt-db.h" + +#include "log.h" +#include "error.h" +#include "adapter.h" +#include "device.h" +#include "dbus-common.h" +#include "set.h" + +static struct queue *set_list; + +struct btd_device_set { + struct btd_adapter *adapter; + char *path; + uint8_t sirk[16]; + uint8_t size; + bool auto_connect; + struct queue *devices; + struct btd_device *device; +}; + +static DBusMessage *set_disconnect(DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + /* TODO */ + return NULL; +} + +static DBusMessage *set_connect(DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + /* TODO */ + return NULL; +} + +static const GDBusMethodTable set_methods[] = { + { GDBUS_EXPERIMENTAL_ASYNC_METHOD("Disconnect", NULL, NULL, + set_disconnect) }, + { GDBUS_EXPERIMENTAL_ASYNC_METHOD("Connect", NULL, NULL, + set_connect) }, + {} +}; + +static gboolean get_adapter(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct btd_device_set *set = data; + const char *path = adapter_get_path(set->adapter); + + dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path); + + return TRUE; +} + +static gboolean get_auto_connect(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct btd_device_set *set = data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, + &set->auto_connect); + + return TRUE; +} + +static void set_auto_connect(const GDBusPropertyTable *property, + DBusMessageIter *iter, + GDBusPendingPropertySet id, void *data) +{ + struct btd_device_set *set = data; + dbus_bool_t b; + + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN) { + g_dbus_pending_property_error(id, + ERROR_INTERFACE ".InvalidArguments", + "Invalid arguments in method call"); + return; + } + + dbus_message_iter_get_basic(iter, &b); + + set->auto_connect = b ? true : false; + + g_dbus_pending_property_success(id); +} + +static void append_device(void *data, void *user_data) +{ + struct btd_device *device = data; + const char *path = device_get_path(device); + DBusMessageIter *entry = user_data; + + dbus_message_iter_append_basic(entry, DBUS_TYPE_OBJECT_PATH, &path); +} + +static gboolean get_devices(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct btd_device_set *set = data; + DBusMessageIter entry; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_OBJECT_PATH_AS_STRING, + &entry); + + queue_foreach(set->devices, append_device, &entry); + + dbus_message_iter_close_container(iter, &entry); + + return TRUE; +} + +static gboolean get_size(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct btd_device_set *set = data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE, &set->size); + + return TRUE; +} + +static const GDBusPropertyTable set_properties[] = { + { "Adapter", "o", get_adapter, NULL, NULL, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { "AutoConnect", "b", get_auto_connect, set_auto_connect, NULL, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { "Devices", "ao", get_devices, NULL, NULL, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + { "Size", "y", get_size, NULL, NULL, + G_DBUS_PROPERTY_FLAG_EXPERIMENTAL }, + {} +}; + +static void set_free(void *data) +{ + struct btd_device_set *set = data; + + queue_destroy(set->devices, NULL); + g_free(set->path); + free(set); +} + +static struct btd_device_set *set_new(struct btd_device *device, + const uint8_t sirk[16], uint8_t size) +{ + struct btd_device_set *set; + + set = new0(struct btd_device_set, 1); + set->adapter = device_get_adapter(device); + memcpy(set->sirk, sirk, sizeof(set->sirk)); + set->size = size; + set->auto_connect = true; + set->devices = queue_new(); + queue_push_tail(set->devices, device); + set->path = g_strdup_printf("%s/set_%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x", + adapter_get_path(set->adapter), + sirk[15], sirk[14], sirk[13], sirk[12], + sirk[11], sirk[10], sirk[9], sirk[8], + sirk[7], sirk[6], sirk[5], sirk[4], + sirk[3], sirk[2], sirk[1], sirk[0]); + + DBG("Creating set %s", set->path); + + if (g_dbus_register_interface(btd_get_dbus_connection(), + set->path, BTD_DEVICE_SET_INTERFACE, + set_methods, NULL, + set_properties, set, + set_free) == FALSE) { + error("Unable to register set interface"); + set_free(set); + return NULL; + } + + return set; +} + +static struct btd_device_set *set_find(struct btd_device *device, + const uint8_t sirk[16]) +{ + struct btd_adapter *adapter = device_get_adapter(device); + const struct queue_entry *entry; + + for (entry = queue_get_entries(set_list); entry; entry = entry->next) { + struct btd_device_set *set = entry->data; + + if (set->adapter != adapter) + continue; + + if (!memcmp(set->sirk, sirk, sizeof(set->sirk))) + return set; + } + + return NULL; +} + +static void set_connect_next(struct btd_device_set *set) +{ + const struct queue_entry *entry; + + for (entry = queue_get_entries(set->devices); entry; + entry = entry->next) { + struct btd_device *device = entry->data; + + /* Only connect one at time(?) */ + if (!device_connect_le(device)) + return; + } +} + +static void set_add(struct btd_device_set *set, struct btd_device *device) +{ + /* Check if device is already part of the set then skip to connect */ + if (queue_find(set->devices, NULL, device)) + goto done; + + DBG("set %s device %s", set->path, device_get_path(device)); + + queue_push_tail(set->devices, device); + g_dbus_emit_property_changed(btd_get_dbus_connection(), set->path, + BTD_DEVICE_SET_INTERFACE, "Devices"); + +done: + /* Check if set is marked to auto-connect */ + if (btd_device_is_connected(device) && set->auto_connect) + set_connect_next(set); +} + +static void foreach_rsi(void *data, void *user_data) +{ + struct bt_ad_data *ad = data; + struct btd_device_set *set = user_data; + struct bt_crypto *crypto; + uint8_t res[3]; + + if (ad->type != BT_AD_CSIP_RSI || ad->len < 6) + return; + + crypto = bt_crypto_new(); + if (!crypto) + return; + + if (!bt_crypto_sih(crypto, set->sirk, ad->data + 3, res)) { + bt_crypto_unref(crypto); + return; + } + + bt_crypto_unref(crypto); + + if (memcmp(ad->data, res, sizeof(res))) + return; + + /* Attempt to use existing gatt_db from set if device has never been + * connected before. + * + * If dbs don't really match bt_gatt_client will attempt to rediscover + * the ranges that don't match. + */ + if (gatt_db_isempty(btd_device_get_gatt_db(set->device))) { + struct btd_device *device; + + device = queue_get_entries(set->devices)->data; + btd_device_set_gatt_db(set->device, + btd_device_get_gatt_db(device)); + } + + device_connect_le(set->device); +} + +static void foreach_device(struct btd_device *device, void *data) +{ + struct btd_device_set *set = data; + + /* Check if device is already part of the set then skip */ + if (queue_find(set->devices, NULL, device)) + return; + + set->device = device; + + btd_device_foreach_ad(device, foreach_rsi, set); +} + +struct btd_device_set *btd_set_add_device(struct btd_device *device, + const uint8_t *key, + const uint8_t sirk_value[16], + uint8_t size) +{ + struct btd_device_set *set; + uint8_t sirk[16]; + + memcpy(sirk, sirk_value, sizeof(sirk)); + + /* In case key has been set it means SIRK is encrypted */ + if (key) { + struct bt_crypto *crypto = bt_crypto_new(); + + if (!crypto) + return NULL; + + /* sef and sdf are symmetric */ + bt_crypto_sef(crypto, key, sirk, sirk); + + bt_crypto_unref(crypto); + } + + /* Check if DeviceSet already exists */ + set = set_find(device, sirk); + if (set) { + set_add(set, device); + /* Check if there are new devices with RSI found */ + goto done; + } + + set = set_new(device, sirk, size); + if (!set) + return NULL; + + if (!set_list) + set_list = queue_new(); + + queue_push_tail(set_list, set); + +done: + /* Attempt to add devices which have matching RSI */ + btd_adapter_for_each_device(device_get_adapter(device), foreach_device, + set); + + return set; +} + +bool btd_set_remove_device(struct btd_device_set *set, + struct btd_device *device) +{ + if (!set || !device) + return false; + + if (!queue_remove_if(set->devices, NULL, device)) + return false; + + if (!queue_isempty(set->devices)) { + g_dbus_emit_property_changed(btd_get_dbus_connection(), + set->path, + BTD_DEVICE_SET_INTERFACE, + "Devices"); + return true; + } + + if (!queue_remove(set_list, set)) + return false; + + /* Unregister if there are no devices left in the set */ + g_dbus_unregister_interface(btd_get_dbus_connection(), set->path, + BTD_DEVICE_SET_INTERFACE); + + return true; +} + +const char *btd_set_get_path(struct btd_device_set *set) +{ + return set->path; +} diff --git a/src/set.h b/src/set.h new file mode 100644 index 0000000000000000000000000000000000000000..2307218c4a0bb5af9ae8bd17e4841bfee89667c9 --- /dev/null +++ b/src/set.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2023 Intel Corporation + * + * + */ + +#define BTD_DEVICE_SET_INTERFACE "org.bluez.DeviceSet1" + +struct btd_device_set; + +struct btd_device_set *btd_set_add_device(struct btd_device *device, + const uint8_t *ltk, + const uint8_t sirk[16], + uint8_t size); +bool btd_set_remove_device(struct btd_device_set *set, + struct btd_device *device); +const char *btd_set_get_path(struct btd_device_set *set); diff --git a/src/settings.c b/src/settings.c index 85534f2c7aca96cd97892f8264a9927d0035eeda..37164939573f8d3e7f77ba45a24832d7afe6f1ac 100644 --- a/src/settings.c +++ b/src/settings.c @@ -58,13 +58,17 @@ static int load_desc(struct gatt_db *db, char *handle, char *value, uint16_t val; bt_uuid_t uuid, ext_uuid; - if (sscanf(handle, "%04hx", &handle_int) != 1) + if (sscanf(handle, "%04hx", &handle_int) != 1) { + DBG("Failed to parse handle: %s", handle); return -EIO; + } /* Check if there is any value stored, otherwise it is just the UUID */ if (sscanf(value, "%04hx:%36s", &val, uuid_str) != 2) { - if (sscanf(value, "%36s", uuid_str) != 1) + if (sscanf(value, "%36s", uuid_str) != 1) { + DBG("Failed to parse value: %s", value); return -EIO; + } val = 0; } @@ -104,8 +108,10 @@ static int load_chrc(struct gatt_db *db, char *handle, char *value, size_t val_len; bt_uuid_t uuid; - if (sscanf(handle, "%04hx", &handle_int) != 1) + if (sscanf(handle, "%04hx", &handle_int) != 1) { + DBG("Failed to parse handle: %s", handle); return -EIO; + } /* Check if there is any value stored */ if (sscanf(value, GATT_CHARAC_UUID_STR ":%04hx:%02hx:%32s:%36s", @@ -125,7 +131,8 @@ static int load_chrc(struct gatt_db *db, char *handle, char *value, handle_int, value_handle, properties, val_len ? val_str : "", uuid_str); - att = gatt_db_service_insert_characteristic(service, value_handle, + att = gatt_db_service_insert_characteristic(service, handle_int, + value_handle, &uuid, 0, properties, NULL, NULL, NULL); if (!att || gatt_db_attribute_get_handle(att) != value_handle) @@ -147,12 +154,16 @@ static int load_incl(struct gatt_db *db, char *handle, char *value, struct gatt_db_attribute *att; uint16_t start, end; - if (sscanf(handle, "%04hx", &start) != 1) + if (sscanf(handle, "%04hx", &start) != 1) { + DBG("Failed to parse handle: %s", handle); return -EIO; + } if (sscanf(value, GATT_INCLUDE_UUID_STR ":%04hx:%04hx:%36s", &start, - &end, uuid_str) != 3) + &end, uuid_str) != 3) { + DBG("Failed to parse value: %s", value); return -EIO; + } /* Log debug message. */ DBG("loading included service: 0x%04x, end: 0x%04x, uuid: %s", @@ -177,11 +188,15 @@ static int load_service(struct gatt_db *db, char *handle, char *value) bt_uuid_t uuid; bool primary; - if (sscanf(handle, "%04hx", &start) != 1) + if (sscanf(handle, "%04hx", &start) != 1) { + DBG("Failed to parse handle: %s", handle); return -EIO; + } - if (sscanf(value, "%[^:]:%04hx:%36s", type, &end, uuid_str) != 3) + if (sscanf(value, "%36[^:]:%04hx:%36s", type, &end, uuid_str) != 3) { + DBG("Failed to parse value: %s", value); return -EIO; + } if (g_str_equal(type, GATT_PRIM_SVC_UUID_STR)) primary = true; @@ -217,7 +232,7 @@ static int gatt_db_load(struct gatt_db *db, GKeyFile *key_file, char **keys) value = g_key_file_get_string(key_file, "Attributes", *handle, NULL); - if (sscanf(value, "%[^:]:", type) != 1) { + if (!value || sscanf(value, "%36[^:]:", type) != 1) { g_free(value); return -EIO; } @@ -240,7 +255,7 @@ static int gatt_db_load(struct gatt_db *db, GKeyFile *key_file, char **keys) value = g_key_file_get_string(key_file, "Attributes", *handle, NULL); - if (sscanf(value, "%[^:]:", type) != 1) { + if (!value || sscanf(value, "%36[^:]:", type) != 1) { g_free(value); return -EIO; } diff --git a/src/shared/ad.c b/src/shared/ad.c index 27b76dc8179b46107264d03c85818781b7680da5..d08ce7af9b85a3ddb8c7a1faa5a08ab13c63863a 100644 --- a/src/shared/ad.c +++ b/src/shared/ad.c @@ -14,6 +14,11 @@ #define _GNU_SOURCE +#include <ctype.h> + +#include "lib/bluetooth.h" +#include "lib/hci.h" + #include "src/shared/ad.h" #include "src/eir.h" @@ -22,6 +27,7 @@ struct bt_ad { int ref_count; + uint8_t max_len; char *name; uint16_t appearance; struct queue *service_uuids; @@ -42,6 +48,7 @@ struct bt_ad *bt_ad_new(void) struct bt_ad *ad; ad = new0(struct bt_ad, 1); + ad->max_len = BT_EA_MAX_DATA_LEN; ad->service_uuids = queue_new(); ad->manufacturer_data = queue_new(); ad->solicit_uuids = queue_new(); @@ -52,6 +59,16 @@ struct bt_ad *bt_ad_new(void) return bt_ad_ref(ad); } +bool bt_ad_set_max_len(struct bt_ad *ad, uint8_t len) +{ + if (!ad || len < BT_AD_MAX_DATA_LEN) + return false; + + ad->max_len = len; + + return true; +} + static bool ad_replace_data(struct bt_ad *ad, uint8_t type, const void *data, size_t len); @@ -68,7 +85,11 @@ static bool ad_is_type_valid(uint8_t type) struct bt_ad *bt_ad_new_with_data(size_t len, const uint8_t *data) { struct bt_ad *ad; - uint16_t parsed_len = 0; + struct iovec iov = { + .iov_base = (void *)data, + .iov_len = len, + }; + uint8_t elen; if (data == NULL || !len) return NULL; @@ -77,31 +98,29 @@ struct bt_ad *bt_ad_new_with_data(size_t len, const uint8_t *data) if (!ad) return NULL; - while (parsed_len < len - 1) { - uint8_t d_len; - uint8_t d_type; - const uint8_t *d; - uint8_t field_len = data[0]; - - if (field_len == 0) - break; + bt_ad_set_max_len(ad, len); - parsed_len += field_len + 1; + while (util_iov_pull_u8(&iov, &elen)) { + uint8_t type; + void *data; - if (parsed_len > len) + if (elen == 0 || elen > iov.iov_len) break; - d = &data[2]; - d_type = data[1]; - d_len = field_len - 1; + if (!util_iov_pull_u8(&iov, &type)) + goto failed; + + elen--; - if (!ad_is_type_valid(d_type)) + if (!ad_is_type_valid(type)) goto failed; - if (!ad_replace_data(ad, d_type, d, d_len)) + data = util_iov_pull_mem(&iov, elen); + if (!data) goto failed; - data += field_len + 1; + if (!ad_replace_data(ad, type, data, elen)) + goto failed; } return ad; @@ -191,10 +210,181 @@ static bool data_type_match(const void *data, const void *user_data) return a->type == type; } +static bool ad_replace_uuid16(struct bt_ad *ad, struct iovec *iov) +{ + uint16_t value; + + while ((util_iov_pull_le16(iov, &value))) { + bt_uuid_t uuid; + + if (bt_uuid16_create(&uuid, value)) + return false; + + if (bt_ad_has_service_uuid(ad, &uuid)) + continue; + + if (!bt_ad_add_service_uuid(ad, &uuid)) + return false; + } + + return true; +} + +static bool ad_replace_uuid32(struct bt_ad *ad, struct iovec *iov) +{ + uint32_t value; + + while ((util_iov_pull_le32(iov, &value))) { + bt_uuid_t uuid; + + if (bt_uuid32_create(&uuid, value)) + return false; + + if (bt_ad_has_service_uuid(ad, &uuid)) + continue; + + if (!bt_ad_add_service_uuid(ad, &uuid)) + return false; + } + + return true; +} + +static bool ad_replace_uuid128(struct bt_ad *ad, struct iovec *iov) +{ + void *data; + + while ((data = util_iov_pull_mem(iov, 16))) { + uint128_t value; + bt_uuid_t uuid; + + bswap_128(data, &value); + + if (bt_uuid128_create(&uuid, value)) + return false; + + if (bt_ad_has_service_uuid(ad, &uuid)) + continue; + + if (!bt_ad_add_service_uuid(ad, &uuid)) + return false; + } + + return true; +} + +static bool ad_replace_name(struct bt_ad *ad, struct iovec *iov) +{ + char utf8_name[HCI_MAX_NAME_LENGTH + 2]; + int i; + + memset(utf8_name, 0, sizeof(utf8_name)); + strncpy(utf8_name, (const char *)iov->iov_base, iov->iov_len); + + if (strisutf8(utf8_name, iov->iov_len)) + goto done; + + /* Assume ASCII, and replace all non-ASCII with spaces */ + for (i = 0; utf8_name[i] != '\0'; i++) { + if (!isascii(utf8_name[i])) + utf8_name[i] = ' '; + } + + /* Remove leading and trailing whitespace characters */ + strstrip(utf8_name); + +done: + return bt_ad_add_name(ad, utf8_name); +} + +static bool ad_replace_uuid16_data(struct bt_ad *ad, struct iovec *iov) +{ + uint16_t value; + bt_uuid_t uuid; + + if (!util_iov_pull_le16(iov, &value)) + return false; + + if (bt_uuid16_create(&uuid, value)) + return false; + + return bt_ad_add_service_data(ad, &uuid, iov->iov_base, iov->iov_len); +} + +static bool ad_replace_uuid32_data(struct bt_ad *ad, struct iovec *iov) +{ + uint32_t value; + bt_uuid_t uuid; + + if (!util_iov_pull_le32(iov, &value)) + return false; + + if (bt_uuid32_create(&uuid, value)) + return false; + + return bt_ad_add_service_data(ad, &uuid, iov->iov_base, iov->iov_len); +} + +static bool ad_replace_uuid128_data(struct bt_ad *ad, struct iovec *iov) +{ + void *data; + uint128_t value; + bt_uuid_t uuid; + + data = util_iov_pull_mem(iov, 16); + if (!data) + return false; + + bswap_128(data, &value); + + if (bt_uuid128_create(&uuid, value)) + return false; + + return bt_ad_add_service_data(ad, &uuid, iov->iov_base, iov->iov_len); +} + +static bool ad_replace_manufacturer_data(struct bt_ad *ad, struct iovec *iov) +{ + uint16_t value; + + if (!util_iov_pull_le16(iov, &value)) + return false; + + return bt_ad_add_manufacturer_data(ad, value, iov->iov_base, + iov->iov_len); +} + static bool ad_replace_data(struct bt_ad *ad, uint8_t type, const void *data, size_t len) { struct bt_ad_data *new_data; + struct iovec iov = { + .iov_base = (void *)data, + .iov_len = len, + }; + + switch (type) { + case BT_AD_UUID16_SOME: + case BT_AD_UUID16_ALL: + return ad_replace_uuid16(ad, &iov); + case BT_AD_UUID32_SOME: + case BT_AD_UUID32_ALL: + return ad_replace_uuid32(ad, &iov); + case BT_AD_UUID128_SOME: + case BT_AD_UUID128_ALL: + return ad_replace_uuid128(ad, &iov); + case BT_AD_NAME_SHORT: + case BT_AD_NAME_COMPLETE: + return ad_replace_name(ad, &iov); + case BT_AD_SERVICE_DATA16: + return ad_replace_uuid16_data(ad, &iov); + case BT_AD_SERVICE_DATA32: + return ad_replace_uuid32_data(ad, &iov); + case BT_AD_SERVICE_DATA128: + return ad_replace_uuid128_data(ad, &iov); + case BT_AD_MANUFACTURER_DATA: + return ad_replace_manufacturer_data(ad, &iov); + } new_data = queue_find(ad->data, data_type_match, UINT_TO_PTR(type)); if (new_data) { @@ -208,13 +398,12 @@ static bool ad_replace_data(struct bt_ad *ad, uint8_t type, const void *data, new_data = new0(struct bt_ad_data, 1); new_data->type = type; - new_data->data = malloc(len); + new_data->data = util_memdup(data, len); if (!new_data->data) { free(new_data); return false; } - memcpy(new_data->data, data, len); new_data->len = len; if (queue_push_tail(ad->data, new_data)) @@ -298,17 +487,17 @@ static size_t uuid_data_length(struct queue *uuid_data) return length; } -static size_t name_length(const char *name, size_t *pos) +static size_t name_length(struct bt_ad *ad, size_t *pos) { size_t len; - if (!name) + if (!ad->name) return 0; - len = 2 + strlen(name); + len = 2 + strlen(ad->name); - if (len > BT_AD_MAX_DATA_LEN - *pos) - len = BT_AD_MAX_DATA_LEN - *pos; + if (len > ad->max_len - (*pos)) + len = ad->max_len - (*pos); return len; } @@ -331,9 +520,14 @@ static size_t data_length(struct queue *queue) return length; } -static size_t calculate_length(struct bt_ad *ad) +size_t bt_ad_length(struct bt_ad *ad) { - size_t length = 0; + size_t length; + + if (!ad) + return 0; + + length = 0; length += uuid_list_length(ad->service_uuids); @@ -343,7 +537,7 @@ static size_t calculate_length(struct bt_ad *ad) length += uuid_data_length(ad->service_data); - length += name_length(ad->name, &length); + length += name_length(ad, &length); length += ad->appearance != UINT16_MAX ? 4 : 0; @@ -353,84 +547,80 @@ static size_t calculate_length(struct bt_ad *ad) } static void serialize_uuids(struct queue *uuids, uint8_t uuid_type, - uint8_t ad_type, uint8_t *buf, - uint8_t *pos) + uint8_t ad_type, struct iovec *iov) { const struct queue_entry *entry = queue_get_entries(uuids); - bool added = false; - uint8_t length_pos = 0; + uint8_t *len = NULL; while (entry) { bt_uuid_t *uuid = entry->data; if (uuid->type == uuid_type) { - if (!added) { - length_pos = (*pos)++; - buf[(*pos)++] = ad_type; - added = true; + if (!len) { + len = iov->iov_base + iov->iov_len; + util_iov_push_u8(iov, 1); + util_iov_push_u8(iov, ad_type); } - if (uuid_type != BT_UUID32) - bt_uuid_to_le(uuid, buf + *pos); - else - bt_put_le32(uuid->value.u32, buf + *pos); - - *pos += bt_uuid_len(uuid); + switch (uuid->type) { + case BT_UUID16: + util_iov_push_le16(iov, uuid->value.u16); + *len += 2; + break; + case BT_UUID32: + util_iov_push_le32(iov, uuid->value.u32); + *len += 4; + break; + case BT_UUID128: + bt_uuid_to_le(uuid, util_iov_push(iov, 16)); + *len += 16; + break; + case BT_UUID_UNSPEC: + break; + } } entry = entry->next; } - - if (added) - buf[length_pos] = *pos - length_pos - 1; } -static void serialize_service_uuids(struct queue *uuids, uint8_t *buf, - uint8_t *pos) +static void serialize_service_uuids(struct queue *uuids, struct iovec *iov) { - serialize_uuids(uuids, BT_UUID16, BT_AD_UUID16_ALL, buf, pos); + serialize_uuids(uuids, BT_UUID16, BT_AD_UUID16_ALL, iov); - serialize_uuids(uuids, BT_UUID32, BT_AD_UUID32_ALL, buf, pos); + serialize_uuids(uuids, BT_UUID32, BT_AD_UUID32_ALL, iov); - serialize_uuids(uuids, BT_UUID128, BT_AD_UUID128_ALL, buf, pos); + serialize_uuids(uuids, BT_UUID128, BT_AD_UUID128_ALL, iov); } -static void serialize_solicit_uuids(struct queue *uuids, uint8_t *buf, - uint8_t *pos) +static void serialize_solicit_uuids(struct queue *uuids, struct iovec *iov) { - serialize_uuids(uuids, BT_UUID16, BT_AD_SOLICIT16, buf, pos); + serialize_uuids(uuids, BT_UUID16, BT_AD_SOLICIT16, iov); - serialize_uuids(uuids, BT_UUID32, BT_AD_SOLICIT32, buf, pos); + serialize_uuids(uuids, BT_UUID32, BT_AD_SOLICIT32, iov); - serialize_uuids(uuids, BT_UUID128, BT_AD_SOLICIT128, buf, pos); + serialize_uuids(uuids, BT_UUID128, BT_AD_SOLICIT128, iov); } -static void serialize_manuf_data(struct queue *manuf_data, uint8_t *buf, - uint8_t *pos) +static void serialize_manuf_data(struct queue *manuf_data, struct iovec *iov) { const struct queue_entry *entry = queue_get_entries(manuf_data); while (entry) { struct bt_ad_manufacturer_data *data = entry->data; - buf[(*pos)++] = data->len + 2 + 1; - - buf[(*pos)++] = BT_AD_MANUFACTURER_DATA; - - bt_put_le16(data->manufacturer_id, buf + (*pos)); - - *pos += 2; - - memcpy(buf + *pos, data->data, data->len); + util_iov_push_u8(iov, data->len + 2 + 1); + util_iov_push_u8(iov, BT_AD_MANUFACTURER_DATA); - *pos += data->len; + util_iov_push_le16(iov, data->manufacturer_id); + util_iov_push_mem(iov, data->len, data->data); entry = entry->next; } } -static void serialize_service_data(struct queue *service_data, uint8_t *buf, - uint8_t *pos) +static void serialize_service_data(struct queue *service_data, + struct iovec *iov) { const struct queue_entry *entry = queue_get_entries(service_data); @@ -438,81 +628,69 @@ static void serialize_service_data(struct queue *service_data, uint8_t *buf, struct bt_ad_service_data *data = entry->data; int uuid_len = bt_uuid_len(&data->uuid); - buf[(*pos)++] = uuid_len + data->len + 1; + util_iov_push_u8(iov, data->len + uuid_len + 1); switch (uuid_len) { case 2: - buf[(*pos)++] = BT_AD_SERVICE_DATA16; + util_iov_push_u8(iov, BT_AD_SERVICE_DATA16); + util_iov_push_le16(iov, data->uuid.value.u16); break; case 4: - buf[(*pos)++] = BT_AD_SERVICE_DATA32; + util_iov_push_u8(iov, BT_AD_SERVICE_DATA32); + util_iov_push_le32(iov, data->uuid.value.u32); break; case 16: - buf[(*pos)++] = BT_AD_SERVICE_DATA128; + util_iov_push_u8(iov, BT_AD_SERVICE_DATA128); + bt_uuid_to_le(&data->uuid, + util_iov_push(iov, uuid_len)); break; } - if (uuid_len != 4) - bt_uuid_to_le(&data->uuid, buf + *pos); - else - bt_put_le32(data->uuid.value.u32, buf + *pos); - - *pos += uuid_len; - - memcpy(buf + *pos, data->data, data->len); - - *pos += data->len; + util_iov_push_mem(iov, data->len, data->data); entry = entry->next; } } -static void serialize_name(const char *name, uint8_t *buf, uint8_t *pos) +static void serialize_name(struct bt_ad *ad, struct iovec *iov) { - int len; + size_t len; uint8_t type = BT_AD_NAME_COMPLETE; - if (!name) + if (!ad->name) return; - len = strlen(name); - if (len > BT_AD_MAX_DATA_LEN - (*pos + 2)) { + len = strlen(ad->name); + if (len > ad->max_len - (iov->iov_len + 2)) { type = BT_AD_NAME_SHORT; - len = BT_AD_MAX_DATA_LEN - (*pos + 2); + len = ad->max_len - (iov->iov_len + 2); } - buf[(*pos)++] = len + 1; - buf[(*pos)++] = type; - - memcpy(buf + *pos, name, len); - *pos += len; + util_iov_push_u8(iov, len + 1); + util_iov_push_u8(iov, type); + util_iov_push_mem(iov, len, ad->name); } -static void serialize_appearance(uint16_t value, uint8_t *buf, uint8_t *pos) +static void serialize_appearance(struct bt_ad *ad, struct iovec *iov) { - if (value == UINT16_MAX) + if (ad->appearance == UINT16_MAX) return; - buf[(*pos)++] = sizeof(value) + 1; - buf[(*pos)++] = BT_AD_GAP_APPEARANCE; - - bt_put_le16(value, buf + (*pos)); - *pos += 2; + util_iov_push_u8(iov, sizeof(ad->appearance) + 1); + util_iov_push_u8(iov, BT_AD_GAP_APPEARANCE); + util_iov_push_le16(iov, ad->appearance); } -static void serialize_data(struct queue *queue, uint8_t *buf, uint8_t *pos) +static void serialize_data(struct queue *queue, struct iovec *iov) { const struct queue_entry *entry = queue_get_entries(queue); while (entry) { struct bt_ad_data *data = entry->data; - buf[(*pos)++] = data->len + 1; - buf[(*pos)++] = data->type; - - memcpy(buf + *pos, data->data, data->len); - - *pos += data->len; + util_iov_push_u8(iov, data->len + 1); + util_iov_push_u8(iov, data->type); + util_iov_push_mem(iov, data->len, data->data); entry = entry->next; } @@ -520,36 +698,37 @@ static void serialize_data(struct queue *queue, uint8_t *buf, uint8_t *pos) uint8_t *bt_ad_generate(struct bt_ad *ad, size_t *length) { - uint8_t *adv_data; - uint8_t pos = 0; + struct iovec iov; if (!ad) return NULL; - *length = calculate_length(ad); + *length = bt_ad_length(ad); - if (*length > BT_AD_MAX_DATA_LEN) + if (*length > ad->max_len) return NULL; - adv_data = malloc0(*length); - if (!adv_data) + iov.iov_base = malloc0(*length); + if (!iov.iov_base) return NULL; - serialize_service_uuids(ad->service_uuids, adv_data, &pos); + iov.iov_len = 0; - serialize_solicit_uuids(ad->solicit_uuids, adv_data, &pos); + serialize_service_uuids(ad->service_uuids, &iov); - serialize_manuf_data(ad->manufacturer_data, adv_data, &pos); + serialize_solicit_uuids(ad->solicit_uuids, &iov); - serialize_service_data(ad->service_data, adv_data, &pos); + serialize_manuf_data(ad->manufacturer_data, &iov); - serialize_name(ad->name, adv_data, &pos); + serialize_service_data(ad->service_data, &iov); - serialize_appearance(ad->appearance, adv_data, &pos); + serialize_name(ad, &iov); - serialize_data(ad->data, adv_data, &pos); + serialize_appearance(ad, &iov); - return adv_data; + serialize_data(ad->data, &iov); + + return iov.iov_base; } bool bt_ad_is_empty(struct bt_ad *ad) @@ -593,7 +772,7 @@ static bool uuid_match(const void *data, const void *elem) const bt_uuid_t *match_uuid = data; const bt_uuid_t *uuid = elem; - return bt_uuid_cmp(match_uuid, uuid); + return !bt_uuid_cmp(match_uuid, uuid); } static bool queue_remove_uuid(struct queue *queue, bt_uuid_t *uuid) @@ -621,6 +800,14 @@ bool bt_ad_add_service_uuid(struct bt_ad *ad, const bt_uuid_t *uuid) return queue_add_uuid(ad->service_uuids, uuid); } +bool bt_ad_has_service_uuid(struct bt_ad *ad, const bt_uuid_t *uuid) +{ + if (!ad) + return false; + + return queue_find(ad->service_uuids, uuid_match, uuid); +} + bool bt_ad_remove_service_uuid(struct bt_ad *ad, bt_uuid_t *uuid) { if (!ad) @@ -653,7 +840,7 @@ bool bt_ad_add_manufacturer_data(struct bt_ad *ad, uint16_t manufacturer_id, if (!ad) return false; - if (len > (BT_AD_MAX_DATA_LEN - 2 - sizeof(uint16_t))) + if (len > (ad->max_len - 2 - sizeof(uint16_t))) return false; new_data = queue_find(ad->manufacturer_data, manufacturer_id_data_match, @@ -790,7 +977,7 @@ bool bt_ad_add_service_data(struct bt_ad *ad, const bt_uuid_t *uuid, void *data, if (!ad) return false; - if (len > (BT_AD_MAX_DATA_LEN - 2 - (size_t)bt_uuid_len(uuid))) + if (len > (ad->max_len - 2 - (size_t)bt_uuid_len(uuid))) return false; new_data = queue_find(ad->service_data, service_uuid_match, uuid); @@ -897,6 +1084,14 @@ bool bt_ad_add_name(struct bt_ad *ad, const char *name) return true; } +const char *bt_ad_get_name(struct bt_ad *ad) +{ + if (!ad) + return false; + + return ad->name; +} + void bt_ad_clear_name(struct bt_ad *ad) { if (!ad) @@ -936,6 +1131,20 @@ bool bt_ad_add_flags(struct bt_ad *ad, uint8_t *flags, size_t len) return ad_replace_data(ad, BT_AD_FLAGS, flags, len); } +uint8_t bt_ad_get_flags(struct bt_ad *ad) +{ + struct bt_ad_data *data; + + if (!ad) + return 0; + + data = queue_find(ad->data, data_type_match, UINT_TO_PTR(BT_AD_FLAGS)); + if (!data || data->len != 1) + return 0; + + return data->data[0]; +} + bool bt_ad_has_flags(struct bt_ad *ad) { struct bt_ad_data *data; @@ -1009,7 +1218,7 @@ bool bt_ad_add_data(struct bt_ad *ad, uint8_t type, void *data, size_t len) if (!ad) return false; - if (len > (BT_AD_MAX_DATA_LEN - 2)) + if (len > (size_t)(ad->max_len - 2)) return false; for (i = 0; i < sizeof(type_reject_list); i++) { @@ -1028,6 +1237,9 @@ static bool data_match(const void *data, const void *user_data) if (d1->type != d2->type) return false; + if (!d2->len && !d2->data) + return true; + if (d1->len != d2->len) return false; @@ -1077,6 +1289,21 @@ void bt_ad_clear_data(struct bt_ad *ad) queue_remove_all(ad->data, NULL, NULL, data_destroy); } +int8_t bt_ad_get_tx_power(struct bt_ad *ad) +{ + struct bt_ad_data *data; + + if (!ad) + return 0; + + data = queue_find(ad->data, data_type_match, + UINT_TO_PTR(BT_AD_TX_POWER)); + if (!data || data->len != 1) + return 127; + + return data->data[0]; +} + struct bt_ad_pattern *bt_ad_pattern_new(uint8_t type, size_t offset, size_t len, const uint8_t *data) { @@ -1102,36 +1329,110 @@ struct bt_ad_pattern *bt_ad_pattern_new(uint8_t type, size_t offset, size_t len, return pattern; } -static void pattern_ad_data_match(void *data, void *user_data) +static bool match_manufacturer(const void *data, const void *user_data) { - struct bt_ad_data *ad_data = data; - struct pattern_match_info *info = user_data; - struct bt_ad_pattern *pattern; + const struct bt_ad_manufacturer_data *manufacturer_data = data; + const struct pattern_match_info *info = user_data; + const struct bt_ad_pattern *pattern; + uint8_t all_data[BT_AD_MAX_DATA_LEN]; + + if (!manufacturer_data || !info) + return false; + + if (info->matched_pattern) + return false; + + pattern = info->current_pattern; + + if (!pattern || pattern->type != BT_AD_MANUFACTURER_DATA) + return false; + + /* Take the manufacturer ID into account */ + if (manufacturer_data->len + 2 < pattern->offset + pattern->len) + return false; + + memcpy(&all_data[0], &manufacturer_data->manufacturer_id, 2); + memcpy(&all_data[2], manufacturer_data->data, manufacturer_data->len); + + if (!memcmp(all_data + pattern->offset, pattern->data, + pattern->len)) { + return true; + } + + return false; +} + +static bool match_service(const void *data, const void *user_data) +{ + const struct bt_ad_service_data *service_data = data; + const struct pattern_match_info *info = user_data; + const struct bt_ad_pattern *pattern; + + if (!service_data || !info) + return false; + + if (info->matched_pattern) + return false; + + pattern = info->current_pattern; + + if (!pattern) + return false; + + switch (pattern->type) { + case BT_AD_SERVICE_DATA16: + case BT_AD_SERVICE_DATA32: + case BT_AD_SERVICE_DATA128: + break; + default: + return false; + } + + if (service_data->len < pattern->offset + pattern->len) + return false; + + if (!memcmp(service_data->data + pattern->offset, pattern->data, + pattern->len)) { + return true; + } + + return false; +} + +static bool match_ad_data(const void *data, const void *user_data) +{ + const struct bt_ad_data *ad_data = data; + const struct pattern_match_info *info = user_data; + const struct bt_ad_pattern *pattern; if (!ad_data || !info) - return; + return false; if (info->matched_pattern) - return; + return false; pattern = info->current_pattern; if (!pattern || ad_data->type != pattern->type) - return; + return false; if (ad_data->len < pattern->offset + pattern->len) - return; + return false; if (!memcmp(ad_data->data + pattern->offset, pattern->data, pattern->len)) { - info->matched_pattern = pattern; + return true; } + + return false; } static void pattern_match(void *data, void *user_data) { struct bt_ad_pattern *pattern = data; struct pattern_match_info *info = user_data; + struct bt_ad *ad; + void *matched = NULL; if (!pattern || !info) return; @@ -1140,8 +1441,29 @@ static void pattern_match(void *data, void *user_data) return; info->current_pattern = pattern; + ad = info->ad; + + if (!ad) + return; + + switch (pattern->type) { + case BT_AD_MANUFACTURER_DATA: + matched = queue_find(ad->manufacturer_data, match_manufacturer, + user_data); + break; + case BT_AD_SERVICE_DATA16: + case BT_AD_SERVICE_DATA32: + case BT_AD_SERVICE_DATA128: + matched = queue_find(ad->service_data, match_service, + user_data); + break; + default: + matched = queue_find(ad->data, match_ad_data, user_data); + break; + } - bt_ad_foreach_data(info->ad, pattern_ad_data_match, info); + if (matched) + info->matched_pattern = info->current_pattern; } struct bt_ad_pattern *bt_ad_pattern_match(struct bt_ad *ad, diff --git a/src/shared/ad.h b/src/shared/ad.h index feb712f508cfe5b64a74da67a1404b3388ab04f3..90cc82de9d63b9c3ff2a41109f49a97c1036af88 100644 --- a/src/shared/ad.h +++ b/src/shared/ad.h @@ -15,6 +15,8 @@ #include "lib/uuid.h" #define BT_AD_MAX_DATA_LEN 31 +#define BT_EA_MAX_DATA_LEN 251 +#define BT_PA_MAX_DATA_LEN 252 #define BT_AD_FLAGS 0x01 #define BT_AD_UUID16_SOME 0x02 @@ -57,6 +59,7 @@ #define BT_AD_MESH_PROV 0x29 #define BT_AD_MESH_DATA 0x2a #define BT_AD_MESH_BEACON 0x2b +#define BT_AD_CSIP_RSI 0x2e #define BT_AD_3D_INFO_DATA 0x3d #define BT_AD_MANUFACTURER_DATA 0xff @@ -97,23 +100,29 @@ struct bt_ad_pattern { struct bt_ad *bt_ad_new(void); +bool bt_ad_set_max_len(struct bt_ad *ad, uint8_t len); + struct bt_ad *bt_ad_new_with_data(size_t len, const uint8_t *data); struct bt_ad *bt_ad_ref(struct bt_ad *ad); void bt_ad_unref(struct bt_ad *ad); +size_t bt_ad_length(struct bt_ad *ad); + uint8_t *bt_ad_generate(struct bt_ad *ad, size_t *length); bool bt_ad_is_empty(struct bt_ad *ad); bool bt_ad_add_service_uuid(struct bt_ad *ad, const bt_uuid_t *uuid); +bool bt_ad_has_service_uuid(struct bt_ad *ad, const bt_uuid_t *uuid); + bool bt_ad_remove_service_uuid(struct bt_ad *ad, bt_uuid_t *uuid); void bt_ad_clear_service_uuid(struct bt_ad *ad); -bool bt_ad_add_manufacturer_data(struct bt_ad *ad, uint16_t manufacturer_data, +bool bt_ad_add_manufacturer_data(struct bt_ad *ad, uint16_t id, void *data, size_t len); bool bt_ad_has_manufacturer_data(struct bt_ad *ad, @@ -147,6 +156,8 @@ void bt_ad_clear_service_data(struct bt_ad *ad); bool bt_ad_add_name(struct bt_ad *ad, const char *name); +const char *bt_ad_get_name(struct bt_ad *ad); + void bt_ad_clear_name(struct bt_ad *ad); bool bt_ad_add_appearance(struct bt_ad *ad, uint16_t appearance); @@ -157,6 +168,8 @@ bool bt_ad_add_flags(struct bt_ad *ad, uint8_t *flags, size_t len); bool bt_ad_has_flags(struct bt_ad *ad); +uint8_t bt_ad_get_flags(struct bt_ad *ad); + void bt_ad_clear_flags(struct bt_ad *ad); bool bt_ad_add_data(struct bt_ad *ad, uint8_t type, void *data, size_t len); @@ -169,6 +182,8 @@ bool bt_ad_remove_data(struct bt_ad *ad, uint8_t type); void bt_ad_clear_data(struct bt_ad *ad); +int8_t bt_ad_get_tx_power(struct bt_ad *ad); + struct bt_ad_pattern *bt_ad_pattern_new(uint8_t type, size_t offset, size_t len, const uint8_t *data); diff --git a/src/shared/asha.c b/src/shared/asha.c new file mode 100644 index 0000000000000000000000000000000000000000..67f2631cd2ed0ce69b62f612a8d9829cb68222d9 --- /dev/null +++ b/src/shared/asha.c @@ -0,0 +1,359 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2024 Asymptotic Inc. + * + * Author: Arun Raghavan <arun@asymptotic.io> + * + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "lib/bluetooth.h" +#include "lib/uuid.h" + +#include "src/shared/util.h" +#include "src/shared/att.h" +#include "src/log.h" + +#include "src/shared/queue.h" +#include "src/shared/gatt-db.h" +#include "src/shared/gatt-client.h" + +#include "asha.h" + +/* We use strings instead of uint128_t to maintain readability */ +#define ASHA_CHRC_READ_ONLY_PROPERTIES_UUID "6333651e-c481-4a3e-9169-7c902aad37bb" +#define ASHA_CHRC_AUDIO_CONTROL_POINT_UUID "f0d4de7e-4a88-476c-9d9f-1937b0996cc0" +#define ASHA_CHRC_AUDIO_STATUS_UUID "38663f1a-e711-4cac-b641-326b56404837" +#define ASHA_CHRC_VOLUME_UUID "00e4ca9e-ab14-41e4-8823-f9e70c7e91df" +#define ASHA_CHRC_LE_PSM_OUT_UUID "2d410339-82b6-42aa-b34e-e2e01df8cc1a" + +struct bt_asha *bt_asha_new(void) +{ + struct bt_asha *asha; + + asha = new0(struct bt_asha, 1); + + return asha; +} + +void bt_asha_reset(struct bt_asha *asha) +{ + if (asha->status_notify_id) { + bt_gatt_client_unregister_notify(asha->client, + asha->status_notify_id); + } + + gatt_db_unref(asha->db); + asha->db = NULL; + + bt_gatt_client_unref(asha->client); + asha->client = NULL; + + asha->psm = 0; +} + +void bt_asha_state_reset(struct bt_asha *asha) +{ + asha->state = ASHA_STOPPED; + + asha->cb = NULL; + asha->cb_user_data = NULL; +} + +void bt_asha_free(struct bt_asha *asha) +{ + gatt_db_unref(asha->db); + bt_gatt_client_unref(asha->client); + free(asha); +} + +static void asha_acp_sent(bool success, uint8_t err, void *user_data) +{ + struct bt_asha *asha = user_data; + + if (success) { + DBG("AudioControlPoint command successfully sent"); + } else { + error("Failed to send AudioControlPoint command: %d", err); + + if (asha->cb) + asha->cb(-1, asha->cb_user_data); + + bt_asha_state_reset(asha); + } +} + +static int asha_send_acp(struct bt_asha *asha, uint8_t *cmd, + unsigned int len, bt_asha_cb_t cb, void *user_data) +{ + if (!bt_gatt_client_write_value(asha->client, asha->acp_handle, cmd, + len, asha_acp_sent, asha, NULL)) { + error("Error writing ACP command"); + return -1; + } + + asha->cb = cb; + asha->cb_user_data = user_data; + + return 0; +} + +unsigned int bt_asha_start(struct bt_asha *asha, bt_asha_cb_t cb, + void *user_data) +{ + uint8_t acp_start_cmd[] = { + 0x01, /* START */ + 0x01, /* G.722, 16 kHz */ + 0, /* Unknown media type */ + asha->volume, /* Volume */ + 0, /* Other disconnected */ + }; + int ret; + + if (asha->state != ASHA_STOPPED) { + error("ASHA device start failed. Bad state %d", asha->state); + return 0; + } + + ret = asha_send_acp(asha, acp_start_cmd, sizeof(acp_start_cmd), cb, + user_data); + if (ret < 0) + return ret; + + asha->state = ASHA_STARTING; + + return 0; +} + +unsigned int bt_asha_stop(struct bt_asha *asha, bt_asha_cb_t cb, + void *user_data) +{ + uint8_t acp_stop_cmd[] = { + 0x02, /* STOP */ + }; + + if (asha->state != ASHA_STARTED) + return 0; + + asha->state = ASHA_STOPPING; + + return asha_send_acp(asha, acp_stop_cmd, sizeof(acp_stop_cmd), + cb, user_data); +} + +bool bt_asha_set_volume(struct bt_asha *asha, int8_t volume) +{ + if (!bt_gatt_client_write_without_response(asha->client, + asha->volume_handle, false, + (const uint8_t *)&volume, 1)) { + error("Error writing volume"); + return false; + } + + asha->volume = volume; + return true; +} + +static bool uuid_cmp(const char *uuid1, const bt_uuid_t *uuid2) +{ + bt_uuid_t lhs; + + bt_string_to_uuid(&lhs, uuid1); + + return bt_uuid_cmp(&lhs, uuid2) == 0; +} + +static void read_psm(bool success, + uint8_t att_ecode, + const uint8_t *value, + uint16_t length, + void *user_data) +{ + struct bt_asha *asha = user_data; + + if (!success) { + DBG("Reading PSM failed with ATT error: %u", att_ecode); + return; + } + + if (length != 2) { + DBG("Reading PSM failed: unexpected length %u", length); + return; + } + + asha->psm = get_le16(value); + + DBG("Got PSM: %u", asha->psm); +} + +static void read_rops(bool success, + uint8_t att_ecode, + const uint8_t *value, + uint16_t length, + void *user_data) +{ + struct bt_asha *asha = user_data; + + if (!success) { + DBG("Reading ROPs failed with ATT error: %u", att_ecode); + return; + } + + if (length != 17) { + DBG("Reading ROPs failed: unexpected length %u", length); + return; + } + + if (value[0] != 0x01) { + DBG("Unexpected ASHA version: %u", value[0]); + return; + } + + /* Device Capabilities */ + asha->right_side = (value[1] & 0x1) != 0; + asha->binaural = (value[1] & 0x2) != 0; + asha->csis_supported = (value[1] & 0x4) != 0; + /* HiSyncId: 2 byte company id, 6 byte ID shared by left and right */ + memcpy(asha->hisyncid, &value[2], 8); + /* FeatureMap */ + asha->coc_streaming_supported = (value[10] & 0x1) != 0; + /* RenderDelay */ + asha->render_delay = get_le16(&value[11]); + /* byte 13 & 14 are reserved */ + /* Codec IDs */ + asha->codec_ids = get_le16(&value[15]); + + DBG("Got ROPS: side %u, binaural %u, csis: %u, delay %u, codecs: %u", + asha->right_side, asha->binaural, asha->csis_supported, + asha->render_delay, asha->codec_ids); +} + +static void audio_status_register(uint16_t att_ecode, void *user_data) +{ + if (att_ecode) + DBG("AudioStatusPoint register failed 0x%04x", att_ecode); + else + DBG("AudioStatusPoint register succeeded"); +} + +static void audio_status_notify(uint16_t value_handle, const uint8_t *value, + uint16_t length, void *user_data) +{ + struct bt_asha *asha = user_data; + uint8_t status = *value; + /* Back these up to survive the reset paths */ + bt_asha_cb_t cb = asha->cb; + bt_asha_cb_t cb_user_data = asha->cb_user_data; + + if (asha->state == ASHA_STARTING) { + if (status == 0) { + asha->state = ASHA_STARTED; + DBG("ASHA start complete"); + } else { + bt_asha_state_reset(asha); + DBG("ASHA start failed"); + } + } else if (asha->state == ASHA_STOPPING) { + /* We reset our state, regardless */ + bt_asha_state_reset(asha); + DBG("ASHA stop %s", status == 0 ? "complete" : "failed"); + } + + if (cb) { + cb(status, cb_user_data); + asha->cb = NULL; + asha->cb_user_data = NULL; + } +} + +static void handle_characteristic(struct gatt_db_attribute *attr, + void *user_data) +{ + struct bt_asha *asha = user_data; + uint16_t value_handle; + bt_uuid_t uuid; + char uuid_str[MAX_LEN_UUID_STR]; + + if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, NULL, + NULL, &uuid)) { + error("Failed to obtain characteristic data"); + return; + } + + bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str)); + if (uuid_cmp(ASHA_CHRC_LE_PSM_OUT_UUID, &uuid)) { + DBG("Got chrc %s/0x%x: LE_PSM_ID", uuid_str, value_handle); + if (!bt_gatt_client_read_value(asha->client, value_handle, + read_psm, asha, NULL)) + DBG("Failed to send request to read battery level"); + } else if (uuid_cmp(ASHA_CHRC_READ_ONLY_PROPERTIES_UUID, &uuid)) { + DBG("Got chrc %s/0x%x: READ_ONLY_PROPERTIES", uuid_str, + value_handle); + if (!bt_gatt_client_read_value(asha->client, value_handle, + read_rops, asha, NULL)) + DBG("Failed to send request for readonly properties"); + } else if (uuid_cmp(ASHA_CHRC_AUDIO_CONTROL_POINT_UUID, &uuid)) { + DBG("Got chrc %s/0x%x: AUDIO_CONTROL_POINT", uuid_str, + value_handle); + /* Store this for later writes */ + asha->acp_handle = value_handle; + } else if (uuid_cmp(ASHA_CHRC_VOLUME_UUID, &uuid)) { + DBG("Got chrc %s/0x%x: VOLUME", uuid_str, value_handle); + /* Store this for later writes */ + asha->volume_handle = value_handle; + } else if (uuid_cmp(ASHA_CHRC_AUDIO_STATUS_UUID, &uuid)) { + DBG("Got chrc %s/0x%x: AUDIO_STATUS", uuid_str, value_handle); + asha->status_notify_id = + bt_gatt_client_register_notify(asha->client, + value_handle, audio_status_register, + audio_status_notify, asha, NULL); + if (!asha->status_notify_id) + DBG("Failed to send request to notify AudioStatus"); + } else { + DBG("Unsupported characteristic: %s", uuid_str); + } +} + +static void foreach_asha_service(struct gatt_db_attribute *attr, + void *user_data) +{ + struct bt_asha *asha = user_data; + + DBG("Found ASHA GATT service"); + + asha->attr = attr; + gatt_db_service_set_claimed(attr, true); + gatt_db_service_foreach_char(asha->attr, handle_characteristic, asha); +} + +bool bt_asha_probe(struct bt_asha *asha, struct gatt_db *db, + struct bt_gatt_client *client) +{ + bt_uuid_t asha_uuid; + + asha->db = gatt_db_ref(db); + asha->client = bt_gatt_client_clone(client); + + bt_uuid16_create(&asha_uuid, ASHA_SERVICE); + gatt_db_foreach_service(db, &asha_uuid, foreach_asha_service, asha); + + if (!asha->attr) { + error("ASHA attribute not found"); + bt_asha_reset(asha); + return false; + } + + return true; +} diff --git a/src/shared/asha.h b/src/shared/asha.h new file mode 100644 index 0000000000000000000000000000000000000000..c2c232fff650cda75c6aa3d74ac8e28bc5f05b1d --- /dev/null +++ b/src/shared/asha.h @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2024 Asymptotic Inc. + * + * Author: Arun Raghavan <arun@asymptotic.io> + * + * + */ + +# + +#include <stdbool.h> +#include <stdint.h> + +enum bt_asha_state_t { + ASHA_STOPPED = 0, + ASHA_STARTING, + ASHA_STARTED, + ASHA_STOPPING, +}; + +typedef void (*bt_asha_cb_t)(int status, void *data); + +struct bt_asha { + struct bt_gatt_client *client; + struct gatt_db *db; + struct gatt_db_attribute *attr; + uint16_t acp_handle; + uint16_t volume_handle; + unsigned int status_notify_id; + + uint16_t psm; + bool right_side; + bool binaural; + bool csis_supported; + bool coc_streaming_supported; + uint8_t hisyncid[8]; + uint16_t render_delay; + uint16_t codec_ids; + int8_t volume; + + enum bt_asha_state_t state; + bt_asha_cb_t cb; + void *cb_user_data; +}; + +struct bt_asha *bt_asha_new(void); +void bt_asha_reset(struct bt_asha *asha); +void bt_asha_state_reset(struct bt_asha *asha); +void bt_asha_free(struct bt_asha *asha); + +unsigned int bt_asha_start(struct bt_asha *asha, bt_asha_cb_t cb, + void *user_data); +unsigned int bt_asha_stop(struct bt_asha *asha, bt_asha_cb_t cb, + void *user_data); + +bool bt_asha_set_volume(struct bt_asha *asha, int8_t volume); + +bool bt_asha_probe(struct bt_asha *asha, struct gatt_db *db, + struct bt_gatt_client *client); diff --git a/src/shared/att-types.h b/src/shared/att-types.h index a08b241554da4398382bd6b77075a192a243362a..69f45b6aa6d7ec2df51f2317bb08e44af4e945ae 100644 --- a/src/shared/att-types.h +++ b/src/shared/att-types.h @@ -4,6 +4,7 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2014 Google Inc. + * Copyright 2023 NXP * * */ @@ -101,9 +102,10 @@ struct bt_att_pdu_error_rsp { /* * Common Profile and Service Error Code descriptions (see Supplement to the * Bluetooth Core Specification, sections 1.2 and 2). The error codes within - * 0xE0-0xFC are reserved for future use. The remaining 3 are defined as the + * 0xE0-0xFB are reserved for future use. The remaining 4 are defined as the * following: */ +#define BT_ERROR_WRITE_REQUEST_REJECTED 0xfc #define BT_ERROR_CCC_IMPROPERLY_CONFIGURED 0xfd #define BT_ERROR_ALREADY_IN_PROGRESS 0xfe #define BT_ERROR_OUT_OF_RANGE 0xff diff --git a/src/shared/att.c b/src/shared/att.c index f7bef08bc169b8eb6f81944f1b0ec634cfea5dd8..4a406f4b91a40ffa55d4217653cea8f76ad86b62 100644 --- a/src/shared/att.c +++ b/src/shared/att.c @@ -193,6 +193,7 @@ struct att_send_op { uint8_t opcode; void *pdu; uint16_t len; + bool retry; bt_att_response_func_t callback; bt_att_destroy_func_t destroy; void *user_data; @@ -550,7 +551,7 @@ static bool can_write_data(struct io *io, void *user_data) if (!op) return false; - if (!bt_att_chan_write(chan, op->opcode, op->pdu, op->len)) { + if (bt_att_chan_write(chan, op->opcode, op->pdu, op->len) < 0) { if (op->callback) op->callback(BT_ATT_OP_ERROR_RSP, NULL, 0, op->user_data); @@ -785,6 +786,12 @@ static bool handle_error_rsp(struct bt_att_chan *chan, uint8_t *pdu, *opcode = rsp->opcode; + /* If operation has already been marked as retry don't attempt to change + * the security again. + */ + if (op->retry) + return false; + /* Attempt to change security */ if (!change_security(chan, rsp->ecode)) return false; @@ -798,9 +805,10 @@ static bool handle_error_rsp(struct bt_att_chan *chan, uint8_t *pdu, DBG(att, "(chan %p) Retrying operation %p", chan, op); chan->pending_req = NULL; + op->retry = true; - /* Push operation back to request queue */ - return queue_push_head(att->req_queue, op); + /* Push operation back to channel queue */ + return queue_push_head(chan->queue, op); } static void handle_rsp(struct bt_att_chan *chan, uint8_t opcode, uint8_t *pdu, @@ -1001,8 +1009,9 @@ static void handle_notify(struct bt_att_chan *chan, uint8_t *pdu, found = true; if (notify->callback) - notify->callback(chan, opcode, pdu + 1, pdu_len - 1, - notify->user_data); + notify->callback(chan, chan->mtu, opcode, + pdu + 1, pdu_len - 1, + notify->user_data); /* callback could remove all entries from notify list */ if (queue_isempty(att->notify_list)) @@ -1588,6 +1597,14 @@ unsigned int bt_att_send(struct bt_att *att, uint8_t opcode, op->id = att->next_send_id++; + /* Always use fixed channel for BT_ATT_OP_MTU_REQ */ + if (opcode == BT_ATT_OP_MTU_REQ) { + struct bt_att_chan *chan = queue_peek_tail(att->chans); + + result = queue_push_tail(chan->queue, op); + goto done; + } + /* Add the op to the correct queue based on its type */ switch (op->type) { case ATT_OP_TYPE_REQ: @@ -1606,6 +1623,7 @@ unsigned int bt_att_send(struct bt_att *att, uint8_t opcode, break; } +done: if (!result) { free(op->pdu); free(op); @@ -2025,3 +2043,29 @@ bool bt_att_has_crypto(struct bt_att *att) return att->crypto ? true : false; } + +bool bt_att_set_retry(struct bt_att *att, unsigned int id, bool retry) +{ + struct att_send_op *op; + + if (!id) + return false; + + op = queue_find(att->req_queue, match_op_id, UINT_TO_PTR(id)); + if (op) + goto done; + + op = queue_find(att->ind_queue, match_op_id, UINT_TO_PTR(id)); + if (op) + goto done; + + op = queue_find(att->write_queue, match_op_id, UINT_TO_PTR(id)); + +done: + if (!op) + return false; + + op->retry = !retry; + + return true; +} diff --git a/src/shared/att.h b/src/shared/att.h index 4aa3de87be08efb5ffa420573bcc0326db6b16fc..53a3f7a2ae98da48184a1c712be80cd4b4ebee1c 100644 --- a/src/shared/att.h +++ b/src/shared/att.h @@ -35,7 +35,7 @@ int bt_att_get_channels(struct bt_att *att); typedef void (*bt_att_response_func_t)(uint8_t opcode, const void *pdu, uint16_t length, void *user_data); -typedef void (*bt_att_notify_func_t)(struct bt_att_chan *chan, +typedef void (*bt_att_notify_func_t)(struct bt_att_chan *chan, uint16_t mtu, uint8_t opcode, const void *pdu, uint16_t length, void *user_data); typedef void (*bt_att_destroy_func_t)(void *user_data); @@ -110,3 +110,4 @@ bool bt_att_set_local_key(struct bt_att *att, uint8_t sign_key[16], bool bt_att_set_remote_key(struct bt_att *att, uint8_t sign_key[16], bt_att_counter_func_t func, void *user_data); bool bt_att_has_crypto(struct bt_att *att); +bool bt_att_set_retry(struct bt_att *att, unsigned int id, bool retry); diff --git a/src/shared/bap-debug.c b/src/shared/bap-debug.c new file mode 100644 index 0000000000000000000000000000000000000000..495a22c441268a9234a8253ca4d2711be52ecec8 --- /dev/null +++ b/src/shared/bap-debug.c @@ -0,0 +1,543 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2023 Intel Corporation. + */ + +#define _GNU_SOURCE +#include <inttypes.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> +#include <unistd.h> +#include <errno.h> + +#include "src/shared/util.h" +#include "src/shared/bap-debug.h" + +static const struct util_bit_debugger pac_freq_table[] = { + UTIL_BIT_DEBUG(0, "8 Khz (0x0001)"), + UTIL_BIT_DEBUG(1, "11.25 Khz (0x0002)"), + UTIL_BIT_DEBUG(2, "16 Khz (0x0004)"), + UTIL_BIT_DEBUG(3, "22.05 Khz (0x0008)"), + UTIL_BIT_DEBUG(4, "24 Khz (0x0010)"), + UTIL_BIT_DEBUG(5, "32 Khz (0x0020)"), + UTIL_BIT_DEBUG(6, "44.1 Khz (0x0040)"), + UTIL_BIT_DEBUG(7, "48 Khz (0x0080)"), + UTIL_BIT_DEBUG(8, "88.2 Khz (0x0100)"), + UTIL_BIT_DEBUG(9, "96 Khz (0x0200)"), + UTIL_BIT_DEBUG(10, "176.4 Khz (0x0400)"), + UTIL_BIT_DEBUG(11, "192 Khz (0x0800)"), + UTIL_BIT_DEBUG(12, "384 Khz (0x1000)"), + UTIL_BIT_DEBUG(13, "RFU (0x2000)"), + UTIL_BIT_DEBUG(14, "RFU (0x4000)"), + UTIL_BIT_DEBUG(15, "RFU (0x8000)"), + { } +}; + +static void pac_debug_freq(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) +{ + struct iovec frame = { (void *)data, len }; + uint16_t value; + uint16_t mask; + + if (!util_iov_pull_le16(&frame, &value)) { + util_debug(func, user_data, "value: invalid size"); + goto done; + } + + util_debug(func, user_data, "Sampling Frequencies: 0x%4.4x", value); + + mask = util_debug_bit("Sampling Frequency: ", value, pac_freq_table, + func, user_data); + if (mask) + util_debug(func, user_data, "Unknown fields (0x%4.4x)", + mask); + +done: + if (frame.iov_len) + util_hexdump(' ', frame.iov_base, frame.iov_len, func, + user_data); +} + +static const struct util_bit_debugger pac_duration_table[] = { + UTIL_BIT_DEBUG(0, "7.5 ms (0x01)"), + UTIL_BIT_DEBUG(1, "10 ms (0x02)"), + UTIL_BIT_DEBUG(2, "RFU (0x04)"), + UTIL_BIT_DEBUG(3, "RFU (0x08)"), + UTIL_BIT_DEBUG(4, "7.5 ms preferred (0x10)"), + UTIL_BIT_DEBUG(5, "10 ms preferred (0x20)"), + UTIL_BIT_DEBUG(6, "RFU (0x40)"), + UTIL_BIT_DEBUG(7, "RFU (0x80)"), + { } +}; + +static void pac_debug_duration(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) +{ + struct iovec frame = { (void *)data, len }; + uint8_t value; + uint8_t mask; + + if (!util_iov_pull_u8(&frame, &value)) { + util_debug(func, user_data, "value: invalid size"); + goto done; + } + + util_debug(func, user_data, "Frame Duration: 0x%2.2x", value); + + mask = util_debug_bit("Frame Duration: ", value, pac_duration_table, + func, user_data); + if (mask) + util_debug(func, user_data, "Unknown fields (0x%2.2x)", + mask); + +done: + if (frame.iov_len) + util_hexdump(' ', frame.iov_base, frame.iov_len, func, + user_data); +} + +static const struct util_bit_debugger pac_channel_table[] = { + UTIL_BIT_DEBUG(0, "1 channel (0x01)"), + UTIL_BIT_DEBUG(1, "2 channel (0x02)"), + UTIL_BIT_DEBUG(2, "3 channel (0x04)"), + UTIL_BIT_DEBUG(3, "4 channel (0x08)"), + UTIL_BIT_DEBUG(4, "5 channel (0x10)"), + UTIL_BIT_DEBUG(5, "6 channel (0x20)"), + UTIL_BIT_DEBUG(6, "7 channel (0x40)"), + UTIL_BIT_DEBUG(7, "8 channel (0x80)"), + { } +}; + +static void pac_debug_channels(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) +{ + struct iovec frame = { (void *)data, len }; + uint8_t value; + uint8_t mask; + + if (!util_iov_pull_u8(&frame, &value)) { + util_debug(func, user_data, "value: invalid size"); + goto done; + } + + util_debug(func, user_data, "Audio Channel Count: 0x%2.2x", value); + + mask = util_debug_bit("Audio Channel Count: ", value, + pac_channel_table, func, user_data); + if (mask) + util_debug(func, user_data, "Unknown fields (0x%2.2x)", + mask); + +done: + if (frame.iov_len) + util_hexdump(' ', frame.iov_base, frame.iov_len, func, + user_data); +} + +static void pac_debug_frame_length(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) +{ + struct iovec frame = { (void *)data, len }; + uint16_t min, max; + + if (!util_iov_pull_le16(&frame, &min)) { + util_debug(func, user_data, "min: invalid size"); + goto done; + } + + if (!util_iov_pull_le16(&frame, &max)) { + util_debug(func, user_data, "max: invalid size"); + goto done; + } + + util_debug(func, user_data, + "Frame Length: %u (0x%4.4x) - %u (0x%4.4x)", + min, min, max, max); + +done: + if (frame.iov_len) + util_hexdump(' ', frame.iov_base, frame.iov_len, func, + user_data); +} + +static void pac_debug_sdu(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) +{ + struct iovec frame = { (void *)data, len }; + uint8_t value; + + if (!util_iov_pull_u8(&frame, &value)) { + util_debug(func, user_data, "value: invalid size"); + goto done; + } + + util_debug(func, user_data, "Max SDU: %u (0x%2.2x)", value, value); + +done: + if (frame.iov_len) + util_hexdump(' ', frame.iov_base, frame.iov_len, func, + user_data); +} + +static const struct util_ltv_debugger pac_cap_table[] = { + UTIL_LTV_DEBUG(0x01, pac_debug_freq), + UTIL_LTV_DEBUG(0x02, pac_debug_duration), + UTIL_LTV_DEBUG(0x03, pac_debug_channels), + UTIL_LTV_DEBUG(0x04, pac_debug_frame_length), + UTIL_LTV_DEBUG(0x05, pac_debug_sdu) +}; + +bool bt_bap_debug_caps(void *data, size_t len, util_debug_func_t func, + void *user_data) +{ + return util_debug_ltv(data, len, pac_cap_table, + ARRAY_SIZE(pac_cap_table), + func, user_data); +} + +static void ase_debug_freq(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) +{ + struct iovec frame = { (void *)data, len }; + uint8_t value; + + if (!util_iov_pull_u8(&frame, &value)) { + util_debug(func, user_data, "value: invalid size"); + goto done; + } + + switch (value) { + case 0x01: + util_debug(func, user_data, "Sampling Frequency: 8 Khz (0x01)"); + break; + case 0x02: + util_debug(func, user_data, + "Sampling Frequency: 11.25 Khz (0x02)"); + break; + case 0x03: + util_debug(func, user_data, + "Sampling Frequency: 16 Khz (0x03)"); + break; + case 0x04: + util_debug(func, user_data, + "Sampling Frequency: 22.05 Khz (0x04)"); + break; + case 0x05: + util_debug(func, user_data, + "Sampling Frequency: 24 Khz (0x05)"); + break; + case 0x06: + util_debug(func, user_data, + "Sampling Frequency: 32 Khz (0x06)"); + break; + case 0x07: + util_debug(func, user_data, + "Sampling Frequency: 44.1 Khz (0x07)"); + break; + case 0x08: + util_debug(func, user_data, + "Sampling Frequency: 48 Khz (0x08)"); + break; + case 0x09: + util_debug(func, user_data, + "Sampling Frequency: 88.2 Khz (0x09)"); + break; + case 0x0a: + util_debug(func, user_data, + "Sampling Frequency: 96 Khz (0x0a)"); + break; + case 0x0b: + util_debug(func, user_data, + "Sampling Frequency: 176.4 Khz (0x0b)"); + break; + case 0x0c: + util_debug(func, user_data, + "Sampling Frequency: 192 Khz (0x0c)"); + break; + case 0x0d: + util_debug(func, user_data, + "Sampling Frequency: 384 Khz (0x0d)"); + break; + default: + util_debug(func, user_data, + "Sampling Frequency: RFU (0x%2.2x)", value); + break; + } + +done: + if (frame.iov_len) + util_hexdump(' ', frame.iov_base, frame.iov_len, func, + user_data); +} + +static void ase_debug_duration(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) +{ + struct iovec frame = { (void *)data, len }; + uint8_t value; + + if (!util_iov_pull_u8(&frame, &value)) { + util_debug(func, user_data, "\tvalue: invalid size\n"); + goto done; + } + + switch (value) { + case 0x00: + util_debug(func, user_data, "Frame Duration: 7.5 ms (0x00)"); + break; + case 0x01: + util_debug(func, user_data, "Frame Duration: 10 ms (0x01)"); + break; + default: + util_debug(func, user_data, "Frame Duration: RFU (0x%2.2x)", + value); + break; + } + +done: + if (frame.iov_len) + util_hexdump(' ', frame.iov_base, frame.iov_len, func, + user_data); +} + +static const struct util_bit_debugger channel_location_table[] = { + UTIL_BIT_DEBUG(0, "Front Left (0x00000001)"), + UTIL_BIT_DEBUG(1, "Front Right (0x00000002)"), + UTIL_BIT_DEBUG(2, "Front Center (0x00000004)"), + UTIL_BIT_DEBUG(3, "Low Frequency Effects 1 (0x00000008)"), + UTIL_BIT_DEBUG(4, "Back Left (0x00000010)"), + UTIL_BIT_DEBUG(5, "Back Right (0x00000020)"), + UTIL_BIT_DEBUG(6, "Front Left of Center (0x00000040)"), + UTIL_BIT_DEBUG(7, "Front Right of Center (0x00000080)"), + UTIL_BIT_DEBUG(8, "Back Center (0x00000100)"), + UTIL_BIT_DEBUG(9, "Low Frequency Effects 2 (0x00000200)"), + UTIL_BIT_DEBUG(10, "Side Left (0x00000400)"), + UTIL_BIT_DEBUG(11, "Side Right (0x00000800)"), + UTIL_BIT_DEBUG(12, "Top Front Left (0x00001000)"), + UTIL_BIT_DEBUG(13, "Top Front Right (0x00002000)"), + UTIL_BIT_DEBUG(14, "Top Front Center (0x00004000)"), + UTIL_BIT_DEBUG(15, "Top Center (0x00008000)"), + UTIL_BIT_DEBUG(16, "Top Back Left (0x00010000)"), + UTIL_BIT_DEBUG(17, "Top Back Right (0x00020000)"), + UTIL_BIT_DEBUG(18, "Top Side Left (0x00040000)"), + UTIL_BIT_DEBUG(19, "Top Side Right (0x00080000)"), + UTIL_BIT_DEBUG(20, "Top Back Center (0x00100000)"), + UTIL_BIT_DEBUG(21, "Bottom Front Center (0x00200000)"), + UTIL_BIT_DEBUG(22, "Bottom Front Left (0x00400000)"), + UTIL_BIT_DEBUG(23, "Bottom Front Right (0x00800000)"), + UTIL_BIT_DEBUG(24, "Front Left Wide (0x01000000)"), + UTIL_BIT_DEBUG(25, "Front Right Wide (0x02000000)"), + UTIL_BIT_DEBUG(26, "Left Surround (0x04000000)"), + UTIL_BIT_DEBUG(27, "Right Surround (0x08000000)"), + UTIL_BIT_DEBUG(28, "RFU (0x10000000)"), + UTIL_BIT_DEBUG(29, "RFU (0x20000000)"), + UTIL_BIT_DEBUG(30, "RFU (0x40000000)"), + UTIL_BIT_DEBUG(31, "RFU (0x80000000)"), + { } +}; + +static void debug_location(const struct iovec *frame, util_debug_func_t func, + void *user_data) +{ + uint32_t value; + uint32_t mask; + + if (!util_iov_pull_le32((void *)frame, &value)) { + util_debug(func, user_data, "value: invalid size"); + goto done; + } + + util_debug(func, user_data, "Location: 0x%8.8x", value); + + mask = util_debug_bit("Location: ", value, channel_location_table, + func, user_data); + if (mask) + util_debug(func, user_data, "Unknown fields (0x%8.8x)", mask); + +done: + if (frame->iov_len) + util_hexdump(' ', frame->iov_base, frame->iov_len, func, + user_data); +} + +static void ase_debug_location(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) +{ + struct iovec frame = { (void *)data, len }; + + debug_location(&frame, func, user_data); +} + +static void ase_debug_frame_length(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) +{ + struct iovec frame = { (void *)data, len }; + uint16_t value; + + if (!util_iov_pull_le16(&frame, &value)) { + util_debug(func, user_data, "\tvalue: invalid size\n"); + goto done; + } + + util_debug(func, user_data, "Frame Length: %u (0x%4.4x)", + value, value); + +done: + if (frame.iov_len) + util_hexdump(' ', frame.iov_base, frame.iov_len, func, + user_data); +} + +static void ase_debug_blocks(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) +{ + struct iovec frame = { (void *)data, len }; + uint8_t value; + + if (!util_iov_pull_u8(&frame, &value)) { + util_debug(func, user_data, "value: invalid size"); + goto done; + } + + util_debug(func, user_data, "Frame Blocks per SDU: %u (0x%2.2x)", + value, value); + +done: + if (frame.iov_len) + util_hexdump(' ', frame.iov_base, frame.iov_len, func, + user_data); +} + +static const struct util_ltv_debugger ase_cc_table[] = { + UTIL_LTV_DEBUG(0x01, ase_debug_freq), + UTIL_LTV_DEBUG(0x02, ase_debug_duration), + UTIL_LTV_DEBUG(0x03, ase_debug_location), + UTIL_LTV_DEBUG(0x04, ase_debug_frame_length), + UTIL_LTV_DEBUG(0x05, ase_debug_blocks) +}; + +bool bt_bap_debug_config(void *data, size_t len, util_debug_func_t func, + void *user_data) +{ + return util_debug_ltv(data, len, ase_cc_table, + ARRAY_SIZE(ase_cc_table), + func, user_data); +} + +static const struct util_bit_debugger pac_context_table[] = { + UTIL_BIT_DEBUG(0, "\tUnspecified (0x0001)"), + UTIL_BIT_DEBUG(1, "\tConversational (0x0002)"), + UTIL_BIT_DEBUG(2, "\tMedia (0x0004)"), + UTIL_BIT_DEBUG(3, "\tGame (0x0008)"), + UTIL_BIT_DEBUG(4, "\tInstructional (0x0010)"), + UTIL_BIT_DEBUG(5, "\tVoice Assistants (0x0020)"), + UTIL_BIT_DEBUG(6, "\tLive (0x0040)"), + UTIL_BIT_DEBUG(7, "\tSound Effects (0x0080)"), + UTIL_BIT_DEBUG(8, "\tNotifications (0x0100)"), + UTIL_BIT_DEBUG(9, "\tRingtone (0x0200)"), + UTIL_BIT_DEBUG(10, "\tAlerts (0x0400)"), + UTIL_BIT_DEBUG(11, "\tEmergency alarm (0x0800)"), + UTIL_BIT_DEBUG(12, "\tRFU (0x1000)"), + UTIL_BIT_DEBUG(13, "\tRFU (0x2000)"), + UTIL_BIT_DEBUG(14, "\tRFU (0x4000)"), + UTIL_BIT_DEBUG(15, "\tRFU (0x8000)"), + { } +}; + +static void debug_context(const struct iovec *frame, const char *label, + util_debug_func_t func, void *user_data) +{ + uint16_t value; + uint16_t mask; + + if (!util_iov_pull_le16((void *)frame, &value)) { + util_debug(func, user_data, "value: invalid size"); + goto done; + } + + util_debug(func, user_data, "%s: 0x%4.4x", label, value); + + mask = util_debug_bit(label, value, pac_context_table, func, user_data); + if (mask) + util_debug(func, user_data, "Unknown fields (0x%4.4x)", mask); + +done: + if (frame->iov_len) + util_hexdump(' ', frame->iov_base, frame->iov_len, func, + user_data); +} + +static void ase_debug_preferred_context(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) +{ + struct iovec frame = { (void *)data, len }; + + debug_context(&frame, "Preferred Context", func, user_data); +} + +static void ase_debug_context(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) +{ + struct iovec frame = { (void *)data, len }; + + debug_context(&frame, "Context", func, user_data); +} + +static void ase_debug_program_info(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) +{ + struct iovec frame = { (void *)data, len }; + const char *str; + + str = util_iov_pull_mem(&frame, len); + if (!str) { + util_debug(func, user_data, "value: invalid size"); + goto done; + } + + util_debug(func, user_data, "Program Info: %*s", len, str); + +done: + if (frame.iov_len) + util_hexdump(' ', frame.iov_base, frame.iov_len, func, + user_data); +} + +static void ase_debug_language(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data) +{ + struct iovec frame = { (void *)data, len }; + uint32_t value; + + if (!util_iov_pull_le24(&frame, &value)) { + util_debug(func, user_data, "value: invalid size"); + goto done; + } + + util_debug(func, user_data, "Language: 0x%6.6x\n", value); + +done: + if (frame.iov_len) + util_hexdump(' ', frame.iov_base, frame.iov_len, func, + user_data); +} + +static const struct util_ltv_debugger ase_metadata_table[] = { + UTIL_LTV_DEBUG(0x01, ase_debug_preferred_context), + UTIL_LTV_DEBUG(0x02, ase_debug_context), + UTIL_LTV_DEBUG(0x03, ase_debug_program_info), + UTIL_LTV_DEBUG(0x04, ase_debug_language) +}; + +bool bt_bap_debug_metadata(void *data, size_t len, util_debug_func_t func, + void *user_data) +{ + return util_debug_ltv(data, len, ase_metadata_table, + ARRAY_SIZE(ase_metadata_table), + func, user_data); +} diff --git a/src/shared/bap-debug.h b/src/shared/bap-debug.h new file mode 100644 index 0000000000000000000000000000000000000000..93f3b18e17c4fa4297c71cd47a67726166fa4174 --- /dev/null +++ b/src/shared/bap-debug.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2023 Intel Corporation. + */ + +bool bt_bap_debug_caps(void *data, size_t len, util_debug_func_t func, + void *user_data); +bool bt_bap_debug_config(void *data, size_t len, util_debug_func_t func, + void *user_data); +bool bt_bap_debug_metadata(void *data, size_t len, util_debug_func_t func, + void *user_data); diff --git a/src/shared/bap-defs.h b/src/shared/bap-defs.h new file mode 100644 index 0000000000000000000000000000000000000000..27fefa34f1ec7fa538ff651ff677366f009fad85 --- /dev/null +++ b/src/shared/bap-defs.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2022 Intel Corporation. All rights reserved. + * Copyright 2023-2024 NXP + * + */ + +#ifndef SRC_SHARED_BAP_DEFS_H_ +#define SRC_SHARED_BAP_DEFS_H_ + +#ifndef __packed +#define __packed __attribute__((packed)) +#endif + +#define BT_BAP_SINK BIT(0) +#define BT_BAP_SOURCE BIT(1) +#define BT_BAP_BCAST_SOURCE BIT(2) +#define BT_BAP_BCAST_SINK BIT(3) + +#define BT_BAP_STREAM_TYPE_UCAST 0x01 +#define BT_BAP_STREAM_TYPE_BCAST 0x02 + +#define BT_BAP_STREAM_STATE_IDLE 0x00 +#define BT_BAP_STREAM_STATE_CONFIG 0x01 +#define BT_BAP_STREAM_STATE_QOS 0x02 +#define BT_BAP_STREAM_STATE_ENABLING 0x03 +#define BT_BAP_STREAM_STATE_STREAMING 0x04 +#define BT_BAP_STREAM_STATE_DISABLING 0x05 +#define BT_BAP_STREAM_STATE_RELEASING 0x06 + +#define BT_BAP_CONFIG_LATENCY_LOW 0x01 +#define BT_BAP_CONFIG_LATENCY_BALANCED 0x02 +#define BT_BAP_CONFIG_LATENCY_HIGH 0x03 + +#define BT_BAP_CONFIG_PHY_1M 0x01 +#define BT_BAP_CONFIG_PHY_2M 0x02 +#define BT_BAP_CONFIG_PHY_CODEC 0x03 + +struct bt_bap_codec { + uint8_t id; + uint16_t cid; + uint16_t vid; +} __packed; + +struct bt_ltv { + uint8_t len; + uint8_t type; + uint8_t value[]; +} __packed; + +struct bt_bap_io_qos { + uint32_t interval; /* Frame interval */ + uint16_t latency; /* Transport Latency */ + uint16_t sdu; /* Maximum SDU Size */ + uint8_t phy; /* PHY */ + uint8_t rtn; /* Retransmission Effort */ +}; + +struct bt_bap_ucast_qos { + uint8_t cig_id; + uint8_t cis_id; + uint8_t framing; /* Frame framing */ + uint32_t delay; /* Presentation Delay */ + uint8_t target_latency; /* Target Latency */ + struct bt_bap_io_qos io_qos; +}; + +struct bt_bap_bcast_qos { + uint8_t big; + uint8_t bis; + uint8_t sync_factor; + uint8_t packing; + uint8_t framing; + uint8_t encryption; + struct iovec *bcode; + uint8_t options; + uint16_t skip; + uint16_t sync_timeout; + uint8_t sync_cte_type; + uint8_t mse; + uint16_t timeout; + uint8_t pa_sync; + struct bt_bap_io_qos io_qos; + uint32_t delay; /* Presentation Delay */ +}; + +struct bt_bap_qos { + union { + struct bt_bap_ucast_qos ucast; + struct bt_bap_bcast_qos bcast; + }; +}; + +#endif /* SRC_SHARED_BAP_DEFS_H_ */ diff --git a/src/shared/bap.c b/src/shared/bap.c index c3c0d596fe91f3e6cff35df8d7a4f81a0159733f..658ee1370bd89de12db53080771344971d509b40 100644 --- a/src/shared/bap.c +++ b/src/shared/bap.c @@ -4,6 +4,7 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2022 Intel Corporation. All rights reserved. + * Copyright 2023-2024 NXP * */ @@ -28,6 +29,7 @@ #include "src/shared/gatt-client.h" #include "src/shared/bap.h" #include "src/shared/ascs.h" +#include "src/shared/bap-debug.h" /* Maximum number of ASE(s) */ #define NUM_SINKS 2 @@ -46,7 +48,17 @@ #define BAP_PROCESS_TIMEOUT 10 +#define BAP_FREQ_LTV_TYPE 1 +#define BAP_DURATION_LTV_TYPE 2 +#define BAP_CHANNEL_ALLOCATION_LTV_TYPE 3 +#define BAP_FRAME_LEN_LTV_TYPE 4 +#define CODEC_SPECIFIC_CONFIGURATION_MASK (\ + (1<<BAP_FREQ_LTV_TYPE)|\ + (1<<BAP_DURATION_LTV_TYPE)|\ + (1<<BAP_FRAME_LEN_LTV_TYPE)) + struct bt_bap_pac_changed { + unsigned int id; bt_bap_pac_func_t added; bt_bap_pac_func_t removed; bt_bap_destroy_func_t destroy; @@ -90,6 +102,12 @@ struct bt_pacs { struct gatt_db_attribute *context_ccc; struct gatt_db_attribute *supported_context; struct gatt_db_attribute *supported_context_ccc; + uint32_t source_loc_value; + uint32_t sink_loc_value; + uint16_t source_context_value; + uint16_t sink_context_value; + uint16_t supported_source_context_value; + uint16_t supported_sink_context_value; }; struct bt_ase { @@ -113,7 +131,8 @@ struct bt_bap_db { struct bt_ascs *ascs; struct queue *sinks; struct queue *sources; - struct queue *endpoints; + struct queue *broadcast_sources; + struct queue *broadcast_sinks; }; struct bt_bap_req { @@ -127,17 +146,6 @@ struct bt_bap_req { void *user_data; }; -typedef void (*bap_func_t)(struct bt_bap *bap, bool success, uint8_t att_ecode, - const uint8_t *value, uint16_t length, - void *user_data); - -struct bt_bap_pending { - unsigned int id; - struct bt_bap *bap; - bap_func_t func; - void *user_data; -}; - typedef void (*bap_notify_t)(struct bt_bap *bap, uint16_t value_handle, const uint8_t *value, uint16_t length, void *user_data); @@ -156,15 +164,20 @@ struct bt_bap { struct bt_gatt_client *client; struct bt_att *att; struct bt_bap_req *req; - unsigned int cp_id; + unsigned int cp_id; unsigned int process_id; unsigned int disconn_id; + unsigned int idle_id; + bool in_cp_write; + struct queue *reqs; - struct queue *pending; struct queue *notify; struct queue *streams; + struct queue *local_eps; + struct queue *remote_eps; + struct queue *pac_cbs; struct queue *ready_cbs; struct queue *state_cbs; @@ -174,21 +187,26 @@ struct bt_bap { void *user_data; }; +struct bt_bap_chan { + uint8_t count; + uint32_t location; +}; + struct bt_bap_pac { struct bt_bap_db *bdb; char *name; uint8_t type; - uint32_t locations; - uint16_t contexts; struct bt_bap_codec codec; struct bt_bap_pac_qos qos; struct iovec *data; struct iovec *metadata; + struct queue *channels; struct bt_bap_pac_ops *ops; void *user_data; }; struct bt_bap_endpoint { + struct bt_bap *bap; struct bt_bap_db *bdb; struct bt_bap_stream *stream; struct gatt_db_attribute *attr; @@ -206,10 +224,47 @@ struct bt_bap_stream_io { bool connecting; }; +struct bt_bap_stream_ops { + uint8_t type; + void (*set_state)(struct bt_bap_stream *stream, uint8_t state); + unsigned int (*get_state)(struct bt_bap_stream *stream); + unsigned int (*config)(struct bt_bap_stream *stream, + struct bt_bap_qos *qos, struct iovec *data, + bt_bap_stream_func_t func, void *user_data); + unsigned int (*qos)(struct bt_bap_stream *stream, + struct bt_bap_qos *qos, + bt_bap_stream_func_t func, void *user_data); + unsigned int (*enable)(struct bt_bap_stream *stream, bool enable_links, + struct iovec *metadata, + bt_bap_stream_func_t func, void *user_data); + unsigned int (*start)(struct bt_bap_stream *stream, + bt_bap_stream_func_t func, void *user_data); + unsigned int (*disable)(struct bt_bap_stream *stream, + bool disable_links, bt_bap_stream_func_t func, + void *user_data); + unsigned int (*stop)(struct bt_bap_stream *stream, + bt_bap_stream_func_t func, void *user_data); + unsigned int (*metadata)(struct bt_bap_stream *stream, + struct iovec *data, bt_bap_stream_func_t func, + void *user_data); + unsigned int (*get_dir)(struct bt_bap_stream *stream); + unsigned int (*get_loc)(struct bt_bap_stream *stream); + unsigned int (*release)(struct bt_bap_stream *stream, + bt_bap_stream_func_t func, void *user_data); + void (*detach)(struct bt_bap_stream *stream); + bool (*set_io)(struct bt_bap_stream *stream, int fd); + struct bt_bap_stream_io* (*get_io)(struct bt_bap_stream *stream); + uint8_t (*io_dir)(struct bt_bap_stream *stream); + int (*io_link)(struct bt_bap_stream *stream, + struct bt_bap_stream *link); + int (*io_unlink)(struct bt_bap_stream *stream, + struct bt_bap_stream *link); +}; + struct bt_bap_stream { + int ref_count; struct bt_bap *bap; struct bt_bap_endpoint *ep; - struct queue *pacs; struct bt_bap_pac *lpac; struct bt_bap_pac *rpac; struct iovec *cc; @@ -217,6 +272,10 @@ struct bt_bap_stream { struct bt_bap_qos qos; struct queue *links; struct bt_bap_stream_io *io; + const struct bt_bap_stream_ops *ops; + uint8_t old_state; + uint8_t state; + unsigned int state_id; bool client; void *user_data; }; @@ -248,12 +307,38 @@ struct bt_pacs_context { uint16_t src; } __packed; +struct bt_base { + uint8_t big_id; + uint32_t pres_delay; + uint8_t next_bis_index; + struct queue *subgroups; +}; + +struct bt_subgroup { + uint8_t index; + struct bt_bap_codec codec; + struct iovec *caps; + struct iovec *meta; + struct queue *bises; +}; + +struct bt_bis { + uint8_t index; + struct iovec *caps; +}; + /* Contains local bt_bap_db */ static struct queue *bap_db; -static struct queue *pac_cbs; static struct queue *bap_cbs; static struct queue *sessions; +static void bap_stream_set_io(void *data, void *user_data); +static void stream_find_io(void *data, void *user_data); +static void bap_stream_get_dir(void *data, void *user_data); +static struct bt_bap_stream_io *stream_io_ref(struct bt_bap_stream_io *io); +static int bap_bcast_io_unlink(struct bt_bap_stream *stream, + struct bt_bap_stream *link); + static bool bap_db_match(const void *data, const void *match_data) { const struct bt_bap_db *bdb = data; @@ -262,94 +347,26 @@ static bool bap_db_match(const void *data, const void *match_data) return (bdb->db == db); } -static void *iov_add(struct iovec *iov, size_t len) -{ - void *data; - - data = iov->iov_base + iov->iov_len; - iov->iov_len += len; - - return data; -} - -static void *iov_add_mem(struct iovec *iov, size_t len, const void *d) -{ - void *data; - - data = iov->iov_base + iov->iov_len; - iov->iov_len += len; - - memcpy(data, d, len); - - return data; -} - -static void iov_free(void *data) -{ - struct iovec *iov = data; - - if (!iov) - return; - - free(iov->iov_base); - free(iov); -} - -static void iov_memcpy(struct iovec *iov, void *src, size_t len) -{ - iov->iov_base = realloc(iov->iov_base, len); - iov->iov_len = len; - memcpy(iov->iov_base, src, len); -} - -static int iov_memcmp(struct iovec *iov1, struct iovec *iov2) -{ - if (!iov1) - return 1; - - if (!iov2) - return -1; - - if (iov1->iov_len != iov2->iov_len) - return iov1->iov_len - iov2->iov_len; - - return memcmp(iov1->iov_base, iov2->iov_base, iov1->iov_len); -} - -static struct iovec *iov_dup(struct iovec *iov, size_t len) -{ - struct iovec *dup; - size_t i; - - if (!iov) - return NULL; - - dup = new0(struct iovec, len); - - for (i = 0; i < len; i++) - iov_memcpy(&dup[i], iov[i].iov_base, iov[i].iov_len); - - return dup; -} - -unsigned int bt_bap_pac_register(bt_bap_pac_func_t added, +unsigned int bt_bap_pac_register(struct bt_bap *bap, bt_bap_pac_func_t added, bt_bap_pac_func_t removed, void *user_data, bt_bap_destroy_func_t destroy) { struct bt_bap_pac_changed *changed; + static unsigned int id; + + if (!bap) + return 0; changed = new0(struct bt_bap_pac_changed, 1); + changed->id = ++id ? id : ++id; changed->added = added; changed->removed = removed; changed->destroy = destroy; changed->data = user_data; - if (!pac_cbs) - pac_cbs = queue_new(); + queue_push_tail(bap->pac_cbs, changed); - queue_push_tail(pac_cbs, changed); - - return queue_length(pac_cbs); + return changed->id; } static void pac_changed_free(void *data) @@ -362,39 +379,28 @@ static void pac_changed_free(void *data) free(changed); } -struct match_pac_id { - unsigned int id; - unsigned int index; -}; - -static bool match_index(const void *data, const void *match_data) +static bool match_pac_changed_id(const void *data, const void *match_data) { - struct match_pac_id *match = (void *)match_data; - - match->index++; + const struct bt_bap_pac_changed *changed = data; + unsigned int id = PTR_TO_UINT(match_data); - return match->id == match->index; + return (changed->id == id); } -bool bt_bap_pac_unregister(unsigned int id) +bool bt_bap_pac_unregister(struct bt_bap *bap, unsigned int id) { struct bt_bap_pac_changed *changed; - struct match_pac_id match; - memset(&match, 0, sizeof(match)); - match.id = id; + if (!bap) + return false; - changed = queue_remove_if(pac_cbs, match_index, &match); + changed = queue_remove_if(bap->pac_cbs, match_pac_changed_id, + UINT_TO_PTR(id)); if (!changed) return false; pac_changed_free(changed); - if (queue_isempty(pac_cbs)) { - queue_destroy(pac_cbs, NULL); - pac_cbs = NULL; - } - return true; } @@ -407,27 +413,29 @@ static void pac_foreach(void *data, void *user_data) struct bt_pac_metadata *meta; if (!iov->iov_len) { - rsp = iov_add(iov, sizeof(*rsp)); + rsp = util_iov_push(iov, sizeof(*rsp)); rsp->num_pac = 0; } else rsp = iov->iov_base; rsp->num_pac++; - p = iov_add(iov, sizeof(*p)); + p = util_iov_push(iov, sizeof(*p)); p->codec.id = pac->codec.id; + p->codec.cid = cpu_to_le16(pac->codec.cid); + p->codec.vid = cpu_to_le16(pac->codec.vid); if (pac->data) { p->cc_len = pac->data->iov_len; - iov_add_mem(iov, p->cc_len, pac->data->iov_base); + util_iov_push_mem(iov, p->cc_len, pac->data->iov_base); } else p->cc_len = 0; - meta = iov_add(iov, sizeof(*meta)); + meta = util_iov_push(iov, sizeof(*meta)); if (pac->metadata) { meta->len = pac->metadata->iov_len; - iov_add_mem(iov, meta->len, pac->metadata->iov_base); + util_iov_push_mem(iov, meta->len, pac->metadata->iov_base); } else meta->len = 0; } @@ -448,6 +456,7 @@ static void pacs_sink_read(struct gatt_db_attribute *attrib, iov.iov_len = 0; queue_foreach(bdb->sinks, pac_foreach, &iov); + queue_foreach(bdb->broadcast_sinks, pac_foreach, &iov); gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base, iov.iov_len); @@ -458,7 +467,8 @@ static void pacs_sink_loc_read(struct gatt_db_attribute *attrib, uint8_t opcode, struct bt_att *att, void *user_data) { - uint32_t value = 0x00000003; + struct bt_pacs *pacs = user_data; + uint32_t value = cpu_to_le32(pacs->sink_loc_value); gatt_db_attribute_read_result(attrib, id, 0, (void *) &value, sizeof(value)); @@ -490,7 +500,8 @@ static void pacs_source_loc_read(struct gatt_db_attribute *attrib, uint8_t opcode, struct bt_att *att, void *user_data) { - uint32_t value = 0x00000001; + struct bt_pacs *pacs = user_data; + uint32_t value = cpu_to_le32(pacs->source_loc_value); gatt_db_attribute_read_result(attrib, id, 0, (void *) &value, sizeof(value)); @@ -501,9 +512,10 @@ static void pacs_context_read(struct gatt_db_attribute *attrib, uint8_t opcode, struct bt_att *att, void *user_data) { + struct bt_pacs *pacs = user_data; struct bt_pacs_context ctx = { - .snk = 0x0fff, - .src = 0x000e + .snk = cpu_to_le16(pacs->sink_context_value), + .src = cpu_to_le16(pacs->source_context_value) }; gatt_db_attribute_read_result(attrib, id, 0, (void *) &ctx, @@ -515,9 +527,10 @@ static void pacs_supported_context_read(struct gatt_db_attribute *attrib, uint8_t opcode, struct bt_att *att, void *user_data) { + struct bt_pacs *pacs = user_data; struct bt_pacs_context ctx = { - .snk = 0x0fff, - .src = 0x000e + .snk = cpu_to_le16(pacs->supported_sink_context_value), + .src = cpu_to_le16(pacs->supported_source_context_value) }; gatt_db_attribute_read_result(attrib, id, 0, (void *) &ctx, @@ -561,14 +574,14 @@ static struct bt_pacs *pacs_new(struct gatt_db *db) BT_ATT_PERM_READ | BT_ATT_PERM_WRITE); bt_uuid16_create(&uuid, PAC_SOURCE_CHRC_UUID); - pacs->sink = gatt_db_service_add_characteristic(pacs->service, &uuid, + pacs->source = gatt_db_service_add_characteristic(pacs->service, &uuid, BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_NOTIFY, pacs_source_read, NULL, pacs); - pacs->sink_ccc = gatt_db_service_add_ccc(pacs->service, + pacs->source_ccc = gatt_db_service_add_ccc(pacs->service, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE); bt_uuid16_create(&uuid, PAC_SOURCE_LOC_CHRC_UUID); @@ -685,7 +698,24 @@ static struct bt_bap_endpoint *bap_endpoint_new(struct bt_bap_db *bdb, return ep; } -static struct bt_bap_endpoint *bap_get_endpoint(struct bt_bap_db *db, +static struct bt_bap_endpoint *bap_endpoint_new_broadcast(struct bt_bap_db *bdb, + uint8_t type) +{ + struct bt_bap_endpoint *ep; + + ep = new0(struct bt_bap_endpoint, 1); + ep->bdb = bdb; + ep->attr = NULL; + if (type == BT_BAP_BCAST_SINK) + ep->dir = BT_BAP_BCAST_SOURCE; + else + ep->dir = BT_BAP_BCAST_SINK; + + return ep; +} + +static struct bt_bap_endpoint *bap_get_endpoint(struct queue *endpoints, + struct bt_bap_db *db, struct gatt_db_attribute *attr) { struct bt_bap_endpoint *ep; @@ -693,7 +723,7 @@ static struct bt_bap_endpoint *bap_get_endpoint(struct bt_bap_db *db, if (!db || !attr) return NULL; - ep = queue_find(db->endpoints, bap_endpoint_match, attr); + ep = queue_find(endpoints, bap_endpoint_match, attr); if (ep) return ep; @@ -701,7 +731,36 @@ static struct bt_bap_endpoint *bap_get_endpoint(struct bt_bap_db *db, if (!ep) return NULL; - queue_push_tail(db->endpoints, ep); + queue_push_tail(endpoints, ep); + + return ep; +} + +static bool match_ep_type(const void *data, const void *match_data) +{ + const struct bt_bap_endpoint *ep = data; + const uint8_t type = PTR_TO_INT(match_data); + + return (ep->dir == type); +} + +static struct bt_bap_endpoint *bap_get_endpoint_bcast(struct queue *endpoints, + struct bt_bap_db *db, uint8_t type) +{ + struct bt_bap_endpoint *ep; + + if (!db) + return NULL; + + ep = queue_find(endpoints, match_ep_type, INT_TO_PTR(type)); + if (ep) + return ep; + + ep = bap_endpoint_new_broadcast(db, type); + if (!ep) + return NULL; + + queue_push_tail(endpoints, ep); return ep; } @@ -714,23 +773,22 @@ static bool bap_endpoint_match_id(const void *data, const void *match_data) return (ep->id == id); } -static struct bt_bap_endpoint *bap_get_endpoint_id(struct bt_bap *bap, - struct bt_bap_db *db, - uint8_t id) +static struct bt_bap_endpoint *bap_get_local_endpoint_id(struct bt_bap *bap, + uint8_t id) { struct bt_bap_endpoint *ep; struct gatt_db_attribute *attr = NULL; size_t i; - if (!bap || !db) + if (!bap) return NULL; - ep = queue_find(db->endpoints, bap_endpoint_match_id, UINT_TO_PTR(id)); + ep = queue_find(bap->local_eps, bap_endpoint_match_id, UINT_TO_PTR(id)); if (ep) return ep; - for (i = 0; i < ARRAY_SIZE(db->ascs->ase); i++) { - struct bt_ase *ase = db->ascs->ase[i]; + for (i = 0; i < ARRAY_SIZE(bap->ldb->ascs->ase); i++) { + struct bt_ase *ase = bap->ldb->ascs->ase[i]; if (id) { if (ase->id != id) @@ -739,7 +797,7 @@ static struct bt_bap_endpoint *bap_get_endpoint_id(struct bt_bap *bap, break; } - ep = queue_find(db->endpoints, bap_endpoint_match, ase->attr); + ep = queue_find(bap->local_eps, bap_endpoint_match, ase->attr); if (!ep) { attr = ase->attr; break; @@ -749,12 +807,12 @@ static struct bt_bap_endpoint *bap_get_endpoint_id(struct bt_bap *bap, if (!attr) return NULL; - ep = bap_endpoint_new(db, attr); + ep = bap_endpoint_new(bap->ldb, attr); if (!ep) return NULL; ep->id = id; - queue_push_tail(db->endpoints, ep); + queue_push_tail(bap->local_eps, ep); return ep; } @@ -765,11 +823,17 @@ static void ascs_ase_read(struct gatt_db_attribute *attrib, void *user_data) { struct bt_ase *ase = user_data; - struct bt_bap *bap = bap_get_session(att, ase->ascs->bdb->db); - struct bt_bap_endpoint *ep = bap_get_endpoint(bap->ldb, attrib); + struct bt_bap *bap = NULL; + struct bt_bap_endpoint *ep = NULL; struct bt_ascs_ase_status rsp; - if (!ase || !bap || !ep) { + if (ase) + bap = bap_get_session(att, ase->ascs->bdb->db); + + if (bap) + ep = bap_get_endpoint(bap->local_eps, bap->ldb, attrib); + + if (!ep) { gatt_db_attribute_read_result(attrib, id, BT_ATT_ERROR_UNLIKELY, NULL, 0); return; @@ -814,19 +878,6 @@ static void ase_new(struct bt_ascs *ascs, int i) ascs->ase[i] = ase; } -static void *iov_pull_mem(struct iovec *iov, size_t len) -{ - void *data = iov->iov_base; - - if (iov->iov_len < len) - return NULL; - - iov->iov_base += len; - iov->iov_len -= len; - - return data; -} - static bool bap_codec_equal(const struct bt_bap_codec *c1, const struct bt_bap_codec *c2) { @@ -837,27 +888,46 @@ static bool bap_codec_equal(const struct bt_bap_codec *c1, return c1->id == c2->id; } -static struct bt_bap_stream *bap_stream_new(struct bt_bap *bap, - struct bt_bap_endpoint *ep, - struct bt_bap_pac *lpac, - struct bt_bap_pac *rpac, - struct iovec *data, - bool client) +static void ascs_ase_rsp_add(struct iovec *iov, uint8_t id, + uint8_t code, uint8_t reason) { - struct bt_bap_stream *stream; + struct bt_ascs_cp_rsp *cp; + struct bt_ascs_ase_rsp *rsp; - stream = new0(struct bt_bap_stream, 1); - stream->bap = bap; - stream->ep = ep; - ep->stream = stream; - stream->lpac = lpac; - stream->rpac = rpac; - stream->cc = iov_dup(data, 1); - stream->client = client; + if (!iov) + return; - queue_push_tail(bap->streams, stream); + cp = iov->iov_base; - return stream; + if (cp->num_ase == 0xff) + return; + + switch (code) { + /* If the Response_Code value is 0x01 or 0x02, Number_of_ASEs shall be + * set to 0xFF. + */ + case BT_ASCS_RSP_NOT_SUPPORTED: + case BT_ASCS_RSP_TRUNCATED: + cp->num_ase = 0xff; + break; + default: + cp->num_ase++; + break; + } + + iov->iov_len += sizeof(*rsp); + iov->iov_base = realloc(iov->iov_base, iov->iov_len); + + rsp = iov->iov_base + (iov->iov_len - sizeof(*rsp)); + rsp->ase = id; + rsp->code = code; + rsp->reason = reason; +} + +static void ascs_ase_rsp_success(struct iovec *iov, uint8_t id) +{ + return ascs_ase_rsp_add(iov, id, BT_ASCS_RSP_SUCCESS, + BT_ASCS_REASON_NONE); } static void stream_notify_config(struct bt_bap_stream *stream) @@ -910,6 +980,12 @@ static void stream_notify_config(struct bt_bap_stream *stream) put_le24(lpac->qos.ppd_min, config->ppd_min); put_le24(lpac->qos.ppd_max, config->ppd_max); config->codec = lpac->codec; + + if (config->codec.id == 0x0ff) { + config->codec.vid = cpu_to_le16(config->codec.vid); + config->codec.cid = cpu_to_le16(config->codec.cid); + } + config->cc_len = stream->cc->iov_len; memcpy(config->cc, stream->cc->iov_base, stream->cc->iov_len); @@ -936,15 +1012,15 @@ static void stream_notify_qos(struct bt_bap_stream *stream) status->state = ep->state; qos = (void *)status->params; - qos->cis_id = stream->qos.cis_id; - qos->cig_id = stream->qos.cig_id; - put_le24(stream->qos.interval, qos->interval); - qos->framing = stream->qos.framing; - qos->phy = stream->qos.phy; - qos->sdu = cpu_to_le16(stream->qos.sdu); - qos->rtn = stream->qos.rtn; - qos->latency = cpu_to_le16(stream->qos.latency); - put_le24(stream->qos.delay, qos->pd); + qos->cis_id = stream->qos.ucast.cis_id; + qos->cig_id = stream->qos.ucast.cig_id; + put_le24(stream->qos.ucast.io_qos.interval, qos->interval); + qos->framing = stream->qos.ucast.framing; + qos->phy = stream->qos.ucast.io_qos.phy; + qos->sdu = cpu_to_le16(stream->qos.ucast.io_qos.sdu); + qos->rtn = stream->qos.ucast.io_qos.rtn; + qos->latency = cpu_to_le16(stream->qos.ucast.io_qos.latency); + put_le24(stream->qos.ucast.delay, qos->pd); gatt_db_attribute_notify(ep->attr, (void *) status, len, bt_bap_get_att(stream->bap)); @@ -973,8 +1049,8 @@ static void stream_notify_metadata(struct bt_bap_stream *stream) status->state = ep->state; meta = (void *)status->params; - meta->cis_id = stream->qos.cis_id; - meta->cig_id = stream->qos.cig_id; + meta->cis_id = stream->qos.ucast.cis_id; + meta->cig_id = stream->qos.ucast.cig_id; if (stream->meta) { meta->len = stream->meta->iov_len; @@ -987,6 +1063,14 @@ static void stream_notify_metadata(struct bt_bap_stream *stream) free(status); } +static struct bt_bap *bt_bap_ref_safe(struct bt_bap *bap) +{ + if (!bap || !bap->ref_count || !queue_find(sessions, NULL, bap)) + return NULL; + + return bt_bap_ref(bap); +} + static void bap_stream_clear_cfm(struct bt_bap_stream *stream) { if (!stream->lpac->ops || !stream->lpac->ops->clear) @@ -1034,149 +1118,166 @@ static void stream_io_unref(struct bt_bap_stream_io *io) static void bap_stream_unlink(void *data, void *user_data) { - struct bt_bap_stream *link = data; - struct bt_bap_stream *stream = user_data; + struct bt_bap_stream *stream = data; + struct bt_bap_stream *link = user_data; - queue_remove(link->links, stream); + queue_remove(stream->links, link); } static void bap_stream_free(void *data) { struct bt_bap_stream *stream = data; + timeout_remove(stream->state_id); + if (stream->ep) stream->ep->stream = NULL; queue_foreach(stream->links, bap_stream_unlink, stream); queue_destroy(stream->links, NULL); + stream_io_unref(stream->io); - iov_free(stream->cc); - iov_free(stream->meta); + util_iov_free(stream->cc, 1); + util_iov_free(stream->meta, 1); free(stream); } -static void bap_stream_detach(struct bt_bap_stream *stream) +static void bap_req_free(void *data) { - struct bt_bap_endpoint *ep = stream->ep; - - if (!ep) - return; + struct bt_bap_req *req = data; + size_t i; - DBG(stream->bap, "stream %p ep %p", stream, ep); + queue_destroy(req->group, bap_req_free); - queue_remove(stream->bap->streams, stream); - bap_stream_clear_cfm(stream); + for (i = 0; i < req->len; i++) + free(req->iov[i].iov_base); - stream->ep = NULL; - ep->stream = NULL; - bap_stream_free(stream); + free(req->iov); + free(req); } -static void bap_stream_io_link(void *data, void *user_data) +static void bap_req_complete(struct bt_bap_req *req, + const struct bt_ascs_ase_rsp *rsp) { - struct bt_bap_stream *stream = data; - struct bt_bap_stream *link = user_data; + struct queue *group; - bt_bap_stream_io_link(stream, link); -} + if (!req->func) + goto done; -static void bap_stream_update_io_links(struct bt_bap_stream *stream) -{ - struct bt_bap *bap = stream->bap; + if (rsp) + req->func(req->stream, rsp->code, rsp->reason, req->user_data); + else + req->func(req->stream, BT_ASCS_RSP_UNSPECIFIED, 0x00, + req->user_data); - DBG(bap, "stream %p", stream); +done: + /* Detach from request so it can be freed separately */ + group = req->group; + req->group = NULL; + + queue_foreach(group, (queue_foreach_func_t)bap_req_complete, + (void *)rsp); - queue_foreach(bap->streams, bap_stream_io_link, stream); + queue_destroy(group, NULL); + + bap_req_free(req); } -static struct bt_bap_stream_io *stream_io_ref(struct bt_bap_stream_io *io) +static bool match_req_stream(const void *data, const void *match_data) { - if (!io) - return NULL; - - __sync_fetch_and_add(&io->ref_count, 1); + const struct bt_bap_req *req = data; - return io; + return req->stream == match_data; } -static struct bt_bap_stream_io *stream_io_new(struct bt_bap *bap, int fd) +static void bap_req_abort(void *data) { - struct io *io; - struct bt_bap_stream_io *sio; + struct bt_bap_req *req = data; + struct bt_bap *bap = req->stream->bap; - io = io_new(fd); - if (!io) - return NULL; + DBG(bap, "req %p", req); + bap_req_complete(req, NULL); +} - DBG(bap, "fd %d", fd); +static void bap_abort_stream_req(struct bt_bap *bap, + struct bt_bap_stream *stream) +{ + queue_remove_all(bap->reqs, match_req_stream, stream, bap_req_abort); +} - sio = new0(struct bt_bap_stream_io, 1); - sio->bap = bap; - sio->io = io; +static void bt_bap_stream_unref(struct bt_bap_stream *stream) +{ + if (!stream) + return; - return stream_io_ref(sio); + if (__sync_sub_and_fetch(&stream->ref_count, 1)) + return; + + bap_stream_free(stream); } -static void stream_find_io(void *data, void *user_data) +static void bap_ucast_detach(struct bt_bap_stream *stream) { - struct bt_bap_stream *stream = data; - struct bt_bap_stream_io **io = user_data; + struct bt_bap_endpoint *ep = stream->ep; - if (*io) + if (!ep) return; - *io = stream->io; + DBG(stream->bap, "stream %p ep %p", stream, ep); + + bap_abort_stream_req(stream->bap, stream); + + queue_remove(stream->bap->streams, stream); + bap_stream_clear_cfm(stream); + + stream->ep = NULL; + ep->stream = NULL; + bt_bap_stream_unref(stream); } -static struct bt_bap_stream_io *stream_get_io(struct bt_bap_stream *stream) +static void bap_bcast_src_detach(struct bt_bap_stream *stream) { - struct bt_bap_stream_io *io; + struct bt_bap_endpoint *ep = stream->ep; - if (!stream) - return NULL; + if (!ep) + return; - if (stream->io) - return stream->io; + DBG(stream->bap, "stream %p ep %p", stream, ep); - io = NULL; - queue_foreach(stream->links, stream_find_io, &io); + queue_remove(stream->bap->streams, stream); + bap_stream_clear_cfm(stream); - return io; -} + stream->ep = NULL; + ep->stream = NULL; -static bool stream_io_disconnected(struct io *io, void *user_data); + bt_bap_stream_unref(stream); +} -static bool bap_stream_io_attach(struct bt_bap_stream *stream, int fd, - bool connecting) +static void bap_bcast_sink_detach(struct bt_bap_stream *stream) { - struct bt_bap_stream_io *io; + DBG(stream->bap, "stream %p", stream); - io = stream_get_io(stream); - if (io) { - if (fd == stream_io_get_fd(io)) { - if (!stream->io) - stream->io = stream_io_ref(io); + queue_remove(stream->bap->streams, stream); + bap_stream_clear_cfm(stream); - io->connecting = connecting; - return true; - } + bt_bap_stream_unref(stream); +} - DBG(stream->bap, "stream %p io already set", stream); - return false; - } +static bool bap_stream_io_link(const void *data, const void *user_data) +{ + struct bt_bap_stream *stream = (void *)data; + struct bt_bap_stream *link = (void *)user_data; - DBG(stream->bap, "stream %p connecting %s", stream, - connecting ? "true" : "false"); + return !bt_bap_stream_io_link(stream, link); +} - io = stream_io_new(stream->bap, fd); - if (!io) - return false; +static void bap_stream_update_io_links(struct bt_bap_stream *stream) +{ + struct bt_bap *bap = stream->bap; - io->connecting = connecting; - stream->io = io; - io_set_disconnect_handler(io->io, stream_io_disconnected, stream, NULL); + DBG(bap, "stream %p", stream); - return true; + queue_find(bap->streams, bap_stream_io_link, stream); } static bool match_stream_io(const void *data, const void *user_data) @@ -1215,32 +1316,13 @@ static bool bap_stream_io_detach(struct bt_bap_stream *stream) return true; } -static void bap_stream_set_io(void *data, void *user_data) +static void stream_stop_complete(struct bt_bap_stream *stream, uint8_t code, + uint8_t reason, void *user_data) { - struct bt_bap_stream *stream = data; - int fd = PTR_TO_INT(user_data); - bool ret; - - if (fd >= 0) - ret = bap_stream_io_attach(stream, fd, false); - else - ret = bap_stream_io_detach(stream); - - if (!ret) - return; + DBG(stream->bap, "stream %p stop 0x%02x 0x%02x", stream, code, reason); - switch (stream->ep->state) { - case BT_BAP_STREAM_STATE_ENABLING: - if (fd < 0) - bt_bap_stream_disable(stream, false, NULL, NULL); - else - bt_bap_stream_start(stream, NULL, NULL); - break; - case BT_BAP_STREAM_STATE_DISABLING: - if (fd < 0) - bt_bap_stream_stop(stream, NULL, NULL); - break; - } + if (stream->ep->state == BT_ASCS_ASE_STATE_DISABLING) + bap_stream_io_detach(stream); } static void bap_stream_state_changed(struct bt_bap_stream *stream) @@ -1248,13 +1330,6 @@ static void bap_stream_state_changed(struct bt_bap_stream *stream) struct bt_bap *bap = stream->bap; const struct queue_entry *entry; - DBG(bap, "stream %p dir 0x%02x: %s -> %s", stream, - bt_bap_stream_get_dir(stream), - bt_bap_stream_statestr(stream->ep->old_state), - bt_bap_stream_statestr(stream->ep->state)); - - bt_bap_ref(bap); - /* Pre notification updates */ switch (stream->ep->state) { case BT_ASCS_ASE_STATE_IDLE: @@ -1263,7 +1338,9 @@ static void bap_stream_state_changed(struct bt_bap_stream *stream) bap_stream_update_io_links(stream); break; case BT_ASCS_ASE_STATE_DISABLING: - bap_stream_io_detach(stream); + /* As client, we detach after Receiver Stop Ready */ + if (!stream->client) + bap_stream_io_detach(stream); break; case BT_ASCS_ASE_STATE_QOS: if (stream->io && !stream->io->connecting) @@ -1288,7 +1365,14 @@ static void bap_stream_state_changed(struct bt_bap_stream *stream) /* Post notification updates */ switch (stream->ep->state) { case BT_ASCS_ASE_STATE_IDLE: - bap_stream_detach(stream); + if (bap->req && bap->req->stream == stream) { + bap_req_complete(bap->req, NULL); + bap->req = NULL; + } + + if (stream->ops && stream->ops->detach) + stream->ops->detach(stream); + break; case BT_ASCS_ASE_STATE_QOS: break; @@ -1297,476 +1381,502 @@ static void bap_stream_state_changed(struct bt_bap_stream *stream) bt_bap_stream_start(stream, NULL, NULL); break; case BT_ASCS_ASE_STATE_DISABLING: - if (!bt_bap_stream_get_io(stream)) - bt_bap_stream_stop(stream, NULL, NULL); + /* Send Stop Ready, and detach IO after remote replies */ + if (stream->client) + bt_bap_stream_stop(stream, stream_stop_complete, NULL); break; } +} + +/* Return false if the stream is being detached */ +static bool stream_set_state(struct bt_bap_stream *stream, uint8_t state) +{ + struct bt_bap *bap = stream->bap; + + /* Check if ref_count is already 0 which means detaching is in + * progress. + */ + bap = bt_bap_ref_safe(bap); + if (!bap) { + if (stream->ops && stream->ops->detach) + stream->ops->detach(stream); + + return false; + } + + if (stream->ops && stream->ops->set_state) + stream->ops->set_state(stream, state); bt_bap_unref(bap); + return true; } -static void stream_set_state(struct bt_bap_stream *stream, uint8_t state) +static void ep_config_cb(struct bt_bap_stream *stream, int err) { - struct bt_bap_endpoint *ep = stream->ep; + if (err) + return; - ep->old_state = ep->state; - ep->state = state; + stream_set_state(stream, BT_BAP_STREAM_STATE_CONFIG); +} - if (stream->client) - goto done; +static uint8_t stream_config(struct bt_bap_stream *stream, struct iovec *cc, + struct iovec *rsp) +{ + struct bt_bap_pac *pac = stream->lpac; - switch (ep->state) { - case BT_ASCS_ASE_STATE_IDLE: - break; - case BT_ASCS_ASE_STATE_CONFIG: - stream_notify_config(stream); - break; - case BT_ASCS_ASE_STATE_QOS: - stream_notify_qos(stream); - break; - case BT_ASCS_ASE_STATE_ENABLING: - case BT_ASCS_ASE_STATE_STREAMING: - case BT_ASCS_ASE_STATE_DISABLING: - stream_notify_metadata(stream); - break; + DBG(stream->bap, "stream %p", stream); + + /* TODO: Wait for pac->ops response */ + ascs_ase_rsp_success(rsp, stream->ep->id); + + if (!util_iov_memcmp(stream->cc, cc)) { + stream_set_state(stream, BT_BAP_STREAM_STATE_CONFIG); + return 0; } -done: - bap_stream_state_changed(stream); + util_iov_free(stream->cc, 1); + stream->cc = util_iov_dup(cc, 1); + + if (pac->ops && pac->ops->config) + pac->ops->config(stream, cc, NULL, ep_config_cb, + pac->user_data); + + return 0; } -static void ascs_ase_rsp_add(struct iovec *iov, uint8_t id, - uint8_t code, uint8_t reason) +static struct bt_bap_req *bap_req_new(struct bt_bap_stream *stream, + uint8_t op, struct iovec *iov, + size_t len, + bt_bap_stream_func_t func, + void *user_data) { - struct bt_ascs_cp_rsp *cp; - struct bt_ascs_ase_rsp *rsp; + struct bt_bap_req *req; + static unsigned int id; - if (!iov) - return; + req = new0(struct bt_bap_req, 1); + req->id = ++id ? id : ++id; + req->stream = stream; + req->op = op; + req->iov = util_iov_dup(iov, len); + req->len = len; + req->func = func; + req->user_data = user_data; - cp = iov->iov_base; + return req; +} - if (cp->num_ase == 0xff) - return; +static uint16_t bap_req_len(struct bt_bap_req *req) +{ + uint16_t len = 0; + size_t i; + const struct queue_entry *e; - switch (code) { - /* If the Response_Code value is 0x01 or 0x02, Number_of_ASEs shall be - * set to 0xFF. - */ - case BT_ASCS_RSP_NOT_SUPPORTED: - case BT_ASCS_RSP_TRUNCATED: - cp->num_ase = 0xff; - break; - default: - cp->num_ase++; - break; - } + for (i = 0; i < req->len; i++) + len += req->iov[i].iov_len; - iov->iov_len += sizeof(*rsp); - iov->iov_base = realloc(iov->iov_base, iov->iov_len); + e = queue_get_entries(req->group); + for (; e; e = e->next) + len += bap_req_len(e->data); - rsp = iov->iov_base + (iov->iov_len - sizeof(*rsp)); - rsp->ase = id; - rsp->code = code; - rsp->reason = reason; + return len; } -static void ascs_ase_rsp_add_errno(struct iovec *iov, uint8_t id, int err) +static bool match_req(const void *data, const void *match_data) { - struct bt_ascs_cp_rsp *rsp = iov->iov_base; + const struct bt_bap_req *pend = data; + const struct bt_bap_req *req = match_data; - switch (err) { - case -ENOBUFS: - case -ENOMEM: - return ascs_ase_rsp_add(iov, id, BT_ASCS_RSP_NO_MEM, - BT_ASCS_REASON_NONE); - case -EINVAL: - switch (rsp->op) { - case BT_ASCS_CONFIG: - /* Fallthrough */ - case BT_ASCS_QOS: - return ascs_ase_rsp_add(iov, id, - BT_ASCS_RSP_CONF_INVALID, - BT_ASCS_REASON_NONE); - case BT_ASCS_ENABLE: - /* Fallthrough */ - case BT_ASCS_METADATA: - return ascs_ase_rsp_add(iov, id, - BT_ASCS_RSP_METADATA_INVALID, - BT_ASCS_REASON_NONE); - default: - return ascs_ase_rsp_add(iov, id, - BT_ASCS_RSP_UNSPECIFIED, - BT_ASCS_REASON_NONE); - } - case -ENOTSUP: - switch (rsp->op) { - case BT_ASCS_CONFIG: - /* Fallthrough */ - case BT_ASCS_QOS: - return ascs_ase_rsp_add(iov, id, - BT_ASCS_RSP_CONF_UNSUPPORTED, - BT_ASCS_REASON_NONE); - case BT_ASCS_ENABLE: - /* Fallthrough */ - case BT_ASCS_METADATA: - return ascs_ase_rsp_add(iov, id, - BT_ASCS_RSP_METADATA_UNSUPPORTED, - BT_ASCS_REASON_NONE); - default: - return ascs_ase_rsp_add(iov, id, - BT_ASCS_RSP_NOT_SUPPORTED, - BT_ASCS_REASON_NONE); - } - case -EBADMSG: - return ascs_ase_rsp_add(iov, id, BT_ASCS_RSP_INVALID_ASE_STATE, - BT_ASCS_REASON_NONE); - case -ENOMSG: - return ascs_ase_rsp_add(iov, id, BT_ASCS_RSP_TRUNCATED, - BT_ASCS_REASON_NONE); - default: - return ascs_ase_rsp_add(iov, id, BT_ASCS_RSP_UNSPECIFIED, - BT_ASCS_REASON_NONE); - } + return pend->op == req->op; } -static void ascs_ase_rsp_success(struct iovec *iov, uint8_t id) +static struct bt_ascs *bap_get_ascs(struct bt_bap *bap) { - return ascs_ase_rsp_add(iov, id, BT_ASCS_RSP_SUCCESS, - BT_ASCS_REASON_NONE); + if (!bap || !bap->rdb) + return NULL; + + if (bap->rdb->ascs) + return bap->rdb->ascs; + + bap->rdb->ascs = new0(struct bt_ascs, 1); + bap->rdb->ascs->bdb = bap->rdb; + + return bap->rdb->ascs; } -static void ep_config_cb(struct bt_bap_stream *stream, int err) +static void append_group(void *data, void *user_data) { - if (err) - return; + struct bt_bap_req *req = data; + struct iovec *iov = user_data; + size_t i; - stream_set_state(stream, BT_BAP_STREAM_STATE_CONFIG); + for (i = 0; i < req->len; i++) + util_iov_push_mem(iov, req->iov[i].iov_len, + req->iov[i].iov_base); } -static uint8_t stream_config(struct bt_bap_stream *stream, struct iovec *cc, - struct iovec *rsp) +static bool bap_send(struct bt_bap *bap, struct bt_bap_req *req) { - struct bt_bap_pac *pac = stream->lpac; + struct bt_ascs *ascs = bap_get_ascs(bap); + int ret; + uint16_t handle; + struct bt_ascs_ase_hdr hdr; + struct iovec iov; + size_t i; - DBG(stream->bap, "stream %p", stream); + iov.iov_len = sizeof(hdr) + bap_req_len(req); - /* TODO: Wait for pac->ops response */ - ascs_ase_rsp_success(rsp, stream->ep->id); + DBG(bap, "req %p len %u", req, iov.iov_len); - if (!iov_memcmp(stream->cc, cc)) { - stream_set_state(stream, BT_BAP_STREAM_STATE_CONFIG); - return 0; + if (req->stream && !queue_find(bap->streams, NULL, req->stream)) { + DBG(bap, "stream %p detached, aborting op 0x%02x", req->op); + return false; } - iov_free(stream->cc); - stream->cc = iov_dup(cc, 1); - - if (pac->ops && pac->ops->config) - pac->ops->config(stream, cc, NULL, ep_config_cb, - pac->user_data); - - return 0; -} + if (!gatt_db_attribute_get_char_data(ascs->ase_cp, NULL, &handle, + NULL, NULL, NULL)) { + DBG(bap, "Unable to find Control Point"); + return false; + } -static uint8_t ep_config(struct bt_bap_endpoint *ep, struct bt_bap *bap, - struct bt_ascs_config *req, - struct iovec *iov, struct iovec *rsp) -{ - struct iovec cc; - const struct queue_entry *e; + iov.iov_base = alloca(iov.iov_len); + iov.iov_len = 0; - DBG(bap, "ep %p id 0x%02x dir 0x%02x", ep, ep->id, ep->dir); + hdr.op = req->op; + hdr.num = 1 + queue_length(req->group); - switch (ep->state) { - /* Valid only if ASE_State field = 0x00 (Idle) */ - case BT_ASCS_ASE_STATE_IDLE: - /* or 0x01 (Codec Configured) */ - case BT_ASCS_ASE_STATE_CONFIG: - /* or 0x02 (QoS Configured) */ - case BT_ASCS_ASE_STATE_QOS: - break; - default: - DBG(bap, "Invalid state %s", bt_bap_stream_statestr(ep->state)); - ascs_ase_rsp_add(rsp, req->ase, - BT_ASCS_RSP_INVALID_ASE_STATE, - BT_ASCS_REASON_NONE); - return 0; - } + util_iov_push_mem(&iov, sizeof(hdr), &hdr); - if (iov->iov_len < req->cc_len) - return BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN; + for (i = 0; i < req->len; i++) + util_iov_push_mem(&iov, req->iov[i].iov_len, + req->iov[i].iov_base); - cc.iov_base = iov_pull_mem(iov, req->cc_len); - cc.iov_len = req->cc_len; + /* Append the request group with the same opcode */ + queue_foreach(req->group, append_group, &iov); - if (!bap_print_cc(cc.iov_base, cc.iov_len, bap->debug_func, - bap->debug_data)) { - ascs_ase_rsp_add(rsp, req->ase, - BT_ASCS_RSP_CONF_INVALID, - BT_ASCS_REASON_CODEC_DATA); - return 0; + ret = bt_gatt_client_write_without_response(bap->client, handle, + false, iov.iov_base, + iov.iov_len); + if (!ret) { + DBG(bap, "Unable to Write to Control Point"); + return false; } - switch (ep->dir) { - case BT_BAP_SINK: - e = queue_get_entries(bap->ldb->sinks); - break; - case BT_BAP_SOURCE: - e = queue_get_entries(bap->ldb->sources); - break; - default: - e = NULL; - } + bap->req = req; - for (; e; e = e->next) { - struct bt_bap_pac *pac = e->data; + return true; +} - if (!bap_codec_equal(&req->codec, &pac->codec)) - continue; +static bool bap_process_queue(void *data) +{ + struct bt_bap *bap = data; + struct bt_bap_req *req; - if (!ep->stream) - ep->stream = bap_stream_new(bap, ep, pac, NULL, NULL, - false); + DBG(bap, ""); - break; + if (bap->process_id) { + timeout_remove(bap->process_id); + bap->process_id = 0; } - if (!e) { - ascs_ase_rsp_add(rsp, req->ase, - BT_ASCS_RSP_CONF_INVALID, - BT_ASCS_REASON_CODEC); - return 0; + while ((req = queue_pop_head(bap->reqs))) { + if (bap_send(bap, req)) + break; + bap_req_complete(req, NULL); } - return stream_config(ep->stream, &cc, rsp); + return false; } -static uint8_t ascs_config(struct bt_ascs *ascs, struct bt_bap *bap, - struct iovec *iov, struct iovec *rsp) +static bool bap_queue_req(struct bt_bap *bap, struct bt_bap_req *req) { - struct bt_bap_endpoint *ep; - struct bt_ascs_config *req; - - req = iov_pull_mem(iov, sizeof(*req)); - - DBG(bap, "codec 0x%02x phy 0x%02x latency %u", req->codec.id, req->phy, - req->latency); + struct bt_bap_req *pend; + struct queue *queue; + struct bt_att *att = bt_bap_get_att(bap); + uint16_t mtu = bt_att_get_mtu(att); + uint16_t len = 2 + bap_req_len(req); - ep = bap_get_endpoint_id(bap, bap->ldb, req->ase); - if (!ep) { - DBG(bap, "Invalid ASE ID 0x%02x", req->ase); - ascs_ase_rsp_add(rsp, req->ase, - BT_ASCS_RSP_INVALID_ASE, BT_ASCS_REASON_NONE); - return 0; + if (len > mtu) { + DBG(bap, "Unable to queue request: req len %u > %u mtu", len, + mtu); + return false; } - return ep_config(ep, bap, req, iov, rsp); -} - -static uint8_t stream_qos(struct bt_bap_stream *stream, struct bt_bap_qos *qos, - struct iovec *rsp) -{ - DBG(stream->bap, "stream %p", stream); + pend = queue_find(bap->reqs, match_req, req); + /* Check if req can be grouped together and it fits in the MTU */ + if (pend && (bap_req_len(pend) + len < mtu)) { + if (!pend->group) + pend->group = queue_new(); + /* Group requests with the same opcode */ + queue = pend->group; + } else { + queue = bap->reqs; + } - ascs_ase_rsp_success(rsp, stream->ep->id); + DBG(bap, "req %p (op 0x%2.2x) queue %p", req, req->op, queue); - if (memcmp(&stream->qos, qos, sizeof(*qos))) - stream->qos = *qos; + if (!queue_push_tail(queue, req)) { + DBG(bap, "Unable to queue request"); + return false; + } - stream_set_state(stream, BT_BAP_STREAM_STATE_QOS); + /* Only attempot to process queue if there is no outstanding request + * and it has not been scheduled. + */ + if (!bap->req && !bap->process_id) + bap->process_id = timeout_add(BAP_PROCESS_TIMEOUT, + bap_process_queue, bap, NULL); - return 0; + return true; } -static uint8_t ep_qos(struct bt_bap_endpoint *ep, struct bt_bap *bap, - struct bt_bap_qos *qos, struct iovec *rsp) +static bool stream_notify_state(void *data) { - DBG(bap, "ep %p id 0x%02x dir 0x%02x", ep, ep->id, ep->dir); + struct bt_bap_stream *stream = data; + struct bt_bap_endpoint *ep = stream->ep; + + DBG(stream->bap, "stream %p", stream); + + if (stream->state_id) { + timeout_remove(stream->state_id); + stream->state_id = 0; + } switch (ep->state) { - /* Valid only if ASE_State field = 0x01 (Codec Configured) */ + case BT_ASCS_ASE_STATE_IDLE: + break; case BT_ASCS_ASE_STATE_CONFIG: - /* or 0x02 (QoS Configured) */ + stream_notify_config(stream); + break; case BT_ASCS_ASE_STATE_QOS: + stream_notify_qos(stream); + break; + case BT_ASCS_ASE_STATE_ENABLING: + case BT_ASCS_ASE_STATE_STREAMING: + case BT_ASCS_ASE_STATE_DISABLING: + stream_notify_metadata(stream); break; - default: - DBG(bap, "Invalid state %s", bt_bap_stream_statestr(ep->state)); - ascs_ase_rsp_add(rsp, ep->id, - BT_ASCS_RSP_INVALID_ASE_STATE, - BT_ASCS_REASON_NONE); - return 0; - } - - if (!ep->stream) { - DBG(bap, "No stream found"); - ascs_ase_rsp_add(rsp, ep->id, - BT_ASCS_RSP_INVALID_ASE_STATE, - BT_ASCS_REASON_NONE); - return 0; } - return stream_qos(ep->stream, qos, rsp); + return false; } -static uint8_t ascs_qos(struct bt_ascs *ascs, struct bt_bap *bap, - struct iovec *iov, struct iovec *rsp) +static void bap_ucast_set_state(struct bt_bap_stream *stream, uint8_t state) { - struct bt_bap_endpoint *ep; - struct bt_ascs_qos *req; - struct bt_bap_qos qos; - - req = iov_pull_mem(iov, sizeof(*req)); - - memset(&qos, 0, sizeof(qos)); + struct bt_bap_endpoint *ep = stream->ep; - qos.cig_id = req->cig; - qos.cis_id = req->cis; - qos.interval = get_le24(req->interval); - qos.framing = req->framing; - qos.phy = req->phy; - qos.sdu = le16_to_cpu(req->sdu); - qos.rtn = req->rtn; - qos.latency = le16_to_cpu(req->latency); - qos.delay = get_le24(req->pd); + ep->old_state = ep->state; + ep->state = state; - DBG(bap, "CIG 0x%02x CIS 0x%02x interval %u framing 0x%02x " - "phy 0x%02x SDU %u rtn %u latency %u pd %u", - req->cig, req->cis, qos.interval, qos.framing, qos.phy, - qos.sdu, qos.rtn, qos.latency, qos.delay); + DBG(stream->bap, "stream %p dir 0x%02x: %s -> %s", stream, + bt_bap_stream_get_dir(stream), + bt_bap_stream_statestr(stream->ep->old_state), + bt_bap_stream_statestr(stream->ep->state)); - ep = bap_get_endpoint_id(bap, bap->ldb, req->ase); - if (!ep) { - DBG(bap, "%s: Invalid ASE ID 0x%02x", req->ase); - ascs_ase_rsp_add(rsp, req->ase, - BT_ASCS_RSP_INVALID_ASE, BT_ASCS_REASON_NONE); - return 0; - } + if (stream->client) + goto done; - return ep_qos(ep, bap, &qos, rsp); + if (!stream->bap->in_cp_write) + stream_notify_state(stream); + else if (!stream->state_id) + stream->state_id = timeout_add(BAP_PROCESS_TIMEOUT, + stream_notify_state, + stream, NULL); + +done: + bap_stream_state_changed(stream); } -static uint8_t stream_enable(struct bt_bap_stream *stream, struct iovec *meta, - struct iovec *rsp) +static unsigned int bap_ucast_get_state(struct bt_bap_stream *stream) { - DBG(stream->bap, "stream %p", stream); + return stream->ep->state; +} - ascs_ase_rsp_success(rsp, stream->ep->id); +static unsigned int bap_ucast_config(struct bt_bap_stream *stream, + struct bt_bap_qos *qos, + struct iovec *data, + bt_bap_stream_func_t func, + void *user_data) +{ + struct iovec iov[2]; + struct bt_ascs_config config; + uint8_t iovlen = 1; + struct bt_bap_req *req; - iov_free(stream->meta); - stream->meta = iov_dup(meta, 1); + if (!stream->client) { + stream_config(stream, data, NULL); + return -EINVAL; + } - stream_set_state(stream, BT_BAP_STREAM_STATE_ENABLING); + memset(&config, 0, sizeof(config)); - /* Sink can autonomously for to Streaming state if io already exits */ - if (stream->io && stream->ep->dir == BT_BAP_SINK) - stream_set_state(stream, BT_BAP_STREAM_STATE_STREAMING); + config.ase = stream->ep->id; + config.latency = qos->ucast.target_latency; + config.phy = qos->ucast.io_qos.phy; + config.codec = stream->rpac->codec; - return 0; + if (config.codec.id == 0xff) { + config.codec.cid = cpu_to_le16(config.codec.cid); + config.codec.vid = cpu_to_le16(config.codec.vid); + } + + iov[0].iov_base = &config; + iov[0].iov_len = sizeof(config); + + if (data) { + if (!bt_bap_debug_config(data->iov_base, data->iov_len, + stream->bap->debug_func, + stream->bap->debug_data)) + return 0; + + config.cc_len = data->iov_len; + iov[1] = *data; + iovlen++; + } + + req = bap_req_new(stream, BT_ASCS_CONFIG, iov, iovlen, func, user_data); + if (!bap_queue_req(stream->bap, req)) { + bap_req_free(req); + return 0; + } + + stream->qos = *qos; + + return req->id; } -static bool bap_print_ltv(const char *label, void *data, size_t len, - util_debug_func_t func, void *user_data) +static unsigned int bap_ucast_qos(struct bt_bap_stream *stream, + struct bt_bap_qos *data, + bt_bap_stream_func_t func, + void *user_data) { - struct iovec iov = { - .iov_base = data, - .iov_len = len, - }; - int i; + struct iovec iov; + struct bt_ascs_qos qos; + struct bt_bap_req *req; - util_debug(func, user_data, "Length %zu", iov.iov_len); + /* Table 3.2: ASE state machine transition + * Initiating device - client Only + */ + if (!stream->client) + return 0; - for (i = 0; iov.iov_len > 1; i++) { - struct bt_ltv *ltv = iov_pull_mem(&iov, sizeof(*ltv)); - uint8_t *data; + memset(&qos, 0, sizeof(qos)); - if (!ltv) { - util_debug(func, user_data, "Unable to parse %s", - label); - return false; - } + /* TODO: Figure out how to pass these values around */ + qos.ase = stream->ep->id; + qos.cig = data->ucast.cig_id; + qos.cis = data->ucast.cis_id; + put_le24(data->ucast.io_qos.interval, qos.interval); + qos.framing = data->ucast.framing; + qos.phy = data->ucast.io_qos.phy; + qos.sdu = cpu_to_le16(data->ucast.io_qos.sdu); + qos.rtn = data->ucast.io_qos.rtn; + qos.latency = cpu_to_le16(data->ucast.io_qos.latency); + put_le24(data->ucast.delay, qos.pd); - util_debug(func, user_data, "%s #%u: len %u type %u", - label, i, ltv->len, ltv->type); + iov.iov_base = &qos; + iov.iov_len = sizeof(qos); - data = iov_pull_mem(&iov, ltv->len - 1); - if (!data) { - util_debug(func, user_data, "Unable to parse %s", - label); - return false; - } + req = bap_req_new(stream, BT_ASCS_QOS, &iov, 1, func, user_data); - util_hexdump(' ', ltv->value, ltv->len - 1, func, user_data); + if (!bap_queue_req(stream->bap, req)) { + bap_req_free(req); + return 0; } - return true; -} + stream->qos = *data; -static bool bap_print_metadata(void *data, size_t len, util_debug_func_t func, - void *user_data) -{ - return bap_print_ltv("Metadata", data, len, func, user_data); + return req->id; } -static uint8_t ep_enable(struct bt_bap_endpoint *ep, struct bt_bap *bap, - struct bt_ascs_enable *req, struct iovec *iov, - struct iovec *rsp) +static unsigned int bap_stream_metadata(struct bt_bap_stream *stream, + uint8_t op, struct iovec *data, + bt_bap_stream_func_t func, + void *user_data) { - struct iovec meta; + struct iovec iov[2]; + struct bt_ascs_metadata meta; + struct bt_bap_req *req; + struct metadata { + uint8_t len; + uint8_t type; + uint8_t data[2]; + } ctx = LTV(0x02, 0x01, 0x00); /* Context = Unspecified */ - DBG(bap, "ep %p id 0x%02x dir 0x%02x", ep, ep->id, ep->dir); + memset(&meta, 0, sizeof(meta)); - switch (ep->state) { - /* Valid only if ASE_State field = 0x02 (QoS Configured) */ - case BT_ASCS_ASE_STATE_QOS: - break; - default: - DBG(bap, "Invalid state %s", bt_bap_stream_statestr(ep->state)); - ascs_ase_rsp_add(rsp, ep->id, - BT_ASCS_RSP_INVALID_ASE_STATE, - BT_ASCS_REASON_NONE); - return 0; - } + meta.ase = stream->ep->id; - meta.iov_base = iov_pull_mem(iov, req->meta.len); - meta.iov_len = req->meta.len; + iov[0].iov_base = &meta; + iov[0].iov_len = sizeof(meta); - if (!bap_print_metadata(meta.iov_base, meta.iov_len, bap->debug_func, - bap->debug_data)) { - ascs_ase_rsp_add(rsp, ep->id, - BT_ASCS_RSP_METADATA_INVALID, - BT_ASCS_REASON_NONE); - return 0; + if (data) + iov[1] = *data; + else { + iov[1].iov_base = &ctx; + iov[1].iov_len = sizeof(ctx); } - if (!ep->stream) { - DBG(bap, "No stream found"); - ascs_ase_rsp_add(rsp, ep->id, - BT_ASCS_RSP_INVALID_ASE_STATE, - BT_ASCS_REASON_NONE); + meta.len = iov[1].iov_len; + + req = bap_req_new(stream, op, iov, 2, func, user_data); + + if (!bap_queue_req(stream->bap, req)) { + bap_req_free(req); return 0; } - return stream_enable(ep->stream, &meta, rsp); + return req->id; } -static uint8_t ascs_enable(struct bt_ascs *ascs, struct bt_bap *bap, - struct iovec *iov, struct iovec *rsp) +static unsigned int bap_bcast_qos(struct bt_bap_stream *stream, + struct bt_bap_qos *data, + bt_bap_stream_func_t func, + void *user_data) { - struct bt_bap_endpoint *ep; - struct bt_ascs_enable *req; + stream->qos = *data; + return 1; +} + +static unsigned int bap_bcast_config(struct bt_bap_stream *stream, + struct bt_bap_qos *qos, struct iovec *data, + bt_bap_stream_func_t func, void *user_data) +{ + stream->qos = *qos; + stream->lpac->ops->config(stream, stream->cc, &stream->qos, + ep_config_cb, stream->lpac->user_data); - req = iov_pull_mem(iov, sizeof(*req)); + return 1; +} - ep = bap_get_endpoint_id(bap, bap->ldb, req->meta.ase); - if (!ep) { - DBG(bap, "Invalid ASE ID 0x%02x", req->meta.ase); - ascs_ase_rsp_add(rsp, req->meta.ase, - BT_ASCS_RSP_INVALID_ASE, BT_ASCS_REASON_NONE); +static void bap_stream_enable_link(void *data, void *user_data) +{ + struct bt_bap_stream *stream = data; + struct iovec *metadata = user_data; + + bap_stream_metadata(stream, BT_ASCS_ENABLE, metadata, NULL, NULL); +} + +static unsigned int bap_ucast_enable(struct bt_bap_stream *stream, + bool enable_links, struct iovec *data, + bt_bap_stream_func_t func, + void *user_data) +{ + int ret; + + /* Table 3.2: ASE state machine transition + * Initiating device - client Only + */ + if (!stream->client) return 0; - } - return ep_enable(ep, bap, req, iov, rsp); + ret = bap_stream_metadata(stream, BT_ASCS_ENABLE, data, func, + user_data); + if (!ret || !enable_links) + return ret; + + queue_foreach(stream->links, bap_stream_enable_link, data); + + return ret; } static uint8_t stream_start(struct bt_bap_stream *stream, struct iovec *rsp) @@ -1780,75 +1890,47 @@ static uint8_t stream_start(struct bt_bap_stream *stream, struct iovec *rsp) return 0; } -static uint8_t ep_start(struct bt_bap_endpoint *ep, struct iovec *rsp) +static unsigned int bap_ucast_start(struct bt_bap_stream *stream, + bt_bap_stream_func_t func, + void *user_data) { - struct bt_bap_stream *stream = ep->stream; - - DBG(stream->bap, "ep %p id 0x%02x dir 0x%02x", ep, ep->id, ep->dir); + struct iovec iov; + struct bt_ascs_start start; + struct bt_bap_req *req; - switch (ep->state) { - /* Valid only if ASE_State field = 0x03 (Enabling) */ - case BT_ASCS_ASE_STATE_ENABLING: - break; - default: - DBG(ep->stream->bap, "Invalid state %s", - bt_bap_stream_statestr(ep->state)); - ascs_ase_rsp_add(rsp, ep->id, - BT_ASCS_RSP_INVALID_ASE_STATE, - BT_ASCS_REASON_NONE); + if (!stream->client) { + if (stream->ep->dir == BT_BAP_SINK) + stream_start(stream, NULL); return 0; } - /* If the ASE_ID written by the client represents a Sink ASE, the - * server shall not accept the Receiver Start Ready operation for that - * ASE. The server shall send a notification of the ASE Control Point - * characteristic to the client, and the server shall set the - * Response_Code value for that ASE to 0x05 (Invalid ASE direction). - */ - if (ep->dir == BT_BAP_SINK) { - ascs_ase_rsp_add(rsp, ep->id, - BT_ASCS_RSP_INVALID_DIR, BT_ASCS_REASON_NONE); + if (stream->ep->dir == BT_BAP_SINK) return 0; - } - return stream_start(ep->stream, rsp); -} - -static uint8_t ascs_start(struct bt_ascs *ascs, struct bt_bap *bap, - struct iovec *iov, struct iovec *rsp) -{ - struct bt_bap_endpoint *ep; - struct bt_ascs_start *req; + memset(&start, 0, sizeof(start)); - req = iov_pull_mem(iov, sizeof(*req)); + start.ase = stream->ep->id; - ep = bap_get_endpoint_id(bap, bap->ldb, req->ase); - if (!ep) { - DBG(bap, "Invalid ASE ID 0x%02x", req->ase); - ascs_ase_rsp_add(rsp, req->ase, - BT_ASCS_RSP_INVALID_ASE, BT_ASCS_REASON_NONE); - return 0; - } + iov.iov_base = &start; + iov.iov_len = sizeof(start); - if (!ep->stream) { - DBG(bap, "No stream found for %p", ep); - ascs_ase_rsp_add(rsp, ep->id, - BT_ASCS_RSP_INVALID_ASE_STATE, - BT_ASCS_REASON_NONE); + req = bap_req_new(stream, BT_ASCS_START, &iov, 1, func, user_data); + if (!bap_queue_req(stream->bap, req)) { + bap_req_free(req); return 0; } - return ep_start(ep, rsp); + return req->id; } static uint8_t stream_disable(struct bt_bap_stream *stream, struct iovec *rsp) { - DBG(stream->bap, "stream %p", stream); - if (!stream || stream->ep->state == BT_BAP_STREAM_STATE_QOS || stream->ep->state == BT_BAP_STREAM_STATE_IDLE) return 0; + DBG(stream->bap, "stream %p", stream); + ascs_ase_rsp_success(rsp, stream->ep->id); /* Sink can autonomously transit to QOS while source needs to go to @@ -1862,64 +1944,51 @@ static uint8_t stream_disable(struct bt_bap_stream *stream, struct iovec *rsp) return 0; } -static uint8_t ep_disable(struct bt_bap_endpoint *ep, struct iovec *rsp) +static void bap_stream_disable_link(void *data, void *user_data) { - struct bt_bap_stream *stream = ep->stream; + struct bt_bap_stream *stream = data; - DBG(stream->bap, "ep %p id 0x%02x dir 0x%02x", ep, ep->id, ep->dir); - - switch (ep->state) { - /* Valid only if ASE_State field = 0x03 (Enabling) */ - case BT_ASCS_ASE_STATE_ENABLING: - /* or 0x04 (Streaming) */ - case BT_ASCS_ASE_STATE_STREAMING: - break; - default: - DBG(stream->bap, "Invalid state %s", - bt_bap_stream_statestr(ep->state)); - ascs_ase_rsp_add(rsp, ep->id, - BT_ASCS_RSP_INVALID_ASE_STATE, - BT_ASCS_REASON_NONE); - return 0; - } - - return stream_disable(ep->stream, rsp); + bt_bap_stream_disable(stream, false, NULL, NULL); } -static uint8_t ascs_disable(struct bt_ascs *ascs, struct bt_bap *bap, - struct iovec *iov, struct iovec *rsp) +static unsigned int bap_ucast_disable(struct bt_bap_stream *stream, + bool disable_links, + bt_bap_stream_func_t func, + void *user_data) { - struct bt_bap_endpoint *ep; - struct bt_ascs_disable *req; + struct iovec iov; + struct bt_ascs_disable disable; + struct bt_bap_req *req; - req = iov_pull_mem(iov, sizeof(*req)); + if (!stream->client) + return stream_disable(stream, NULL); - ep = bap_get_endpoint_id(bap, bap->ldb, req->ase); - if (!ep) { - DBG(bap, "Invalid ASE ID 0x%02x", req->ase); - ascs_ase_rsp_add(rsp, req->ase, - BT_ASCS_RSP_INVALID_ASE, BT_ASCS_REASON_NONE); - return 0; - } + memset(&disable, 0, sizeof(disable)); - if (!ep->stream) { - DBG(bap, "No stream found"); - ascs_ase_rsp_add(rsp, ep->id, - BT_ASCS_RSP_INVALID_ASE_STATE, - BT_ASCS_REASON_NONE); + disable.ase = stream->ep->id; + + iov.iov_base = &disable; + iov.iov_len = sizeof(disable); + + req = bap_req_new(stream, BT_ASCS_DISABLE, &iov, 1, func, user_data); + if (!bap_queue_req(stream->bap, req)) { + bap_req_free(req); return 0; } - return ep_disable(ep, rsp); + if (disable_links) + queue_foreach(stream->links, bap_stream_disable_link, NULL); + + return req->id; } static uint8_t stream_stop(struct bt_bap_stream *stream, struct iovec *rsp) { - DBG(stream->bap, "stream %p", stream); - if (!stream) return 0; + DBG(stream->bap, "stream %p", stream); + ascs_ase_rsp_success(rsp, stream->ep->id); stream_set_state(stream, BT_BAP_STREAM_STATE_QOS); @@ -1927,65 +1996,38 @@ static uint8_t stream_stop(struct bt_bap_stream *stream, struct iovec *rsp) return 0; } -static uint8_t ep_stop(struct bt_bap_endpoint *ep, struct iovec *rsp) +static unsigned int bap_ucast_stop(struct bt_bap_stream *stream, + bt_bap_stream_func_t func, + void *user_data) { - struct bt_bap_stream *stream = ep->stream; - - DBG(stream->bap, "ep %p id 0x%02x dir 0x%02x", ep, ep->id, ep->dir); + struct iovec iov; + struct bt_ascs_stop stop; + struct bt_bap_req *req; - switch (ep->state) { - /* Valid only if ASE_State field = 0x05 (Disabling) */ - case BT_ASCS_ASE_STATE_DISABLING: - break; - default: - DBG(stream->bap, "Invalid state %s", - bt_bap_stream_statestr(ep->state)); - ascs_ase_rsp_add(rsp, ep->id, - BT_ASCS_RSP_INVALID_ASE_STATE, - BT_ASCS_REASON_NONE); + if (!stream->client) { + if (stream->ep->dir == BT_BAP_SINK) + stream_stop(stream, NULL); return 0; } - /* If the ASE_ID written by the client represents a Sink ASE, the - * server shall not accept the Receiver Stop Ready operation for that - * ASE. The server shall send a notification of the ASE Control Point - * characteristic to the client, and the server shall set the - * Response_Code value for that ASE to 0x05 (Invalid ASE direction). - */ - if (ep->dir == BT_BAP_SINK) { - ascs_ase_rsp_add(rsp, ep->id, - BT_ASCS_RSP_INVALID_DIR, BT_ASCS_REASON_NONE); + if (stream->ep->dir == BT_BAP_SINK) return 0; - } - return stream_stop(ep->stream, rsp); -} + memset(&stop, 0, sizeof(stop)); -static uint8_t ascs_stop(struct bt_ascs *ascs, struct bt_bap *bap, - struct iovec *iov, struct iovec *rsp) -{ - struct bt_bap_endpoint *ep; - struct bt_ascs_stop *req; + stop.ase = stream->ep->id; - req = iov_pull_mem(iov, sizeof(*req)); + iov.iov_base = &stop; + iov.iov_len = sizeof(stop); - ep = bap_get_endpoint_id(bap, bap->ldb, req->ase); - if (!ep) { - DBG(bap, "Invalid ASE ID 0x%02x", req->ase); - ascs_ase_rsp_add(rsp, req->ase, - BT_ASCS_RSP_INVALID_ASE, BT_ASCS_REASON_NONE); - return 0; - } + req = bap_req_new(stream, BT_ASCS_STOP, &iov, 1, func, user_data); - if (!ep->stream) { - DBG(bap, "No stream found"); - ascs_ase_rsp_add(rsp, ep->id, - BT_ASCS_RSP_INVALID_ASE_STATE, - BT_ASCS_REASON_NONE); + if (!bap_queue_req(stream->bap, req)) { + bap_req_free(req); return 0; } - return ep_stop(ep, rsp); + return req->id; } static uint8_t stream_metadata(struct bt_bap_stream *stream, struct iovec *meta, @@ -1995,62 +2037,33 @@ static uint8_t stream_metadata(struct bt_bap_stream *stream, struct iovec *meta, ascs_ase_rsp_success(rsp, stream->ep->id); - iov_free(stream->meta); - stream->meta = iov_dup(meta, 1); + util_iov_free(stream->meta, 1); + stream->meta = util_iov_dup(meta, 1); return 0; } -static uint8_t ep_metadata(struct bt_bap_endpoint *ep, struct iovec *meta, - struct iovec *rsp) -{ - struct bt_bap_stream *stream = ep->stream; - - DBG(stream->bap, "ep %p id 0x%02x dir 0x%02x", ep, ep->id, ep->dir); - - switch (ep->state) { - /* Valid only if ASE_State field = 0x03 (Enabling) */ - case BT_ASCS_ASE_STATE_ENABLING: - /* or 0x04 (Streaming) */ - case BT_ASCS_ASE_STATE_STREAMING: - break; - default: - DBG(stream->bap, "Invalid state %s", - bt_bap_stream_statestr(ep->state)); - ascs_ase_rsp_add(rsp, ep->id, - BT_ASCS_RSP_INVALID_ASE_STATE, - BT_ASCS_REASON_NONE); - return 0; - } - - return stream_metadata(ep->stream, meta, rsp); -} - -static uint8_t ascs_metadata(struct bt_ascs *ascs, struct bt_bap *bap, - struct iovec *iov, struct iovec *rsp) +static unsigned int bap_ucast_metadata(struct bt_bap_stream *stream, + struct iovec *data, + bt_bap_stream_func_t func, + void *user_data) { - struct bt_bap_endpoint *ep; - struct bt_ascs_metadata *req; - - req = iov_pull_mem(iov, sizeof(*req)); - - ep = bap_get_endpoint_id(bap, bap->ldb, req->ase); - if (!ep) { - DBG(bap, "Invalid ASE ID 0x%02x", req->ase); - ascs_ase_rsp_add(rsp, req->ase, - BT_ASCS_RSP_INVALID_ASE, BT_ASCS_REASON_NONE); + if (!stream->client) { + stream_metadata(stream, data, NULL); return 0; } - if (!ep->stream) { - DBG(bap, "No stream found"); - ascs_ase_rsp_add(rsp, ep->id, - BT_ASCS_RSP_INVALID_ASE_STATE, - BT_ASCS_REASON_NONE); - return 0; + switch (bt_bap_stream_get_state(stream)) { + /* Valid only if ASE_State field = 0x03 (Enabling) */ + case BT_BAP_STREAM_STATE_ENABLING: + /* or 0x04 (Streaming) */ + case BT_BAP_STREAM_STATE_STREAMING: + return bap_stream_metadata(stream, BT_ASCS_METADATA, data, func, + user_data); } - return ep_metadata(ep, iov, rsp); + stream_metadata(stream, data, NULL); + return 0; } static uint8_t stream_release(struct bt_bap_stream *stream, struct iovec *rsp) @@ -2070,45 +2083,1268 @@ static uint8_t stream_release(struct bt_bap_stream *stream, struct iovec *rsp) return 0; } -static uint8_t ascs_release(struct bt_ascs *ascs, struct bt_bap *bap, - struct iovec *iov, struct iovec *rsp) +static bool bap_stream_valid(struct bt_bap_stream *stream) { - struct bt_bap_endpoint *ep; - struct bt_ascs_release *req; + if (!stream || !stream->bap) + return false; + + return queue_find(stream->bap->streams, NULL, stream); +} - req = iov_pull_mem(iov, sizeof(*req)); +static unsigned int bap_ucast_get_dir(struct bt_bap_stream *stream) +{ + return stream->ep->dir; +} - ep = bap_get_endpoint_id(bap, bap->ldb, req->ase); - if (!ep) { - DBG(bap, "Invalid ASE ID 0x%02x", req->ase); - ascs_ase_rsp_add(rsp, req->ase, - BT_ASCS_RSP_INVALID_ASE, BT_ASCS_REASON_NONE); +static unsigned int bap_ucast_get_location(struct bt_bap_stream *stream) +{ + struct bt_pacs *pacs; + + if (!stream) + return 0x00000000; + + pacs = stream->client ? stream->bap->rdb->pacs : stream->bap->ldb->pacs; + + if (stream->ep->dir == BT_BAP_SOURCE) + return pacs->source_loc_value; + else if (stream->ep->dir == BT_BAP_SINK) + return pacs->sink_loc_value; + return 0x00000000; +} + +static unsigned int bap_ucast_release(struct bt_bap_stream *stream, + bt_bap_stream_func_t func, + void *user_data) +{ + struct iovec iov; + struct bt_ascs_release rel; + struct bt_bap_req *req; + struct bt_bap *bap; + + if (!stream->client) { + stream_release(stream, NULL); return 0; } - if (!ep->stream) { - DBG(bap, "No stream found"); - ascs_ase_rsp_add(rsp, ep->id, - BT_ASCS_RSP_INVALID_ASE_STATE, - BT_ASCS_REASON_NONE); + memset(&req, 0, sizeof(req)); + + rel.ase = stream->ep->id; + + iov.iov_base = &rel; + iov.iov_len = sizeof(rel); + + bap = stream->bap; + + /* If stream does not belong to a client session, clean it up now */ + if (!bap_stream_valid(stream)) { + stream_set_state(stream, BT_BAP_STREAM_STATE_IDLE); + stream = NULL; return 0; } - return stream_release(ep->stream, rsp); + req = bap_req_new(stream, BT_ASCS_RELEASE, &iov, 1, func, user_data); + if (!bap_queue_req(bap, req)) { + bap_req_free(req); + return 0; + } + + return req->id; } -#define ASCS_OP(_str, _op, _size, _func) \ - { \ - .str = _str, \ - .op = _op, \ - .size = _size, \ - .func = _func, \ +static struct bt_bap_stream *bt_bap_stream_ref(struct bt_bap_stream *stream) +{ + if (!stream) + return NULL; + + __sync_fetch_and_add(&stream->ref_count, 1); + + return stream; +} + +static void bap_bcast_set_state(struct bt_bap_stream *stream, uint8_t state) +{ + struct bt_bap *bap = stream->bap; + const struct queue_entry *entry; + + stream->old_state = stream->state; + stream->state = state; + + bt_bap_stream_ref(stream); + + DBG(bap, "stream %p dir 0x%02x: %s -> %s", stream, + bt_bap_stream_get_dir(stream), + bt_bap_stream_statestr(stream->old_state), + bt_bap_stream_statestr(stream->state)); + + for (entry = queue_get_entries(bap->state_cbs); entry; + entry = entry->next) { + struct bt_bap_state *state = entry->data; + + if (state->func) + state->func(stream, stream->old_state, + stream->state, state->data); } -struct ascs_op_handler { - const char *str; - uint8_t op; - size_t size; + /* Post notification updates */ + switch (stream->state) { + case BT_ASCS_ASE_STATE_IDLE: + if (stream->ops && stream->ops->detach) + stream->ops->detach(stream); + break; + case BT_ASCS_ASE_STATE_RELEASING: + bap_stream_io_detach(stream); + stream_set_state(stream, BT_BAP_STREAM_STATE_IDLE); + break; + case BT_ASCS_ASE_STATE_ENABLING: + if (bt_bap_stream_get_io(stream)) + /* Start stream if fd has already been set */ + bt_bap_stream_start(stream, NULL, NULL); + + break; + } + + bt_bap_stream_unref(stream); +} + +static unsigned int bap_bcast_get_state(struct bt_bap_stream *stream) +{ + return stream->state; +} + +static bool bcast_sink_stream_enabled(const void *data, const void *match_data) +{ + struct bt_bap_stream *stream = (struct bt_bap_stream *)data; + struct bt_bap_stream *match = (struct bt_bap_stream *)match_data; + uint8_t state = bt_bap_stream_get_state(stream); + + if (stream == match) + return false; + + if (queue_find(stream->links, NULL, match)) + return false; + + /* Ignore streams that are not Broadcast Sink */ + if (bt_bap_pac_get_type(stream->lpac) != BT_BAP_BCAST_SINK) + return false; + + return ((state == BT_BAP_STREAM_STATE_ENABLING) || + bt_bap_stream_get_io(stream)); +} + +static unsigned int bap_bcast_sink_enable(struct bt_bap_stream *stream, + bool enable_links, struct iovec *data, + bt_bap_stream_func_t func, + void *user_data) +{ + struct bt_bap *bap = stream->bap; + + /* The stream cannot be enabled if there is any other + * unlinked stream for the same source that is in the + * process of enabling or that has already been started. + */ + if (queue_find(bap->streams, bcast_sink_stream_enabled, stream)) + return 0; + + stream_set_state(stream, BT_BAP_STREAM_STATE_ENABLING); + + return 1; +} + +static unsigned int bap_bcast_src_enable(struct bt_bap_stream *stream, + bool enable_links, struct iovec *data, + bt_bap_stream_func_t func, + void *user_data) +{ + stream_set_state(stream, BT_BAP_STREAM_STATE_ENABLING); + + return 1; +} + +static unsigned int bap_bcast_start(struct bt_bap_stream *stream, + bt_bap_stream_func_t func, + void *user_data) +{ + stream_set_state(stream, BT_BAP_STREAM_STATE_STREAMING); + + return 1; +} + +static unsigned int bap_bcast_disable(struct bt_bap_stream *stream, + bool disable_links, + bt_bap_stream_func_t func, + void *user_data) +{ + bap_stream_io_detach(stream); + stream_set_state(stream, BT_BAP_STREAM_STATE_CONFIG); + + return 1; +} + +static unsigned int bap_bcast_metadata(struct bt_bap_stream *stream, + struct iovec *data, + bt_bap_stream_func_t func, + void *user_data) +{ + util_iov_free(stream->meta, 1); + stream->meta = util_iov_dup(data, 1); + + return 1; +} + +static unsigned int bap_bcast_src_get_dir(struct bt_bap_stream *stream) +{ + return BT_BAP_BCAST_SINK; +} + +static unsigned int bap_bcast_sink_get_dir(struct bt_bap_stream *stream) +{ + return BT_BAP_BCAST_SOURCE; +} + +static void bap_sink_get_allocation(size_t i, uint8_t l, uint8_t t, + uint8_t *v, void *user_data) +{ + uint32_t location32; + + if (!v) + return; + + memcpy(&location32, v, l); + *((uint32_t *)user_data) = le32_to_cpu(location32); +} + +static unsigned int bap_bcast_get_location(struct bt_bap_stream *stream) +{ + uint8_t type = BAP_CHANNEL_ALLOCATION_LTV_TYPE; + uint32_t allocation = 0; + struct iovec *caps; + + caps = bt_bap_stream_get_config(stream); + + /* Get stream allocation from capabilities */ + util_ltv_foreach(caps->iov_base, caps->iov_len, &type, + bap_sink_get_allocation, &allocation); + + return allocation; +} + +static unsigned int bap_bcast_release(struct bt_bap_stream *stream, + bt_bap_stream_func_t func, + void *user_data) +{ + stream_set_state(stream, BT_BAP_STREAM_STATE_RELEASING); + + return 1; +} + +static bool bap_ucast_set_io(struct bt_bap_stream *stream, int fd) +{ + if (!stream || (fd >= 0 && stream->io && !stream->io->connecting)) + return false; + + bap_stream_set_io(stream, INT_TO_PTR(fd)); + + queue_foreach(stream->links, bap_stream_set_io, INT_TO_PTR(fd)); + + return true; +} + +static bool bap_bcast_set_io(struct bt_bap_stream *stream, int fd) +{ + if (!stream || (fd >= 0 && stream->io && !stream->io->connecting)) + return false; + + bap_stream_set_io(stream, INT_TO_PTR(fd)); + + return true; +} + +static struct bt_bap_stream_io *bap_ucast_get_io(struct bt_bap_stream *stream) +{ + struct bt_bap_stream_io *io = NULL; + + if (!stream) + return NULL; + + if (stream->io) + return stream->io; + + queue_foreach(stream->links, stream_find_io, &io); + + return io; +} + +static struct bt_bap_stream_io *bap_bcast_get_io(struct bt_bap_stream *stream) +{ + if (!stream) + return NULL; + + return stream->io; +} + +static uint8_t bap_ucast_io_dir(struct bt_bap_stream *stream) +{ + uint8_t dir; + + if (!stream) + return 0x00; + + dir = stream->ep->dir; + + queue_foreach(stream->links, bap_stream_get_dir, &dir); + + return dir; +} + +static uint8_t bap_bcast_io_dir(struct bt_bap_stream *stream) +{ + uint8_t dir; + uint8_t pac_type = bt_bap_pac_get_type(stream->lpac); + + if (!stream) + return 0x00; + + if (pac_type == BT_BAP_BCAST_SINK) + dir = BT_BAP_BCAST_SOURCE; + else + dir = BT_BAP_BCAST_SINK; + + return dir; +} + +static int bap_ucast_io_link(struct bt_bap_stream *stream, + struct bt_bap_stream *link) +{ + struct bt_bap *bap; + + if (!stream || !link || stream == link) + return -EINVAL; + + bap = stream->bap; + + if (!queue_isempty(stream->links) || !queue_isempty(link->links)) + return -EALREADY; + + if (stream->client != link->client || + stream->qos.ucast.cig_id != link->qos.ucast.cig_id || + stream->qos.ucast.cis_id != link->qos.ucast.cis_id || + stream->ep->dir == link->ep->dir) + return -EINVAL; + + if (!stream->links) + stream->links = queue_new(); + + if (!link->links) + link->links = queue_new(); + + queue_push_tail(stream->links, link); + queue_push_tail(link->links, stream); + + /* Link IOs if already set on stream/link */ + if (stream->io && !link->io) + link->io = stream_io_ref(stream->io); + else if (link->io && !stream->io) + stream->io = stream_io_ref(link->io); + + DBG(bap, "stream %p link %p", stream, link); + + return 0; +} + +static void stream_link(void *data, void *user_data) +{ + struct bt_bap_stream *stream = (void *)data; + struct bt_bap_stream *link = (void *)user_data; + + bt_bap_stream_io_link(stream, link); +} + +static int bap_bcast_io_link(struct bt_bap_stream *stream, + struct bt_bap_stream *link) +{ + struct bt_bap *bap; + + if (!stream || !link || stream == link) + return -EINVAL; + + bap = stream->bap; + + if (queue_find(stream->links, NULL, link) || + queue_find(link->links, NULL, stream)) + return -EALREADY; + + if (!stream->links) + stream->links = queue_new(); + + if (!link->links) + link->links = queue_new(); + + queue_push_tail(stream->links, link); + queue_push_tail(link->links, stream); + + DBG(bap, "stream %p link %p", stream, link); + + queue_foreach(stream->links, stream_link, link); + + return 0; +} + +static void stream_unlink(void *data, void *user_data) +{ + struct bt_bap_stream *stream = (void *)data; + struct bt_bap_stream *link = (void *)user_data; + + bap_bcast_io_unlink(stream, link); +} + +static int bap_bcast_io_unlink(struct bt_bap_stream *stream, + struct bt_bap_stream *link) +{ + struct bt_bap *bap; + + if (!stream || !link || stream == link) + return -EINVAL; + + bap = stream->bap; + + if (!queue_find(stream->links, NULL, link) || + !queue_find(link->links, NULL, stream)) + return -EALREADY; + + queue_remove(stream->links, link); + queue_remove(link->links, stream); + + DBG(bap, "stream %p unlink %p", stream, link); + + queue_foreach(stream->links, stream_unlink, link); + + return 0; +} + +#define STREAM_OPS(_type, _set_state, _get_state, _config, _qos, _enable, \ + _start, _disable, _stop, _metadata, _get_dir, _get_loc, _release, \ + _detach, _set_io, _get_io, _io_dir, _io_link, _io_unlink) \ +{ \ + .type = _type, \ + .set_state = _set_state, \ + .get_state = _get_state, \ + .config = _config, \ + .qos = _qos, \ + .enable = _enable, \ + .start = _start, \ + .disable = _disable, \ + .stop = _stop, \ + .metadata = _metadata, \ + .get_dir = _get_dir,\ + .get_loc = _get_loc, \ + .release = _release, \ + .detach = _detach, \ + .set_io = _set_io, \ + .get_io = _get_io, \ + .io_dir = _io_dir, \ + .io_link = _io_link, \ + .io_unlink = _io_unlink, \ +} + +static const struct bt_bap_stream_ops stream_ops[] = { + STREAM_OPS(BT_BAP_SINK, bap_ucast_set_state, + bap_ucast_get_state, + bap_ucast_config, bap_ucast_qos, bap_ucast_enable, + bap_ucast_start, bap_ucast_disable, bap_ucast_stop, + bap_ucast_metadata, bap_ucast_get_dir, + bap_ucast_get_location, + bap_ucast_release, bap_ucast_detach, + bap_ucast_set_io, bap_ucast_get_io, + bap_ucast_io_dir, bap_ucast_io_link, + NULL), + STREAM_OPS(BT_BAP_SOURCE, bap_ucast_set_state, + bap_ucast_get_state, + bap_ucast_config, bap_ucast_qos, bap_ucast_enable, + bap_ucast_start, bap_ucast_disable, bap_ucast_stop, + bap_ucast_metadata, bap_ucast_get_dir, + bap_ucast_get_location, + bap_ucast_release, bap_ucast_detach, + bap_ucast_set_io, bap_ucast_get_io, + bap_ucast_io_dir, bap_ucast_io_link, + NULL), + STREAM_OPS(BT_BAP_BCAST_SINK, bap_bcast_set_state, + bap_bcast_get_state, + bap_bcast_config, bap_bcast_qos, bap_bcast_sink_enable, + bap_bcast_start, bap_bcast_disable, NULL, + bap_bcast_metadata, bap_bcast_sink_get_dir, + bap_bcast_get_location, + bap_bcast_release, bap_bcast_sink_detach, + bap_bcast_set_io, bap_bcast_get_io, + bap_bcast_io_dir, bap_bcast_io_link, + bap_bcast_io_unlink), + STREAM_OPS(BT_BAP_BCAST_SOURCE, bap_bcast_set_state, + bap_bcast_get_state, + bap_bcast_config, bap_bcast_qos, bap_bcast_src_enable, + bap_bcast_start, bap_bcast_disable, NULL, + bap_bcast_metadata, bap_bcast_src_get_dir, + bap_bcast_get_location, + bap_bcast_release, bap_bcast_src_detach, + bap_bcast_set_io, bap_bcast_get_io, + bap_bcast_io_dir, bap_bcast_io_link, + bap_bcast_io_unlink), +}; + +static const struct bt_bap_stream_ops * +bap_stream_new_ops(struct bt_bap_stream *stream) +{ + const struct bt_bap_stream_ops *ops; + uint8_t type = bt_bap_pac_get_type(stream->lpac); + size_t i; + + for (i = 0; i < ARRAY_SIZE(stream_ops); i++) { + ops = &stream_ops[i]; + + if (ops->type == type) + return ops; + } + + return NULL; +} + +static struct bt_bap_stream *bap_stream_new(struct bt_bap *bap, + struct bt_bap_endpoint *ep, + struct bt_bap_pac *lpac, + struct bt_bap_pac *rpac, + struct iovec *data, + bool client) +{ + struct bt_bap_stream *stream; + + stream = new0(struct bt_bap_stream, 1); + stream->bap = bap; + stream->ep = ep; + if (ep != NULL) + ep->stream = stream; + stream->lpac = lpac; + stream->rpac = rpac; + stream->cc = util_iov_dup(data, 1); + stream->client = client; + stream->ops = bap_stream_new_ops(stream); + + queue_push_tail(bap->streams, stream); + + return bt_bap_stream_ref(stream); +} + +static struct bt_bap_stream_io *stream_io_ref(struct bt_bap_stream_io *io) +{ + if (!io) + return NULL; + + __sync_fetch_and_add(&io->ref_count, 1); + + return io; +} + +static struct bt_bap_stream_io *stream_io_new(struct bt_bap *bap, int fd) +{ + struct io *io; + struct bt_bap_stream_io *sio; + + io = io_new(fd); + if (!io) + return NULL; + + DBG(bap, "fd %d", fd); + + sio = new0(struct bt_bap_stream_io, 1); + sio->bap = bap; + sio->io = io; + + return stream_io_ref(sio); +} + +static void stream_find_io(void *data, void *user_data) +{ + struct bt_bap_stream *stream = data; + struct bt_bap_stream_io **io = user_data; + + if (*io) + return; + + *io = stream->io; +} + +static struct bt_bap_stream_io *stream_get_io(struct bt_bap_stream *stream) +{ + struct bt_bap_stream_io *io; + struct bt_bap *bap; + + if (!bap_stream_valid(stream)) + return NULL; + + if (!stream->ops || !stream->ops->get_io) + return NULL; + + if (!bt_bap_ref_safe(stream->bap)) + return NULL; + + bap = stream->bap; + + io = stream->ops->get_io(stream); + + bt_bap_unref(bap); + + return io; +} + +static bool stream_io_disconnected(struct io *io, void *user_data); + +static bool bap_stream_io_attach(struct bt_bap_stream *stream, int fd, + bool connecting) +{ + struct bt_bap_stream_io *io; + + io = stream_get_io(stream); + if (io) { + if (fd == stream_io_get_fd(io)) { + if (!stream->io) + stream->io = stream_io_ref(io); + + io->connecting = connecting; + return true; + } + + DBG(stream->bap, "stream %p io already set", stream); + return false; + } + + DBG(stream->bap, "stream %p connecting %s", stream, + connecting ? "true" : "false"); + + io = stream_io_new(stream->bap, fd); + if (!io) + return false; + + io->connecting = connecting; + stream->io = io; + io_set_disconnect_handler(io->io, stream_io_disconnected, stream, NULL); + + return true; +} + +static void bap_stream_set_io(void *data, void *user_data) +{ + struct bt_bap_stream *stream = data; + int fd = PTR_TO_INT(user_data); + bool ret; + uint8_t state; + + if (fd >= 0) + ret = bap_stream_io_attach(stream, fd, false); + else + ret = bap_stream_io_detach(stream); + + if (!ret) + return; + + if (bt_bap_stream_get_type(stream) == BT_BAP_STREAM_TYPE_BCAST) + state = stream->state; + else + state = stream->ep->state; + + switch (state) { + case BT_BAP_STREAM_STATE_ENABLING: + if (fd < 0) + bt_bap_stream_disable(stream, false, NULL, NULL); + else + bt_bap_stream_start(stream, NULL, NULL); + break; + case BT_BAP_STREAM_STATE_DISABLING: + if (fd < 0) + bt_bap_stream_stop(stream, NULL, NULL); + break; + } +} + +static void ascs_ase_rsp_add_errno(struct iovec *iov, uint8_t id, int err) +{ + struct bt_ascs_cp_rsp *rsp = iov->iov_base; + + switch (err) { + case -ENOBUFS: + case -ENOMEM: + return ascs_ase_rsp_add(iov, id, BT_ASCS_RSP_NO_MEM, + BT_ASCS_REASON_NONE); + case -EINVAL: + switch (rsp->op) { + case BT_ASCS_CONFIG: + /* Fallthrough */ + case BT_ASCS_QOS: + return ascs_ase_rsp_add(iov, id, + BT_ASCS_RSP_CONF_INVALID, + BT_ASCS_REASON_NONE); + case BT_ASCS_ENABLE: + /* Fallthrough */ + case BT_ASCS_METADATA: + return ascs_ase_rsp_add(iov, id, + BT_ASCS_RSP_METADATA_INVALID, + BT_ASCS_REASON_NONE); + default: + return ascs_ase_rsp_add(iov, id, + BT_ASCS_RSP_UNSPECIFIED, + BT_ASCS_REASON_NONE); + } + case -ENOTSUP: + switch (rsp->op) { + case BT_ASCS_CONFIG: + /* Fallthrough */ + case BT_ASCS_QOS: + return ascs_ase_rsp_add(iov, id, + BT_ASCS_RSP_CONF_UNSUPPORTED, + BT_ASCS_REASON_NONE); + case BT_ASCS_ENABLE: + /* Fallthrough */ + case BT_ASCS_METADATA: + return ascs_ase_rsp_add(iov, id, + BT_ASCS_RSP_METADATA_UNSUPPORTED, + BT_ASCS_REASON_NONE); + default: + return ascs_ase_rsp_add(iov, id, + BT_ASCS_RSP_NOT_SUPPORTED, + BT_ASCS_REASON_NONE); + } + case -EBADMSG: + return ascs_ase_rsp_add(iov, id, BT_ASCS_RSP_INVALID_ASE_STATE, + BT_ASCS_REASON_NONE); + case -ENOMSG: + return ascs_ase_rsp_add(iov, id, BT_ASCS_RSP_TRUNCATED, + BT_ASCS_REASON_NONE); + default: + return ascs_ase_rsp_add(iov, id, BT_ASCS_RSP_UNSPECIFIED, + BT_ASCS_REASON_NONE); + } +} + +static uint8_t ep_config(struct bt_bap_endpoint *ep, struct bt_bap *bap, + struct bt_ascs_config *req, + struct iovec *iov, struct iovec *rsp) +{ + struct iovec cc; + const struct queue_entry *e; + + DBG(bap, "ep %p id 0x%02x dir 0x%02x", ep, ep->id, ep->dir); + + switch (ep->state) { + /* Valid only if ASE_State field = 0x00 (Idle) */ + case BT_ASCS_ASE_STATE_IDLE: + /* or 0x01 (Codec Configured) */ + case BT_ASCS_ASE_STATE_CONFIG: + /* or 0x02 (QoS Configured) */ + case BT_ASCS_ASE_STATE_QOS: + break; + default: + DBG(bap, "Invalid state %s", bt_bap_stream_statestr(ep->state)); + ascs_ase_rsp_add(rsp, req->ase, + BT_ASCS_RSP_INVALID_ASE_STATE, + BT_ASCS_REASON_NONE); + return 0; + } + + if (iov->iov_len < req->cc_len) + return BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN; + + cc.iov_base = util_iov_pull_mem(iov, req->cc_len); + cc.iov_len = req->cc_len; + + if (!bt_bap_debug_caps(cc.iov_base, cc.iov_len, bap->debug_func, + bap->debug_data)) { + ascs_ase_rsp_add(rsp, req->ase, + BT_ASCS_RSP_CONF_INVALID, + BT_ASCS_REASON_CODEC_DATA); + return 0; + } + + switch (ep->dir) { + case BT_BAP_SINK: + e = queue_get_entries(bap->ldb->sinks); + break; + case BT_BAP_SOURCE: + e = queue_get_entries(bap->ldb->sources); + break; + default: + e = NULL; + } + + for (; e; e = e->next) { + struct bt_bap_pac *pac = e->data; + + if (!bap_codec_equal(&req->codec, &pac->codec)) + continue; + + if (!ep->stream) + ep->stream = bap_stream_new(bap, ep, pac, NULL, NULL, + false); + + break; + } + + if (!e) { + ascs_ase_rsp_add(rsp, req->ase, + BT_ASCS_RSP_CONF_INVALID, + BT_ASCS_REASON_CODEC); + return 0; + } + + return stream_config(ep->stream, &cc, rsp); +} + +static uint8_t ascs_config(struct bt_ascs *ascs, struct bt_bap *bap, + struct iovec *iov, struct iovec *rsp) +{ + struct bt_bap_endpoint *ep; + struct bt_ascs_config *req; + + req = util_iov_pull_mem(iov, sizeof(*req)); + + DBG(bap, "codec 0x%02x phy 0x%02x latency %u", req->codec.id, req->phy, + req->latency); + + ep = bap_get_local_endpoint_id(bap, req->ase); + if (!ep) { + DBG(bap, "Invalid ASE ID 0x%02x", req->ase); + ascs_ase_rsp_add(rsp, req->ase, + BT_ASCS_RSP_INVALID_ASE, BT_ASCS_REASON_NONE); + return 0; + } + + return ep_config(ep, bap, req, iov, rsp); +} + +static uint8_t stream_qos(struct bt_bap_stream *stream, struct bt_bap_qos *qos, + struct iovec *rsp) +{ + DBG(stream->bap, "stream %p", stream); + + ascs_ase_rsp_success(rsp, stream->ep->id); + + if (memcmp(&stream->qos, qos, sizeof(*qos))) + stream->qos = *qos; + + stream_set_state(stream, BT_BAP_STREAM_STATE_QOS); + + return 0; +} + +static uint8_t ep_qos(struct bt_bap_endpoint *ep, struct bt_bap *bap, + struct bt_bap_qos *qos, struct iovec *rsp) +{ + DBG(bap, "ep %p id 0x%02x dir 0x%02x", ep, ep->id, ep->dir); + + switch (ep->state) { + /* Valid only if ASE_State field = 0x01 (Codec Configured) */ + case BT_ASCS_ASE_STATE_CONFIG: + /* or 0x02 (QoS Configured) */ + case BT_ASCS_ASE_STATE_QOS: + break; + default: + DBG(bap, "Invalid state %s", bt_bap_stream_statestr(ep->state)); + ascs_ase_rsp_add(rsp, ep->id, + BT_ASCS_RSP_INVALID_ASE_STATE, + BT_ASCS_REASON_NONE); + return 0; + } + + if (!ep->stream) { + DBG(bap, "No stream found"); + ascs_ase_rsp_add(rsp, ep->id, + BT_ASCS_RSP_INVALID_ASE_STATE, + BT_ASCS_REASON_NONE); + return 0; + } + + return stream_qos(ep->stream, qos, rsp); +} + +static uint8_t ascs_qos(struct bt_ascs *ascs, struct bt_bap *bap, + struct iovec *iov, struct iovec *rsp) +{ + struct bt_bap_endpoint *ep; + struct bt_ascs_qos *req; + struct bt_bap_qos qos; + + req = util_iov_pull_mem(iov, sizeof(*req)); + + memset(&qos, 0, sizeof(qos)); + + qos.ucast.cig_id = req->cig; + qos.ucast.cis_id = req->cis; + qos.ucast.io_qos.interval = get_le24(req->interval); + qos.ucast.framing = req->framing; + qos.ucast.io_qos.phy = req->phy; + qos.ucast.io_qos.sdu = le16_to_cpu(req->sdu); + qos.ucast.io_qos.rtn = req->rtn; + qos.ucast.io_qos.latency = le16_to_cpu(req->latency); + qos.ucast.delay = get_le24(req->pd); + + DBG(bap, "CIG 0x%02x CIS 0x%02x interval %u framing 0x%02x " + "phy 0x%02x SDU %u rtn %u latency %u pd %u", + req->cig, req->cis, qos.ucast.io_qos.interval, + qos.ucast.framing, qos.ucast.io_qos.phy, + qos.ucast.io_qos.sdu, qos.ucast.io_qos.rtn, + qos.ucast.io_qos.latency, qos.ucast.delay); + + ep = bap_get_local_endpoint_id(bap, req->ase); + if (!ep) { + DBG(bap, "%s: Invalid ASE ID 0x%02x", req->ase); + ascs_ase_rsp_add(rsp, req->ase, + BT_ASCS_RSP_INVALID_ASE, BT_ASCS_REASON_NONE); + return 0; + } + + return ep_qos(ep, bap, &qos, rsp); +} + +static uint8_t stream_enable(struct bt_bap_stream *stream, struct iovec *meta, + struct iovec *rsp) +{ + DBG(stream->bap, "stream %p", stream); + + ascs_ase_rsp_success(rsp, stream->ep->id); + + util_iov_free(stream->meta, 1); + stream->meta = util_iov_dup(meta, 1); + + if (!stream_set_state(stream, BT_BAP_STREAM_STATE_ENABLING)) + return 1; + + /* Sink can autonomously for to Streaming state if io already exits */ + if (stream->io && stream->ep->dir == BT_BAP_SINK) + stream_set_state(stream, BT_BAP_STREAM_STATE_STREAMING); + + return 0; +} + +static uint8_t ep_enable(struct bt_bap_endpoint *ep, struct bt_bap *bap, + struct bt_ascs_enable *req, struct iovec *iov, + struct iovec *rsp) +{ + struct iovec meta; + + DBG(bap, "ep %p id 0x%02x dir 0x%02x", ep, ep->id, ep->dir); + + switch (ep->state) { + /* Valid only if ASE_State field = 0x02 (QoS Configured) */ + case BT_ASCS_ASE_STATE_QOS: + break; + default: + DBG(bap, "Invalid state %s", bt_bap_stream_statestr(ep->state)); + ascs_ase_rsp_add(rsp, ep->id, + BT_ASCS_RSP_INVALID_ASE_STATE, + BT_ASCS_REASON_NONE); + return 0; + } + + meta.iov_base = util_iov_pull_mem(iov, req->meta.len); + meta.iov_len = req->meta.len; + + if (!bt_bap_debug_metadata(meta.iov_base, meta.iov_len, + bap->debug_func, bap->debug_data)) { + ascs_ase_rsp_add(rsp, ep->id, + BT_ASCS_RSP_METADATA_INVALID, + BT_ASCS_REASON_NONE); + return 0; + } + + if (!ep->stream) { + DBG(bap, "No stream found"); + ascs_ase_rsp_add(rsp, ep->id, + BT_ASCS_RSP_INVALID_ASE_STATE, + BT_ASCS_REASON_NONE); + return 0; + } + + return stream_enable(ep->stream, &meta, rsp); +} + +static uint8_t ascs_enable(struct bt_ascs *ascs, struct bt_bap *bap, + struct iovec *iov, struct iovec *rsp) +{ + struct bt_bap_endpoint *ep; + struct bt_ascs_enable *req; + + req = util_iov_pull_mem(iov, sizeof(*req)); + + ep = bap_get_local_endpoint_id(bap, req->meta.ase); + if (!ep) { + DBG(bap, "Invalid ASE ID 0x%02x", req->meta.ase); + ascs_ase_rsp_add(rsp, req->meta.ase, + BT_ASCS_RSP_INVALID_ASE, BT_ASCS_REASON_NONE); + return 0; + } + + return ep_enable(ep, bap, req, iov, rsp); +} + +static uint8_t ep_start(struct bt_bap_endpoint *ep, struct iovec *rsp) +{ + struct bt_bap_stream *stream = ep->stream; + + DBG(stream->bap, "ep %p id 0x%02x dir 0x%02x", ep, ep->id, ep->dir); + + switch (ep->state) { + /* Valid only if ASE_State field = 0x03 (Enabling) */ + case BT_ASCS_ASE_STATE_ENABLING: + break; + default: + DBG(ep->stream->bap, "Invalid state %s", + bt_bap_stream_statestr(ep->state)); + ascs_ase_rsp_add(rsp, ep->id, + BT_ASCS_RSP_INVALID_ASE_STATE, + BT_ASCS_REASON_NONE); + return 0; + } + + /* If the ASE_ID written by the client represents a Sink ASE, the + * server shall not accept the Receiver Start Ready operation for that + * ASE. The server shall send a notification of the ASE Control Point + * characteristic to the client, and the server shall set the + * Response_Code value for that ASE to 0x05 (Invalid ASE direction). + */ + if (ep->dir == BT_BAP_SINK) { + ascs_ase_rsp_add(rsp, ep->id, + BT_ASCS_RSP_INVALID_DIR, BT_ASCS_REASON_NONE); + return 0; + } + + return stream_start(ep->stream, rsp); +} + +static uint8_t ascs_start(struct bt_ascs *ascs, struct bt_bap *bap, + struct iovec *iov, struct iovec *rsp) +{ + struct bt_bap_endpoint *ep; + struct bt_ascs_start *req; + + req = util_iov_pull_mem(iov, sizeof(*req)); + + ep = bap_get_local_endpoint_id(bap, req->ase); + if (!ep) { + DBG(bap, "Invalid ASE ID 0x%02x", req->ase); + ascs_ase_rsp_add(rsp, req->ase, + BT_ASCS_RSP_INVALID_ASE, BT_ASCS_REASON_NONE); + return 0; + } + + if (!ep->stream) { + DBG(bap, "No stream found for %p", ep); + ascs_ase_rsp_add(rsp, ep->id, + BT_ASCS_RSP_INVALID_ASE_STATE, + BT_ASCS_REASON_NONE); + return 0; + } + + return ep_start(ep, rsp); +} + +static uint8_t ep_disable(struct bt_bap_endpoint *ep, struct iovec *rsp) +{ + struct bt_bap_stream *stream = ep->stream; + + DBG(stream->bap, "ep %p id 0x%02x dir 0x%02x", ep, ep->id, ep->dir); + + switch (ep->state) { + /* Valid only if ASE_State field = 0x03 (Enabling) */ + case BT_ASCS_ASE_STATE_ENABLING: + /* or 0x04 (Streaming) */ + case BT_ASCS_ASE_STATE_STREAMING: + break; + default: + DBG(stream->bap, "Invalid state %s", + bt_bap_stream_statestr(ep->state)); + ascs_ase_rsp_add(rsp, ep->id, + BT_ASCS_RSP_INVALID_ASE_STATE, + BT_ASCS_REASON_NONE); + return 0; + } + + return stream_disable(ep->stream, rsp); +} + +static uint8_t ascs_disable(struct bt_ascs *ascs, struct bt_bap *bap, + struct iovec *iov, struct iovec *rsp) +{ + struct bt_bap_endpoint *ep; + struct bt_ascs_disable *req; + + req = util_iov_pull_mem(iov, sizeof(*req)); + + ep = bap_get_local_endpoint_id(bap, req->ase); + if (!ep) { + DBG(bap, "Invalid ASE ID 0x%02x", req->ase); + ascs_ase_rsp_add(rsp, req->ase, + BT_ASCS_RSP_INVALID_ASE, BT_ASCS_REASON_NONE); + return 0; + } + + if (!ep->stream) { + DBG(bap, "No stream found"); + ascs_ase_rsp_add(rsp, ep->id, + BT_ASCS_RSP_INVALID_ASE_STATE, + BT_ASCS_REASON_NONE); + return 0; + } + + return ep_disable(ep, rsp); +} + +static uint8_t ep_stop(struct bt_bap_endpoint *ep, struct iovec *rsp) +{ + struct bt_bap_stream *stream = ep->stream; + + DBG(stream->bap, "ep %p id 0x%02x dir 0x%02x", ep, ep->id, ep->dir); + + switch (ep->state) { + /* Valid only if ASE_State field = 0x05 (Disabling) */ + case BT_ASCS_ASE_STATE_DISABLING: + break; + default: + DBG(stream->bap, "Invalid state %s", + bt_bap_stream_statestr(ep->state)); + ascs_ase_rsp_add(rsp, ep->id, + BT_ASCS_RSP_INVALID_ASE_STATE, + BT_ASCS_REASON_NONE); + return 0; + } + + /* If the ASE_ID written by the client represents a Sink ASE, the + * server shall not accept the Receiver Stop Ready operation for that + * ASE. The server shall send a notification of the ASE Control Point + * characteristic to the client, and the server shall set the + * Response_Code value for that ASE to 0x05 (Invalid ASE direction). + */ + if (ep->dir == BT_BAP_SINK) { + ascs_ase_rsp_add(rsp, ep->id, + BT_ASCS_RSP_INVALID_DIR, BT_ASCS_REASON_NONE); + return 0; + } + + return stream_stop(ep->stream, rsp); +} + +static uint8_t ascs_stop(struct bt_ascs *ascs, struct bt_bap *bap, + struct iovec *iov, struct iovec *rsp) +{ + struct bt_bap_endpoint *ep; + struct bt_ascs_stop *req; + + req = util_iov_pull_mem(iov, sizeof(*req)); + + ep = bap_get_local_endpoint_id(bap, req->ase); + if (!ep) { + DBG(bap, "Invalid ASE ID 0x%02x", req->ase); + ascs_ase_rsp_add(rsp, req->ase, + BT_ASCS_RSP_INVALID_ASE, BT_ASCS_REASON_NONE); + return 0; + } + + if (!ep->stream) { + DBG(bap, "No stream found"); + ascs_ase_rsp_add(rsp, ep->id, + BT_ASCS_RSP_INVALID_ASE_STATE, + BT_ASCS_REASON_NONE); + return 0; + } + + return ep_stop(ep, rsp); +} + +static uint8_t ep_metadata(struct bt_bap_endpoint *ep, struct iovec *meta, + struct iovec *rsp) +{ + struct bt_bap_stream *stream = ep->stream; + + DBG(stream->bap, "ep %p id 0x%02x dir 0x%02x", ep, ep->id, ep->dir); + + switch (ep->state) { + /* Valid only if ASE_State field = 0x03 (Enabling) */ + case BT_ASCS_ASE_STATE_ENABLING: + /* or 0x04 (Streaming) */ + case BT_ASCS_ASE_STATE_STREAMING: + break; + default: + DBG(stream->bap, "Invalid state %s", + bt_bap_stream_statestr(ep->state)); + ascs_ase_rsp_add(rsp, ep->id, + BT_ASCS_RSP_INVALID_ASE_STATE, + BT_ASCS_REASON_NONE); + return 0; + } + + return stream_metadata(ep->stream, meta, rsp); +} + +static uint8_t ascs_metadata(struct bt_ascs *ascs, struct bt_bap *bap, + struct iovec *iov, struct iovec *rsp) +{ + struct bt_bap_endpoint *ep; + struct bt_ascs_metadata *req; + + req = util_iov_pull_mem(iov, sizeof(*req)); + + ep = bap_get_local_endpoint_id(bap, req->ase); + if (!ep) { + DBG(bap, "Invalid ASE ID 0x%02x", req->ase); + ascs_ase_rsp_add(rsp, req->ase, + BT_ASCS_RSP_INVALID_ASE, BT_ASCS_REASON_NONE); + return 0; + } + + if (!ep->stream) { + DBG(bap, "No stream found"); + ascs_ase_rsp_add(rsp, ep->id, + BT_ASCS_RSP_INVALID_ASE_STATE, + BT_ASCS_REASON_NONE); + return 0; + } + + return ep_metadata(ep, iov, rsp); +} + +static uint8_t ascs_release(struct bt_ascs *ascs, struct bt_bap *bap, + struct iovec *iov, struct iovec *rsp) +{ + struct bt_bap_endpoint *ep; + struct bt_ascs_release *req; + + req = util_iov_pull_mem(iov, sizeof(*req)); + + ep = bap_get_local_endpoint_id(bap, req->ase); + if (!ep) { + DBG(bap, "Invalid ASE ID 0x%02x", req->ase); + ascs_ase_rsp_add(rsp, req->ase, + BT_ASCS_RSP_INVALID_ASE, BT_ASCS_REASON_NONE); + return 0; + } + + if (!ep->stream) { + DBG(bap, "No stream found"); + ascs_ase_rsp_add(rsp, ep->id, + BT_ASCS_RSP_INVALID_ASE_STATE, + BT_ASCS_REASON_NONE); + return 0; + } + + return stream_release(ep->stream, rsp); +} + +#define ASCS_OP(_str, _op, _size, _func) \ + { \ + .str = _str, \ + .op = _op, \ + .size = _size, \ + .func = _func, \ + } + +struct ascs_op_handler { + const char *str; + uint8_t op; + size_t size; uint8_t (*func)(struct bt_ascs *ascs, struct bt_bap *bap, struct iovec *iov, struct iovec *rsp); } handlers[] = { @@ -2131,2671 +3367,3703 @@ struct ascs_op_handler { {} }; -static struct iovec *ascs_ase_cp_rsp_new(uint8_t op) +static struct iovec *ascs_ase_cp_rsp_new(uint8_t op) +{ + struct bt_ascs_cp_rsp *rsp; + struct iovec *iov; + + iov = new0(struct iovec, 1); + rsp = new0(struct bt_ascs_cp_rsp, 1); + rsp->op = op; + iov->iov_base = rsp; + iov->iov_len = sizeof(*rsp); + + return iov; +} + +static void ascs_ase_cp_write(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + const uint8_t *value, size_t len, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct bt_ascs *ascs = user_data; + struct bt_bap *bap = bap_get_session(att, ascs->bdb->db); + struct iovec iov = { + .iov_base = (void *) value, + .iov_len = len, + }; + struct bt_ascs_ase_hdr *hdr; + struct ascs_op_handler *handler; + uint8_t ret = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED; + struct iovec *rsp; + + if (offset) { + DBG(bap, "invalid offset %u", offset); + gatt_db_attribute_write_result(attrib, id, + BT_ATT_ERROR_INVALID_OFFSET); + return; + } + + if (len < sizeof(*hdr)) { + DBG(bap, "invalid len %u < %u sizeof(*hdr)", len, + sizeof(*hdr)); + gatt_db_attribute_write_result(attrib, id, + BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN); + return; + } + + hdr = util_iov_pull_mem(&iov, sizeof(*hdr)); + rsp = ascs_ase_cp_rsp_new(hdr->op); + + for (handler = handlers; handler && handler->str; handler++) { + if (handler->op != hdr->op) + continue; + + if (iov.iov_len < hdr->num * handler->size) { + DBG(bap, "invalid len %u < %u " + "hdr->num * handler->size", len, + hdr->num * handler->size); + ret = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN; + goto respond; + } + + break; + } + + if (handler && handler->str) { + int i; + + DBG(bap, "%s", handler->str); + + /* Set in_cp_write so ASE notification are not sent ahead of + * CP notifcation. + */ + bap->in_cp_write = true; + + for (i = 0; i < hdr->num; i++) + ret = handler->func(ascs, bap, &iov, rsp); + + bap->in_cp_write = false; + } else { + DBG(bap, "Unknown opcode 0x%02x", hdr->op); + ascs_ase_rsp_add_errno(rsp, 0x00, -ENOTSUP); + } + +respond: + if (ret == BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN) + ascs_ase_rsp_add_errno(rsp, 0x00, -ENOMSG); + + gatt_db_attribute_notify(attrib, rsp->iov_base, rsp->iov_len, att); + gatt_db_attribute_write_result(attrib, id, ret); + + util_iov_free(rsp, 1); +} + +static struct bt_ascs *ascs_new(struct gatt_db *db) +{ + struct bt_ascs *ascs; + bt_uuid_t uuid; + int i; + + if (!db) + return NULL; + + ascs = new0(struct bt_ascs, 1); + + /* Populate DB with ASCS attributes */ + bt_uuid16_create(&uuid, ASCS_UUID); + ascs->service = gatt_db_add_service(db, &uuid, true, + 4 + (NUM_ASES * 3)); + + for (i = 0; i < NUM_ASES; i++) + ase_new(ascs, i); + + bt_uuid16_create(&uuid, ASE_CP_UUID); + ascs->ase_cp = gatt_db_service_add_characteristic(ascs->service, + &uuid, + BT_ATT_PERM_WRITE, + BT_GATT_CHRC_PROP_WRITE | + BT_GATT_CHRC_PROP_NOTIFY, + NULL, ascs_ase_cp_write, + ascs); + + ascs->ase_cp_ccc = gatt_db_service_add_ccc(ascs->service, + BT_ATT_PERM_READ | BT_ATT_PERM_WRITE); + + gatt_db_service_set_active(ascs->service, true); + + return ascs; +} + +static struct bt_bap_db *bap_db_new(struct gatt_db *db) +{ + struct bt_bap_db *bdb; + + if (!db) + return NULL; + + bdb = new0(struct bt_bap_db, 1); + bdb->db = gatt_db_ref(db); + bdb->sinks = queue_new(); + bdb->sources = queue_new(); + bdb->broadcast_sources = queue_new(); + bdb->broadcast_sinks = queue_new(); + + if (!bap_db) + bap_db = queue_new(); + + bdb->pacs = pacs_new(db); + bdb->pacs->bdb = bdb; + + bdb->ascs = ascs_new(db); + bdb->ascs->bdb = bdb; + + queue_push_tail(bap_db, bdb); + + return bdb; +} + +static struct bt_bap_db *bap_get_db(struct gatt_db *db) +{ + struct bt_bap_db *bdb; + + bdb = queue_find(bap_db, bap_db_match, db); + if (bdb) + return bdb; + + return bap_db_new(db); +} + +static struct bt_pacs *bap_get_pacs(struct bt_bap *bap) +{ + if (!bap) + return NULL; + + if (bap->rdb->pacs) + return bap->rdb->pacs; + + bap->rdb->pacs = new0(struct bt_pacs, 1); + bap->rdb->pacs->bdb = bap->rdb; + + return bap->rdb->pacs; +} + +static bool match_codec(const void *data, const void *user_data) +{ + const struct bt_bap_pac *pac = data; + const struct bt_bap_codec *codec = user_data; + + return bap_codec_equal(&pac->codec, codec); +} + +static struct bt_bap_pac *bap_pac_find(struct bt_bap_db *bdb, uint8_t type, + struct bt_bap_codec *codec) +{ + switch (type) { + case BT_BAP_SOURCE: + return queue_find(bdb->sources, match_codec, codec); + case BT_BAP_SINK: + return queue_find(bdb->sinks, match_codec, codec); + case BT_BAP_BCAST_SOURCE: + return queue_find(bdb->broadcast_sources, match_codec, codec); + case BT_BAP_BCAST_SINK: + return queue_find(bdb->broadcast_sinks, match_codec, codec); + } + + return NULL; +} + +static void *ltv_merge(struct iovec *data, struct iovec *cont) +{ + uint8_t delimiter = 0; + + if (!data) + return NULL; + + if (!cont || !cont->iov_len || !cont->iov_base) + return data->iov_base; + + util_iov_append(data, &delimiter, sizeof(delimiter)); + + return util_iov_append(data, cont->iov_base, cont->iov_len); +} + +static void bap_pac_chan_add(struct bt_bap_pac *pac, uint8_t count, + uint32_t location) +{ + struct bt_bap_chan *chan; + + if (!pac->channels) + pac->channels = queue_new(); + + chan = new0(struct bt_bap_chan, 1); + chan->count = count; + chan->location = location; + + queue_push_tail(pac->channels, chan); +} + +static void bap_pac_foreach_channel(size_t i, uint8_t l, uint8_t t, uint8_t *v, + void *user_data) +{ + struct bt_bap_pac *pac = user_data; + + if (!v) + return; + + bap_pac_chan_add(pac, *v, bt_bap_pac_get_locations(pac)); +} + +static void bap_pac_update_channels(struct bt_bap_pac *pac, struct iovec *data) +{ + uint8_t type = 0x03; + + if (!data) + return; + + util_ltv_foreach(data->iov_base, data->iov_len, &type, + bap_pac_foreach_channel, pac); + + /* If record didn't set a channel count but set a location use that as + * channel count. + */ + if (queue_isempty(pac->channels) && pac->qos.location) + bap_pac_chan_add(pac, pac->qos.location, pac->qos.location); + +} + +static void bap_pac_merge(struct bt_bap_pac *pac, struct iovec *data, + struct iovec *metadata) +{ + /* Merge data into existing record */ + if (pac->data) + ltv_merge(pac->data, data); + else + pac->data = util_iov_dup(data, 1); + + /* Update channels */ + bap_pac_update_channels(pac, data); + + /* Merge metadata into existing record */ + if (pac->metadata) + ltv_merge(pac->metadata, metadata); + else + pac->metadata = util_iov_dup(metadata, 1); +} + +static struct bt_bap_pac *bap_pac_new(struct bt_bap_db *bdb, const char *name, + uint8_t type, + struct bt_bap_codec *codec, + struct bt_bap_pac_qos *qos, + struct iovec *data, + struct iovec *metadata) +{ + struct bt_bap_pac *pac; + + pac = new0(struct bt_bap_pac, 1); + pac->bdb = bdb; + pac->name = name ? strdup(name) : NULL; + pac->type = type; + + if (codec) + pac->codec = *codec; + + if (qos) + pac->qos = *qos; + + bap_pac_merge(pac, data, metadata); + + return pac; +} + +static void bap_pac_free(void *data) { - struct bt_ascs_cp_rsp *rsp; - struct iovec *iov; + struct bt_bap_pac *pac = data; - iov = new0(struct iovec, 1); - rsp = new0(struct bt_ascs_cp_rsp, 1); - rsp->op = op; - iov->iov_base = rsp; - iov->iov_len = sizeof(*rsp); + free(pac->name); + util_iov_free(pac->metadata, 1); + util_iov_free(pac->data, 1); + queue_destroy(pac->channels, free); + free(pac); +} - return iov; +static void pacs_sink_location_changed(struct bt_pacs *pacs) +{ + uint32_t location = cpu_to_le32(pacs->sink_loc_value); + + gatt_db_attribute_notify(pacs->sink_loc, (void *)&location, + sizeof(location), NULL); } -static void ascs_ase_cp_write(struct gatt_db_attribute *attrib, - unsigned int id, uint16_t offset, - const uint8_t *value, size_t len, - uint8_t opcode, struct bt_att *att, - void *user_data) +static void pacs_add_sink_location(struct bt_pacs *pacs, uint32_t location) { - struct bt_ascs *ascs = user_data; - struct bt_bap *bap = bap_get_session(att, ascs->bdb->db); - struct iovec iov = { - .iov_base = (void *) value, - .iov_len = len, - }; - struct bt_ascs_ase_hdr *hdr; - struct ascs_op_handler *handler; - uint8_t ret = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED; - struct iovec *rsp; + /* Check if location value needs updating */ + if (location == pacs->sink_loc_value) + return; - if (offset) { - DBG(bap, "invalid offset %u", offset); - gatt_db_attribute_write_result(attrib, id, - BT_ATT_ERROR_INVALID_OFFSET); + pacs->sink_loc_value |= location; + + pacs_sink_location_changed(pacs); +} + +static void pacs_supported_context_changed(struct bt_pacs *pacs) +{ + struct bt_pacs_context ctx; + + memset(&ctx, 0, sizeof(ctx)); + + ctx.snk = cpu_to_le16(pacs->supported_sink_context_value); + ctx.src = cpu_to_le16(pacs->supported_source_context_value); + + gatt_db_attribute_notify(pacs->supported_context, (void *)&ctx, + sizeof(ctx), NULL); +} + +static void pacs_add_sink_supported_context(struct bt_pacs *pacs, + uint16_t context) +{ + context |= pacs->supported_sink_context_value; + + /* Check if context value needs updating */ + if (context == pacs->supported_sink_context_value) return; - } - if (len < sizeof(*hdr)) { - DBG(bap, "invalid len %u < %u sizeof(*hdr)", len, - sizeof(*hdr)); - gatt_db_attribute_write_result(attrib, id, - BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN); + pacs->supported_sink_context_value = context; + + pacs_supported_context_changed(pacs); +} + +static void pacs_context_changed(struct bt_pacs *pacs) +{ + struct bt_pacs_context ctx; + + memset(&ctx, 0, sizeof(ctx)); + + ctx.snk = cpu_to_le16(pacs->sink_context_value); + ctx.src = cpu_to_le16(pacs->source_context_value); + + gatt_db_attribute_notify(pacs->context, (void *)&ctx, sizeof(ctx), + NULL); +} + +static void pacs_add_sink_context(struct bt_pacs *pacs, uint16_t context) +{ + context |= pacs->supported_sink_context_value; + + /* Check if context value needs updating */ + if (context == pacs->sink_context_value) + return; + + pacs->sink_context_value = context; + + pacs_context_changed(pacs); +} + +static void bap_add_sink(struct bt_bap_pac *pac) +{ + struct iovec iov; + uint8_t value[512]; + + queue_push_tail(pac->bdb->sinks, pac); + + memset(value, 0, sizeof(value)); + + iov.iov_base = value; + iov.iov_len = 0; + + queue_foreach(pac->bdb->sinks, pac_foreach, &iov); + + pacs_add_sink_location(pac->bdb->pacs, pac->qos.location); + pacs_add_sink_supported_context(pac->bdb->pacs, + pac->qos.supported_context); + pacs_add_sink_context(pac->bdb->pacs, pac->qos.context); + gatt_db_attribute_notify(pac->bdb->pacs->sink, iov.iov_base, + iov.iov_len, NULL); +} + +static void pacs_source_location_changed(struct bt_pacs *pacs) +{ + uint32_t location = cpu_to_le32(pacs->source_loc_value); + + gatt_db_attribute_notify(pacs->source_loc, (void *)&location, + sizeof(location), NULL); +} + +static void pacs_add_source_location(struct bt_pacs *pacs, uint32_t location) +{ + location |= pacs->source_loc_value; + + /* Check if location value needs updating */ + if (location == pacs->source_loc_value) + return; + + pacs->source_loc_value = location; + + pacs_source_location_changed(pacs); +} + +static void pacs_add_source_supported_context(struct bt_pacs *pacs, + uint16_t context) +{ + context |= pacs->supported_source_context_value; + + /* Check if context value needs updating */ + if (context == pacs->supported_source_context_value) + return; + + pacs->supported_source_context_value = context; + + pacs_supported_context_changed(pacs); +} + +static void pacs_add_source_context(struct bt_pacs *pacs, uint16_t context) +{ + context |= pacs->source_context_value; + + /* Check if context value needs updating */ + if (context == pacs->source_context_value) return; + + pacs->source_context_value = context; + + pacs_context_changed(pacs); +} + +static void bap_add_source(struct bt_bap_pac *pac) +{ + struct iovec iov; + uint8_t value[512]; + + queue_push_tail(pac->bdb->sources, pac); + + memset(value, 0, sizeof(value)); + + iov.iov_base = value; + iov.iov_len = 0; + + queue_foreach(pac->bdb->sources, pac_foreach, &iov); + + pacs_add_source_location(pac->bdb->pacs, pac->qos.location); + pacs_add_source_supported_context(pac->bdb->pacs, + pac->qos.supported_context); + pacs_add_source_context(pac->bdb->pacs, pac->qos.context); + + gatt_db_attribute_notify(pac->bdb->pacs->source, iov.iov_base, + iov.iov_len, NULL); +} + +static void bap_add_broadcast_source(struct bt_bap_pac *pac) +{ + queue_push_tail(pac->bdb->broadcast_sources, pac); +} + +static void bap_add_broadcast_sink(struct bt_bap_pac *pac) +{ + queue_push_tail(pac->bdb->broadcast_sinks, pac); + + /* Update local PACS for broadcast sink also, when registering an + * endpoint + */ + pacs_add_sink_location(pac->bdb->pacs, pac->qos.location); + pacs_add_sink_supported_context(pac->bdb->pacs, + pac->qos.supported_context); +} + +static void notify_pac_added(void *data, void *user_data) +{ + struct bt_bap_pac_changed *changed = data; + struct bt_bap_pac *pac = user_data; + + if (changed->added) + changed->added(pac, changed->data); +} + +static void notify_session_pac_added(void *data, void *user_data) +{ + struct bt_bap *bap = data; + + queue_foreach(bap->pac_cbs, notify_pac_added, user_data); +} + +struct bt_bap_pac *bt_bap_add_vendor_pac(struct gatt_db *db, + const char *name, uint8_t type, + uint8_t id, uint16_t cid, uint16_t vid, + struct bt_bap_pac_qos *qos, + struct iovec *data, + struct iovec *metadata) +{ + struct bt_bap_db *bdb; + struct bt_bap_pac *pac; + struct bt_bap_codec codec; + + if (!db) + return NULL; + + bdb = bap_get_db(db); + if (!bdb) + return NULL; + + if ((id != 0xff) && ((cid != 0U) || (vid != 0U))) + return NULL; + + codec.id = id; + codec.cid = cid; + codec.vid = vid; + + pac = bap_pac_new(bdb, name, type, &codec, qos, data, metadata); + + switch (type) { + case BT_BAP_SINK: + bap_add_sink(pac); + break; + case BT_BAP_SOURCE: + bap_add_source(pac); + break; + case BT_BAP_BCAST_SOURCE: + bap_add_broadcast_source(pac); + break; + case BT_BAP_BCAST_SINK: + bap_add_broadcast_sink(pac); + break; + default: + bap_pac_free(pac); + return NULL; + } + + queue_foreach(sessions, notify_session_pac_added, pac); + + return pac; +} + +struct bt_bap_pac *bt_bap_add_pac(struct gatt_db *db, const char *name, + uint8_t type, uint8_t id, + struct bt_bap_pac_qos *qos, + struct iovec *data, + struct iovec *metadata) +{ + return bt_bap_add_vendor_pac(db, name, type, id, 0x0000, 0x0000, qos, + data, metadata); +} + +uint8_t bt_bap_pac_get_type(struct bt_bap_pac *pac) +{ + if (!pac) + return 0x00; + + return pac->type; +} + +uint32_t bt_bap_pac_get_locations(struct bt_bap_pac *pac) +{ + struct bt_pacs *pacs; + + if (!pac) + return 0; + + if (pac->qos.location) + return pac->qos.location; + + pacs = pac->bdb->pacs; + + switch (pac->type) { + case BT_BAP_SOURCE: + return pacs->source_loc_value; + case BT_BAP_SINK: + return pacs->sink_loc_value; + default: + return 0; + } +} + +uint16_t bt_bap_pac_get_supported_context(struct bt_bap_pac *pac) +{ + struct bt_pacs *pacs; + + if (!pac) + return 0; + + pacs = pac->bdb->pacs; + + switch (pac->type) { + case BT_BAP_SOURCE: + return pacs->supported_source_context_value; + case BT_BAP_SINK: + return pacs->supported_sink_context_value; + default: + return 0; } +} - hdr = iov_pull_mem(&iov, sizeof(*hdr)); - rsp = ascs_ase_cp_rsp_new(hdr->op); +uint16_t bt_bap_pac_get_context(struct bt_bap_pac *pac) +{ + struct bt_pacs *pacs; - for (handler = handlers; handler && handler->str; handler++) { - if (handler->op != hdr->op) - continue; + if (!pac) + return 0; - if (iov.iov_len < hdr->num * handler->size) { - DBG(bap, "invalid len %u < %u " - "hdr->num * handler->size", len, - hdr->num * handler->size); - ret = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN; - goto respond; - } + pacs = pac->bdb->pacs; - break; + switch (pac->type) { + case BT_BAP_SOURCE: + return pacs->source_context_value; + case BT_BAP_SINK: + return pacs->sink_context_value; + default: + return 0; } +} - if (handler && handler->str) { - int i; +struct bt_bap_pac_qos *bt_bap_pac_get_qos(struct bt_bap_pac *pac) +{ + if (!pac || !pac->qos.phy) + return NULL; - DBG(bap, "%s", handler->str); + return &pac->qos; +} - for (i = 0; i < hdr->num; i++) - ret = handler->func(ascs, bap, &iov, rsp); - } else { - DBG(bap, "Unknown opcode 0x%02x", hdr->op); - ascs_ase_rsp_add_errno(rsp, 0x00, -ENOTSUP); +struct iovec *bt_bap_pac_get_data(struct bt_bap_pac *pac) +{ + return pac->data; +} + +struct iovec *bt_bap_pac_get_metadata(struct bt_bap_pac *pac) +{ + return pac->metadata; +} + +uint8_t bt_bap_stream_get_type(struct bt_bap_stream *stream) +{ + if (!stream) + return 0x00; + + switch (bt_bap_pac_get_type(stream->lpac)) { + case BT_BAP_SINK: + case BT_BAP_SOURCE: + return BT_BAP_STREAM_TYPE_UCAST; + case BT_BAP_BCAST_SOURCE: + case BT_BAP_BCAST_SINK: + return BT_BAP_STREAM_TYPE_BCAST; } -respond: - if (ret == BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN) - ascs_ase_rsp_add_errno(rsp, 0x00, -ENOMSG); + return 0x00; +} - gatt_db_attribute_notify(attrib, rsp->iov_base, rsp->iov_len, att); - gatt_db_attribute_write_result(attrib, id, ret); +static void notify_pac_removed(void *data, void *user_data) +{ + struct bt_bap_pac_changed *changed = data; + struct bt_bap_pac *pac = user_data; - iov_free(rsp); + if (changed->removed) + changed->removed(pac, changed->data); } -static struct bt_ascs *ascs_new(struct gatt_db *db) +static void notify_session_pac_removed(void *data, void *user_data) { - struct bt_ascs *ascs; - bt_uuid_t uuid; - int i; + struct bt_bap *bap = data; - if (!db) - return NULL; + queue_foreach(bap->pac_cbs, notify_pac_removed, user_data); +} - ascs = new0(struct bt_ascs, 1); +bool bt_bap_pac_set_ops(struct bt_bap_pac *pac, struct bt_bap_pac_ops *ops, + void *user_data) +{ + if (!pac) + return false; - /* Populate DB with ASCS attributes */ - bt_uuid16_create(&uuid, ASCS_UUID); - ascs->service = gatt_db_add_service(db, &uuid, true, - 4 + (NUM_ASES * 3)); + pac->ops = ops; + pac->user_data = user_data; - for (i = 0; i < NUM_ASES; i++) - ase_new(ascs, i); + return true; +} - bt_uuid16_create(&uuid, ASE_CP_UUID); - ascs->ase_cp = gatt_db_service_add_characteristic(ascs->service, - &uuid, - BT_ATT_PERM_WRITE, - BT_GATT_CHRC_PROP_WRITE | - BT_GATT_CHRC_PROP_NOTIFY, - NULL, ascs_ase_cp_write, - ascs); +static bool match_stream_lpac(const void *data, const void *user_data) +{ + const struct bt_bap_stream *stream = data; + const struct bt_bap_pac *pac = user_data; - ascs->ase_cp_ccc = gatt_db_service_add_ccc(ascs->service, - BT_ATT_PERM_READ | BT_ATT_PERM_WRITE); + return stream->lpac == pac; +} - gatt_db_service_set_active(ascs->service, true); +static void remove_streams(void *data, void *user_data) +{ + struct bt_bap *bap = data; + struct bt_bap_pac *pac = user_data; + struct bt_bap_stream *stream; - return ascs; + stream = queue_remove_if(bap->streams, match_stream_lpac, pac); + if (stream) + bt_bap_stream_release(stream, NULL, NULL); } -static struct bt_bap_db *bap_db_new(struct gatt_db *db) +static void bap_pac_sink_removed(void *data, void *user_data) { - struct bt_bap_db *bdb; + struct bt_bap_pac *pac = data; + struct bt_bap_pac_qos *qos = user_data; - if (!db) - return NULL; + qos->location |= pac->qos.location; + qos->supported_context |= pac->qos.supported_context; + qos->context |= pac->qos.context; +} - bdb = new0(struct bt_bap_db, 1); - bdb->db = gatt_db_ref(db); - bdb->sinks = queue_new(); - bdb->sources = queue_new(); - bdb->endpoints = queue_new(); +bool bt_bap_remove_pac(struct bt_bap_pac *pac) +{ + if (!pac) + return false; - if (!bap_db) - bap_db = queue_new(); + if (queue_remove_if(pac->bdb->sinks, NULL, pac)) { + struct bt_pacs *pacs = pac->bdb->pacs; + struct bt_bap_pac_qos qos; - bdb->pacs = pacs_new(db); - bdb->pacs->bdb = bdb; + memset(&qos, 0, sizeof(qos)); + queue_foreach(pac->bdb->sinks, bap_pac_sink_removed, &qos); - bdb->ascs = ascs_new(db); - bdb->ascs->bdb = bdb; + if (pacs->sink_loc_value != qos.location) { + pacs->sink_loc_value = qos.location; + pacs_sink_location_changed(pacs); + } - queue_push_tail(bap_db, bdb); + if (pacs->supported_sink_context_value != + qos.supported_context) { + pacs->supported_sink_context_value = + qos.supported_context; + pacs_supported_context_changed(pacs); + } - return bdb; + if (pacs->sink_context_value != qos.context) { + pacs->sink_context_value = qos.context; + pacs_context_changed(pacs); + } + + + goto found; + } + + if (queue_remove_if(pac->bdb->sources, NULL, pac)) + goto found; + + if (queue_remove_if(pac->bdb->broadcast_sources, NULL, pac)) + goto found; + + return false; + +found: + queue_foreach(sessions, remove_streams, pac); + queue_foreach(sessions, notify_session_pac_removed, pac); + bap_pac_free(pac); + return true; } -static struct bt_bap_db *bap_get_db(struct gatt_db *db) +static void bap_db_free(void *data) { - struct bt_bap_db *bdb; + struct bt_bap_db *bdb = data; - bdb = queue_find(bap_db, bap_db_match, db); - if (bdb) - return bdb; + if (!bdb) + return; - return bap_db_new(db); + queue_destroy(bdb->sinks, bap_pac_free); + queue_destroy(bdb->sources, bap_pac_free); + gatt_db_unref(bdb->db); + + free(bdb->pacs); + free(bdb->ascs); + free(bdb); } -static struct bt_pacs *bap_get_pacs(struct bt_bap *bap) +static void bap_ready_free(void *data) { - if (!bap) - return NULL; - - if (bap->rdb->pacs) - return bap->rdb->pacs; + struct bt_bap_ready *ready = data; - bap->rdb->pacs = new0(struct bt_pacs, 1); - bap->rdb->pacs->bdb = bap->rdb; + if (ready->destroy) + ready->destroy(ready->data); - return bap->rdb->pacs; + free(ready); } -static struct bt_ascs *bap_get_ascs(struct bt_bap *bap) +static void bap_state_free(void *data) { - if (!bap) - return NULL; + struct bt_bap_state *state = data; - if (bap->rdb->ascs) - return bap->rdb->ascs; + if (state->destroy) + state->destroy(state->data); - bap->rdb->ascs = new0(struct bt_ascs, 1); - bap->rdb->ascs->bdb = bap->rdb; + free(state); +} - return bap->rdb->ascs; +static void bap_ep_free(void *data) +{ + struct bt_bap_endpoint *ep = data; + + if (ep && ep->stream) + ep->stream->ep = NULL; + + free(ep); } -static struct bt_bap_pac *bap_pac_new(struct bt_bap_db *bdb, const char *name, - uint8_t type, - struct bt_bap_codec *codec, - struct bt_bap_pac_qos *qos, - struct iovec *data, - struct iovec *metadata) +static void bap_detached(void *data, void *user_data) { - struct bt_bap_pac *pac; + struct bt_bap_cb *cb = data; + struct bt_bap *bap = user_data; - pac = new0(struct bt_bap_pac, 1); - pac->bdb = bdb; - pac->name = name ? strdup(name) : NULL; - pac->type = type; - pac->codec = *codec; - pac->data = iov_dup(data, 1); - pac->metadata = iov_dup(metadata, 1); + cb->detached(bap, cb->user_data); +} - if (qos) - pac->qos = *qos; +static void bap_stream_unref(void *data) +{ + struct bt_bap_stream *stream = data; - return pac; + bt_bap_stream_unref(stream); } -static void bap_pac_free(void *data) +static void bap_free(void *data) { - struct bt_bap_pac *pac = data; + struct bt_bap *bap = data; - free(pac->name); - iov_free(pac->metadata); - iov_free(pac->data); - free(pac); + timeout_remove(bap->process_id); + + bt_bap_detach(bap); + + bap_db_free(bap->rdb); + + queue_destroy(bap->pac_cbs, pac_changed_free); + queue_destroy(bap->ready_cbs, bap_ready_free); + queue_destroy(bap->state_cbs, bap_state_free); + queue_destroy(bap->local_eps, free); + queue_destroy(bap->remote_eps, bap_ep_free); + + queue_destroy(bap->reqs, bap_req_free); + queue_destroy(bap->notify, NULL); + queue_destroy(bap->streams, bap_stream_unref); + + free(bap); } -static void bap_add_sink(struct bt_bap_pac *pac) +unsigned int bt_bap_register(bt_bap_func_t attached, bt_bap_func_t detached, + void *user_data) { - struct iovec iov; - uint8_t value[512]; + struct bt_bap_cb *cb; + static unsigned int id; - queue_push_tail(pac->bdb->sinks, pac); + if (!attached && !detached) + return 0; - memset(value, 0, sizeof(value)); + if (!bap_cbs) + bap_cbs = queue_new(); - iov.iov_base = value; - iov.iov_len = 0; + cb = new0(struct bt_bap_cb, 1); + cb->id = ++id ? id : ++id; + cb->attached = attached; + cb->detached = detached; + cb->user_data = user_data; - queue_foreach(pac->bdb->sinks, pac_foreach, &iov); + queue_push_tail(bap_cbs, cb); - gatt_db_attribute_notify(pac->bdb->pacs->sink, iov.iov_base, - iov.iov_len, NULL); + return cb->id; } -static void bap_add_source(struct bt_bap_pac *pac) +static bool match_id(const void *data, const void *match_data) { - struct iovec iov; - uint8_t value[512]; + const struct bt_bap_cb *cb = data; + unsigned int id = PTR_TO_UINT(match_data); - queue_push_tail(pac->bdb->sources, pac); + return (cb->id == id); +} - memset(value, 0, sizeof(value)); +bool bt_bap_unregister(unsigned int id) +{ + struct bt_bap_cb *cb; - iov.iov_base = value; - iov.iov_len = 0; + cb = queue_remove_if(bap_cbs, match_id, UINT_TO_PTR(id)); + if (!cb) + return false; - queue_foreach(pac->bdb->sinks, pac_foreach, &iov); + free(cb); - gatt_db_attribute_notify(pac->bdb->pacs->source, iov.iov_base, - iov.iov_len, NULL); + return true; } -static void notify_pac_added(void *data, void *user_data) +static void bap_attached(void *data, void *user_data) { - struct bt_bap_pac_changed *changed = data; - struct bt_bap_pac *pac = user_data; + struct bt_bap_cb *cb = data; + struct bt_bap *bap = user_data; - if (changed->added) - changed->added(pac, changed->data); + cb->attached(bap, cb->user_data); } -struct bt_bap_pac *bt_bap_add_vendor_pac(struct gatt_db *db, - const char *name, uint8_t type, - uint8_t id, uint16_t cid, uint16_t vid, - struct bt_bap_pac_qos *qos, - struct iovec *data, - struct iovec *metadata) +struct bt_bap *bt_bap_new(struct gatt_db *ldb, struct gatt_db *rdb) { + struct bt_bap *bap; struct bt_bap_db *bdb; - struct bt_bap_pac *pac; - struct bt_bap_codec codec; - if (!db) + if (!ldb) return NULL; - bdb = bap_get_db(db); + bdb = bap_get_db(ldb); if (!bdb) return NULL; - codec.id = id; - codec.cid = cid; - codec.vid = vid; + bap = new0(struct bt_bap, 1); + bap->ldb = bdb; + bap->reqs = queue_new(); + bap->notify = queue_new(); + bap->pac_cbs = queue_new(); + bap->ready_cbs = queue_new(); + bap->streams = queue_new(); + bap->state_cbs = queue_new(); + bap->local_eps = queue_new(); - pac = bap_pac_new(bdb, name, type, &codec, qos, data, metadata); + if (!rdb) + goto done; - switch (type) { - case BT_BAP_SINK: - bap_add_sink(pac); - break; - case BT_BAP_SOURCE: - bap_add_source(pac); - break; - default: - bap_pac_free(pac); - return NULL; - } + bdb = new0(struct bt_bap_db, 1); + bdb->db = gatt_db_ref(rdb); + bdb->sinks = queue_new(); + bdb->sources = queue_new(); - queue_foreach(pac_cbs, notify_pac_added, pac); + bap->rdb = bdb; + bap->remote_eps = queue_new(); - return pac; +done: + return bt_bap_ref(bap); } -struct bt_bap_pac *bt_bap_add_pac(struct gatt_db *db, const char *name, - uint8_t type, uint8_t id, - struct bt_bap_pac_qos *qos, - struct iovec *data, - struct iovec *metadata) +bool bt_bap_set_user_data(struct bt_bap *bap, void *user_data) { - return bt_bap_add_vendor_pac(db, name, type, id, 0x0000, 0x0000, qos, - data, metadata); -} + if (!bap) + return false; -uint8_t bt_bap_pac_get_type(struct bt_bap_pac *pac) -{ - if (!pac) - return 0x00; + bap->user_data = user_data; - return pac->type; + return true; } -static void notify_pac_removed(void *data, void *user_data) +void *bt_bap_get_user_data(struct bt_bap *bap) { - struct bt_bap_pac_changed *changed = data; - struct bt_bap_pac *pac = user_data; + if (!bap) + return NULL; - if (changed->removed) - changed->removed(pac, changed->data); + return bap->user_data; } -bool bt_bap_pac_set_ops(struct bt_bap_pac *pac, struct bt_bap_pac_ops *ops, - void *user_data) +struct bt_att *bt_bap_get_att(struct bt_bap *bap) { - if (!pac) - return false; + if (!bap) + return NULL; - pac->ops = ops; - pac->user_data = user_data; + if (bap->att) + return bap->att; - return true; + return bt_gatt_client_get_att(bap->client); } -static bool match_stream_lpac(const void *data, const void *user_data) +struct bt_bap *bt_bap_ref(struct bt_bap *bap) { - const struct bt_bap_stream *stream = data; - const struct bt_bap_pac *pac = user_data; + if (!bap) + return NULL; - return stream->lpac == pac; + __sync_fetch_and_add(&bap->ref_count, 1); + + return bap; } -static void remove_streams(void *data, void *user_data) +void bt_bap_unref(struct bt_bap *bap) { - struct bt_bap *bap = data; - struct bt_bap_pac *pac = user_data; - struct bt_bap_stream *stream; + if (!bap) + return; - stream = queue_remove_if(bap->streams, match_stream_lpac, pac); - if (stream) - bt_bap_stream_release(stream, NULL, NULL); + if (__sync_sub_and_fetch(&bap->ref_count, 1)) + return; + + bap_free(bap); } -bool bt_bap_remove_pac(struct bt_bap_pac *pac) +static void bap_notify_ready(struct bt_bap *bap) { - if (!pac) - return false; + const struct queue_entry *entry; - if (queue_remove_if(pac->bdb->sinks, NULL, pac)) - goto found; + if (!bt_bap_ref_safe(bap)) + return; - if (queue_remove_if(pac->bdb->sources, NULL, pac)) - goto found; + for (entry = queue_get_entries(bap->ready_cbs); entry; + entry = entry->next) { + struct bt_bap_ready *ready = entry->data; - return false; + ready->func(bap, ready->data); + } -found: - queue_foreach(sessions, remove_streams, pac); - queue_foreach(pac_cbs, notify_pac_removed, pac); - bap_pac_free(pac); - return true; + bt_bap_unref(bap); } -static void bap_db_free(void *data) +static void bap_parse_pacs(struct bt_bap *bap, uint8_t type, + struct queue *queue, + const uint8_t *value, + uint16_t len) { - struct bt_bap_db *bdb = data; + struct bt_pacs_read_rsp *rsp; + struct iovec iov = { + .iov_base = (void *) value, + .iov_len = len, + }; + int i; - if (!bdb) + rsp = util_iov_pull_mem(&iov, sizeof(*rsp)); + if (!rsp) { + DBG(bap, "Unable to parse PAC"); return; + } - queue_destroy(bdb->sinks, bap_pac_free); - queue_destroy(bdb->sources, bap_pac_free); - queue_destroy(bdb->endpoints, free); - gatt_db_unref(bdb->db); + DBG(bap, "PAC(s) %u", rsp->num_pac); - free(bdb->pacs); - free(bdb->ascs); - free(bdb); -} + for (i = 0; i < rsp->num_pac; i++) { + struct bt_bap_pac *pac; + struct bt_pac *p; + struct bt_ltv *cc; + struct bt_pac_metadata *meta; + struct iovec data, metadata; -static void bap_ready_free(void *data) -{ - struct bt_bap_ready *ready = data; + p = util_iov_pull_mem(&iov, sizeof(*p)); + if (!p) { + DBG(bap, "Unable to parse PAC"); + return; + } - if (ready->destroy) - ready->destroy(ready->data); + if (p->codec.id == 0xff) { + p->codec.cid = le16_to_cpu(p->codec.cid); + p->codec.vid = le16_to_cpu(p->codec.vid); + } - free(ready); -} + pac = NULL; -static void bap_state_free(void *data) -{ - struct bt_bap_state *state = data; + if (!bt_bap_debug_caps(iov.iov_base, p->cc_len, bap->debug_func, + bap->debug_data)) + return; - if (state->destroy) - state->destroy(state->data); + cc = util_iov_pull_mem(&iov, p->cc_len); + if (!cc) { + DBG(bap, "Unable to parse PAC codec capabilities"); + return; + } - free(state); -} + meta = util_iov_pull_mem(&iov, sizeof(*meta)); + if (!meta) { + DBG(bap, "Unable to parse PAC metadata"); + return; + } -static void bap_req_free(void *data) -{ - struct bt_bap_req *req = data; - size_t i; + data.iov_len = p->cc_len; + data.iov_base = cc; + + metadata.iov_len = meta->len; + metadata.iov_base = meta->data; + + util_iov_pull_mem(&iov, meta->len); + + DBG(bap, "PAC #%u: type %u codec 0x%02x cc_len %u meta_len %u", + i, type, p->codec.id, p->cc_len, meta->len); + + /* Check if there is already a PAC record for the codec */ + pac = bap_pac_find(bap->rdb, type, &p->codec); + if (pac) { + bap_pac_merge(pac, &data, &metadata); + continue; + } + + pac = bap_pac_new(bap->rdb, NULL, type, &p->codec, NULL, &data, + &metadata); + if (!pac) + continue; + + queue_push_tail(queue, pac); + } +} - queue_destroy(req->group, bap_req_free); +static void read_source_pac(bool success, uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) +{ + struct bt_bap *bap = user_data; - for (i = 0; i < req->len; i++) - free(req->iov[i].iov_base); + if (!success) { + DBG(bap, "Unable to read Source PAC: error 0x%02x", att_ecode); + return; + } - free(req->iov); - free(req); + bap_parse_pacs(bap, BT_BAP_SOURCE, bap->rdb->sources, value, length); } -static void bap_detached(void *data, void *user_data) +static void read_sink_pac(bool success, uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) { - struct bt_bap_cb *cb = data; struct bt_bap *bap = user_data; - cb->detached(bap, cb->user_data); + if (!success) { + DBG(bap, "Unable to read Sink PAC: error 0x%02x", att_ecode); + return; + } + + bap_parse_pacs(bap, BT_BAP_SINK, bap->rdb->sinks, value, length); } -static void bap_free(void *data) +static void read_source_pac_loc(bool success, uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) { - struct bt_bap *bap = data; + struct bt_bap *bap = user_data; + struct bt_pacs *pacs = bap_get_pacs(bap); - bt_bap_detach(bap); + if (!success) { + DBG(bap, "Unable to read Source PAC Location: error 0x%02x", + att_ecode); + return; + } - bap_db_free(bap->rdb); + if (length != sizeof(uint32_t)) { + DBG(bap, "Invalid Source PAC Location size: %d", length); + return; + } - queue_destroy(bap->ready_cbs, bap_ready_free); - queue_destroy(bap->state_cbs, bap_state_free); + pacs->source_loc_value = get_le32(value); - queue_destroy(bap->reqs, bap_req_free); - queue_destroy(bap->pending, NULL); - queue_destroy(bap->notify, NULL); - queue_destroy(bap->streams, bap_stream_free); + /* Resume reading sinks if supported but for some reason is empty */ + if (pacs->source && queue_isempty(bap->rdb->sources)) { + uint16_t value_handle; - free(bap); + if (gatt_db_attribute_get_char_data(pacs->source, + NULL, &value_handle, + NULL, NULL, NULL)) + bt_gatt_client_read_value(bap->client, value_handle, + read_source_pac, bap, + NULL); + } } -unsigned int bt_bap_register(bt_bap_func_t attached, bt_bap_func_t detached, - void *user_data) +static void read_sink_pac_loc(bool success, uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) { - struct bt_bap_cb *cb; - static unsigned int id; + struct bt_bap *bap = user_data; + struct bt_pacs *pacs = bap_get_pacs(bap); - if (!attached && !detached) - return 0; + if (!success) { + DBG(bap, "Unable to read Sink PAC Location: error 0x%02x", + att_ecode); + return; + } - if (!bap_cbs) - bap_cbs = queue_new(); + if (length != sizeof(uint32_t)) { + DBG(bap, "Invalid Sink PAC Location size: %d", length); + return; + } - cb = new0(struct bt_bap_cb, 1); - cb->id = ++id ? id : ++id; - cb->attached = attached; - cb->detached = detached; - cb->user_data = user_data; + pacs->sink_loc_value = get_le32(value); - queue_push_tail(bap_cbs, cb); + /* Resume reading sinks if supported but for some reason is empty */ + if (pacs->sink && queue_isempty(bap->rdb->sinks)) { + uint16_t value_handle; - return cb->id; + if (gatt_db_attribute_get_char_data(pacs->sink, + NULL, &value_handle, + NULL, NULL, NULL)) + bt_gatt_client_read_value(bap->client, value_handle, + read_sink_pac, bap, + NULL); + } } -static bool match_id(const void *data, const void *match_data) +static void read_pac_context(bool success, uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) { - const struct bt_bap_cb *cb = data; - unsigned int id = PTR_TO_UINT(match_data); + struct bt_bap *bap = user_data; + struct bt_pacs *pacs = bap_get_pacs(bap); + const struct bt_pacs_context *ctx = (void *)value; - return (cb->id == id); + if (!success) { + DBG(bap, "Unable to read PAC Context: error 0x%02x", att_ecode); + return; + } + + if (length != sizeof(*ctx)) { + DBG(bap, "Invalid PAC Context size: %d", length); + return; + } + + pacs->sink_context_value = le16_to_cpu(ctx->snk); + pacs->source_context_value = le16_to_cpu(ctx->src); } -bool bt_bap_unregister(unsigned int id) +static void read_pac_supported_context(bool success, uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) { - struct bt_bap_cb *cb; + struct bt_bap *bap = user_data; + struct bt_pacs *pacs = bap_get_pacs(bap); + const struct bt_pacs_context *ctx = (void *)value; - cb = queue_remove_if(bap_cbs, match_id, UINT_TO_PTR(id)); - if (!cb) - return false; + if (!success) { + DBG(bap, "Unable to read PAC Supproted Context: error 0x%02x", + att_ecode); + return; + } - free(cb); + if (length != sizeof(*ctx)) { + DBG(bap, "Invalid PAC Supported Context size: %d", length); + return; + } - return true; + pacs->supported_sink_context_value = le16_to_cpu(ctx->snk); + pacs->supported_source_context_value = le16_to_cpu(ctx->src); } -static void bap_attached(void *data, void *user_data) +static void foreach_pacs_char(struct gatt_db_attribute *attr, void *user_data) { - struct bt_bap_cb *cb = data; struct bt_bap *bap = user_data; + uint16_t value_handle; + bt_uuid_t uuid, uuid_sink, uuid_source, uuid_sink_loc, uuid_source_loc; + bt_uuid_t uuid_context, uuid_supported_context; + struct bt_pacs *pacs; - cb->attached(bap, cb->user_data); -} - -struct bt_bap *bt_bap_new(struct gatt_db *ldb, struct gatt_db *rdb) -{ - struct bt_bap *bap; - struct bt_bap_db *bdb; + if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, + NULL, NULL, &uuid)) + return; - if (!ldb) - return NULL; + bt_uuid16_create(&uuid_sink, PAC_SINK_CHRC_UUID); + bt_uuid16_create(&uuid_source, PAC_SOURCE_CHRC_UUID); + bt_uuid16_create(&uuid_sink_loc, PAC_SINK_LOC_CHRC_UUID); + bt_uuid16_create(&uuid_source_loc, PAC_SOURCE_LOC_CHRC_UUID); + bt_uuid16_create(&uuid_context, PAC_CONTEXT); + bt_uuid16_create(&uuid_supported_context, PAC_SUPPORTED_CONTEXT); - bdb = bap_get_db(ldb); - if (!bdb) - return NULL; + if (!bt_uuid_cmp(&uuid, &uuid_sink)) { + DBG(bap, "Sink PAC found: handle 0x%04x", value_handle); - bap = new0(struct bt_bap, 1); - bap->ldb = bdb; - bap->reqs = queue_new(); - bap->pending = queue_new(); - bap->notify = queue_new(); - bap->ready_cbs = queue_new(); - bap->streams = queue_new(); - bap->state_cbs = queue_new(); + pacs = bap_get_pacs(bap); + if (!pacs) + return; - if (!rdb) - goto done; + if (!pacs->sink) + pacs->sink = attr; - bdb = new0(struct bt_bap_db, 1); - bdb->db = gatt_db_ref(rdb); - bdb->sinks = queue_new(); - bdb->sources = queue_new(); - bdb->endpoints = queue_new(); + bt_gatt_client_read_value(bap->client, value_handle, + read_sink_pac, bap, NULL); + } - bap->rdb = bdb; + if (!bt_uuid_cmp(&uuid, &uuid_source)) { + DBG(bap, "Source PAC found: handle 0x%04x", value_handle); -done: - return bt_bap_ref(bap); -} + pacs = bap_get_pacs(bap); + if (!pacs) + return; -bool bt_bap_set_user_data(struct bt_bap *bap, void *user_data) -{ - if (!bap) - return false; + if (!pacs->source) + pacs->source = attr; - bap->user_data = user_data; + bt_gatt_client_read_value(bap->client, value_handle, + read_source_pac, bap, NULL); + } - return true; -} + if (!bt_uuid_cmp(&uuid, &uuid_sink_loc)) { + DBG(bap, "Sink PAC Location found: handle 0x%04x", + value_handle); -void *bt_bap_get_user_data(struct bt_bap *bap) -{ - if (!bap) - return NULL; + pacs = bap_get_pacs(bap); + if (!pacs || pacs->sink_loc) + return; - return bap->user_data; -} + pacs->sink_loc = attr; + bt_gatt_client_read_value(bap->client, value_handle, + read_sink_pac_loc, bap, NULL); + } -struct bt_att *bt_bap_get_att(struct bt_bap *bap) -{ - if (!bap) - return NULL; + if (!bt_uuid_cmp(&uuid, &uuid_source_loc)) { + DBG(bap, "Source PAC Location found: handle 0x%04x", + value_handle); - if (bap->att) - return bap->att; + pacs = bap_get_pacs(bap); + if (!pacs || pacs->source_loc) + return; - return bt_gatt_client_get_att(bap->client); -} + pacs->source_loc = attr; + bt_gatt_client_read_value(bap->client, value_handle, + read_source_pac_loc, bap, NULL); + } -struct bt_bap *bt_bap_ref(struct bt_bap *bap) -{ - if (!bap) - return NULL; + if (!bt_uuid_cmp(&uuid, &uuid_context)) { + DBG(bap, "PAC Context found: handle 0x%04x", value_handle); - __sync_fetch_and_add(&bap->ref_count, 1); + pacs = bap_get_pacs(bap); + if (!pacs || pacs->context) + return; - return bap; -} + pacs->context = attr; + bt_gatt_client_read_value(bap->client, value_handle, + read_pac_context, bap, NULL); + } -void bt_bap_unref(struct bt_bap *bap) -{ - if (!bap) - return; + if (!bt_uuid_cmp(&uuid, &uuid_supported_context)) { + DBG(bap, "PAC Supported Context found: handle 0x%04x", + value_handle); - if (__sync_sub_and_fetch(&bap->ref_count, 1)) - return; + pacs = bap_get_pacs(bap); + if (!pacs || pacs->supported_context) + return; - bap_free(bap); + pacs->supported_context = attr; + bt_gatt_client_read_value(bap->client, value_handle, + read_pac_supported_context, + bap, NULL); + } } -static void bap_notify_ready(struct bt_bap *bap) +static void foreach_pacs_service(struct gatt_db_attribute *attr, + void *user_data) { - const struct queue_entry *entry; + struct bt_bap *bap = user_data; + struct bt_pacs *pacs = bap_get_pacs(bap); - if (!queue_isempty(bap->pending)) - return; + pacs->service = attr; - bt_bap_ref(bap); + gatt_db_service_foreach_char(attr, foreach_pacs_char, bap); +} - for (entry = queue_get_entries(bap->ready_cbs); entry; - entry = entry->next) { - struct bt_bap_ready *ready = entry->data; +struct match_pac { + struct bt_bap_codec codec; + struct bt_bap_pac *lpac; + struct bt_bap_pac *rpac; + struct bt_bap_endpoint *ep; +}; + +static bool match_stream_pac(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, + void *user_data) +{ + struct match_pac *match = user_data; - ready->func(bap, ready->data); - } + if (!bap_codec_equal(&match->codec, &lpac->codec)) + return true; - bt_bap_unref(bap); -} + match->lpac = lpac; + match->rpac = rpac; -bool bap_print_cc(void *data, size_t len, util_debug_func_t func, - void *user_data) -{ - return bap_print_ltv("CC", data, len, func, user_data); + return false; } -static void bap_parse_pacs(struct bt_bap *bap, uint8_t type, - struct queue *queue, - const uint8_t *value, - uint16_t len) +static void ep_status_config(struct bt_bap *bap, struct bt_bap_endpoint *ep, + struct iovec *iov) { - struct bt_pacs_read_rsp *rsp; - struct iovec iov = { - .iov_base = (void *) value, - .iov_len = len, - }; + struct bt_ascs_ase_status_config *cfg; + struct bt_ltv *cc; + uint32_t pd_min, pd_max, ppd_min, ppd_max; int i; - rsp = iov_pull_mem(&iov, sizeof(*rsp)); - if (!rsp) { - DBG(bap, "Unable to parse PAC"); + cfg = util_iov_pull_mem(iov, sizeof(*cfg)); + if (!cfg) { + DBG(bap, "Unable to parse Config Status"); return; } - DBG(bap, "PAC(s) %u", rsp->num_pac); - - for (i = 0; i < rsp->num_pac; i++) { - struct bt_bap_pac *pac; - struct bt_pac *p; - struct bt_ltv *cc; - struct bt_pac_metadata *meta; - struct iovec data, metadata; + pd_min = get_le24(cfg->pd_min); + pd_max = get_le24(cfg->pd_max); + ppd_min = get_le24(cfg->ppd_min); + ppd_max = get_le24(cfg->ppd_max); - p = iov_pull_mem(&iov, sizeof(*p)); - if (!p) { - DBG(bap, "Unable to parse PAC"); - return; - } + DBG(bap, "codec 0x%02x framing 0x%02x phy 0x%02x rtn %u " + "latency %u pd %u - %u ppd %u - %u", cfg->codec.id, + cfg->framing, cfg->phy, cfg->rtn, + le16_to_cpu(cfg->latency), + pd_min, pd_max, ppd_min, ppd_max); - pac = NULL; + if (iov->iov_len < cfg->cc_len) { + DBG(bap, "Unable to parse Config Status: len %zu < %u cc_len", + iov->iov_len, cfg->cc_len); + return; + } - if (!bap_print_cc(iov.iov_base, p->cc_len, bap->debug_func, - bap->debug_data)) - return; + for (i = 0; iov->iov_len >= sizeof(*cc); i++) { + cc = util_iov_pull_mem(iov, sizeof(*cc)); + if (!cc) + break; - cc = iov_pull_mem(&iov, p->cc_len); - if (!cc) { - DBG(bap, "Unable to parse PAC codec capabilities"); - return; - } + DBG(bap, "Codec Config #%u: type 0x%02x len %u", i, + cc->type, cc->len); - meta = iov_pull_mem(&iov, sizeof(*meta)); - if (!meta) { - DBG(bap, "Unable to parse PAC metadata"); - return; - } + util_iov_pull_mem(iov, cc->len - 1); + } - data.iov_len = p->cc_len; - data.iov_base = cc; + /* Any previously applied codec configuration may be cached by the + * server. + */ + if (!ep->stream) { + struct match_pac match; - metadata.iov_len = meta->len; - metadata.iov_base = meta->data; + match.lpac = NULL; + match.rpac = NULL; + match.codec.id = cfg->codec.id; + match.codec.cid = le16_to_cpu(cfg->codec.cid); + match.codec.vid = le16_to_cpu(cfg->codec.vid); - iov_pull_mem(&iov, meta->len); + bt_bap_foreach_pac(bap, ep->dir, match_stream_pac, &match); + if (!match.lpac || !match.rpac) + return; - pac = bap_pac_new(bap->rdb, NULL, type, &p->codec, NULL, &data, - &metadata); - if (!pac) - continue; + bap_stream_new(bap, ep, match.lpac, match.rpac, NULL, true); + } - DBG(bap, "PAC #%u: type %u codec 0x%02x cc_len %u meta_len %u", - i, type, p->codec.id, p->cc_len, meta->len); + if (!ep->stream) + return; - queue_push_tail(queue, pac); + /* Set preferred settings */ + if (ep->stream->rpac) { + ep->stream->rpac->qos.framing = cfg->framing; + ep->stream->rpac->qos.phy = cfg->phy; + ep->stream->rpac->qos.rtn = cfg->rtn; + ep->stream->rpac->qos.latency = le16_to_cpu(cfg->latency); + ep->stream->rpac->qos.pd_min = pd_min; + ep->stream->rpac->qos.pd_max = pd_max; + ep->stream->rpac->qos.ppd_min = ppd_min; + ep->stream->rpac->qos.ppd_max = ppd_max; } + + if (!ep->stream->cc) + ep->stream->cc = new0(struct iovec, 1); + + util_iov_memcpy(ep->stream->cc, cfg->cc, cfg->cc_len); } -static void read_source_pac(struct bt_bap *bap, bool success, uint8_t att_ecode, - const uint8_t *value, uint16_t length, - void *user_data) +static void bap_stream_config_cfm_cb(struct bt_bap_stream *stream, int err) { - if (!success) { - DBG(bap, "Unable to read Source PAC: error 0x%02x", att_ecode); + struct bt_bap *bap = stream->bap; + + if (err) { + DBG(bap, "Config Confirmation failed: %d", err); + bt_bap_stream_release(stream, NULL, NULL); return; } - - bap_parse_pacs(bap, BT_BAP_SOURCE, bap->rdb->sources, value, length); } -static void read_sink_pac(struct bt_bap *bap, bool success, uint8_t att_ecode, - const uint8_t *value, uint16_t length, - void *user_data) +static void bap_stream_config_cfm(struct bt_bap_stream *stream) { - if (!success) { - DBG(bap, "Unable to read Sink PAC: error 0x%02x", att_ecode); + int err; + + if (!stream->lpac->ops || !stream->lpac->ops->config) return; - } - bap_parse_pacs(bap, BT_BAP_SINK, bap->rdb->sinks, value, length); + err = stream->lpac->ops->config(stream, stream->cc, &stream->qos, + bap_stream_config_cfm_cb, + stream->lpac->user_data); + if (err < 0) { + DBG(stream->bap, "Unable to send Config Confirmation: %d", + err); + bt_bap_stream_release(stream, NULL, NULL); + } } -static void read_source_pac_loc(struct bt_bap *bap, bool success, - uint8_t att_ecode, const uint8_t *value, - uint16_t length, void *user_data) +static void ep_status_qos(struct bt_bap *bap, struct bt_bap_endpoint *ep, + struct iovec *iov) { - struct bt_pacs *pacs = bap_get_pacs(bap); + struct bt_ascs_ase_status_qos *qos; + uint32_t interval; + uint32_t pd; + uint16_t sdu; + uint16_t latency; - if (!success) { - DBG(bap, "Unable to read Source PAC Location: error 0x%02x", - att_ecode); + qos = util_iov_pull_mem(iov, sizeof(*qos)); + if (!qos) { + DBG(bap, "Unable to parse QoS Status"); return; } - gatt_db_attribute_write(pacs->source_loc, 0, value, length, 0, NULL, - NULL, NULL); + interval = get_le24(qos->interval); + pd = get_le24(qos->pd); + sdu = le16_to_cpu(qos->sdu); + latency = le16_to_cpu(qos->latency); + + DBG(bap, "CIG 0x%02x CIS 0x%02x interval %u framing 0x%02x " + "phy 0x%02x rtn %u latency %u pd %u", qos->cig_id, + qos->cis_id, interval, qos->framing, qos->phy, + qos->rtn, latency, pd); + + if (!ep->stream) + return; + + ep->stream->qos.ucast.io_qos.interval = interval; + ep->stream->qos.ucast.framing = qos->framing; + ep->stream->qos.ucast.io_qos.phy = qos->phy; + ep->stream->qos.ucast.io_qos.sdu = sdu; + ep->stream->qos.ucast.io_qos.rtn = qos->rtn; + ep->stream->qos.ucast.io_qos.latency = latency; + ep->stream->qos.ucast.delay = pd; + + if (ep->old_state == BT_ASCS_ASE_STATE_CONFIG) + bap_stream_config_cfm(ep->stream); } -static void read_sink_pac_loc(struct bt_bap *bap, bool success, - uint8_t att_ecode, const uint8_t *value, - uint16_t length, void *user_data) +static void ep_status_metadata(struct bt_bap *bap, struct bt_bap_endpoint *ep, + struct iovec *iov) { - struct bt_pacs *pacs = bap_get_pacs(bap); + struct bt_ascs_ase_status_metadata *meta; - if (!success) { - DBG(bap, "Unable to read Sink PAC Location: error 0x%02x", - att_ecode); + meta = util_iov_pull_mem(iov, sizeof(*meta)); + if (!meta) { + DBG(bap, "Unable to parse Metadata Status"); return; } - gatt_db_attribute_write(pacs->sink_loc, 0, value, length, 0, NULL, - NULL, NULL); + DBG(bap, "CIS 0x%02x CIG 0x%02x metadata len %u", + meta->cis_id, meta->cig_id, meta->len); } -static void read_pac_context(struct bt_bap *bap, bool success, - uint8_t att_ecode, const uint8_t *value, - uint16_t length, void *user_data) +static void bap_ep_set_status(struct bt_bap *bap, struct bt_bap_endpoint *ep, + const uint8_t *value, uint16_t length) { - struct bt_pacs *pacs = bap_get_pacs(bap); + struct bt_ascs_ase_status *rsp; + struct iovec iov = { + .iov_base = (void *) value, + .iov_len = length, + }; - if (!success) { - DBG(bap, "Unable to read PAC Context: error 0x%02x", att_ecode); + rsp = util_iov_pull_mem(&iov, sizeof(*rsp)); + if (!rsp) return; + + ep->id = rsp->id; + ep->old_state = ep->state; + ep->state = rsp->state; + + DBG(bap, "ASE status: ep %p id 0x%02x handle 0x%04x state %s " + "len %zu", ep, ep->id, + gatt_db_attribute_get_handle(ep->attr), + bt_bap_stream_statestr(ep->state), iov.iov_len); + + switch (ep->state) { + case BT_ASCS_ASE_STATE_IDLE: + break; + case BT_ASCS_ASE_STATE_CONFIG: + ep_status_config(bap, ep, &iov); + break; + case BT_ASCS_ASE_STATE_QOS: + ep_status_qos(bap, ep, &iov); + break; + case BT_ASCS_ASE_STATE_ENABLING: + case BT_ASCS_ASE_STATE_STREAMING: + case BT_ASCS_ASE_STATE_DISABLING: + ep_status_metadata(bap, ep, &iov); + break; + case BT_ASCS_ASE_STATE_RELEASING: + break; } - gatt_db_attribute_write(pacs->context, 0, value, length, 0, NULL, - NULL, NULL); + /* Only notifify if there is a stream */ + if (!ep->stream) + return; + + bap_stream_state_changed(ep->stream); } -static void read_pac_supported_context(struct bt_bap *bap, bool success, - uint8_t att_ecode, const uint8_t *value, - uint16_t length, void *user_data) +static void read_ase_status(bool success, uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) { - struct bt_pacs *pacs = bap_get_pacs(bap); + struct bt_bap_endpoint *ep = user_data; + struct bt_bap *bap = ep->bap; if (!success) { - DBG(bap, "Unable to read PAC Supproted Context: error 0x%02x", - att_ecode); + DBG(bap, "ASE read status failed: 0x%04x", att_ecode); return; } - gatt_db_attribute_write(pacs->supported_context, 0, value, length, 0, - NULL, NULL, NULL); + bap_ep_set_status(bap, ep, value, length); +} + +static void bap_register(uint16_t att_ecode, void *user_data) +{ + struct bt_bap_notify *notify = user_data; + + if (att_ecode) + DBG(notify->bap, "ASE register failed: 0x%04x", att_ecode); } -static void bap_pending_destroy(void *data) +static void bap_endpoint_notify(struct bt_bap *bap, uint16_t value_handle, + const uint8_t *value, uint16_t length, + void *user_data) { - struct bt_bap_pending *pending = data; - struct bt_bap *bap = pending->bap; + struct bt_bap_endpoint *ep = user_data; + + bap_ep_set_status(bap, ep, value, length); +} - if (queue_remove_if(bap->pending, NULL, pending)) - free(pending); +static void bap_notify(uint16_t value_handle, const uint8_t *value, + uint16_t length, void *user_data) +{ + struct bt_bap_notify *notify = user_data; - bap_notify_ready(bap); + if (notify->func) + notify->func(notify->bap, value_handle, value, length, + notify->user_data); } -static void bap_pending_complete(bool success, uint8_t att_ecode, - const uint8_t *value, uint16_t length, - void *user_data) +static void bap_notify_destroy(void *data) { - struct bt_bap_pending *pending = user_data; + struct bt_bap_notify *notify = data; + struct bt_bap *bap = notify->bap; - if (pending->func) - pending->func(pending->bap, success, att_ecode, value, length, - pending->user_data); + if (queue_remove_if(bap->notify, NULL, notify)) + free(notify); } -static void bap_read_value(struct bt_bap *bap, uint16_t value_handle, - bap_func_t func, void *user_data) +static unsigned int bap_register_notify(struct bt_bap *bap, + uint16_t value_handle, + bap_notify_t func, + void *user_data) { - struct bt_bap_pending *pending; + struct bt_bap_notify *notify; - pending = new0(struct bt_bap_pending, 1); - pending->bap = bap; - pending->func = func; - pending->user_data = user_data; + notify = new0(struct bt_bap_notify, 1); + notify->bap = bap; + notify->func = func; + notify->user_data = user_data; - pending->id = bt_gatt_client_read_value(bap->client, value_handle, - bap_pending_complete, pending, - bap_pending_destroy); - if (!pending->id) { - DBG(bap, "Unable to send Read request"); - free(pending); - return; + notify->id = bt_gatt_client_register_notify(bap->client, + value_handle, bap_register, + bap_notify, notify, + bap_notify_destroy); + if (!notify->id) { + DBG(bap, "Unable to register for notifications"); + free(notify); + return 0; } - queue_push_tail(bap->pending, pending); + queue_push_tail(bap->notify, notify); + + return notify->id; } -static void foreach_pacs_char(struct gatt_db_attribute *attr, void *user_data) +static void bap_endpoint_attach(struct bt_bap *bap, struct bt_bap_endpoint *ep) { - struct bt_bap *bap = user_data; uint16_t value_handle; - bt_uuid_t uuid, uuid_sink, uuid_source, uuid_sink_loc, uuid_source_loc; - bt_uuid_t uuid_context, uuid_supported_context; - struct bt_pacs *pacs; - if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, - NULL, NULL, &uuid)) + if (!gatt_db_attribute_get_char_data(ep->attr, NULL, &value_handle, + NULL, NULL, NULL)) return; - bt_uuid16_create(&uuid_sink, PAC_SINK_CHRC_UUID); - bt_uuid16_create(&uuid_source, PAC_SOURCE_CHRC_UUID); - bt_uuid16_create(&uuid_sink_loc, PAC_SINK_LOC_CHRC_UUID); - bt_uuid16_create(&uuid_source_loc, PAC_SOURCE_LOC_CHRC_UUID); - bt_uuid16_create(&uuid_context, PAC_CONTEXT); - bt_uuid16_create(&uuid_supported_context, PAC_SUPPORTED_CONTEXT); - - if (!bt_uuid_cmp(&uuid, &uuid_sink)) { - DBG(bap, "Sink PAC found: handle 0x%04x", value_handle); - - pacs = bap_get_pacs(bap); - if (!pacs || pacs->sink) - return; + DBG(bap, "ASE handle 0x%04x", value_handle); - pacs->sink = attr; - bap_read_value(bap, value_handle, read_sink_pac, bap); - } + ep->bap = bap; - if (!bt_uuid_cmp(&uuid, &uuid_source)) { - DBG(bap, "Source PAC found: handle 0x%04x", value_handle); + bt_gatt_client_read_value(bap->client, value_handle, read_ase_status, + ep, NULL); - pacs = bap_get_pacs(bap); - if (!pacs || pacs->source) - return; + ep->state_id = bap_register_notify(bap, value_handle, + bap_endpoint_notify, ep); +} - pacs->source = attr; - bap_read_value(bap, value_handle, read_source_pac, NULL); - } +static void bap_cp_notify(struct bt_bap *bap, uint16_t value_handle, + const uint8_t *value, uint16_t length, + void *user_data) +{ + const struct bt_ascs_cp_rsp *rsp = (void *)value; + const struct bt_ascs_ase_rsp *ase_rsp = NULL; + struct bt_bap_req *req; + int i; - if (!bt_uuid_cmp(&uuid, &uuid_sink_loc)) { - DBG(bap, "Sink PAC Location found: handle 0x%04x", - value_handle); + if (!bap->req) + return; - pacs = bap_get_pacs(bap); - if (!pacs || pacs->sink_loc) - return; + req = bap->req; + bap->req = NULL; - pacs->sink_loc = attr; - bap_read_value(bap, value_handle, read_sink_pac_loc, NULL); + if (length < sizeof(*rsp)) { + DBG(bap, "Invalid ASE CP notification: length %u < %zu", + length, sizeof(*rsp)); + goto done; } - if (!bt_uuid_cmp(&uuid, &uuid_source_loc)) { - DBG(bap, "Source PAC Location found: handle 0x%04x", - value_handle); - - pacs = bap_get_pacs(bap); - if (!pacs || pacs->source_loc) - return; - - pacs->source_loc = attr; - bap_read_value(bap, value_handle, read_source_pac_loc, NULL); + if (rsp->op != req->op) { + DBG(bap, "Invalid ASE CP notification: op 0x%02x != 0x%02x", + rsp->op, req->op); + goto done; } - if (!bt_uuid_cmp(&uuid, &uuid_context)) { - DBG(bap, "PAC Context found: handle 0x%04x", value_handle); - - pacs = bap_get_pacs(bap); - if (!pacs || pacs->context) - return; + length -= sizeof(*rsp); - pacs->context = attr; - bap_read_value(bap, value_handle, read_pac_context, NULL); + if (rsp->num_ase == 0xff) { + ase_rsp = rsp->rsp; + goto done; } - if (!bt_uuid_cmp(&uuid, &uuid_supported_context)) { - DBG(bap, "PAC Supported Context found: handle 0x%04x", - value_handle); - - pacs = bap_get_pacs(bap); - if (!pacs || pacs->supported_context) - return; + for (i = 0; i < rsp->num_ase; i++) { + if (length < sizeof(*ase_rsp)) { + DBG(bap, "Invalid ASE CP notification: length %u < %zu", + length, sizeof(*ase_rsp)); + goto done; + } - pacs->supported_context = attr; - bap_read_value(bap, value_handle, read_pac_supported_context, - NULL); + ase_rsp = &rsp->rsp[i]; } -} - -static void foreach_pacs_service(struct gatt_db_attribute *attr, - void *user_data) -{ - struct bt_bap *bap = user_data; - struct bt_pacs *pacs = bap_get_pacs(bap); - - pacs->service = attr; - gatt_db_service_foreach_char(attr, foreach_pacs_char, bap); +done: + bap_req_complete(req, ase_rsp); + bap_process_queue(bap); } -struct match_pac { - struct bt_bap_codec codec; - struct bt_bap_pac *lpac; - struct bt_bap_pac *rpac; - struct bt_bap_endpoint *ep; -}; - -static bool match_stream_pac(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, - void *user_data) +static void bap_cp_attach(struct bt_bap *bap) { - struct match_pac *match = user_data; + uint16_t value_handle; + struct bt_ascs *ascs = bap_get_ascs(bap); - if (!bap_codec_equal(&match->codec, &lpac->codec)) - return true; + if (!gatt_db_attribute_get_char_data(ascs->ase_cp, NULL, + &value_handle, + NULL, NULL, NULL)) + return; - match->lpac = lpac; - match->rpac = rpac; + DBG(bap, "ASE CP handle 0x%04x", value_handle); - return false; + bap->cp_id = bap_register_notify(bap, value_handle, bap_cp_notify, + NULL); } -static void ep_status_config(struct bt_bap *bap, struct bt_bap_endpoint *ep, - struct iovec *iov) +static void foreach_ascs_char(struct gatt_db_attribute *attr, void *user_data) { - struct bt_ascs_ase_status_config *cfg; - struct bt_ltv *cc; - uint32_t pd_min, pd_max, ppd_min, ppd_max; - int i; + struct bt_bap *bap = user_data; + uint16_t value_handle; + bt_uuid_t uuid, uuid_sink, uuid_source, uuid_cp; + struct bt_ascs *ascs; - cfg = iov_pull_mem(iov, sizeof(*cfg)); - if (!cfg) { - DBG(bap, "Unable to parse Config Status"); + if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, + NULL, NULL, &uuid)) return; - } - pd_min = get_le24(cfg->pd_min); - pd_max = get_le24(cfg->pd_max); - ppd_min = get_le24(cfg->ppd_min); - ppd_max = get_le24(cfg->ppd_max); + bt_uuid16_create(&uuid_sink, ASE_SINK_UUID); + bt_uuid16_create(&uuid_source, ASE_SOURCE_UUID); + bt_uuid16_create(&uuid_cp, ASE_CP_UUID); - DBG(bap, "codec 0x%02x framing 0x%02x phy 0x%02x rtn %u " - "latency %u pd %u - %u ppd %u - %u", cfg->codec.id, - cfg->framing, cfg->phy, cfg->rtn, - le16_to_cpu(cfg->latency), - pd_min, pd_max, ppd_min, ppd_max); + if (!bt_uuid_cmp(&uuid, &uuid_sink) || + !bt_uuid_cmp(&uuid, &uuid_source)) { + struct bt_bap_endpoint *ep; - if (iov->iov_len < cfg->cc_len) { - DBG(bap, "Unable to parse Config Status: len %zu < %u cc_len", - iov->iov_len, cfg->cc_len); - return; - } + ep = bap_get_endpoint(bap->remote_eps, bap->rdb, attr); + if (!ep) + return; - for (i = 0; iov->iov_len >= sizeof(*cc); i++) { - cc = iov_pull_mem(iov, sizeof(*cc)); - if (!cc) - break; + if (!bt_uuid_cmp(&uuid, &uuid_sink)) + DBG(bap, "ASE Sink found: handle 0x%04x", value_handle); + else + DBG(bap, "ASE Source found: handle 0x%04x", + value_handle); - DBG(bap, "Codec Config #%u: type 0x%02x len %u", i, - cc->type, cc->len); + bap_endpoint_attach(bap, ep); - iov_pull_mem(iov, cc->len - 1); + return; } - /* Any previously applied codec configuration may be cached by the - * server. - */ - if (!ep->stream) { - struct match_pac match; + if (!bt_uuid_cmp(&uuid, &uuid_cp)) { + ascs = bap_get_ascs(bap); + if (!ascs || ascs->ase_cp) + return; - match.lpac = NULL; - match.rpac = NULL; - match.codec.id = cfg->codec.id; - match.codec.cid = le16_to_cpu(cfg->codec.cid); - match.codec.vid = le16_to_cpu(cfg->codec.vid); + ascs->ase_cp = attr; - bt_bap_foreach_pac(bap, ep->dir, match_stream_pac, &match); - if (!match.lpac || !match.rpac) - return; + DBG(bap, "ASE Control Point found: handle 0x%04x", + value_handle); - bap_stream_new(bap, ep, match.lpac, match.rpac, NULL, true); + bap_cp_attach(bap); } +} - if (!ep->stream) - return; +static void foreach_ascs_service(struct gatt_db_attribute *attr, + void *user_data) +{ + struct bt_bap *bap = user_data; + struct bt_ascs *ascs = bap_get_ascs(bap); - /* Set preferred settings */ - if (ep->stream->rpac) { - ep->stream->rpac->qos.framing = cfg->framing; - ep->stream->rpac->qos.phy = cfg->phy; - ep->stream->rpac->qos.rtn = cfg->rtn; - ep->stream->rpac->qos.latency = le16_to_cpu(cfg->latency); - ep->stream->rpac->qos.pd_min = pd_min; - ep->stream->rpac->qos.pd_max = pd_max; - ep->stream->rpac->qos.ppd_min = ppd_min; - ep->stream->rpac->qos.ppd_max = ppd_max; - } + ascs->service = attr; - if (!ep->stream->cc) - ep->stream->cc = new0(struct iovec, 1); + gatt_db_service_set_claimed(attr, true); - iov_memcpy(ep->stream->cc, cfg->cc, cfg->cc_len); + gatt_db_service_foreach_char(attr, foreach_ascs_char, bap); } -static void bap_stream_config_cfm_cb(struct bt_bap_stream *stream, int err) +static void bap_endpoint_foreach(void *data, void *user_data) { - struct bt_bap *bap = stream->bap; + struct bt_bap_endpoint *ep = data; + struct bt_bap *bap = user_data; - if (err) { - DBG(bap, "Config Confirmation failed: %d", err); - bt_bap_stream_release(stream, NULL, NULL); - return; + bap_endpoint_attach(bap, ep); +} + +static void bap_attach_att(struct bt_bap *bap, struct bt_att *att) +{ + if (bap->disconn_id) { + if (att == bt_bap_get_att(bap)) + return; + bt_att_unregister_disconnect(bap->att, bap->disconn_id); } + + bap->disconn_id = bt_att_register_disconnect(bap->att, + bap_disconnected, + bap, NULL); } -static void bap_stream_config_cfm(struct bt_bap_stream *stream) +static void bap_idle(void *data) { - int err; + struct bt_bap *bap = data; - if (!stream->lpac->ops || !stream->lpac->ops->config) - return; + bap->idle_id = 0; - err = stream->lpac->ops->config(stream, stream->cc, &stream->qos, - bap_stream_config_cfm_cb, - stream->lpac->user_data); - if (err < 0) { - DBG(stream->bap, "Unable to send Config Confirmation: %d", - err); - bt_bap_stream_release(stream, NULL, NULL); - } + bap_notify_ready(bap); } -static void ep_status_qos(struct bt_bap *bap, struct bt_bap_endpoint *ep, - struct iovec *iov) +bool bt_bap_attach(struct bt_bap *bap, struct bt_gatt_client *client) { - struct bt_ascs_ase_status_qos *qos; - uint32_t interval; - uint32_t pd; - uint16_t sdu; - uint16_t latency; + bt_uuid_t uuid; - qos = iov_pull_mem(iov, sizeof(*qos)); - if (!qos) { - DBG(bap, "Unable to parse QoS Status"); - return; + if (queue_find(sessions, NULL, bap)) { + /* If instance already been set but there is no client proceed + * to clone it otherwise considered it already attached. + */ + if (client && !bap->client) + goto clone; + return true; } - interval = get_le24(qos->interval); - pd = get_le24(qos->pd); - sdu = le16_to_cpu(qos->sdu); - latency = le16_to_cpu(qos->latency); + if (!sessions) + sessions = queue_new(); - DBG(bap, "CIG 0x%02x CIS 0x%02x interval %u framing 0x%02x " - "phy 0x%02x rtn %u latency %u pd %u", qos->cig_id, - qos->cis_id, interval, qos->framing, qos->phy, - qos->rtn, latency, pd); + queue_push_tail(sessions, bap); - if (!ep->stream) - return; + queue_foreach(bap_cbs, bap_attached, bap); - ep->stream->qos.interval = interval; - ep->stream->qos.framing = qos->framing; - ep->stream->qos.phy = qos->phy; - ep->stream->qos.sdu = sdu; - ep->stream->qos.rtn = qos->rtn; - ep->stream->qos.latency = latency; - ep->stream->qos.delay = pd; + if (!client) { + if (bap->att) + bap_attach_att(bap, bap->att); + return true; + } - if (ep->old_state == BT_ASCS_ASE_STATE_CONFIG) - bap_stream_config_cfm(ep->stream); -} + if (bap->client) + return false; -static void ep_status_metadata(struct bt_bap *bap, struct bt_bap_endpoint *ep, - struct iovec *iov) -{ - struct bt_ascs_ase_status_metadata *meta; +clone: + bap->client = bt_gatt_client_clone(client); + if (!bap->client) + return false; - meta = iov_pull_mem(iov, sizeof(*meta)); - if (!meta) { - DBG(bap, "Unable to parse Metadata Status"); - return; - } + bap_attach_att(bap, bt_gatt_client_get_att(client)); - DBG(bap, "CIS 0x%02x CIG 0x%02x metadata len %u", - meta->cis_id, meta->cig_id, meta->len); -} + bap->idle_id = bt_gatt_client_idle_register(bap->client, bap_idle, + bap, NULL); -static void bap_ep_set_status(struct bt_bap *bap, struct bt_bap_endpoint *ep, - const uint8_t *value, uint16_t length) -{ - struct bt_ascs_ase_status *rsp; - struct iovec iov = { - .iov_base = (void *) value, - .iov_len = length, - }; + if (bap->rdb->pacs) { + uint16_t value_handle; + struct bt_pacs *pacs = bap->rdb->pacs; - rsp = iov_pull_mem(&iov, sizeof(*rsp)); - if (!rsp) - return; + /* Resume reading sinks if supported */ + if (pacs->sink && queue_isempty(bap->rdb->sinks)) { + if (gatt_db_attribute_get_char_data(pacs->sink, + NULL, &value_handle, + NULL, NULL, NULL)) { + bt_gatt_client_read_value(bap->client, + value_handle, + read_sink_pac, + bap, NULL); + } + } - ep->id = rsp->id; - ep->old_state = ep->state; - ep->state = rsp->state; + /* Resume reading sink locations if supported */ + if (pacs->sink && pacs->sink_loc && !pacs->sink_loc_value) { + if (gatt_db_attribute_get_char_data(pacs->sink_loc, + NULL, &value_handle, + NULL, NULL, NULL)) { + bt_gatt_client_read_value(bap->client, + value_handle, + read_sink_pac_loc, + bap, NULL); + } + } - DBG(bap, "ASE status: ep %p id 0x%02x handle 0x%04x state %s " - "len %zu", ep, ep->id, - gatt_db_attribute_get_handle(ep->attr), - bt_bap_stream_statestr(ep->state), iov.iov_len); + /* Resume reading sources if supported */ + if (pacs->source && queue_isempty(bap->rdb->sources)) { + if (gatt_db_attribute_get_char_data(pacs->source, + NULL, &value_handle, + NULL, NULL, NULL)) { + bt_gatt_client_read_value(bap->client, + value_handle, + read_source_pac, + bap, NULL); + } + } - switch (ep->state) { - case BT_ASCS_ASE_STATE_IDLE: - break; - case BT_ASCS_ASE_STATE_CONFIG: - ep_status_config(bap, ep, &iov); - break; - case BT_ASCS_ASE_STATE_QOS: - ep_status_qos(bap, ep, &iov); - break; - case BT_ASCS_ASE_STATE_ENABLING: - case BT_ASCS_ASE_STATE_STREAMING: - case BT_ASCS_ASE_STATE_DISABLING: - ep_status_metadata(bap, ep, &iov); - break; - case BT_ASCS_ASE_STATE_RELEASING: - break; - } + /* Resume reading source locations if supported */ + if (pacs->source && pacs->source_loc && + !pacs->source_loc_value) { + if (gatt_db_attribute_get_char_data(pacs->source_loc, + NULL, &value_handle, + NULL, NULL, NULL)) { + bt_gatt_client_read_value(bap->client, + value_handle, + read_source_pac_loc, + bap, NULL); + } + } - /* Only notifify if there is a stream */ - if (!ep->stream) - return; + /* Resume reading supported contexts if supported */ + if (pacs->sink && pacs->supported_context && + !pacs->supported_sink_context_value && + !pacs->supported_source_context_value) { + if (gatt_db_attribute_get_char_data( + pacs->supported_context, + NULL, &value_handle, + NULL, NULL, NULL)) { + bt_gatt_client_read_value(bap->client, + value_handle, + read_pac_supported_context, + bap, NULL); + } + } - bap_stream_state_changed(ep->stream); -} + /* Resume reading contexts if supported */ + if (pacs->sink && pacs->context && + !pacs->sink_context_value && + !pacs->source_context_value) { + if (gatt_db_attribute_get_char_data(pacs->context, + NULL, &value_handle, + NULL, NULL, NULL)) { + bt_gatt_client_read_value(bap->client, + value_handle, + read_pac_context, + bap, NULL); + } + } -static void read_ase_status(struct bt_bap *bap, bool success, uint8_t att_ecode, - const uint8_t *value, uint16_t length, - void *user_data) -{ - struct bt_bap_endpoint *ep = user_data; + queue_foreach(bap->remote_eps, bap_endpoint_foreach, bap); - if (!success) - return; + bap_cp_attach(bap); - bap_ep_set_status(bap, ep, value, length); -} + return true; + } -static void bap_register(uint16_t att_ecode, void *user_data) -{ - struct bt_bap_notify *notify = user_data; + bt_uuid16_create(&uuid, PACS_UUID); + gatt_db_foreach_service(bap->rdb->db, &uuid, foreach_pacs_service, bap); - if (att_ecode) - DBG(notify->bap, "ASE register failed: 0x%04x", att_ecode); + bt_uuid16_create(&uuid, ASCS_UUID); + gatt_db_foreach_service(bap->rdb->db, &uuid, foreach_ascs_service, bap); + + return true; } -static void bap_endpoint_notify(struct bt_bap *bap, uint16_t value_handle, - const uint8_t *value, uint16_t length, - void *user_data) +bool bt_bap_attach_broadcast(struct bt_bap *bap) { - struct bt_bap_endpoint *ep = user_data; + struct bt_bap_endpoint *ep; - bap_ep_set_status(bap, ep, value, length); + if (queue_find(sessions, NULL, bap)) + return true; + + if (!sessions) + sessions = queue_new(); + + queue_push_tail(sessions, bap); + + ep = bap_get_endpoint_bcast(bap->remote_eps, bap->ldb, + BT_BAP_BCAST_SOURCE); + if (ep) + ep->bap = bap; + + return true; } -static void bap_notify(uint16_t value_handle, const uint8_t *value, - uint16_t length, void *user_data) +static void stream_foreach_detach(void *data, void *user_data) { - struct bt_bap_notify *notify = user_data; + struct bt_bap_stream *stream = data; - if (notify->func) - notify->func(notify->bap, value_handle, value, length, - notify->user_data); + stream_set_state(stream, BT_BAP_STREAM_STATE_IDLE); } -static void bap_notify_destroy(void *data) +static void bap_req_detach(void *data) { - struct bt_bap_notify *notify = data; - struct bt_bap *bap = notify->bap; + struct bt_bap_req *req = data; - if (queue_remove_if(bap->notify, NULL, notify)) - free(notify); + bap_req_complete(req, NULL); } -static unsigned int bap_register_notify(struct bt_bap *bap, - uint16_t value_handle, - bap_notify_t func, - void *user_data) +void bt_bap_detach(struct bt_bap *bap) { - struct bt_bap_notify *notify; + DBG(bap, "%p", bap); - notify = new0(struct bt_bap_notify, 1); - notify->bap = bap; - notify->func = func; - notify->user_data = user_data; + if (!queue_remove(sessions, bap)) + return; - notify->id = bt_gatt_client_register_notify(bap->client, - value_handle, bap_register, - bap_notify, notify, - bap_notify_destroy); - if (!notify->id) { - DBG(bap, "Unable to register for notifications"); - free(notify); - return 0; + /* Cancel ongoing request */ + if (bap->req) { + bap_req_detach(bap->req); + bap->req = NULL; } - queue_push_tail(bap->notify, notify); + bt_gatt_client_idle_unregister(bap->client, bap->idle_id); - return notify->id; + /* Cancel queued requests */ + queue_remove_all(bap->reqs, NULL, NULL, bap_req_detach); + + bt_gatt_client_unref(bap->client); + bap->client = NULL; + + bt_att_unregister_disconnect(bap->att, bap->disconn_id); + bap->att = NULL; + + queue_foreach(bap->streams, stream_foreach_detach, bap); + queue_foreach(bap_cbs, bap_detached, bap); } -static void bap_endpoint_attach(struct bt_bap *bap, struct bt_bap_endpoint *ep) +bool bt_bap_set_debug(struct bt_bap *bap, bt_bap_debug_func_t func, + void *user_data, bt_bap_destroy_func_t destroy) { - uint16_t value_handle; - - if (!gatt_db_attribute_get_char_data(ep->attr, NULL, &value_handle, - NULL, NULL, NULL)) - return; + if (!bap) + return false; - DBG(bap, "ASE handle 0x%04x", value_handle); + if (bap->debug_destroy) + bap->debug_destroy(bap->debug_data); - bap_read_value(bap, value_handle, read_ase_status, ep); + bap->debug_func = func; + bap->debug_destroy = destroy; + bap->debug_data = user_data; - ep->state_id = bap_register_notify(bap, value_handle, - bap_endpoint_notify, ep); + return true; } -static void append_group(void *data, void *user_data) +unsigned int bt_bap_ready_register(struct bt_bap *bap, + bt_bap_ready_func_t func, void *user_data, + bt_bap_destroy_func_t destroy) { - struct bt_bap_req *req = data; - struct iovec *iov = user_data; - size_t i; + struct bt_bap_ready *ready; + static unsigned int id; - for (i = 0; i < req->len; i++) - iov_add_mem(iov, req->iov[i].iov_len, req->iov[i].iov_base); -} + if (!bap) + return 0; -static bool bap_send(struct bt_bap *bap, struct bt_bap_req *req) -{ - struct bt_ascs *ascs = bap_get_ascs(bap); - int ret; - uint16_t handle; - uint8_t buf[64]; - struct bt_ascs_ase_hdr hdr; - struct iovec iov = { - .iov_base = buf, - .iov_len = 0, - }; - size_t i; + ready = new0(struct bt_bap_ready, 1); + ready->id = ++id ? id : ++id; + ready->func = func; + ready->destroy = destroy; + ready->data = user_data; - if (!gatt_db_attribute_get_char_data(ascs->ase_cp, NULL, &handle, - NULL, NULL, NULL)) - return false; + queue_push_tail(bap->ready_cbs, ready); - hdr.op = req->op; - hdr.num = 1 + queue_length(req->group); + return ready->id; +} - iov_add_mem(&iov, sizeof(hdr), &hdr); +static bool match_ready_id(const void *data, const void *match_data) +{ + const struct bt_bap_ready *ready = data; + unsigned int id = PTR_TO_UINT(match_data); - for (i = 0; i < req->len; i++) - iov_add_mem(&iov, req->iov[i].iov_len, req->iov[i].iov_base); + return (ready->id == id); +} - /* Append the request group with the same opcode */ - queue_foreach(req->group, append_group, &iov); +bool bt_bap_ready_unregister(struct bt_bap *bap, unsigned int id) +{ + struct bt_bap_ready *ready; - ret = bt_gatt_client_write_without_response(bap->client, handle, - false, iov.iov_base, - iov.iov_len); - if (!ret) + ready = queue_remove_if(bap->ready_cbs, match_ready_id, + UINT_TO_PTR(id)); + if (!ready) return false; - bap->req = req; + bap_ready_free(ready); - return false; + return true; } -static bool bap_process_queue(void *data) +unsigned int bt_bap_state_register(struct bt_bap *bap, + bt_bap_state_func_t func, + bt_bap_connecting_func_t connecting, + void *user_data, bt_bap_destroy_func_t destroy) { - struct bt_bap *bap = data; - struct bt_bap_req *req; + struct bt_bap_state *state; + static unsigned int id; - if (bap->process_id) { - timeout_remove(bap->process_id); - bap->process_id = 0; - } + if (!bap) + return 0; - while ((req = queue_pop_head(bap->reqs))) { - if (!bap_send(bap, req)) - break; - } + state = new0(struct bt_bap_state, 1); + state->id = ++id ? id : ++id; + state->func = func; + state->connecting = connecting; + state->destroy = destroy; + state->data = user_data; - return false; + queue_push_tail(bap->state_cbs, state); + + return state->id; } -static bool match_req(const void *data, const void *match_data) +static bool match_state_id(const void *data, const void *match_data) { - const struct bt_bap_req *pend = data; - const struct bt_bap_req *req = match_data; + const struct bt_bap_state *state = data; + unsigned int id = PTR_TO_UINT(match_data); - return pend->op == req->op; + return (state->id == id); } -static bool bap_queue_req(struct bt_bap *bap, struct bt_bap_req *req) +bool bt_bap_state_unregister(struct bt_bap *bap, unsigned int id) { - struct bt_bap_req *pend; - struct queue *queue; - - pend = queue_find(bap->reqs, match_req, req); - if (pend) { - if (!pend->group) - pend->group = queue_new(); - /* Group requests with the same opcode */ - queue = pend->group; - } else { - queue = bap->reqs; - } + struct bt_bap_state *state; - DBG(bap, "req %p (op 0x%2.2x) queue %p", req, req->op, queue); + if (!bap) + return false; - if (!queue_push_tail(queue, req)) { - DBG(bap, "Unable to queue request"); + state = queue_remove_if(bap->state_cbs, match_state_id, + UINT_TO_PTR(id)); + if (!state) return false; - } - /* Only attempot to process queue if there is no outstanding request - * and it has not been scheduled. - */ - if (!bap->req && !bap->process_id) - bap->process_id = timeout_add(BAP_PROCESS_TIMEOUT, - bap_process_queue, bap, NULL); + bap_state_free(state); - return true; + return false; } -static void bap_req_complete(struct bt_bap_req *req, - const struct bt_ascs_ase_rsp *rsp) +const char *bt_bap_stream_statestr(uint8_t state) { - struct queue *group; + switch (state) { + case BT_BAP_STREAM_STATE_IDLE: + return "idle"; + case BT_BAP_STREAM_STATE_CONFIG: + return "config"; + case BT_BAP_STREAM_STATE_QOS: + return "qos"; + case BT_BAP_STREAM_STATE_ENABLING: + return "enabling"; + case BT_BAP_STREAM_STATE_STREAMING: + return "streaming"; + case BT_BAP_STREAM_STATE_DISABLING: + return "disabling"; + case BT_BAP_STREAM_STATE_RELEASING: + return "releasing"; + } - if (!req->func) - goto done; + return "unknown"; +} - if (rsp) - req->func(req->stream, rsp->code, rsp->reason, req->user_data); - else - req->func(req->stream, BT_ASCS_RSP_UNSPECIFIED, 0x00, - req->user_data); +static void bap_foreach_pac(struct queue *l, struct queue *r, + bt_bap_pac_foreach_t func, void *user_data) +{ + const struct queue_entry *el; -done: - /* Detach from request so it can be freed separately */ - group = req->group; - req->group = NULL; + for (el = queue_get_entries(l); el; el = el->next) { + struct bt_bap_pac *lpac = el->data; + const struct queue_entry *er; - queue_foreach(group, (queue_foreach_func_t)bap_req_complete, - (void *)rsp); + for (er = queue_get_entries(r); er; er = er->next) { + struct bt_bap_pac *rpac = er->data; - queue_destroy(group, NULL); + /* Skip checking codec for bcast source, + * it will be checked when BASE info are received + */ + if ((rpac->type != BT_BAP_BCAST_SOURCE) && + (!bap_codec_equal(&lpac->codec, &rpac->codec))) + continue; - bap_req_free(req); + if (!func(lpac, rpac, user_data)) + return; + } + } } -static void bap_cp_notify(struct bt_bap *bap, uint16_t value_handle, - const uint8_t *value, uint16_t length, - void *user_data) +void bt_bap_foreach_pac(struct bt_bap *bap, uint8_t type, + bt_bap_pac_foreach_t func, void *user_data) { - const struct bt_ascs_cp_rsp *rsp = (void *)value; - const struct bt_ascs_ase_rsp *ase_rsp = NULL; - struct bt_bap_req *req; - int i; - - if (!bap->req) + if (!bap || !func || !bap->rdb || queue_isempty(bap_db)) return; - req = bap->req; - bap->req = NULL; - - if (length < sizeof(*rsp)) { - DBG(bap, "Invalid ASE CP notification: length %u < %zu", - length, sizeof(*rsp)); - goto done; + switch (type) { + case BT_BAP_SINK: + return bap_foreach_pac(bap->ldb->sources, bap->rdb->sinks, + func, user_data); + case BT_BAP_SOURCE: + return bap_foreach_pac(bap->ldb->sinks, bap->rdb->sources, + func, user_data); + case BT_BAP_BCAST_SOURCE: + case BT_BAP_BCAST_SINK: + return bap_foreach_pac(bap->ldb->broadcast_sinks, + bap->rdb->broadcast_sources, + func, user_data); } +} - if (rsp->op != req->op) { - DBG(bap, "Invalid ASE CP notification: op 0x%02x != 0x%02x", - rsp->op, req->op); - goto done; - } +int bt_bap_pac_get_vendor_codec(struct bt_bap_pac *pac, uint8_t *id, + uint16_t *cid, uint16_t *vid, + struct iovec **data, struct iovec **metadata) +{ + if (!pac) + return -EINVAL; - length -= sizeof(*rsp); + if (id) + *id = pac->codec.id; - if (rsp->num_ase == 0xff) { - ase_rsp = rsp->rsp; - goto done; - } + if (cid) + *cid = pac->codec.cid; - for (i = 0; i < rsp->num_ase; i++) { - if (length < sizeof(*ase_rsp)) { - DBG(bap, "Invalid ASE CP notification: length %u < %zu", - length, sizeof(*ase_rsp)); - goto done; - } + if (vid) + *vid = pac->codec.cid; + + if (data && pac->data) + *data = pac->data; + + if (metadata && pac->metadata) + *metadata = pac->metadata; - ase_rsp = &rsp->rsp[i]; - } + return 0; +} -done: - bap_req_complete(req, ase_rsp); - bap_process_queue(bap); +int bt_bap_pac_get_codec(struct bt_bap_pac *pac, uint8_t *id, + struct iovec **data, struct iovec **metadata) +{ + return bt_bap_pac_get_vendor_codec(pac, id, NULL, NULL, data, metadata); } -static void bap_cp_attach(struct bt_bap *bap) +void bt_bap_pac_set_user_data(struct bt_bap_pac *pac, void *user_data) { - uint16_t value_handle; - struct bt_ascs *ascs = bap_get_ascs(bap); + pac->user_data = user_data; +} - if (!gatt_db_attribute_get_char_data(ascs->ase_cp, NULL, - &value_handle, - NULL, NULL, NULL)) - return; +void *bt_bap_pac_get_user_data(struct bt_bap_pac *pac) +{ + return pac->user_data; +} - DBG(bap, "ASE CP handle 0x%04x", value_handle); +bool bt_bap_pac_bcast_is_local(struct bt_bap *bap, struct bt_bap_pac *pac) +{ + if (!bap->ldb) + return false; - bap->cp_id = bap_register_notify(bap, value_handle, bap_cp_notify, - NULL); + if (queue_find(bap->ldb->broadcast_sinks, NULL, pac)) + return true; + + if (queue_find(bap->ldb->broadcast_sources, NULL, pac)) + return true; + + return false; } -static void foreach_ascs_char(struct gatt_db_attribute *attr, void *user_data) +static bool find_ep_unused(const void *data, const void *user_data) { - struct bt_bap *bap = user_data; - uint16_t value_handle; - bt_uuid_t uuid, uuid_sink, uuid_source, uuid_cp; - struct bt_ascs *ascs; + const struct bt_bap_endpoint *ep = data; + const struct match_pac *match = user_data; - if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, - NULL, NULL, &uuid)) - return; + if (ep->stream) + return false; - bt_uuid16_create(&uuid_sink, ASE_SINK_UUID); - bt_uuid16_create(&uuid_source, ASE_SOURCE_UUID); - bt_uuid16_create(&uuid_cp, ASE_CP_UUID); + if (match->rpac) + return ep->dir == match->rpac->type; + else + return true; +} - if (!bt_uuid_cmp(&uuid, &uuid_sink) || - !bt_uuid_cmp(&uuid, &uuid_source)) { - struct bt_bap_endpoint *ep; +static bool find_ep_pacs(const void *data, const void *user_data) +{ + const struct bt_bap_endpoint *ep = data; + const struct match_pac *match = user_data; - ep = bap_get_endpoint(bap->rdb, attr); - if (!ep) - return; + if (!ep->stream) + return false; - if (!bt_uuid_cmp(&uuid, &uuid_sink)) - DBG(bap, "ASE Sink found: handle 0x%04x", value_handle); - else - DBG(bap, "ASE Source found: handle 0x%04x", - value_handle); + if (ep->stream->lpac != match->lpac) + return false; - bap_endpoint_attach(bap, ep); + if (ep->stream->rpac != match->rpac) + return false; - return; + switch (ep->state) { + case BT_BAP_STREAM_STATE_CONFIG: + case BT_BAP_STREAM_STATE_QOS: + return true; } - if (!bt_uuid_cmp(&uuid, &uuid_cp)) { - ascs = bap_get_ascs(bap); - if (!ascs || ascs->ase_cp) - return; - - ascs->ase_cp = attr; + return false; +} - DBG(bap, "ASE Control Point found: handle 0x%04x", - value_handle); +static bool find_ep_source(const void *data, const void *user_data) +{ + const struct bt_bap_endpoint *ep = data; - bap_cp_attach(bap); - } + if (ep->dir == BT_BAP_BCAST_SINK) + return true; + else + return false; } -static void foreach_ascs_service(struct gatt_db_attribute *attr, - void *user_data) +unsigned int bt_bap_stream_config(struct bt_bap_stream *stream, + struct bt_bap_qos *qos, + struct iovec *data, + bt_bap_stream_func_t func, + void *user_data) { - struct bt_bap *bap = user_data; - struct bt_ascs *ascs = bap_get_ascs(bap); + unsigned int id; + struct bt_bap *bap; - ascs->service = attr; + if (!bap_stream_valid(stream)) + return 0; - gatt_db_service_set_claimed(attr, true); + if (!stream->ops || !stream->ops->config) + return 0; - gatt_db_service_foreach_char(attr, foreach_ascs_char, bap); -} + if (!bt_bap_ref_safe(stream->bap)) + return 0; -static void bap_endpoint_foreach(void *data, void *user_data) -{ - struct bt_bap_endpoint *ep = data; - struct bt_bap *bap = user_data; + bap = stream->bap; - bap_endpoint_attach(bap, ep); -} + id = stream->ops->config(stream, qos, data, func, user_data); -static void bap_attach_att(struct bt_bap *bap, struct bt_att *att) -{ - if (bap->disconn_id) { - if (att == bt_bap_get_att(bap)) - return; - bt_att_unregister_disconnect(bap->att, bap->disconn_id); - } + bt_bap_unref(bap); - bap->disconn_id = bt_att_register_disconnect(bap->att, - bap_disconnected, - bap, NULL); + return id; } -bool bt_bap_attach(struct bt_bap *bap, struct bt_gatt_client *client) +static bool match_pac(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, + void *user_data) { - bt_uuid_t uuid; + struct match_pac *match = user_data; - if (queue_find(sessions, NULL, bap)) { - /* If instance already been set but there is no client proceed - * to clone it otherwise considered it already attached. - */ - if (client && !bap->client) - goto clone; + if (match->lpac && match->lpac != lpac) return true; - } - if (!sessions) - sessions = queue_new(); + if (match->rpac && match->rpac != rpac) + return true; - queue_push_tail(sessions, bap); + match->lpac = lpac; + match->rpac = rpac; - queue_foreach(bap_cbs, bap_attached, bap); + return false; +} - if (!client) { - bap_attach_att(bap, bap->att); - return true; - } +int bt_bap_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, + int *count, bt_bap_pac_select_t func, + void *user_data) +{ + const struct queue_entry *lchan, *rchan; + int selected = 0; - if (bap->client) - return false; + if (!lpac || !rpac || !func) + return -EINVAL; -clone: - bap->client = bt_gatt_client_clone(client); - if (!bap->client) - return false; + if (!lpac->ops || !lpac->ops->select) + return -EOPNOTSUPP; - bap_attach_att(bap, bt_gatt_client_get_att(client)); + for (lchan = queue_get_entries(lpac->channels); lchan; + lchan = lchan->next) { + struct bt_bap_chan *lc = lchan->data; + struct bt_bap_chan map = *lc; + int i; - if (bap->rdb->pacs) { - uint16_t value_handle; - struct bt_pacs *pacs = bap->rdb->pacs; + for (i = 0, rchan = queue_get_entries(rpac->channels); rchan; + rchan = rchan->next, i++) { + struct bt_bap_chan *rc = rchan->data; - /* Resume reading sinks if supported */ - if (pacs->sink && queue_isempty(bap->rdb->sinks)) { - if (gatt_db_attribute_get_char_data(pacs->sink, - NULL, &value_handle, - NULL, NULL, NULL)) { - bap_read_value(bap, value_handle, - read_sink_pac, bap); - } - } + /* Try matching the channel count */ + if (!(map.count & rc->count)) + break; - /* Resume reading sources if supported */ - if (pacs->source && queue_isempty(bap->rdb->sources)) { - if (gatt_db_attribute_get_char_data(pacs->source, - NULL, &value_handle, - NULL, NULL, NULL)) { - bap_read_value(bap, value_handle, - read_source_pac, bap); + /* Check if location was set otherwise attempt to + * assign one based on the number of channels it + * supports. + */ + if (!rc->location) { + rc->location = bt_bap_pac_get_locations(rpac); + /* If channel count is 1 use a single + * location + */ + if (rc->count == 0x01) + rc->location &= BIT(i); } - } - queue_foreach(bap->rdb->endpoints, bap_endpoint_foreach, bap); + /* Try matching the channel location */ + if (!(map.location & rc->location)) + continue; - bap_cp_attach(bap); + lpac->ops->select(lpac, rpac, map.location & + rc->location, &rpac->qos, + func, user_data, + lpac->user_data); + selected++; - bap_notify_ready(bap); + /* Check if there are any channels left to select */ + map.count &= ~(map.count & rc->count); + /* Check if there are any locations left to select */ + map.location &= ~(map.location & rc->location); - return true; + if (!map.count || !map.location) + break; + + /* Check if device require AC*(i) settings */ + if (rc->count == 0x01) + map.count = map.count >> 1; + } } - bt_uuid16_create(&uuid, PACS_UUID); - gatt_db_foreach_service(bap->rdb->db, &uuid, foreach_pacs_service, bap); + /* Fallback to no channel allocation since none could be matched. */ + if (!selected) { + lpac->ops->select(lpac, rpac, 0, &rpac->qos, func, user_data, + lpac->user_data); + selected++; + } - bt_uuid16_create(&uuid, ASCS_UUID); - gatt_db_foreach_service(bap->rdb->db, &uuid, foreach_ascs_service, bap); + if (count) + *count += selected; - return true; + return 0; } -static void stream_foreach_detach(void *data, void *user_data) +void bt_bap_cancel_select(struct bt_bap_pac *lpac, bt_bap_pac_select_t func, + void *user_data) { - struct bt_bap_stream *stream = data; + if (!lpac || !func) + return; - stream_set_state(stream, BT_BAP_STREAM_STATE_IDLE); + if (!lpac->ops || !lpac->ops->cancel_select) + return; + + lpac->ops->cancel_select(lpac, func, user_data, lpac->user_data); } -void bt_bap_detach(struct bt_bap *bap) +static struct bt_bap_stream *bap_bcast_stream_new(struct bt_bap *bap, + struct bt_bap_pac *lpac, + struct bt_bap_qos *pqos, + struct iovec *data) { - DBG(bap, "%p", bap); + struct bt_bap_stream *stream = NULL; + struct bt_bap_endpoint *ep = NULL; + struct match_pac match; - if (!queue_remove(sessions, bap)) - return; + if (!bap) + return NULL; - bt_gatt_client_unref(bap->client); - bap->client = NULL; + if (lpac->type == BT_BAP_BCAST_SOURCE) { + match.lpac = lpac; + match.rpac = NULL; + memset(&match.codec, 0, sizeof(match.codec)); + + bt_bap_foreach_pac(bap, BT_BAP_BCAST_SINK, match_pac, &match); + if ((!match.lpac) || (!lpac)) + return NULL; + + lpac = match.lpac; + + ep = queue_find(bap->remote_eps, find_ep_source, NULL); + if (!ep) + return NULL; + } + + if (!stream) + stream = bap_stream_new(bap, ep, lpac, NULL, data, true); + + return stream; +} + +static struct bt_bap_stream *bap_ucast_stream_new(struct bt_bap *bap, + struct bt_bap_pac *lpac, + struct bt_bap_pac *rpac, + struct bt_bap_qos *pqos, + struct iovec *data) +{ + struct bt_bap_stream *stream = NULL; + struct bt_bap_endpoint *ep = NULL; + struct match_pac match; + + if (!lpac || !rpac || !bap_codec_equal(&lpac->codec, &rpac->codec)) + return NULL; + + memset(&match, 0, sizeof(match)); + match.lpac = lpac; + match.rpac = rpac; + + /* Check for existing stream */ + ep = queue_find(bap->remote_eps, find_ep_pacs, &match); + if (!ep) { + /* Check for unused ASE */ + ep = queue_find(bap->remote_eps, find_ep_unused, &match); + if (!ep) { + DBG(bap, "Unable to find unused ASE"); + return NULL; + } + } - bt_att_unregister_disconnect(bap->att, bap->disconn_id); - bap->att = NULL; + stream = ep->stream; + if (!stream) + stream = bap_stream_new(bap, ep, lpac, rpac, data, true); - queue_foreach(bap->streams, stream_foreach_detach, bap); - queue_foreach(bap_cbs, bap_detached, bap); + return stream; } -bool bt_bap_set_debug(struct bt_bap *bap, bt_bap_debug_func_t func, - void *user_data, bt_bap_destroy_func_t destroy) +struct bt_bap_stream *bt_bap_stream_new(struct bt_bap *bap, + struct bt_bap_pac *lpac, + struct bt_bap_pac *rpac, + struct bt_bap_qos *pqos, + struct iovec *data) { if (!bap) - return false; - - if (bap->debug_destroy) - bap->debug_destroy(bap->debug_data); + return NULL; - bap->debug_func = func; - bap->debug_destroy = destroy; - bap->debug_data = user_data; + /* Check if ATT is attached then it must be a unicast stream */ + if (bt_bap_get_att(bap)) + return bap_ucast_stream_new(bap, lpac, rpac, pqos, data); - return true; + return bap_bcast_stream_new(bap, lpac, pqos, data); } -unsigned int bt_bap_ready_register(struct bt_bap *bap, - bt_bap_ready_func_t func, void *user_data, - bt_bap_destroy_func_t destroy) +struct bt_bap *bt_bap_stream_get_session(struct bt_bap_stream *stream) { - struct bt_bap_ready *ready; - static unsigned int id; - - if (!bap) - return 0; - - ready = new0(struct bt_bap_ready, 1); - ready->id = ++id ? id : ++id; - ready->func = func; - ready->destroy = destroy; - ready->data = user_data; - - queue_push_tail(bap->ready_cbs, ready); + if (!stream) + return NULL; - return ready->id; + return stream->bap; } -static bool match_ready_id(const void *data, const void *match_data) +uint8_t bt_bap_stream_get_state(struct bt_bap_stream *stream) { - const struct bt_bap_ready *ready = data; - unsigned int id = PTR_TO_UINT(match_data); + if (!stream) + return BT_BAP_STREAM_STATE_IDLE; - return (ready->id == id); + return stream->ops->get_state(stream); } -bool bt_bap_ready_unregister(struct bt_bap *bap, unsigned int id) +bool bt_bap_stream_set_user_data(struct bt_bap_stream *stream, void *user_data) { - struct bt_bap_ready *ready; - - ready = queue_remove_if(bap->ready_cbs, match_ready_id, - UINT_TO_PTR(id)); - if (!ready) + if (!stream) return false; - bap_ready_free(ready); + stream->user_data = user_data; return true; } -unsigned int bt_bap_state_register(struct bt_bap *bap, - bt_bap_state_func_t func, - bt_bap_connecting_func_t connecting, - void *user_data, bt_bap_destroy_func_t destroy) +void *bt_bap_stream_get_user_data(struct bt_bap_stream *stream) { - struct bt_bap_state *state; - static unsigned int id; - - if (!bap) - return 0; - - state = new0(struct bt_bap_state, 1); - state->id = ++id ? id : ++id; - state->func = func; - state->connecting = connecting; - state->destroy = destroy; - state->data = user_data; - - queue_push_tail(bap->state_cbs, state); + if (!stream) + return NULL; - return state->id; + return stream->user_data; } -static bool match_state_id(const void *data, const void *match_data) +unsigned int bt_bap_stream_qos(struct bt_bap_stream *stream, + struct bt_bap_qos *data, + bt_bap_stream_func_t func, + void *user_data) { - const struct bt_bap_state *state = data; - unsigned int id = PTR_TO_UINT(match_data); + unsigned int id; - return (state->id == id); -} + if (!bap_stream_valid(stream)) + return 0; -bool bt_bap_state_unregister(struct bt_bap *bap, unsigned int id) -{ - struct bt_bap_state *state; + if (!stream->ops || !stream->ops->qos) + return 0; - if (!bap) - return false; + if (!bt_bap_ref_safe(stream->bap)) + return 0; - state = queue_remove_if(bap->state_cbs, match_state_id, - UINT_TO_PTR(id)); - if (!state) - return false; + id = stream->ops->qos(stream, data, func, user_data); - bap_state_free(state); + bt_bap_unref(stream->bap); - return false; + return id; } -const char *bt_bap_stream_statestr(uint8_t state) +unsigned int bt_bap_stream_enable(struct bt_bap_stream *stream, + bool enable_links, + struct iovec *metadata, + bt_bap_stream_func_t func, + void *user_data) { - switch (state) { - case BT_BAP_STREAM_STATE_IDLE: - return "idle"; - case BT_BAP_STREAM_STATE_CONFIG: - return "config"; - case BT_BAP_STREAM_STATE_QOS: - return "qos"; - case BT_BAP_STREAM_STATE_ENABLING: - return "enabling"; - case BT_BAP_STREAM_STATE_STREAMING: - return "streaming"; - case BT_BAP_STREAM_STATE_DISABLING: - return "disabling"; - case BT_BAP_STREAM_STATE_RELEASING: - return "releasing"; - } - - return "unknown"; -} + unsigned int id; + struct bt_bap *bap; -static void bap_foreach_pac(struct queue *l, struct queue *r, - bt_bap_pac_foreach_t func, void *user_data) -{ - const struct queue_entry *el; + if (!bap_stream_valid(stream)) + return 0; - for (el = queue_get_entries(l); el; el = el->next) { - struct bt_bap_pac *lpac = el->data; - const struct queue_entry *er; + if (!stream->ops || !stream->ops->enable) + return 0; - for (er = queue_get_entries(r); er; er = er->next) { - struct bt_bap_pac *rpac = er->data; + if (!bt_bap_ref_safe(stream->bap)) + return 0; - if (!bap_codec_equal(&lpac->codec, &rpac->codec)) - continue; + bap = stream->bap; - if (!func(lpac, rpac, user_data)) - return; - } - } -} + id = stream->ops->enable(stream, enable_links, metadata, func, + user_data); -void bt_bap_foreach_pac(struct bt_bap *bap, uint8_t type, - bt_bap_pac_foreach_t func, void *user_data) -{ - if (!bap || !func || !bap->rdb || queue_isempty(bap_db)) - return; + bt_bap_unref(bap); - switch (type) { - case BT_BAP_SINK: - return bap_foreach_pac(bap->ldb->sources, bap->rdb->sinks, - func, user_data); - case BT_BAP_SOURCE: - return bap_foreach_pac(bap->ldb->sinks, bap->rdb->sources, - func, user_data); - } + return id; } -int bt_bap_pac_get_vendor_codec(struct bt_bap_pac *pac, uint8_t *id, - uint16_t *cid, uint16_t *vid, - struct iovec **data, struct iovec **metadata) +unsigned int bt_bap_stream_start(struct bt_bap_stream *stream, + bt_bap_stream_func_t func, + void *user_data) { - if (!pac) - return -EINVAL; - - if (id) - *id = pac->codec.id; + unsigned int id; + struct bt_bap *bap; - if (cid) - *cid = pac->codec.cid; + if (!bap_stream_valid(stream)) + return 0; - if (vid) - *vid = pac->codec.cid; + if (!stream->ops || !stream->ops->start) + return 0; - if (data) - *data = pac->data; + if (!bt_bap_ref_safe(stream->bap)) + return 0; - if (metadata) - *metadata = pac->metadata; + bap = stream->bap; - return 0; -} + id = stream->ops->start(stream, func, user_data); -int bt_bap_pac_get_codec(struct bt_bap_pac *pac, uint8_t *id, - struct iovec **data, struct iovec **metadata) -{ - return bt_bap_pac_get_vendor_codec(pac, id, NULL, NULL, data, metadata); -} + bt_bap_unref(bap); -void bt_bap_pac_set_user_data(struct bt_bap_pac *pac, void *user_data) -{ - pac->user_data = user_data; + return id; } -void *bt_bap_pac_get_user_data(struct bt_bap_pac *pac) +unsigned int bt_bap_stream_disable(struct bt_bap_stream *stream, + bool disable_links, + bt_bap_stream_func_t func, + void *user_data) { - return pac->user_data; -} + unsigned int id; + struct bt_bap *bap; -static bool find_ep_unused(const void *data, const void *user_data) -{ - const struct bt_bap_endpoint *ep = data; - const struct match_pac *match = user_data; + if (!bap_stream_valid(stream)) + return 0; - if (ep->stream) - return false; + if (!stream->ops || !stream->ops->disable) + return 0; - return ep->dir == match->rpac->type; -} + if (!bt_bap_ref_safe(stream->bap)) + return 0; -static bool find_ep_pacs(const void *data, const void *user_data) -{ - const struct bt_bap_endpoint *ep = data; - const struct match_pac *match = user_data; + bap = stream->bap; - if (!ep->stream) - return false; + id = stream->ops->disable(stream, disable_links, func, user_data); - if (ep->stream->lpac != match->lpac) - return false; + bt_bap_unref(bap); - return ep->stream->rpac == match->rpac; + return id; } -static struct bt_bap_req *bap_req_new(struct bt_bap_stream *stream, - uint8_t op, struct iovec *iov, - size_t len, +unsigned int bt_bap_stream_stop(struct bt_bap_stream *stream, bt_bap_stream_func_t func, void *user_data) { - struct bt_bap_req *req; - static unsigned int id; + unsigned int id; - req = new0(struct bt_bap_req, 1); - req->id = ++id; - req->stream = stream; - req->op = op; - req->iov = iov_dup(iov, len); - req->len = len; - req->func = func; - req->user_data = user_data; + if (!bap_stream_valid(stream)) + return 0; - return req; -} + if (!stream->ops || !stream->ops->stop) + return 0; -static bool bap_stream_valid(struct bt_bap_stream *stream) -{ - if (!stream || !stream->bap) - return false; + if (!bt_bap_ref_safe(stream->bap)) + return 0; + + id = stream->ops->stop(stream, func, user_data); - return queue_find(stream->bap->streams, NULL, stream); + bt_bap_unref(stream->bap); + + return id; } -unsigned int bt_bap_stream_config(struct bt_bap_stream *stream, - struct bt_bap_qos *qos, - struct iovec *data, +unsigned int bt_bap_stream_metadata(struct bt_bap_stream *stream, + struct iovec *metadata, bt_bap_stream_func_t func, void *user_data) { - struct iovec iov[2]; - struct bt_ascs_config config; - uint8_t iovlen = 1; - struct bt_bap_req *req; + unsigned int id; if (!bap_stream_valid(stream)) return 0; - if (!stream->client) { - stream_config(stream, data, NULL); + if (!stream->ops || !stream->ops->metadata) return 0; - } - memset(&config, 0, sizeof(config)); + if (!bt_bap_ref_safe(stream->bap)) + return 0; - config.ase = stream->ep->id; - config.latency = qos->target_latency; - config.phy = qos->phy; - config.codec = stream->rpac->codec; + id = stream->ops->metadata(stream, metadata, func, user_data); - iov[0].iov_base = &config; - iov[0].iov_len = sizeof(config); + bt_bap_unref(stream->bap); - if (data) { - if (!bap_print_cc(data->iov_base, data->iov_len, - stream->bap->debug_func, - stream->bap->debug_data)) - return 0; + return id; +} - config.cc_len = data->iov_len; - iov[1] = *data; - iovlen++; - } +unsigned int bt_bap_stream_release(struct bt_bap_stream *stream, + bt_bap_stream_func_t func, + void *user_data) +{ + unsigned int id; + struct bt_bap *bap = stream->bap; - req = bap_req_new(stream, BT_ASCS_CONFIG, iov, iovlen, func, user_data); + if (!stream || !stream->ops || !stream->ops->release) + return 0; - if (!bap_queue_req(stream->bap, req)) { - bap_req_free(req); + if (!bt_bap_ref_safe(bap)) return 0; - } - stream->qos = *qos; + id = stream->ops->release(stream, func, user_data); - return req->id; + bt_bap_unref(bap); + + return id; } -static bool match_pac(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, - void *user_data) +uint8_t bt_bap_stream_get_dir(struct bt_bap_stream *stream) { - struct match_pac *match = user_data; + if (!stream) + return 0x00; - if (match->lpac && match->lpac != lpac) - return true; + return stream->ops->get_dir(stream); +} - if (match->rpac && match->rpac != rpac) - return true; +uint32_t bt_bap_stream_get_location(struct bt_bap_stream *stream) +{ + if (!stream) + return 0x00000000; - match->lpac = lpac; - match->rpac = rpac; + return stream->ops->get_loc(stream); +} - return false; +struct iovec *bt_bap_stream_get_config(struct bt_bap_stream *stream) +{ + if (!stream) + return NULL; + + return stream->cc; } -int bt_bap_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, - bt_bap_pac_select_t func, void *user_data) +struct bt_bap_qos *bt_bap_stream_get_qos(struct bt_bap_stream *stream) { - if (!lpac || !rpac || !func) - return -EINVAL; + if (!stream) + return NULL; - if (!lpac->ops || !lpac->ops->select) - return -EOPNOTSUPP; + return &stream->qos; +} - lpac->ops->select(lpac, rpac, &rpac->qos, - func, user_data, lpac->user_data); +struct iovec *bt_bap_stream_get_metadata(struct bt_bap_stream *stream) +{ + if (!stream) + return NULL; - return 0; + return stream->meta; } -struct bt_bap_stream *bt_bap_config(struct bt_bap *bap, - struct bt_bap_pac *lpac, - struct bt_bap_pac *rpac, - struct bt_bap_qos *pqos, - struct iovec *data, - bt_bap_stream_func_t func, - void *user_data) +struct io *bt_bap_stream_get_io(struct bt_bap_stream *stream) { - struct bt_bap_stream *stream; - struct bt_bap_endpoint *ep; - struct match_pac match; - int id; + struct bt_bap_stream_io *io; - if (!bap || !bap->rdb || queue_isempty(bap->rdb->endpoints)) + io = stream_get_io(stream); + if (!io || io->connecting) return NULL; - if (lpac && rpac) { - if (!bap_codec_equal(&lpac->codec, &rpac->codec)) - return NULL; - } else { - uint8_t type; + return io->io; +} - match.lpac = lpac; - match.rpac = rpac; - memset(&match.codec, 0, sizeof(match.codec)); +bool bt_bap_match_bcast_sink_stream(const void *data, const void *user_data) +{ + const struct bt_bap_stream *stream = data; - if (rpac) - type = rpac->type; - else if (lpac) { - switch(lpac->type) { - case BT_BAP_SINK: - type = BT_BAP_SOURCE; - break; - case BT_BAP_SOURCE: - type = BT_BAP_SINK; - break; - default: - return NULL; - } - } else - return NULL; + return stream->lpac->type == BT_BAP_BCAST_SINK; +} - bt_bap_foreach_pac(bap, type, match_pac, &match); - if (!match.lpac || !match.rpac) - return NULL; +static bool stream_io_disconnected(struct io *io, void *user_data) +{ + struct bt_bap_stream *stream = user_data; - lpac = match.lpac; - rpac = match.rpac; - } + DBG(stream->bap, "stream %p io disconnected", stream); - match.lpac = lpac; - match.rpac = rpac; + bt_bap_stream_set_io(stream, -1); - /* Check for existing stream */ - ep = queue_find(bap->rdb->endpoints, find_ep_pacs, &match); - if (!ep) { - /* Check for unused ASE */ - ep = queue_find(bap->rdb->endpoints, find_ep_unused, &match); - if (!ep) { - DBG(bap, "Unable to find unused ASE"); - return NULL; - } - } + return false; +} - stream = ep->stream; - if (!stream) - stream = bap_stream_new(bap, ep, lpac, rpac, data, true); +bool bt_bap_stream_set_io(struct bt_bap_stream *stream, int fd) +{ + bool ret; + struct bt_bap *bap; - id = bt_bap_stream_config(stream, pqos, data, func, user_data); - if (!id) { - DBG(bap, "Unable to config stream"); - queue_remove(bap->streams, stream); - ep->stream = NULL; - free(stream); - return NULL; - } + if (!bap_stream_valid(stream)) + return false; - return stream; + if (!stream->ops || !stream->ops->set_io) + return false; + + if (!bt_bap_ref_safe(stream->bap)) + return false; + + bap = stream->bap; + + ret = stream->ops->set_io(stream, fd); + + bt_bap_unref(bap); + + return ret; } -struct bt_bap *bt_bap_stream_get_session(struct bt_bap_stream *stream) +static bool match_req_id(const void *data, const void *match_data) { - if (!stream) - return NULL; + const struct bt_bap_req *req = data; + unsigned int id = PTR_TO_UINT(match_data); - return stream->bap; + return (req->id == id); } -uint8_t bt_bap_stream_get_state(struct bt_bap_stream *stream) +static bool match_name(const void *data, const void *match_data) { - if (!stream) - return BT_BAP_STREAM_STATE_IDLE; + const struct bt_bap_pac *pac = data; + const char *name = match_data; - return stream->ep->state; + return (!strcmp(pac->name, name)); } -bool bt_bap_stream_set_user_data(struct bt_bap_stream *stream, void *user_data) +int bt_bap_stream_cancel(struct bt_bap_stream *stream, unsigned int id) { + struct bt_bap_req *req; + if (!stream) - return false; + return -EINVAL; - stream->user_data = user_data; + if (stream->bap->req && stream->bap->req->id == id) { + req = stream->bap->req; + stream->bap->req = NULL; + bap_req_free(req); + return 0; + } - return true; + req = queue_remove_if(stream->bap->reqs, match_req_id, + UINT_TO_PTR(id)); + if (!req) + return 0; + + bap_req_free(req); + + return 0; } -void *bt_bap_stream_get_user_data(struct bt_bap_stream *stream) +int bt_bap_stream_io_link(struct bt_bap_stream *stream, + struct bt_bap_stream *link) { - if (!stream) - return NULL; + int ret; + struct bt_bap *bap; - return stream->user_data; + if (!bap_stream_valid(stream)) + return -EINVAL; + + if (!stream->ops || !stream->ops->io_link) + return -EINVAL; + + if (!bt_bap_ref_safe(stream->bap)) + return -EINVAL; + + bap = stream->bap; + + ret = stream->ops->io_link(stream, link); + + bt_bap_unref(bap); + + return ret; } -unsigned int bt_bap_stream_qos(struct bt_bap_stream *stream, - struct bt_bap_qos *data, - bt_bap_stream_func_t func, - void *user_data) +int bt_bap_stream_io_unlink(struct bt_bap_stream *stream, + struct bt_bap_stream *link) { - struct iovec iov; - struct bt_ascs_qos qos; - struct bt_bap_req *req; + int ret; + struct bt_bap *bap; if (!bap_stream_valid(stream)) - return 0; + return -EINVAL; - if (!stream->client) { - stream_qos(stream, data, NULL); - return 0; - } + if (!stream->ops || !stream->ops->io_unlink) + return -EINVAL; - memset(&qos, 0, sizeof(qos)); + if (!bt_bap_ref_safe(stream->bap)) + return -EINVAL; - /* TODO: Figure out how to pass these values around */ - qos.ase = stream->ep->id; - qos.cig = data->cig_id; - qos.cis = data->cis_id; - put_le24(data->interval, qos.interval); - qos.framing = data->framing; - qos.phy = data->phy; - qos.sdu = cpu_to_le16(data->sdu); - qos.rtn = data->rtn; - qos.latency = cpu_to_le16(data->latency); - put_le24(data->delay, qos.pd); + bap = stream->bap; - iov.iov_base = &qos; - iov.iov_len = sizeof(qos); + ret = stream->ops->io_unlink(stream, link); - req = bap_req_new(stream, BT_ASCS_QOS, &iov, 1, func, user_data); + bt_bap_unref(bap); - if (!bap_queue_req(stream->bap, req)) { - bap_req_free(req); - return 0; - } + return ret; +} - stream->qos = *data; +struct queue *bt_bap_stream_io_get_links(struct bt_bap_stream *stream) +{ + if (!stream) + return NULL; + + return stream->links; +} + +static void bap_stream_get_in_qos(void *data, void *user_data) +{ + struct bt_bap_stream *stream = data; + struct bt_bap_qos **qos = user_data; + + if (!stream) + return; + + if (!qos || *qos || stream->ep->dir != BT_BAP_SOURCE || + !stream->qos.ucast.io_qos.sdu) + return; - return req->id; + *qos = &stream->qos; } -static int bap_stream_metadata(struct bt_bap_stream *stream, uint8_t op, - struct iovec *data, - bt_bap_stream_func_t func, - void *user_data) +static void bap_stream_get_out_qos(void *data, void *user_data) { - struct iovec iov[2]; - struct bt_ascs_metadata meta; - struct bt_bap_req *req; - struct metadata { - uint8_t len; - uint8_t type; - uint8_t data[2]; - } ctx = LTV(0x02, 0x01, 0x00); /* Context = Unspecified */ - - memset(&meta, 0, sizeof(meta)); - - meta.ase = stream->ep->id; + struct bt_bap_stream *stream = data; + struct bt_bap_qos **qos = user_data; - iov[0].iov_base = &meta; - iov[0].iov_len = sizeof(meta); + if (!stream) + return; - if (data) - iov[1] = *data; - else { - iov[1].iov_base = &ctx; - iov[1].iov_len = sizeof(ctx); - } + if (!qos || *qos || stream->ep->dir != BT_BAP_SINK || + !stream->qos.ucast.io_qos.sdu) + return; - meta.len = iov[1].iov_len; + *qos = &stream->qos; +} - req = bap_req_new(stream, op, iov, 2, func, user_data); +bool bt_bap_stream_io_get_qos(struct bt_bap_stream *stream, + struct bt_bap_qos **in, + struct bt_bap_qos **out) +{ + if (!stream || (!in && !out)) + return false; - if (!bap_queue_req(stream->bap, req)) { - bap_req_free(req); - return 0; + switch (stream->ep->dir) { + case BT_BAP_SOURCE: + bap_stream_get_in_qos(stream, in); + queue_foreach(stream->links, bap_stream_get_out_qos, out); + break; + case BT_BAP_SINK: + bap_stream_get_out_qos(stream, out); + queue_foreach(stream->links, bap_stream_get_in_qos, in); + break; + default: + return false; } - return req->id; + DBG(stream->bap, "in %p out %p", in ? *in : NULL, out ? *out : NULL); + + return in && out; } -static void bap_stream_enable_link(void *data, void *user_data) +static void bap_stream_get_dir(void *data, void *user_data) { struct bt_bap_stream *stream = data; - struct iovec *metadata = user_data; + uint8_t *dir = user_data; - bap_stream_metadata(stream, BT_ASCS_ENABLE, metadata, NULL, NULL); + *dir |= stream->ep->dir; } -unsigned int bt_bap_stream_enable(struct bt_bap_stream *stream, - bool enable_links, - struct iovec *metadata, - bt_bap_stream_func_t func, - void *user_data) +uint8_t bt_bap_stream_io_dir(struct bt_bap_stream *stream) { - int ret; + uint8_t dir; + struct bt_bap *bap; if (!bap_stream_valid(stream)) return 0; - if (!stream->client) { - stream_enable(stream, metadata, NULL); + if (!stream->ops || !stream->ops->set_io) return 0; - } - ret = bap_stream_metadata(stream, BT_ASCS_ENABLE, metadata, func, - user_data); - if (!ret || !enable_links) - return ret; + if (!bt_bap_ref_safe(stream->bap)) + return 00; - queue_foreach(stream->links, bap_stream_enable_link, metadata); + bap = stream->bap; - return ret; + dir = stream->ops->io_dir(stream); + + bt_bap_unref(bap); + + return dir; } -unsigned int bt_bap_stream_start(struct bt_bap_stream *stream, - bt_bap_stream_func_t func, - void *user_data) +static void bap_stream_io_connecting(void *data, void *user_data) { - struct iovec iov; - struct bt_ascs_start start; - struct bt_bap_req *req; - - if (!bap_stream_valid(stream)) - return 0; + struct bt_bap_stream *stream = data; + int fd = PTR_TO_INT(user_data); + const struct queue_entry *entry; - if (!stream->client) { - if (stream->ep->dir == BT_BAP_SINK) - stream_start(stream, NULL); - return 0; - } + if (!stream) + return; - if (stream->ep->dir == BT_BAP_SINK) - return 0; + if (fd >= 0) + bap_stream_io_attach(stream, fd, true); + else + bap_stream_io_detach(stream); - memset(&start, 0, sizeof(start)); + for (entry = queue_get_entries(stream->bap->state_cbs); entry; + entry = entry->next) { + struct bt_bap_state *state = entry->data; - start.ase = stream->ep->id; + if (state->connecting) + state->connecting(stream, stream->io ? true : false, + fd, state->data); + } +} - iov.iov_base = &start; - iov.iov_len = sizeof(start); +int bt_bap_stream_io_connecting(struct bt_bap_stream *stream, int fd) +{ + if (!stream) + return -EINVAL; - req = bap_req_new(stream, BT_ASCS_START, &iov, 1, func, user_data); + bap_stream_io_connecting(stream, INT_TO_PTR(fd)); - if (!bap_queue_req(stream->bap, req)) { - bap_req_free(req); - return 0; - } + queue_foreach(stream->links, bap_stream_io_connecting, INT_TO_PTR(fd)); - return req->id; + return 0; } -static void bap_stream_disable_link(void *data, void *user_data) +bool bt_bap_stream_io_is_connecting(struct bt_bap_stream *stream, int *fd) { - struct bt_bap_stream *stream = data; - struct bt_bap_req *req; - struct iovec iov; - struct bt_ascs_disable disable; - - memset(&disable, 0, sizeof(disable)); + struct bt_bap_stream_io *io; - disable.ase = stream->ep->id; + if (!stream) + return false; - iov.iov_base = &disable; - iov.iov_len = sizeof(disable); + io = stream_get_io(stream); + if (!io) + return false; - req = bap_req_new(stream, BT_ASCS_DISABLE, &iov, 1, NULL, NULL); + if (fd) + *fd = stream_io_get_fd(io); - if (!bap_queue_req(stream->bap, req)) - bap_req_free(req); + return io->connecting; } -unsigned int bt_bap_stream_disable(struct bt_bap_stream *stream, - bool disable_links, - bt_bap_stream_func_t func, - void *user_data) +bool bt_bap_new_bcast_source(struct bt_bap *bap, const char *name) { - struct iovec iov; - struct bt_ascs_disable disable; - struct bt_bap_req *req; + struct bt_bap_endpoint *ep; + struct bt_bap_pac *pac_broadcast_source; - if (!bap_stream_valid(stream)) - return 0; + /* Add the remote source only if a local sink endpoint was registered */ + if (queue_isempty(bap->ldb->broadcast_sinks)) + return false; - if (!stream->client) { - stream_disable(stream, NULL); - return 0; - } + /* Add remote source endpoint */ + if (!bap->rdb->broadcast_sources) + bap->rdb->broadcast_sources = queue_new(); - memset(&disable, 0, sizeof(disable)); + if (queue_find(bap->rdb->broadcast_sources, match_name, name)) + return true; - disable.ase = stream->ep->id; + pac_broadcast_source = bap_pac_new(bap->rdb, name, BT_BAP_BCAST_SOURCE, + NULL, NULL, NULL, NULL); + queue_push_tail(bap->rdb->broadcast_sources, pac_broadcast_source); - iov.iov_base = &disable; - iov.iov_len = sizeof(disable); + if (!pac_broadcast_source) + return false; - req = bap_req_new(stream, BT_ASCS_DISABLE, &iov, 1, func, user_data); + queue_foreach(bap->pac_cbs, notify_pac_added, pac_broadcast_source); - if (!bap_queue_req(stream->bap, req)) { - bap_req_free(req); - return 0; - } + /* Push remote endpoint with direction sink */ + ep = bap_endpoint_new_broadcast(bap->rdb, BT_BAP_BCAST_SINK); - if (disable_links) - queue_foreach(stream->links, bap_stream_disable_link, NULL); + if (ep) + queue_push_tail(bap->remote_eps, ep); - return req->id; + return true; } -unsigned int bt_bap_stream_stop(struct bt_bap_stream *stream, - bt_bap_stream_func_t func, - void *user_data) +void bt_bap_update_bcast_source(struct bt_bap_pac *pac, + struct bt_bap_codec *codec, + struct iovec *data, + struct iovec *metadata) { - struct iovec iov; - struct bt_ascs_stop stop; - struct bt_bap_req *req; - - if (!bap_stream_valid(stream)) - return 0; - - if (!stream->client) { - if (stream->ep->dir == BT_BAP_SINK) - stream_stop(stream, NULL); - return 0; - } - - if (stream->ep->dir == BT_BAP_SINK) - return 0; - - memset(&stop, 0, sizeof(stop)); - - stop.ase = stream->ep->id; + bap_pac_merge(pac, data, metadata); + pac->codec = *codec; +} - iov.iov_base = &stop; - iov.iov_len = sizeof(stop); +static void destroy_base_bis(void *data) +{ + struct bt_bis *bis = data; - req = bap_req_new(stream, BT_ASCS_STOP, &iov, 1, func, user_data); + if (!bis) + return; - if (!bap_queue_req(stream->bap, req)) { - bap_req_free(req); - return 0; - } + if (bis->caps) + util_iov_free(bis->caps, 1); - return req->id; + free(bis); } -unsigned int bt_bap_stream_metadata(struct bt_bap_stream *stream, - struct iovec *metadata, - bt_bap_stream_func_t func, - void *user_data) +static void generate_bis_base(void *data, void *user_data) { - if (!stream) - return 0; + struct bt_bis *bis = data; + struct iovec *base_iov = user_data; + uint8_t cc_length = bis->caps->iov_len; - if (!stream->client) { - stream_metadata(stream, metadata, NULL); - return 0; - } + if (!util_iov_push_u8(base_iov, bis->index)) + return; + + if (!util_iov_push_u8(base_iov, cc_length)) + return; - return bap_stream_metadata(stream, BT_ASCS_METADATA, metadata, func, - user_data); + if (cc_length) + util_iov_push_mem(base_iov, bis->caps->iov_len, + bis->caps->iov_base); } -unsigned int bt_bap_stream_release(struct bt_bap_stream *stream, - bt_bap_stream_func_t func, - void *user_data) +static void generate_subgroup_base(void *data, void *user_data) { - struct iovec iov; - struct bt_ascs_release rel; - struct bt_bap_req *req; + struct bt_subgroup *sgrp = data; + struct iovec *base_iov = user_data; - if (!stream) - return 0; + if (!util_iov_push_u8(base_iov, queue_length(sgrp->bises))) + return; - if (!stream->client) { - stream_release(stream, NULL); - return 0; - } + if (!util_iov_push_u8(base_iov, sgrp->codec.id)) + return; - memset(&req, 0, sizeof(req)); + if (!util_iov_push_le16(base_iov, sgrp->codec.cid)) + return; - rel.ase = stream->ep->id; + if (!util_iov_push_le16(base_iov, sgrp->codec.vid)) + return; - iov.iov_base = &rel; - iov.iov_len = sizeof(rel); + if (sgrp->caps) { + if (!util_iov_push_u8(base_iov, sgrp->caps->iov_len)) + return; - req = bap_req_new(stream, BT_ASCS_RELEASE, &iov, 1, func, user_data); + if (sgrp->caps->iov_len) + util_iov_push_mem(base_iov, sgrp->caps->iov_len, + sgrp->caps->iov_base); + } else if (!util_iov_push_u8(base_iov, 0)) + return; - if (!bap_queue_req(stream->bap, req)) { - bap_req_free(req); - return 0; - } + if (sgrp->meta) { + if (!util_iov_push_u8(base_iov, sgrp->meta->iov_len)) + return; - return req->id; + if (sgrp->meta->iov_len) + util_iov_push_mem(base_iov, sgrp->meta->iov_len, + sgrp->meta->iov_base); + } else if (!util_iov_push_u8(base_iov, 0)) + return; + + queue_foreach(sgrp->bises, generate_bis_base, base_iov); } -uint8_t bt_bap_stream_get_dir(struct bt_bap_stream *stream) +static struct iovec *generate_base(struct bt_base *base) { - if (!stream) - return 0x00; + struct iovec *base_iov = new0(struct iovec, 0x1); - return stream->ep->dir; -} + base_iov->iov_base = util_malloc(BASE_MAX_LENGTH); -uint32_t bt_bap_stream_get_location(struct bt_bap_stream *stream) -{ - struct bt_bap_pac *pac; + if (!util_iov_push_le24(base_iov, base->pres_delay)) { + free(base_iov->iov_base); + free(base_iov); + return NULL; + } - if (!stream) - return 0x00000000; + if (!util_iov_push_u8(base_iov, + queue_length(base->subgroups))) { + free(base_iov->iov_base); + free(base_iov); + return NULL; + } - pac = stream->rpac ? stream->rpac : stream->lpac; + queue_foreach(base->subgroups, generate_subgroup_base, + base_iov); - return pac->locations; + return base_iov; } -struct iovec *bt_bap_stream_get_config(struct bt_bap_stream *stream) +static void add_new_bis(struct bt_subgroup *subgroup, + uint8_t bis_index, struct iovec *caps) { - if (!stream) - return NULL; + struct bt_bis *bis = new0(struct bt_bis, 1); - return stream->cc; -} + bis->index = bis_index; -struct bt_bap_qos *bt_bap_stream_get_qos(struct bt_bap_stream *stream) -{ - if (!stream) - return NULL; + if (caps) + bis->caps = caps; + else + bis->caps = new0(struct iovec, 1); - return &stream->qos; + queue_push_tail(subgroup->bises, bis); } -struct iovec *bt_bap_stream_get_metadata(struct bt_bap_stream *stream) +static void add_new_subgroup(struct bt_base *base, + struct bt_bap_stream *stream) { - if (!stream) - return NULL; + struct bt_bap_pac *lpac = stream->lpac; + struct bt_subgroup *sgrp = new0( + struct bt_subgroup, 1); + uint16_t cid = 0; + uint16_t vid = 0; + + bt_bap_pac_get_vendor_codec(lpac, &sgrp->codec.id, &cid, + &vid, NULL, NULL); + sgrp->codec.cid = cid; + sgrp->codec.vid = vid; + sgrp->caps = util_iov_dup(stream->cc, 1); + sgrp->meta = util_iov_dup(stream->meta, 1); + sgrp->bises = queue_new(); + + stream->qos.bcast.bis = base->next_bis_index++; + add_new_bis(sgrp, stream->qos.bcast.bis, + NULL); + queue_push_tail(base->subgroups, sgrp); +} + +struct bt_ltv_match { + uint8_t l; + void *data; + bool found; + uint32_t data32; +}; - return stream->meta; -} +struct bt_ltv_search { + struct iovec *iov; + bool found; +}; -struct io *bt_bap_stream_get_io(struct bt_bap_stream *stream) +static void match_ltv(size_t i, uint8_t l, uint8_t t, uint8_t *v, + void *user_data) { - struct bt_bap_stream_io *io; + struct bt_ltv_match *ltv_match = user_data; - io = stream_get_io(stream); - if (!io || io->connecting) - return NULL; + if (ltv_match->found == true) + return; - return io->io; + if (ltv_match->l != l) + return; + + if (!memcmp(v, ltv_match->data, l)) + ltv_match->found = true; } -static bool stream_io_disconnected(struct io *io, void *user_data) +static void search_ltv(size_t i, uint8_t l, uint8_t t, uint8_t *v, + void *user_data) { - struct bt_bap_stream *stream = user_data; + struct bt_ltv_search *ltv_search = user_data; + struct bt_ltv_match ltv_match; - DBG(stream->bap, "stream %p io disconnected", stream); + ltv_match.found = false; + ltv_match.l = l; + ltv_match.data = v; - bt_bap_stream_set_io(stream, -1); + util_ltv_foreach(ltv_search->iov->iov_base, + ltv_search->iov->iov_len, &t, + match_ltv, <v_match); - return false; + /* Once "found" has been updated to "false", + * do not overwrite it anymore. + * It means that an ltv was not found in the search list, + * and this should be detected back in the parent function. + */ + if (ltv_search->found) + ltv_search->found = ltv_match.found; } -bool bt_bap_stream_set_io(struct bt_bap_stream *stream, int fd) +static bool compare_ltv(struct iovec *iov1, + struct iovec *iov2) { - if (!stream || (fd >= 0 && stream->io && !stream->io->connecting)) - return false; + struct bt_ltv_search ltv_search; - bap_stream_set_io(stream, INT_TO_PTR(fd)); + if ((!iov1) && (!iov2)) + return true; - queue_foreach(stream->links, bap_stream_set_io, INT_TO_PTR(fd)); + if ((!iov1) || (!iov2)) + return false; - return true; -} + /* Compare metadata length */ + if (iov1->iov_len != iov2->iov_len) + return false; -static bool match_req_id(const void *data, const void *match_data) -{ - const struct bt_bap_req *req = data; - unsigned int id = PTR_TO_UINT(match_data); + ltv_search.found = true; + ltv_search.iov = iov2; - return (req->id == id); + util_ltv_foreach(iov1->iov_base, + iov1->iov_len, NULL, + search_ltv, <v_search); + + return ltv_search.found; } -int bt_bap_stream_cancel(struct bt_bap_stream *stream, unsigned int id) +struct bt_ltv_extract { + struct iovec *src; + void *value; + uint8_t len; + struct iovec *result; +}; + +static void extract_ltv(size_t i, uint8_t l, uint8_t t, uint8_t *v, + void *user_data) { - struct bt_bap_req *req; + struct bt_ltv_extract *ext_data = user_data; + struct bt_ltv_match ltv_match; + uint8_t ltv_len = 0; - if (!stream) - return -EINVAL; + ltv_match.found = false; + ltv_match.l = l; + ltv_match.data = v; - if (stream->bap->req && stream->bap->req->id == id) { - req = stream->bap->req; - stream->bap->req = NULL; - bap_req_free(req); - return 0; + /* Search each BIS caps ltv in subgroup caps + * to extract the one that are BIS specific + */ + util_ltv_foreach(ext_data->src->iov_base, + ext_data->src->iov_len, &t, + match_ltv, <v_match); + + if (!ltv_match.found) { + ltv_len = l + 1; + util_iov_append(ext_data->result, <v_len, 1); + util_iov_append(ext_data->result, &t, 1); + util_iov_append(ext_data->result, v, l); } +} - req = queue_remove_if(stream->bap->reqs, match_req_id, - UINT_TO_PTR(id)); - if (!req) - return 0; +static struct iovec *extract_diff_caps( + struct iovec *subgroup_caps, struct iovec *bis_caps) +{ + struct bt_ltv_extract ext_data; - bap_req_free(req); + ext_data.src = subgroup_caps; + ext_data.result = new0(struct iovec, 1); - return 0; + util_ltv_foreach(bis_caps->iov_base, + bis_caps->iov_len, NULL, + extract_ltv, &ext_data); + + return ext_data.result; } -int bt_bap_stream_io_link(struct bt_bap_stream *stream, - struct bt_bap_stream *link) +static void set_base_subgroup(void *data, void *user_data) { - struct bt_bap *bap = stream->bap; + struct bt_bap_stream *stream = data; + struct bt_base *base = user_data; + /* BIS specific codec capabilities */ + struct iovec *bis_caps; - if (!stream || !link || stream == link) - return -EINVAL; + if (bt_bap_pac_get_type(stream->lpac) != BT_BAP_BCAST_SOURCE) + return; - if (queue_find(stream->links, NULL, link)) - return -EALREADY; + if (stream->qos.bcast.big != base->big_id) + return; - if (stream->client != link->client || - stream->qos.cig_id != link->qos.cig_id || - stream->qos.cis_id != link->qos.cis_id) - return -EINVAL; + if (base->pres_delay < stream->qos.bcast.delay) + base->pres_delay = stream->qos.bcast.delay; - if (!stream->links) - stream->links = queue_new(); + if (queue_isempty(base->subgroups)) { + add_new_subgroup(base, stream); + } else { + /* Verify if a subgroup has the same metadata */ + const struct queue_entry *entry; + struct bt_subgroup *subgroup = NULL; + bool same_meta = false; + + for (entry = queue_get_entries(base->subgroups); + entry; entry = entry->next) { + subgroup = entry->data; + same_meta = compare_ltv(subgroup->meta, stream->meta); + if (same_meta) + break; + } - if (!link->links) - link->links = queue_new(); + if (!same_meta) { + /* No subgroup with the same metadata found. + * Create a new one. + */ + add_new_subgroup(base, stream); + } else { + /* Subgroup found with the same metadata. + * Extract different codec capabilities. + */ + bis_caps = extract_diff_caps( + subgroup->caps, + stream->cc); + + stream->qos.bcast.bis = base->next_bis_index++; + add_new_bis(subgroup, + stream->qos.bcast.bis, + bis_caps); + } + } +} - queue_push_tail(stream->links, link); - queue_push_tail(link->links, stream); +static void destroy_base_subgroup(void *data) +{ + struct bt_subgroup *subgroup = data; - /* Link IOs if already set on stream/link */ - if (stream->io && !link->io) - link->io = stream_io_ref(stream->io); - else if (link->io && !stream->io) - stream->io = stream_io_ref(link->io); + if (!subgroup) + return; - DBG(bap, "stream %p link %p", stream, link); + if (subgroup->caps) + util_iov_free(subgroup->caps, 1); - return 0; -} + if (subgroup->meta) + util_iov_free(subgroup->meta, 1); -struct queue *bt_bap_stream_io_get_links(struct bt_bap_stream *stream) -{ - if (!stream) - return NULL; + queue_destroy(subgroup->bises, destroy_base_bis); - return stream->links; + free(subgroup); } -static void bap_stream_get_in_qos(void *data, void *user_data) +/* + * Function to update the BASE using configuration data + * from each BIS belonging to the same BIG + */ +struct iovec *bt_bap_stream_get_base(struct bt_bap_stream *stream) { - struct bt_bap_stream *stream = data; - struct bt_bap_qos **qos = user_data; + struct bt_base base; + struct iovec *base_iov; - if (!qos || *qos || stream->ep->dir != BT_BAP_SOURCE || - !stream->qos.sdu) - return; + base.subgroups = queue_new(); + base.next_bis_index = 1; + base.big_id = stream->qos.bcast.big; + base.pres_delay = stream->qos.bcast.delay; - *qos = &stream->qos; -} + /* If the BIG ID was explicitly set, create a BASE with information + * from all streams belonging to this BIG. Otherwise, create a BASE + * with only this BIS. + */ + if (stream->qos.bcast.big != 0xFF) + queue_foreach(stream->bap->streams, set_base_subgroup, &base); + else { + base.pres_delay = stream->qos.bcast.delay; + set_base_subgroup(stream, &base); + } -static void bap_stream_get_out_qos(void *data, void *user_data) -{ - struct bt_bap_stream *stream = data; - struct bt_bap_qos **qos = user_data; + base_iov = generate_base(&base); - if (!qos || *qos || stream->ep->dir != BT_BAP_SINK || !stream->qos.sdu) - return; + queue_destroy(base.subgroups, destroy_base_subgroup); - *qos = &stream->qos; + return base_iov; } -bool bt_bap_stream_io_get_qos(struct bt_bap_stream *stream, - struct bt_bap_qos **in, - struct bt_bap_qos **out) +/* + * This function compares PAC Codec Specific Capabilities, with the Codec + * Specific Configuration LTVs received in the BASE of the BAP Source. The + * result is accumulated in data32 which is a bitmask of types. + */ +static void check_pac_caps_ltv(size_t i, uint8_t l, uint8_t t, uint8_t *v, + void *user_data) { - if (!stream || (!in && !out)) - return false; + struct bt_ltv_match *compare_data = user_data; + uint8_t *bis_v = compare_data->data; + uint16_t mask; + uint16_t min; + uint16_t max; + uint16_t frame_len; - switch (stream->ep->dir) { - case BT_BAP_SOURCE: - bap_stream_get_in_qos(stream, in); - queue_foreach(stream->links, bap_stream_get_out_qos, out); + switch (t) { + case BAP_FREQ_LTV_TYPE: + mask = get_le16(v); + + if (mask & (1 << (bis_v[0] - 1))) + compare_data->data32 |= 1<<t; break; - case BT_BAP_SINK: - bap_stream_get_out_qos(stream, out); - queue_foreach(stream->links, bap_stream_get_in_qos, in); + case BAP_DURATION_LTV_TYPE: + if ((v[0]) & (1 << bis_v[0])) + compare_data->data32 |= 1<<t; + break; + case BAP_FRAME_LEN_LTV_TYPE: + min = get_le16(v); + max = get_le16(v + 2); + frame_len = get_le16(bis_v); + + if ((frame_len >= min) && + (frame_len <= max)) + compare_data->data32 |= 1<<t; break; - default: - return false; } +} - DBG(stream->bap, "in %p out %p", in ? *in : NULL, out ? *out : NULL); +static void check_source_ltv(size_t i, uint8_t l, uint8_t t, uint8_t *v, + void *user_data) +{ + struct bt_ltv_match *local_data = user_data; + struct iovec *pac_caps = local_data->data; + struct bt_ltv_match compare_data; - return in && out; + compare_data.data = v; + + /* Search inside local PAC's caps for LTV of type t */ + util_ltv_foreach(pac_caps->iov_base, pac_caps->iov_len, &t, + check_pac_caps_ltv, &compare_data); + + local_data->data32 |= compare_data.data32; } -static void bap_stream_get_dir(void *data, void *user_data) +static void bap_sink_check_level3_ltv(size_t i, uint8_t l, uint8_t t, + uint8_t *v, void *user_data) { - struct bt_bap_stream *stream = data; - uint8_t *dir = user_data; + struct bt_ltv_extract *merge_data = user_data; - *dir |= stream->ep->dir; + merge_data->value = v; + merge_data->len = l; } -uint8_t bt_bap_stream_io_dir(struct bt_bap_stream *stream) +static void bap_sink_check_level2_ltv(size_t i, uint8_t l, uint8_t t, + uint8_t *v, void *user_data) { - uint8_t dir; + struct bt_ltv_extract *merge_data = user_data; - if (!stream) - return 0x00; + merge_data->value = NULL; + util_ltv_foreach(merge_data->src->iov_base, + merge_data->src->iov_len, + &t, + bap_sink_check_level3_ltv, merge_data); - dir = stream->ep->dir; + /* If the LTV at level 2 was found at level 3 add the one from level 3, + * otherwise add the one at level 2 + */ + if (merge_data->value) + util_ltv_push(merge_data->result, merge_data->len, + t, merge_data->value); + else + util_ltv_push(merge_data->result, l, t, v); +} - queue_foreach(stream->links, bap_stream_get_dir, &dir); +static void check_local_pac(void *data, void *user_data) +{ + struct bt_ltv_match *compare_data = user_data; + struct iovec *bis_data = (struct iovec *)compare_data->data; + const struct bt_bap_pac *pac = data; - return dir; + /* Keep searching for a matching PAC if one wasn't found + * in previous PAC element + */ + if (compare_data->found == false) { + struct bt_ltv_match bis_compare_data = { + .data = pac->data, + .data32 = 0, /* LTVs bitmask result */ + .found = false + }; + + /* loop each BIS LTV */ + util_ltv_foreach(bis_data->iov_base, bis_data->iov_len, NULL, + check_source_ltv, &bis_compare_data); + + /* We have a match if all selected LTVs have a match */ + if ((bis_compare_data.data32 & + CODEC_SPECIFIC_CONFIGURATION_MASK) == + CODEC_SPECIFIC_CONFIGURATION_MASK) { + compare_data->found = true; + compare_data->data = data; + } + } } -static void bap_stream_io_connecting(void *data, void *user_data) +static void bap_sink_match_allocation(size_t i, uint8_t l, uint8_t t, + uint8_t *v, void *user_data) { - struct bt_bap_stream *stream = data; - int fd = PTR_TO_INT(user_data); - const struct queue_entry *entry; + struct bt_ltv_match *data = user_data; + uint32_t location32; - if (fd >= 0) - bap_stream_io_attach(stream, fd, true); + if (!v) + return; + + memcpy(&location32, v, l); + location32 = le32_to_cpu(location32); + + /* If all the bits in the received bitmask are found in + * the local bitmask then we have a match + */ + if ((location32 & data->data32) == location32) + data->found = true; else - bap_stream_io_detach(stream); + data->found = false; +} - for (entry = queue_get_entries(stream->bap->state_cbs); entry; - entry = entry->next) { - struct bt_bap_state *state = entry->data; +static struct bt_ltv_match bap_check_bis(uint32_t sink_loc, struct queue *pacs, + struct iovec *bis_data) +{ + struct bt_ltv_match compare_data = {}; - if (state->connecting) - state->connecting(stream, stream->io ? true : false, - fd, state->data); + /* Check channel allocation against the PACS location. + * If we don't have a location set we can accept any BIS location. + * If the BIS doesn't have a location set we also accept it + */ + compare_data.found = true; + + if (sink_loc) { + uint8_t type = BAP_CHANNEL_ALLOCATION_LTV_TYPE; + + compare_data.data32 = sink_loc; + util_ltv_foreach(bis_data->iov_base, bis_data->iov_len, &type, + bap_sink_match_allocation, &compare_data); + } + + /* Check remaining LTVs against the PACs list */ + if (compare_data.found) { + compare_data.data = bis_data; + compare_data.found = false; + queue_foreach(pacs, check_local_pac, &compare_data); } + + return compare_data; } -int bt_bap_stream_io_connecting(struct bt_bap_stream *stream, int fd) +struct iovec *bt_bap_merge_caps(struct iovec *l2_caps, struct iovec *l3_caps) { - if (!stream) - return -EINVAL; + struct bt_ltv_extract merge_data = {0}; - bap_stream_io_connecting(stream, INT_TO_PTR(fd)); + if (!l2_caps) + /* Codec_Specific_Configuration parameters shall + * be present at Level 2. + */ + return NULL; - queue_foreach(stream->links, bap_stream_io_connecting, INT_TO_PTR(fd)); + if (!l3_caps) + /* Codec_Specific_Configuration parameters may + * be present at Level 3. + */ + return util_iov_dup(l2_caps, 1); - return 0; + merge_data.src = l3_caps; + merge_data.result = new0(struct iovec, 1); + + /* Create a Codec Specific Configuration with LTVs at level 2 (subgroup) + * overwritten by LTVs at level 3 (BIS) + */ + util_ltv_foreach(l2_caps->iov_base, + l2_caps->iov_len, + NULL, + bap_sink_check_level2_ltv, &merge_data); + + return merge_data.result; } -bool bt_bap_stream_io_is_connecting(struct bt_bap_stream *stream, int *fd) +void bt_bap_verify_bis(struct bt_bap *bap, uint8_t bis_index, + struct iovec *caps, + struct bt_bap_pac **lpac) { - struct bt_bap_stream_io *io; + struct bt_ltv_match match_data; + uint32_t sink_loc; + struct queue *pacs; - if (!stream) - return false; + if (!caps) + return; - io = stream_get_io(stream); - if (!io) - return false; + /* If the bap session corresponds to a client connection with + * a BAP Server, bis caps should be checked against peer caps. + * If the bap session corresponds to a scanned broadcast source, + * bis caps should be checked against local broadcast sink caps. + */ + if (bap->client) { + sink_loc = bap->rdb->pacs->sink_loc_value; + pacs = bap->rdb->sinks; + } else { + sink_loc = bap->ldb->pacs->sink_loc_value; + pacs = bap->ldb->broadcast_sinks; + } - if (fd) - *fd = stream_io_get_fd(io); + /* Check each BIS Codec Specific Configuration LTVs against our Codec + * Specific Capabilities and if the BIS matches create a PAC with it + */ + match_data = bap_check_bis(sink_loc, pacs, caps); + if (match_data.found == true) { + *lpac = match_data.data; + DBG(bap, "Matching BIS %i", bis_index); + } else { + *lpac = NULL; + } - return io->connecting; } diff --git a/src/shared/bap.h b/src/shared/bap.h index 7b9f88c8320c1ed6a5431cdbb9c330bb28a511c6..126348e819e42af8f63505797d50acebcea920ed 100644 --- a/src/shared/bap.h +++ b/src/shared/bap.h @@ -4,64 +4,18 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2022 Intel Corporation. All rights reserved. + * Copyright 2023-2024 NXP * */ #include <stdbool.h> #include <inttypes.h> - -#ifndef __packed -#define __packed __attribute__((packed)) -#endif - -#define BT_BAP_SINK 0x01 -#define BT_BAP_SOURCE 0x02 - -#define BT_BAP_STREAM_STATE_IDLE 0x00 -#define BT_BAP_STREAM_STATE_CONFIG 0x01 -#define BT_BAP_STREAM_STATE_QOS 0x02 -#define BT_BAP_STREAM_STATE_ENABLING 0x03 -#define BT_BAP_STREAM_STATE_STREAMING 0x04 -#define BT_BAP_STREAM_STATE_DISABLING 0x05 -#define BT_BAP_STREAM_STATE_RELEASING 0x06 - -#define BT_BAP_CONFIG_LATENCY_LOW 0x01 -#define BT_BAP_CONFIG_LATENCY_BALACED 0x02 -#define BT_BAP_CONFIG_LATENCY_HIGH 0x03 - -#define BT_BAP_CONFIG_PHY_1M 0x01 -#define BT_BAP_CONFIG_PHY_2M 0x02 -#define BT_BAP_CONFIG_PHY_CODEC 0x03 +#include "src/shared/bap-defs.h" struct bt_bap; struct bt_bap_pac; struct bt_bap_stream; -struct bt_bap_codec { - uint8_t id; - uint16_t vid; - uint16_t cid; -} __packed; - -struct bt_ltv { - uint8_t len; - uint8_t type; - uint8_t value[0]; -} __packed; - -struct bt_bap_qos { - uint8_t cig_id; - uint8_t cis_id; - uint32_t interval; /* Frame interval */ - uint8_t framing; /* Frame framing */ - uint8_t phy; /* PHY */ - uint16_t sdu; /* Maximum SDU Size */ - uint8_t rtn; /* Retransmission Effort */ - uint16_t latency; /* Transport Latency */ - uint32_t delay; /* Presentation Delay */ - uint8_t target_latency; /* Target Latency */ -}; - typedef void (*bt_bap_ready_func_t)(struct bt_bap *bap, void *user_data); typedef void (*bt_bap_destroy_func_t)(void *user_data); typedef void (*bt_bap_debug_func_t)(const char *str, void *user_data); @@ -87,12 +41,6 @@ typedef void (*bt_bap_stream_func_t)(struct bt_bap_stream *stream, typedef void (*bt_bap_func_t)(struct bt_bap *bap, void *user_data); /* Local PAC related functions */ - -unsigned int bt_bap_pac_register(bt_bap_pac_func_t added, - bt_bap_pac_func_t removed, void *user_data, - bt_bap_destroy_func_t destroy); -bool bt_bap_pac_unregister(unsigned int id); - struct bt_bap_pac_qos { uint8_t framing; uint8_t phy; @@ -102,6 +50,9 @@ struct bt_bap_pac_qos { uint32_t pd_max; uint32_t ppd_min; uint32_t ppd_max; + uint32_t location; + uint16_t supported_context; + uint16_t context; }; struct bt_bap_pac *bt_bap_add_vendor_pac(struct gatt_db *db, @@ -119,7 +70,9 @@ struct bt_bap_pac *bt_bap_add_pac(struct gatt_db *db, const char *name, struct bt_bap_pac_ops { int (*select)(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, - struct bt_bap_pac_qos *qos, + uint32_t chan_alloc, struct bt_bap_pac_qos *qos, + bt_bap_pac_select_t cb, void *cb_data, void *user_data); + void (*cancel_select)(struct bt_bap_pac *lpac, bt_bap_pac_select_t cb, void *cb_data, void *user_data); int (*config)(struct bt_bap_stream *stream, struct iovec *cfg, struct bt_bap_qos *qos, bt_bap_pac_config_t cb, @@ -134,6 +87,20 @@ bool bt_bap_remove_pac(struct bt_bap_pac *pac); uint8_t bt_bap_pac_get_type(struct bt_bap_pac *pac); +uint32_t bt_bap_pac_get_locations(struct bt_bap_pac *pac); + +uint16_t bt_bap_pac_get_supported_context(struct bt_bap_pac *pac); + +uint16_t bt_bap_pac_get_context(struct bt_bap_pac *pac); + +struct bt_bap_pac_qos *bt_bap_pac_get_qos(struct bt_bap_pac *pac); + +struct iovec *bt_bap_pac_get_data(struct bt_bap_pac *pac); + +struct iovec *bt_bap_pac_get_metadata(struct bt_bap_pac *pac); + +uint8_t bt_bap_stream_get_type(struct bt_bap_stream *stream); + struct bt_bap_stream *bt_bap_pac_get_stream(struct bt_bap_pac *pac); /* Session related function */ @@ -153,13 +120,16 @@ struct bt_bap *bt_bap_ref(struct bt_bap *bap); void bt_bap_unref(struct bt_bap *bap); bool bt_bap_attach(struct bt_bap *bap, struct bt_gatt_client *client); +bool bt_bap_attach_broadcast(struct bt_bap *bap); void bt_bap_detach(struct bt_bap *bap); bool bt_bap_set_debug(struct bt_bap *bap, bt_bap_debug_func_t cb, void *user_data, bt_bap_destroy_func_t destroy); -bool bap_print_cc(void *data, size_t len, util_debug_func_t func, - void *user_data); +unsigned int bt_bap_pac_register(struct bt_bap *bap, bt_bap_pac_func_t added, + bt_bap_pac_func_t removed, void *user_data, + bt_bap_destroy_func_t destroy); +bool bt_bap_pac_unregister(struct bt_bap *bap, unsigned int id); unsigned int bt_bap_ready_register(struct bt_bap *bap, bt_bap_ready_func_t func, void *user_data, @@ -189,15 +159,17 @@ void *bt_bap_pac_get_user_data(struct bt_bap_pac *pac); /* Stream related functions */ int bt_bap_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, - bt_bap_pac_select_t func, void *user_data); + int *count, bt_bap_pac_select_t func, + void *user_data); + +void bt_bap_cancel_select(struct bt_bap_pac *lpac, bt_bap_pac_select_t func, + void *user_data); -struct bt_bap_stream *bt_bap_config(struct bt_bap *bap, +struct bt_bap_stream *bt_bap_stream_new(struct bt_bap *bap, struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, struct bt_bap_qos *pqos, - struct iovec *data, - bt_bap_stream_func_t func, - void *user_data); + struct iovec *data); struct bt_bap *bt_bap_stream_get_session(struct bt_bap_stream *stream); uint8_t bt_bap_stream_get_state(struct bt_bap_stream *stream); @@ -252,13 +224,15 @@ struct bt_bap_qos *bt_bap_stream_get_qos(struct bt_bap_stream *stream); struct iovec *bt_bap_stream_get_metadata(struct bt_bap_stream *stream); struct io *bt_bap_stream_get_io(struct bt_bap_stream *stream); - +bool bt_bap_match_bcast_sink_stream(const void *data, const void *user_data); bool bt_bap_stream_set_io(struct bt_bap_stream *stream, int fd); int bt_bap_stream_cancel(struct bt_bap_stream *stream, unsigned int id); int bt_bap_stream_io_link(struct bt_bap_stream *stream, struct bt_bap_stream *link); +int bt_bap_stream_io_unlink(struct bt_bap_stream *stream, + struct bt_bap_stream *link); struct queue *bt_bap_stream_io_get_links(struct bt_bap_stream *stream); bool bt_bap_stream_io_get_qos(struct bt_bap_stream *stream, struct bt_bap_qos **in, @@ -268,3 +242,20 @@ uint8_t bt_bap_stream_io_dir(struct bt_bap_stream *stream); int bt_bap_stream_io_connecting(struct bt_bap_stream *stream, int fd); bool bt_bap_stream_io_is_connecting(struct bt_bap_stream *stream, int *fd); + +bool bt_bap_new_bcast_source(struct bt_bap *bap, const char *name); +void bt_bap_update_bcast_source(struct bt_bap_pac *pac, + struct bt_bap_codec *codec, + struct iovec *data, + struct iovec *metadata); + +bool bt_bap_pac_bcast_is_local(struct bt_bap *bap, struct bt_bap_pac *pac); + +struct iovec *bt_bap_stream_get_base(struct bt_bap_stream *stream); + +struct iovec *bt_bap_merge_caps(struct iovec *l2_caps, struct iovec *l3_caps); + +void bt_bap_verify_bis(struct bt_bap *bap, uint8_t bis_index, + struct iovec *caps, + struct bt_bap_pac **lpac); + diff --git a/src/shared/bass.c b/src/shared/bass.c new file mode 100644 index 0000000000000000000000000000000000000000..d99a140a1df48a3473bd065bedfce7b253d665a4 --- /dev/null +++ b/src/shared/bass.c @@ -0,0 +1,1875 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright 2023-2024 NXP + * + */ + +#define _GNU_SOURCE +#include <inttypes.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> +#include <unistd.h> +#include <errno.h> + +#include "lib/bluetooth.h" +#include "lib/uuid.h" + +#include "src/shared/queue.h" +#include "src/shared/util.h" +#include "src/shared/att.h" +#include "src/shared/gatt-db.h" +#include "src/shared/gatt-client.h" +#include "src/shared/bass.h" + +#define DBG(_bass, fmt, arg...) \ + bass_debug(_bass, "%s:%s() " fmt, __FILE__, __func__, ## arg) + +struct bt_bass_db; + +struct bt_bass_cb { + unsigned int id; + bt_bass_func_t attached; + bt_bass_func_t detached; + void *user_data; +}; + +struct bt_bcast_recv_state { + struct bt_bass_db *bdb; + struct gatt_db_attribute *attr; + struct gatt_db_attribute *ccc; +}; + +struct bt_bass_db { + struct gatt_db *db; + bdaddr_t adapter_bdaddr; + struct queue *bcast_srcs; + struct gatt_db_attribute *service; + struct gatt_db_attribute *bcast_audio_scan_cp; + struct bt_bcast_recv_state *bcast_recv_states[NUM_BCAST_RECV_STATES]; +}; + +struct bt_bass { + int ref_count; + struct bt_bass_db *ldb; + struct bt_bass_db *rdb; + struct bt_gatt_client *client; + struct bt_att *att; + + struct queue *notify; + + bt_bass_debug_func_t debug_func; + bt_bass_destroy_func_t debug_destroy; + void *debug_data; + + struct queue *src_cbs; + struct queue *cp_handlers; + + unsigned int disconn_id; + + void *user_data; +}; + +struct bt_bass_cp_handler { + unsigned int id; + bt_bass_cp_handler_func_t handler; + bt_bass_destroy_func_t destroy; + void *data; +}; + +/* BASS subgroup field of the Broadcast + * Receive State characteristic + */ +struct bt_bass_subgroup_data { + uint32_t bis_sync; + uint32_t pending_bis_sync; + uint8_t meta_len; + uint8_t *meta; +}; + +/* BASS Broadcast Source structure */ +struct bt_bcast_src { + struct bt_bass *bass; + struct gatt_db_attribute *attr; + uint8_t id; + uint8_t addr_type; + bdaddr_t addr; + uint8_t sid; + uint32_t bid; + uint8_t sync_state; + uint8_t enc; + uint8_t bad_code[BT_BASS_BCAST_CODE_SIZE]; + uint8_t num_subgroups; + struct bt_bass_subgroup_data *subgroup_data; +}; + +typedef void (*bass_notify_t)(struct bt_bass *bass, uint16_t value_handle, + const uint8_t *value, uint16_t length, + void *user_data); + +struct bt_bass_notify { + unsigned int id; + struct bt_bass *bass; + bass_notify_t func; + void *user_data; +}; + +static struct queue *bass_db; +static struct queue *bass_cbs; +static struct queue *sessions; + +struct bt_bass_src_changed { + unsigned int id; + bt_bass_src_func_t cb; + bt_bass_destroy_func_t destroy; + void *data; +}; + +static void bass_bcast_src_free(void *data); + +static void bass_debug(struct bt_bass *bass, const char *format, ...) +{ + va_list ap; + + if (!bass || !format || !bass->debug_func) + return; + + va_start(ap, format); + util_debug_va(bass->debug_func, bass->debug_data, format, ap); + va_end(ap); +} + +unsigned int bt_bass_cp_handler_register(struct bt_bass *bass, + bt_bass_cp_handler_func_t handler, + bt_bass_destroy_func_t destroy, + void *user_data) +{ + struct bt_bass_cp_handler *cb; + static unsigned int id; + + if (!bass) + return 0; + + cb = new0(struct bt_bass_cp_handler, 1); + cb->id = ++id ? id : ++id; + cb->handler = handler; + cb->destroy = destroy; + cb->data = user_data; + + queue_push_tail(bass->cp_handlers, cb); + + return cb->id; +} + +static void bass_cp_handler_free(void *data) +{ + struct bt_bass_cp_handler *cb = data; + + if (cb->destroy) + cb->destroy(cb->data); + + free(cb); +} + +static bool match_cb_id(const void *data, const void *match_data) +{ + const struct bt_bass_cp_handler *cb = data; + unsigned int id = PTR_TO_UINT(match_data); + + return (cb->id == id); +} + +bool bt_bass_cp_handler_unregister(struct bt_bass *bass, + unsigned int id) +{ + struct bt_bass_cp_handler *cb; + + if (!bass) + return false; + + cb = queue_remove_if(bass->cp_handlers, match_cb_id, + UINT_TO_PTR(id)); + if (!cb) + return false; + + bass_cp_handler_free(cb); + + return true; +} + +unsigned int bt_bass_src_register(struct bt_bass *bass, bt_bass_src_func_t cb, + void *user_data, bt_bass_destroy_func_t destroy) +{ + struct bt_bass_src_changed *changed; + static unsigned int id; + + if (!bass) + return 0; + + changed = new0(struct bt_bass_src_changed, 1); + if (!changed) + return 0; + + changed->id = ++id ? id : ++id; + changed->cb = cb; + changed->destroy = destroy; + changed->data = user_data; + + queue_push_tail(bass->src_cbs, changed); + + return changed->id; +} + +static void bass_src_changed_free(void *data) +{ + struct bt_bass_src_changed *changed = data; + + if (changed->destroy) + changed->destroy(changed->data); + + free(changed); +} + +static bool match_src_changed_id(const void *data, const void *match_data) +{ + const struct bt_bass_src_changed *changed = data; + unsigned int id = PTR_TO_UINT(match_data); + + return (changed->id == id); +} + +bool bt_bass_src_unregister(struct bt_bass *bass, unsigned int id) +{ + struct bt_bass_src_changed *changed; + + if (!bass) + return false; + + changed = queue_remove_if(bass->src_cbs, match_src_changed_id, + UINT_TO_PTR(id)); + if (!changed) + return false; + + bass_src_changed_free(changed); + + return true; +} + +static int bass_build_bcast_src(struct bt_bcast_src *bcast_src, + const uint8_t *value, uint16_t length) +{ + struct bt_bass_subgroup_data *subgroup_data = NULL; + uint8_t id; + uint8_t addr_type; + uint8_t *addr; + uint8_t sid; + uint32_t bid; + uint8_t pa_sync_state; + uint8_t enc; + uint8_t *bad_code = NULL; + uint8_t num_subgroups; + uint32_t bis_sync_state; + uint8_t meta_len; + uint8_t *meta; + + struct iovec iov = { + .iov_base = (void *) value, + .iov_len = length, + }; + + /* Extract all fields from notification */ + if (!util_iov_pull_u8(&iov, &id)) { + DBG(bcast_src->bass, "Unable to parse Broadcast Receive State"); + return -1; + } + + if (!util_iov_pull_u8(&iov, &addr_type)) { + DBG(bcast_src->bass, "Unable to parse Broadcast Receive State"); + return -1; + } + + addr = util_iov_pull_mem(&iov, sizeof(bdaddr_t)); + if (!addr) { + DBG(bcast_src->bass, "Unable to parse Broadcast Receive State"); + return -1; + } + + if (!util_iov_pull_u8(&iov, &sid)) { + DBG(bcast_src->bass, "Unable to parse Broadcast Receive State"); + return -1; + } + + if (!util_iov_pull_le24(&iov, &bid)) { + DBG(bcast_src->bass, "Unable to parse Broadcast Receive State"); + return -1; + } + + if (!util_iov_pull_u8(&iov, &pa_sync_state)) { + DBG(bcast_src->bass, "Unable to parse Broadcast Receive State"); + return -1; + } + + if (!util_iov_pull_u8(&iov, &enc)) { + DBG(bcast_src->bass, "Unable to parse Broadcast Receive State"); + return -1; + } + + if (enc == BT_BASS_BIG_ENC_STATE_BAD_CODE) { + bad_code = util_iov_pull_mem(&iov, BT_BASS_BCAST_CODE_SIZE); + if (!bad_code) { + DBG(bcast_src->bass, "Unable to parse " + "Broadcast Receive State"); + return -1; + } + } + + if (!util_iov_pull_u8(&iov, &num_subgroups)) { + DBG(bcast_src->bass, "Unable to parse Broadcast Receive State"); + return -1; + } + + if (num_subgroups == 0) + goto done; + + subgroup_data = new0(struct bt_bass_subgroup_data, 1); + if (!subgroup_data) { + DBG(bcast_src->bass, "Unable to allocate memory"); + return -1; + } + + for (int i = 0; i < num_subgroups; i++) { + if (!util_iov_pull_le32(&iov, &bis_sync_state)) { + DBG(bcast_src->bass, "Unable to parse " + "Broadcast Receive State"); + + for (int j = 0; j < i; j++) + free(subgroup_data[j].meta); + + free(subgroup_data); + return -1; + } + + subgroup_data[i].bis_sync = bis_sync_state; + + if (!util_iov_pull_u8(&iov, &meta_len)) { + DBG(bcast_src->bass, "Unable to parse " + "Broadcast Receive State"); + + for (int j = 0; j < i; j++) + free(subgroup_data[j].meta); + + free(subgroup_data); + return -1; + } + + subgroup_data[i].meta_len = meta_len; + + if (meta_len == 0) + continue; + + subgroup_data[i].meta = malloc0(meta_len); + if (!subgroup_data[i].meta) { + DBG(bcast_src->bass, "Unable to allocate memory"); + + for (int j = 0; j < i; j++) + free(subgroup_data[j].meta); + + free(subgroup_data); + return -1; + } + + meta = util_iov_pull_mem(&iov, meta_len); + if (!meta) { + DBG(bcast_src->bass, "Unable to parse " + "Broadcast Receive State"); + + for (int j = 0; j < i; j++) + free(subgroup_data[j].meta); + + free(subgroup_data); + return -1; + } + + memcpy(subgroup_data[i].meta, meta, meta_len); + } + +done: + /* + * If no errors occurred, copy extracted fields into + * the broadcast source structure + */ + if (bcast_src->subgroup_data) { + for (int i = 0; i < bcast_src->num_subgroups; i++) + free(bcast_src->subgroup_data[i].meta); + + free(bcast_src->subgroup_data); + } + + bcast_src->id = id; + bcast_src->addr_type = addr_type; + memcpy(&bcast_src->addr, addr, sizeof(bdaddr_t)); + bcast_src->sid = sid; + bcast_src->bid = bid; + bcast_src->sync_state = pa_sync_state; + bcast_src->enc = enc; + + if (enc == BT_BASS_BIG_ENC_STATE_BAD_CODE) + memcpy(bcast_src->bad_code, bad_code, BT_BASS_BCAST_CODE_SIZE); + else + memset(bcast_src->bad_code, 0, BT_BASS_BCAST_CODE_SIZE); + + bcast_src->num_subgroups = num_subgroups; + + bcast_src->subgroup_data = subgroup_data; + + return 0; +} + +static struct iovec *bass_parse_bcast_src(struct bt_bcast_src *bcast_src) +{ + size_t len = 0; + uint8_t *notif = NULL; + struct iovec *iov; + + if (!bcast_src) + return NULL; + + len = BT_BASS_BCAST_SRC_LEN + bcast_src->num_subgroups * + BT_BASS_BCAST_SRC_SUBGROUP_LEN; + + if (bcast_src->enc == BT_BASS_BIG_ENC_STATE_BAD_CODE) + len += BT_BASS_BCAST_CODE_SIZE; + + for (size_t i = 0; i < bcast_src->num_subgroups; i++) { + /* Add length for subgroup metadata */ + len += bcast_src->subgroup_data[i].meta_len; + } + + notif = malloc0(len); + if (!notif) + return NULL; + + iov = new0(struct iovec, 1); + if (!iov) { + free(notif); + return NULL; + } + + iov->iov_base = notif; + iov->iov_len = 0; + + util_iov_push_u8(iov, bcast_src->id); + util_iov_push_u8(iov, bcast_src->addr_type); + util_iov_push_mem(iov, sizeof(bcast_src->addr), + &bcast_src->addr); + util_iov_push_u8(iov, bcast_src->sid); + util_iov_push_le24(iov, bcast_src->bid); + util_iov_push_u8(iov, bcast_src->sync_state); + util_iov_push_u8(iov, bcast_src->enc); + + if (bcast_src->enc == BT_BASS_BIG_ENC_STATE_BAD_CODE) + util_iov_push_mem(iov, sizeof(bcast_src->bad_code), + bcast_src->bad_code); + + util_iov_push_u8(iov, bcast_src->num_subgroups); + + for (size_t i = 0; i < bcast_src->num_subgroups; i++) { + /* Add subgroup bis_sync */ + util_iov_push_le32(iov, bcast_src->subgroup_data[i].bis_sync); + + /* Add subgroup meta_len */ + util_iov_push_u8(iov, bcast_src->subgroup_data[i].meta_len); + + /* Add subgroup metadata */ + if (bcast_src->subgroup_data[i].meta_len > 0) + util_iov_push_mem(iov, + bcast_src->subgroup_data[i].meta_len, + bcast_src->subgroup_data[i].meta); + } + + return iov; +} + +static bool bass_check_cp_command_subgroup_data_len(uint8_t num_subgroups, + struct iovec *iov) +{ + uint32_t bis_sync_state; + uint8_t *meta_len; + uint8_t *meta; + + for (int i = 0; i < num_subgroups; i++) { + if (!util_iov_pull_le32(iov, &bis_sync_state)) + return false; + + meta_len = util_iov_pull_mem(iov, + sizeof(*meta_len)); + if (!meta_len) + return false; + + meta = util_iov_pull_mem(iov, *meta_len); + if (!meta) + return false; + } + + return true; +} + +static bool bass_check_cp_command_len(const uint8_t *value, size_t len) +{ + struct bt_bass_bcast_audio_scan_cp_hdr *hdr; + union { + struct bt_bass_add_src_params *add_src_params; + struct bt_bass_mod_src_params *mod_src_params; + struct bt_bass_set_bcast_code_params *set_bcast_code_params; + struct bt_bass_remove_src_params *remove_src_params; + } params; + + struct iovec iov = { + .iov_base = (void *)value, + .iov_len = len, + }; + + /* Get command header */ + hdr = util_iov_pull_mem(&iov, sizeof(*hdr)); + + if (!hdr) + return false; + + /* Check command parameters */ + switch (hdr->op) { + case BT_BASS_ADD_SRC: + params.add_src_params = util_iov_pull_mem(&iov, + sizeof(*params.add_src_params)); + if (!params.add_src_params) + return false; + + if (!bass_check_cp_command_subgroup_data_len( + params.add_src_params->num_subgroups, + &iov)) + return false; + + break; + case BT_BASS_MOD_SRC: + params.mod_src_params = util_iov_pull_mem(&iov, + sizeof(*params.mod_src_params)); + if (!params.mod_src_params) + return false; + + if (!bass_check_cp_command_subgroup_data_len( + params.mod_src_params->num_subgroups, + &iov)) + return false; + + break; + case BT_BASS_SET_BCAST_CODE: + params.set_bcast_code_params = util_iov_pull_mem(&iov, + sizeof(*params.set_bcast_code_params)); + if (!params.set_bcast_code_params) + return false; + + break; + case BT_BASS_REMOVE_SRC: + params.remove_src_params = util_iov_pull_mem(&iov, + sizeof(*params.remove_src_params)); + if (!params.remove_src_params) + return false; + + break; + case BT_BASS_REMOTE_SCAN_STOPPED: + case BT_BASS_REMOTE_SCAN_STARTED: + break; + default: + return true; + } + + if (iov.iov_len > 0) + return false; + + return true; +} + +static void bass_handle_remote_scan_stopped_op(struct bt_bass *bass, + struct gatt_db_attribute *attrib, + uint8_t opcode, + unsigned int id, + struct iovec *iov, + struct bt_att *att) +{ + gatt_db_attribute_write_result(attrib, id, 0x00); +} + +static void bass_handle_remote_scan_started_op(struct bt_bass *bass, + struct gatt_db_attribute *attrib, + uint8_t opcode, + unsigned int id, + struct iovec *iov, + struct bt_att *att) +{ + gatt_db_attribute_write_result(attrib, id, 0x00); +} + +static bool bass_src_id_match(const void *data, const void *match_data) +{ + const struct bt_bcast_src *bcast_src = data; + const uint8_t *id = match_data; + + return (bcast_src->id == *id); +} + +static void bass_handle_remove_src_op(struct bt_bass *bass, + struct gatt_db_attribute *attrib, + uint8_t opcode, + unsigned int id, + struct iovec *iov, + struct bt_att *att) +{ + struct bt_bass_remove_src_params *params; + struct bt_bcast_src *bcast_src; + int att_err = 0; + + /* Get Remove Source command parameters */ + params = util_iov_pull_mem(iov, sizeof(*params)); + + bcast_src = queue_find(bass->ldb->bcast_srcs, + bass_src_id_match, + ¶ms->id); + + if (!bcast_src) { + /* No source matches the written source id */ + att_err = BT_BASS_ERROR_INVALID_SOURCE_ID; + goto done; + } + + /* Ignore if server is synchronized to the PA + * of the source + */ + if (bcast_src->sync_state == BT_BASS_SYNCHRONIZED_TO_PA) + goto done; + + /* Ignore if server is synchronized to any BIS + * of the source + */ + for (int i = 0; i < bcast_src->num_subgroups; i++) + if (bcast_src->subgroup_data[i].bis_sync) + goto done; + + /* Accept the operation and remove source */ + queue_remove(bass->ldb->bcast_srcs, bcast_src); + gatt_db_attribute_notify(bcast_src->attr, NULL, 0, att); + bass_bcast_src_free(bcast_src); + +done: + gatt_db_attribute_write_result(attrib, id, + att_err); +} + +static bool bass_src_attr_match(const void *data, const void *match_data) +{ + const struct bt_bcast_src *bcast_src = data; + const struct gatt_db_attribute *attr = match_data; + + return (bcast_src->attr == attr); +} + +static bool bass_trigger_big_sync(struct bt_bcast_src *bcast_src) +{ + for (int i = 0; i < bcast_src->num_subgroups; i++) { + struct bt_bass_subgroup_data *data = + &bcast_src->subgroup_data[i]; + + if (data->pending_bis_sync && + data->pending_bis_sync != BIS_SYNC_NO_PREF) + return true; + } + + return false; +} + +static struct bt_bass *bass_get_session(struct bt_att *att, struct gatt_db *db, + const bdaddr_t *adapter_bdaddr) +{ + const struct queue_entry *entry; + struct bt_bass *bass; + + for (entry = queue_get_entries(sessions); entry; entry = entry->next) { + struct bt_bass *bass = entry->data; + + if (att == bt_bass_get_att(bass)) + return bass; + } + + bass = bt_bass_new(db, NULL, adapter_bdaddr); + bass->att = att; + + bt_bass_attach(bass, NULL); + + return bass; +} + +static bool bass_validate_bis_sync(uint8_t num_subgroups, + struct iovec *iov) +{ + uint32_t bis_sync_state; + uint32_t bitmask = 0U; + uint8_t *meta_len; + + for (int i = 0; i < num_subgroups; i++) { + util_iov_pull_le32(iov, &bis_sync_state); + + if (bis_sync_state != BIS_SYNC_NO_PREF) + for (int bis_idx = 0; bis_idx < 31; bis_idx++) { + if (bis_sync_state & (1 << bis_idx)) { + if (bitmask & (1 << bis_idx)) + return false; + + bitmask |= (1 << bis_idx); + } + } + + meta_len = util_iov_pull_mem(iov, + sizeof(*meta_len)); + util_iov_pull_mem(iov, *meta_len); + } + + return true; +} + +static bool bass_validate_add_src_params(uint8_t *value, size_t len) +{ + struct bt_bass_add_src_params *params; + struct iovec iov = { + .iov_base = (void *)value, + .iov_len = len, + }; + + params = util_iov_pull_mem(&iov, sizeof(*params)); + + if (params->pa_sync > PA_SYNC_NO_PAST) + return false; + + if (params->addr_type > 0x01) + return false; + + if (params->sid > 0x0F) + return false; + + if (!bass_validate_bis_sync(params->num_subgroups, + &iov)) + return false; + + return true; +} + +static void bass_handle_add_src_op(struct bt_bass *bass, + struct gatt_db_attribute *attrib, + uint8_t opcode, + unsigned int id, + struct iovec *iov, + struct bt_att *att) +{ + struct bt_bcast_src *bcast_src, *src; + uint8_t src_id = 0; + struct gatt_db_attribute *attr; + uint8_t pa_sync; + struct iovec *notif; + int ret; + const struct queue_entry *entry; + struct bt_bass_add_src_params *params; + + gatt_db_attribute_write_result(attrib, id, 0x00); + + /* Ignore operation if parameters are invalid */ + if (!bass_validate_add_src_params(iov->iov_base, iov->iov_len)) + return; + + /* Allocate a new broadcast source */ + bcast_src = new0(struct bt_bcast_src, 1); + if (!bcast_src) { + DBG(bass, "Unable to allocate broadcast source"); + return; + } + + queue_push_tail(bass->ldb->bcast_srcs, bcast_src); + + bcast_src->bass = bass; + + /* Map the source to a Broadcast Receive State characteristic */ + for (int i = 0; i < NUM_BCAST_RECV_STATES; i++) { + src = queue_find(bass->ldb->bcast_srcs, + bass_src_attr_match, + bass->ldb->bcast_recv_states[i]->attr); + if (!src) { + /* Found and empty characteristic */ + bcast_src->attr = + bass->ldb->bcast_recv_states[i]->attr; + break; + } + } + + if (!bcast_src->attr) { + /* If no empty characteristic has been found, + * overwrite an existing one + */ + attr = bass->ldb->bcast_recv_states[0]->attr; + + src = queue_find(bass->ldb->bcast_srcs, + bass_src_attr_match, + attr); + + queue_remove(bass->ldb->bcast_srcs, src); + bass_bcast_src_free(src); + bcast_src->attr = attr; + } + + /* Allocate source id */ + while (true) { + src = queue_find(bass->ldb->bcast_srcs, + bass_src_id_match, + &src_id); + if (!src) + break; + + if (src_id == 0xFF) { + DBG(bass, "Unable to allocate broadcast source id"); + return; + } + + src_id++; + } + + bcast_src->id = src_id; + + params = util_iov_pull_mem(iov, sizeof(*params)); + + /* Populate broadcast source fields from command parameters */ + bcast_src->addr_type = params->addr_type; + + /* Convert to three-value type */ + if (bcast_src->addr_type) + params->addr_type = BDADDR_LE_RANDOM; + else + params->addr_type = BDADDR_LE_PUBLIC; + + bacpy(&bcast_src->addr, ¶ms->addr); + bcast_src->sid = params->sid; + memcpy(&bcast_src->bid, params->bid, sizeof(params->bid)); + + pa_sync = params->pa_sync; + bcast_src->sync_state = BT_BASS_NOT_SYNCHRONIZED_TO_PA; + + bcast_src->num_subgroups = params->num_subgroups; + + if (!bcast_src->num_subgroups) + return; + + bcast_src->subgroup_data = new0(struct bt_bass_subgroup_data, + bcast_src->num_subgroups); + if (!bcast_src->subgroup_data) { + DBG(bass, "Unable to allocate subgroup data"); + goto err; + } + + for (int i = 0; i < bcast_src->num_subgroups; i++) { + struct bt_bass_subgroup_data *data = + &bcast_src->subgroup_data[i]; + + util_iov_pull_le32(iov, &data->pending_bis_sync); + + data->meta_len = *(uint8_t *)util_iov_pull_mem(iov, + sizeof(data->meta_len)); + if (!data->meta_len) + continue; + + data->meta = malloc0(data->meta_len); + if (!data->meta) + goto err; + + memcpy(data->meta, (uint8_t *)util_iov_pull_mem(iov, + data->meta_len), data->meta_len); + } + + if (pa_sync != PA_SYNC_NO_SYNC) { + for (entry = queue_get_entries(bass->cp_handlers); entry; + entry = entry->next) { + struct bt_bass_cp_handler *cb = entry->data; + + if (cb->handler) { + ret = cb->handler(bcast_src, + BT_BASS_ADD_SRC, + params, cb->data); + if (ret) + goto err; + } + } + } else { + for (int i = 0; i < bcast_src->num_subgroups; i++) + bcast_src->subgroup_data[i].bis_sync = + bcast_src->subgroup_data[i].pending_bis_sync; + + notif = bass_parse_bcast_src(bcast_src); + if (!notif) + return; + + gatt_db_attribute_notify(bcast_src->attr, + notif->iov_base, notif->iov_len, + bt_bass_get_att(bcast_src->bass)); + + free(notif->iov_base); + free(notif); + } + + return; + +err: + if (bcast_src->subgroup_data) { + for (int i = 0; i < bcast_src->num_subgroups; i++) + free(bcast_src->subgroup_data[i].meta); + + free(bcast_src->subgroup_data); + } + + free(bcast_src); +} + +static void bass_handle_set_bcast_code_op(struct bt_bass *bass, + struct gatt_db_attribute *attrib, + uint8_t opcode, + unsigned int id, + struct iovec *iov, + struct bt_att *att) +{ + struct bt_bass_set_bcast_code_params *params; + struct bt_bcast_src *bcast_src; + struct iovec *notif; + const struct queue_entry *entry; + int ret; + + /* Get Set Broadcast Code command parameters */ + params = util_iov_pull_mem(iov, sizeof(*params)); + + bcast_src = queue_find(bass->ldb->bcast_srcs, + bass_src_id_match, + ¶ms->id); + + if (!bcast_src) { + /* No source matches the written source id */ + gatt_db_attribute_write_result(attrib, id, + BT_BASS_ERROR_INVALID_SOURCE_ID); + + return; + } + + gatt_db_attribute_write_result(attrib, id, 0x00); + + if (!bass_trigger_big_sync(bcast_src)) { + bcast_src->enc = BT_BASS_BIG_ENC_STATE_DEC; + + notif = bass_parse_bcast_src(bcast_src); + if (!notif) + return; + + gatt_db_attribute_notify(bcast_src->attr, + notif->iov_base, notif->iov_len, + bt_bass_get_att(bcast_src->bass)); + + free(notif->iov_base); + free(notif); + return; + } + + for (entry = queue_get_entries(bass->cp_handlers); entry; + entry = entry->next) { + struct bt_bass_cp_handler *cb = entry->data; + + if (cb->handler) { + ret = cb->handler(bcast_src, + BT_BASS_SET_BCAST_CODE, + params, cb->data); + if (ret) + DBG(bass, "Unable to handle Set " + "Broadcast Code operation"); + } + } +} + +#define BASS_OP(_str, _op, _size, _func) \ + { \ + .str = _str, \ + .op = _op, \ + .size = _size, \ + .func = _func, \ + } + +struct bass_op_handler { + const char *str; + uint8_t op; + size_t size; + void (*func)(struct bt_bass *bass, + struct gatt_db_attribute *attrib, + uint8_t opcode, + unsigned int id, + struct iovec *iov, + struct bt_att *att); +} bass_handlers[] = { + BASS_OP("Remote Scan Stopped", BT_BASS_REMOTE_SCAN_STOPPED, + 0, bass_handle_remote_scan_stopped_op), + BASS_OP("Remote Scan Started", BT_BASS_REMOTE_SCAN_STARTED, + 0, bass_handle_remote_scan_started_op), + BASS_OP("Remove Source", BT_BASS_REMOVE_SRC, + 0, bass_handle_remove_src_op), + BASS_OP("Add Source", BT_BASS_ADD_SRC, + 0, bass_handle_add_src_op), + BASS_OP("Set Broadcast Code", BT_BASS_SET_BCAST_CODE, + 0, bass_handle_set_bcast_code_op), + {} +}; + +static void bass_bcast_audio_scan_cp_write(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + const uint8_t *value, size_t len, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct bt_bass_db *bdb = user_data; + struct bt_bass_bcast_audio_scan_cp_hdr *hdr; + struct bass_op_handler *handler; + struct bt_bass *bass = bass_get_session(att, bdb->db, + &bdb->adapter_bdaddr); + struct iovec iov = { + .iov_base = (void *)value, + .iov_len = len, + }; + + /* Validate written command length */ + if (!bass_check_cp_command_len(value, len)) { + gatt_db_attribute_write_result(attrib, id, + BT_ERROR_WRITE_REQUEST_REJECTED); + return; + } + + /* Get command header */ + hdr = util_iov_pull_mem(&iov, sizeof(*hdr)); + + /* Call the appropriate opcode handler */ + for (handler = bass_handlers; handler && handler->str; handler++) { + if (handler->op == hdr->op) { + handler->func(bass, attrib, opcode, id, &iov, att); + return; + } + } + + /* Send error response if unsupported opcode was written */ + gatt_db_attribute_write_result(attrib, id, + BT_BASS_ERROR_OPCODE_NOT_SUPPORTED); +} + +static bool bass_src_match_attrib(const void *data, const void *match_data) +{ + const struct bt_bcast_src *bcast_src = data; + const struct gatt_db_attribute *attr = match_data; + + return (bcast_src->attr == attr); +} + +static void bass_bcast_recv_state_read(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct bt_bass_db *bdb = user_data; + struct iovec *rsp; + struct bt_bcast_src *bcast_src; + struct bt_bass *bass = bass_get_session(att, bdb->db, + &bdb->adapter_bdaddr); + + bcast_src = queue_find(bass->ldb->bcast_srcs, + bass_src_match_attrib, + attrib); + + if (!bcast_src) { + gatt_db_attribute_read_result(attrib, id, 0, NULL, + 0); + return; + } + + /* Build read response */ + rsp = bass_parse_bcast_src(bcast_src); + + if (!rsp) { + gatt_db_attribute_read_result(attrib, id, + BT_ATT_ERROR_UNLIKELY, + NULL, 0); + return; + } + + gatt_db_attribute_read_result(attrib, id, 0, rsp->iov_base, + rsp->iov_len); + + free(rsp->iov_base); + free(rsp); +} + +static void bcast_recv_new(struct bt_bass_db *bdb, int i) +{ + struct bt_bcast_recv_state *bcast_recv_state; + bt_uuid_t uuid; + + if (!bdb) + return; + + bcast_recv_state = new0(struct bt_bcast_recv_state, 1); + bcast_recv_state->bdb = bdb; + + bt_uuid16_create(&uuid, BCAST_RECV_STATE_UUID); + bcast_recv_state->attr = + gatt_db_service_add_characteristic(bdb->service, &uuid, + BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_NOTIFY, + bass_bcast_recv_state_read, NULL, + bdb); + + bcast_recv_state->ccc = gatt_db_service_add_ccc(bdb->service, + BT_ATT_PERM_READ | BT_ATT_PERM_WRITE); + + bdb->bcast_recv_states[i] = bcast_recv_state; +} + +static void bass_new(struct bt_bass_db *bdb) +{ + bt_uuid_t uuid; + int i; + + /* Populate DB with BASS attributes */ + bt_uuid16_create(&uuid, BASS_UUID); + bdb->service = gatt_db_add_service(bdb->db, &uuid, true, + 3 + (NUM_BCAST_RECV_STATES * 3)); + + for (i = 0; i < NUM_BCAST_RECV_STATES; i++) + bcast_recv_new(bdb, i); + + bt_uuid16_create(&uuid, BCAST_AUDIO_SCAN_CP_UUID); + bdb->bcast_audio_scan_cp = + gatt_db_service_add_characteristic(bdb->service, + &uuid, + BT_ATT_PERM_WRITE, + BT_GATT_CHRC_PROP_WRITE | + BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP, + NULL, bass_bcast_audio_scan_cp_write, + bdb); + + gatt_db_service_set_active(bdb->service, true); +} + +static void bass_bcast_src_free(void *data) +{ + struct bt_bcast_src *bcast_src = data; + + if (!bcast_src) + return; + + for (int i = 0; i < bcast_src->num_subgroups; i++) + free(bcast_src->subgroup_data[i].meta); + + free(bcast_src->subgroup_data); + + free(bcast_src); +} + +static void read_bcast_recv_state(bool success, uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) +{ + struct bt_bcast_src *bcast_src = user_data; + + if (!success) { + DBG(bcast_src->bass, "Unable to read " + "Broadcast Receive State: error 0x%02x", + att_ecode); + return; + } + + if (length == 0) { + queue_remove(bcast_src->bass->rdb->bcast_srcs, bcast_src); + bass_bcast_src_free(bcast_src); + return; + } + + if (bass_build_bcast_src(bcast_src, value, length)) { + queue_remove(bcast_src->bass->rdb->bcast_srcs, bcast_src); + bass_bcast_src_free(bcast_src); + return; + } +} + +static void notify_src_changed(void *data, void *user_data) +{ + struct bt_bass_src_changed *changed = data; + struct bt_bcast_src *bcast_src = user_data; + uint32_t bis_sync = 0; + + for (uint8_t i = 0; i < bcast_src->num_subgroups; i++) { + struct bt_bass_subgroup_data *sgrp = + &bcast_src->subgroup_data[i]; + + /* Create a bitmask of all BIS indices that the peer has + * synchronized with. + */ + bis_sync |= sgrp->bis_sync; + } + + if (changed->cb) + changed->cb(bcast_src->id, bcast_src->bid, bcast_src->enc, + bis_sync, changed->data); +} + +static void bcast_recv_state_notify(struct bt_bass *bass, uint16_t value_handle, + const uint8_t *value, uint16_t length, + void *user_data) +{ + struct gatt_db_attribute *attr = user_data; + struct bt_bcast_src *bcast_src; + bool new_src = false; + + bcast_src = queue_find(bass->rdb->bcast_srcs, + bass_src_match_attrib, attr); + if (!bcast_src) { + new_src = true; + bcast_src = new0(struct bt_bcast_src, 1); + + if (!bcast_src) { + DBG(bass, "Failed to allocate " + "memory for broadcast source"); + return; + } + + bcast_src->bass = bass; + bcast_src->attr = attr; + } + + if (bass_build_bcast_src(bcast_src, value, length) + && new_src) { + bass_bcast_src_free(bcast_src); + return; + } + + if (new_src) + queue_push_tail(bass->rdb->bcast_srcs, bcast_src); + + /* Notify the update in the Broadcast Receive State characteristic + * to all drivers that registered a callback. + */ + queue_foreach(bass->src_cbs, notify_src_changed, bcast_src); +} + +static void bass_register(uint16_t att_ecode, void *user_data) +{ + struct bt_bass_notify *notify = user_data; + + if (att_ecode) + DBG(notify->bass, "BASS register notify failed: 0x%04x", + att_ecode); +} + +static void bass_notify(uint16_t value_handle, const uint8_t *value, + uint16_t length, void *user_data) +{ + struct bt_bass_notify *notify = user_data; + + if (notify->func) + notify->func(notify->bass, value_handle, value, length, + notify->user_data); +} + +static void bass_notify_destroy(void *data) +{ + struct bt_bass_notify *notify = data; + struct bt_bass *bass = notify->bass; + + if (queue_remove_if(bass->notify, NULL, notify)) + free(notify); +} + +static unsigned int bass_register_notify(struct bt_bass *bass, + uint16_t value_handle, + bass_notify_t func, + void *user_data) +{ + struct bt_bass_notify *notify; + + notify = new0(struct bt_bass_notify, 1); + notify->bass = bass; + notify->func = func; + notify->user_data = user_data; + + notify->id = bt_gatt_client_register_notify(bass->client, + value_handle, bass_register, + bass_notify, notify, + bass_notify_destroy); + if (!notify->id) { + DBG(bass, "Unable to register for notifications"); + free(notify); + return 0; + } + + queue_push_tail(bass->notify, notify); + + return notify->id; +} + +static void foreach_bass_char(struct gatt_db_attribute *attr, void *user_data) +{ + struct bt_bass *bass = user_data; + uint16_t value_handle; + bt_uuid_t uuid, uuid_bcast_audio_scan_cp, uuid_bcast_recv_state; + + /* Get attribute value handle and uuid */ + if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, + NULL, NULL, &uuid)) + return; + + bt_uuid16_create(&uuid_bcast_audio_scan_cp, BCAST_AUDIO_SCAN_CP_UUID); + bt_uuid16_create(&uuid_bcast_recv_state, BCAST_RECV_STATE_UUID); + + if (!bt_uuid_cmp(&uuid, &uuid_bcast_audio_scan_cp)) { + /* Found Broadcast Audio Scan Control Point characteristic */ + bass->rdb->bcast_audio_scan_cp = attr; + + DBG(bass, "Broadcast Audio Scan Control Point " + "found: handle 0x%04x", value_handle); + } + + if (!bt_uuid_cmp(&uuid, &uuid_bcast_recv_state)) { + /* Found Broadcast Receive State characteristic */ + struct bt_bcast_src *bcast_src = + queue_find(bass->rdb->bcast_srcs, + bass_src_match_attrib, attr); + + if (!bcast_src) { + bcast_src = new0(struct bt_bcast_src, 1); + + if (bcast_src == NULL) { + DBG(bass, "Failed to allocate " + "memory for broadcast source"); + return; + } + + bcast_src->bass = bass; + bcast_src->attr = attr; + + queue_push_tail(bass->rdb->bcast_srcs, bcast_src); + } + + bt_gatt_client_read_value(bass->client, value_handle, + read_bcast_recv_state, + bcast_src, NULL); + + (void)bass_register_notify(bass, value_handle, + bcast_recv_state_notify, + attr); + + DBG(bass, "Broadcast Receive State found: handle 0x%04x", + value_handle); + } +} + +static void foreach_bass_service(struct gatt_db_attribute *attr, + void *user_data) +{ + struct bt_bass *bass = user_data; + + /* Store BASS service reference */ + bass->rdb->service = attr; + + /* Handle BASS characteristics */ + gatt_db_service_foreach_char(attr, foreach_bass_char, bass); +} + +static void bass_attached(void *data, void *user_data) +{ + struct bt_bass_cb *cb = data; + struct bt_bass *bass = user_data; + + cb->attached(bass, cb->user_data); +} + +static void bass_disconnected(int err, void *user_data) +{ + struct bt_bass *bass = user_data; + + bass->disconn_id = 0; + + DBG(bass, "bass %p disconnected err %d", bass, err); + + bt_bass_detach(bass); +} + +static void bass_attach_att(struct bt_bass *bass, struct bt_att *att) +{ + if (bass->disconn_id) { + if (att == bt_bass_get_att(bass)) + return; + + bt_att_unregister_disconnect(bt_bass_get_att(bass), + bass->disconn_id); + } + + bass->disconn_id = bt_att_register_disconnect(att, + bass_disconnected, + bass, NULL); +} + +bool bt_bass_attach(struct bt_bass *bass, struct bt_gatt_client *client) +{ + bt_uuid_t uuid; + + if (!sessions) + sessions = queue_new(); + + queue_push_tail(sessions, bass); + + queue_foreach(bass_cbs, bass_attached, bass); + + if (!client) { + if (bass->att) + bass_attach_att(bass, bass->att); + return true; + } + + if (bass->client) + return false; + + bass->client = bt_gatt_client_clone(client); + if (!bass->client) + return false; + + bass_attach_att(bass, bt_gatt_client_get_att(client)); + + bt_uuid16_create(&uuid, BASS_UUID); + gatt_db_foreach_service(bass->rdb->db, &uuid, foreach_bass_service, + bass); + + return true; +} + +bool bt_bass_set_att(struct bt_bass *bass, struct bt_att *att) +{ + if (!bass) + return false; + + bass->att = att; + return true; +} + +static void bass_detached(void *data, void *user_data) +{ + struct bt_bass_cb *cb = data; + struct bt_bass *bass = user_data; + + cb->detached(bass, cb->user_data); +} + +void bt_bass_detach(struct bt_bass *bass) +{ + struct bt_att *att; + + if (!queue_remove(sessions, bass)) + return; + + if (bass->client) + att = bt_gatt_client_get_att(bass->client); + else + att = bass->att; + + bt_att_unregister_disconnect(att, bass->disconn_id); + + bt_gatt_client_unref(bass->client); + bass->client = NULL; + + bass->att = NULL; + + queue_foreach(bass_cbs, bass_detached, bass); +} + +static void bass_db_free(void *data) +{ + struct bt_bass_db *bdb = data; + + if (!bdb) + return; + + gatt_db_unref(bdb->db); + queue_destroy(bdb->bcast_srcs, bass_bcast_src_free); + + free(bdb); +} + +static void bass_free(void *data) +{ + struct bt_bass *bass = data; + + bt_bass_detach(bass); + bass_db_free(bass->rdb); + queue_destroy(bass->notify, NULL); + queue_destroy(bass->src_cbs, bass_src_changed_free); + queue_destroy(bass->cp_handlers, bass_cp_handler_free); + + free(bass); +} + +void bt_bass_unref(struct bt_bass *bass) +{ + if (!bass) + return; + + if (__sync_sub_and_fetch(&bass->ref_count, 1)) + return; + + bass_free(bass); +} + +bool bt_bass_set_user_data(struct bt_bass *bass, void *user_data) +{ + if (!bass) + return false; + + bass->user_data = user_data; + + return true; +} + +static struct bt_bass_db *bass_db_new(struct gatt_db *db, + const bdaddr_t *adapter_bdaddr) +{ + struct bt_bass_db *bdb; + + if (!db) + return NULL; + + bdb = new0(struct bt_bass_db, 1); + bdb->db = gatt_db_ref(db); + bacpy(&bdb->adapter_bdaddr, adapter_bdaddr); + bdb->bcast_srcs = queue_new(); + + if (!bass_db) + bass_db = queue_new(); + + bass_new(bdb); + + queue_push_tail(bass_db, bdb); + + return bdb; +} + +static bool bass_db_match(const void *data, const void *match_data) +{ + const struct bt_bass_db *bdb = data; + const struct gatt_db *db = match_data; + + return (bdb->db == db); +} + +static struct bt_bass_db *bass_get_db(struct gatt_db *db, + const bdaddr_t *adapter_bdaddr) +{ + struct bt_bass_db *bdb; + + bdb = queue_find(bass_db, bass_db_match, db); + if (bdb) + return bdb; + + return bass_db_new(db, adapter_bdaddr); +} + +static struct bt_bass *bt_bass_ref(struct bt_bass *bass) +{ + if (!bass) + return NULL; + + __sync_fetch_and_add(&bass->ref_count, 1); + + return bass; +} + +struct bt_bass *bt_bass_new(struct gatt_db *ldb, struct gatt_db *rdb, + const bdaddr_t *adapter_bdaddr) +{ + struct bt_bass *bass; + struct bt_bass_db *db; + + if (!ldb) + return NULL; + + db = bass_get_db(ldb, adapter_bdaddr); + if (!db) + return NULL; + + bass = new0(struct bt_bass, 1); + bass->ldb = db; + bass->notify = queue_new(); + bass->src_cbs = queue_new(); + bass->cp_handlers = queue_new(); + + if (!rdb) + goto done; + + db = new0(struct bt_bass_db, 1); + db->db = gatt_db_ref(rdb); + db->bcast_srcs = queue_new(); + + bass->rdb = db; + +done: + bt_bass_ref(bass); + + return bass; +} + +struct bt_att *bt_bass_get_att(struct bt_bass *bass) +{ + if (!bass) + return NULL; + + if (bass->att) + return bass->att; + + return bt_gatt_client_get_att(bass->client); +} + +struct bt_gatt_client *bt_bass_get_client(struct bt_bass *bass) +{ + if (!bass) + return NULL; + + return bass->client; +} + +bool bt_bass_set_debug(struct bt_bass *bass, bt_bass_debug_func_t func, + void *user_data, bt_bass_destroy_func_t destroy) +{ + if (!bass) + return false; + + if (bass->debug_destroy) + bass->debug_destroy(bass->debug_data); + + bass->debug_func = func; + bass->debug_destroy = destroy; + bass->debug_data = user_data; + + return true; +} + +unsigned int bt_bass_register(bt_bass_func_t attached, bt_bass_func_t detached, + void *user_data) +{ + struct bt_bass_cb *cb; + static unsigned int id; + + if (!attached && !detached) + return 0; + + if (!bass_cbs) + bass_cbs = queue_new(); + + cb = new0(struct bt_bass_cb, 1); + cb->id = ++id ? id : ++id; + cb->attached = attached; + cb->detached = detached; + cb->user_data = user_data; + + queue_push_tail(bass_cbs, cb); + + return cb->id; +} +static bool match_id(const void *data, const void *match_data) +{ + const struct bt_bass_cb *cb = data; + unsigned int id = PTR_TO_UINT(match_data); + + return (cb->id == id); +} + +bool bt_bass_unregister(unsigned int id) +{ + struct bt_bass_cb *cb; + + cb = queue_remove_if(bass_cbs, match_id, UINT_TO_PTR(id)); + if (!cb) + return false; + + free(cb); + + return true; +} + +void bt_bass_add_db(struct gatt_db *db, const bdaddr_t *adapter_bdaddr) +{ + bass_db_new(db, adapter_bdaddr); +} + +int bt_bass_send(struct bt_bass *bass, + struct bt_bass_bcast_audio_scan_cp_hdr *hdr, + struct iovec *params) +{ + struct iovec req = {0}; + uint16_t handle; + int err = 0; + + if (!bass || !bass->client || !bass->rdb) + return -EINVAL; + + DBG(bass, "bass %p", bass); + + req.iov_base = malloc0(sizeof(*hdr) + params->iov_len); + if (!req.iov_base) + return -EINVAL; + + util_iov_push_mem(&req, sizeof(*hdr), hdr); + util_iov_push_mem(&req, params->iov_len, params->iov_base); + + if (!gatt_db_attribute_get_char_data(bass->rdb->bcast_audio_scan_cp, + NULL, &handle, NULL, NULL, NULL)) { + err = -EINVAL; + goto done; + } + + if (!bt_gatt_client_write_without_response(bass->client, handle, + false, req.iov_base, req.iov_len)) + err = -EINVAL; + +done: + free(req.iov_base); + + return err; +} + +static void bt_bass_notify_all(struct gatt_db_attribute *attr, + struct iovec *iov) +{ + const struct queue_entry *entry; + + for (entry = queue_get_entries(sessions); entry; entry = entry->next) { + struct bt_bass *bass = entry->data; + + gatt_db_attribute_notify(attr, iov->iov_base, + iov->iov_len, bt_bass_get_att(bass)); + } +} + +int bt_bass_set_pa_sync(struct bt_bcast_src *bcast_src, uint8_t sync_state) +{ + struct iovec *iov; + + if (!bcast_src) + return -EINVAL; + + bcast_src->sync_state = sync_state; + + iov = bass_parse_bcast_src(bcast_src); + if (!iov) + return -ENOMEM; + + bt_bass_notify_all(bcast_src->attr, iov); + + free(iov->iov_base); + free(iov); + + return 0; +} + +int bt_bass_set_bis_sync(struct bt_bcast_src *bcast_src, uint8_t bis) +{ + struct iovec *iov; + + for (uint8_t i = 0; i < bcast_src->num_subgroups; i++) { + struct bt_bass_subgroup_data *sgrp = + &bcast_src->subgroup_data[i]; + uint32_t bitmask = 1 << (bis - 1); + + if (sgrp->pending_bis_sync & bitmask) { + sgrp->bis_sync |= bitmask; + + if (bcast_src->enc == BT_BASS_BIG_ENC_STATE_BCODE_REQ) + bcast_src->enc = BT_BASS_BIG_ENC_STATE_DEC; + + iov = bass_parse_bcast_src(bcast_src); + if (!iov) + return -ENOMEM; + + bt_bass_notify_all(bcast_src->attr, iov); + + free(iov->iov_base); + free(iov); + } + } + + return 0; +} + +int bt_bass_clear_bis_sync(struct bt_bcast_src *bcast_src, uint8_t bis) +{ + struct iovec *iov; + + for (uint8_t i = 0; i < bcast_src->num_subgroups; i++) { + struct bt_bass_subgroup_data *sgrp = + &bcast_src->subgroup_data[i]; + uint32_t bitmask = 1 << (bis - 1); + + if (sgrp->pending_bis_sync & bitmask) { + sgrp->bis_sync &= ~bitmask; + + iov = bass_parse_bcast_src(bcast_src); + if (!iov) + return -ENOMEM; + + bt_bass_notify_all(bcast_src->attr, iov); + + free(iov->iov_base); + free(iov); + } + } + + return 0; +} + +bool bt_bass_check_bis(struct bt_bcast_src *bcast_src, uint8_t bis) +{ + for (uint8_t i = 0; i < bcast_src->num_subgroups; i++) { + struct bt_bass_subgroup_data *sgrp = + &bcast_src->subgroup_data[i]; + uint32_t bitmask = 1 << (bis - 1); + + if (sgrp->pending_bis_sync & bitmask) + return true; + } + + return false; +} + +int bt_bass_set_enc(struct bt_bcast_src *bcast_src, uint8_t enc) +{ + struct iovec *iov; + + if (!bcast_src) + return -EINVAL; + + if (bcast_src->enc == enc) + return 0; + + bcast_src->enc = enc; + + iov = bass_parse_bcast_src(bcast_src); + if (!iov) + return -ENOMEM; + + bt_bass_notify_all(bcast_src->attr, iov); + + free(iov->iov_base); + free(iov); + + return 0; +} diff --git a/src/shared/bass.h b/src/shared/bass.h new file mode 100644 index 0000000000000000000000000000000000000000..d256b920d4e55d6c72ca5a7f8a69edd13ada1625 --- /dev/null +++ b/src/shared/bass.h @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright 2023-2024 NXP + * + */ + +struct bt_bass; +struct bt_bcast_src; + +#define NUM_BCAST_RECV_STATES 2 +#define BT_BASS_BCAST_CODE_SIZE 16 +#define BT_BASS_BIG_SYNC_FAILED_BITMASK 0xFFFFFFFF +#define BT_BASS_BCAST_SRC_LEN 15 +#define BT_BASS_BCAST_SRC_SUBGROUP_LEN 5 + +/* Application error codes */ +#define BT_BASS_ERROR_OPCODE_NOT_SUPPORTED 0x80 +#define BT_BASS_ERROR_INVALID_SOURCE_ID 0x81 + +/* PA_Sync_State values */ +#define BT_BASS_NOT_SYNCHRONIZED_TO_PA 0x00 +#define BT_BASS_SYNC_INFO_RE 0x01 +#define BT_BASS_SYNCHRONIZED_TO_PA 0x02 +#define BT_BASS_FAILED_TO_SYNCHRONIZE_TO_PA 0x03 +#define BT_BASS_NO_PAST 0x04 + +/* BIG_Encryption values */ +#define BT_BASS_BIG_ENC_STATE_NO_ENC 0x00 +#define BT_BASS_BIG_ENC_STATE_BCODE_REQ 0x01 +#define BT_BASS_BIG_ENC_STATE_DEC 0x02 +#define BT_BASS_BIG_ENC_STATE_BAD_CODE 0x03 + +/* Broadcast Audio Scan Control Point + * header structure + */ +struct bt_bass_bcast_audio_scan_cp_hdr { + uint8_t op; +} __packed; + +#define BT_BASS_REMOTE_SCAN_STOPPED 0x00 + +#define BT_BASS_REMOTE_SCAN_STARTED 0x01 + +#define BT_BASS_ADD_SRC 0x02 + +#define BT_BASS_ADDR_PUBLIC 0x00 +#define BT_BASS_ADDR_RANDOM 0x01 + +/* PA_Sync values */ +#define PA_SYNC_NO_SYNC 0x00 +#define PA_SYNC_PAST 0x01 +#define PA_SYNC_NO_PAST 0x02 + +/* BIS_Sync no preference bitmask */ +#define BIS_SYNC_NO_PREF 0xFFFFFFFF + +#define PA_INTERVAL_UNKNOWN 0xFFFF + +struct bt_bass_add_src_params { + uint8_t addr_type; + bdaddr_t addr; + uint8_t sid; + uint8_t bid[3]; + uint8_t pa_sync; + uint16_t pa_interval; + uint8_t num_subgroups; + uint8_t subgroup_data[]; +} __packed; + +#define BT_BASS_MOD_SRC 0x03 + +struct bt_bass_mod_src_params { + uint8_t id; + uint8_t pa_sync; + uint16_t pa_interval; + uint8_t num_subgroups; + uint8_t subgroup_data[]; +} __packed; + +#define BT_BASS_SET_BCAST_CODE 0x04 + +struct bt_bass_set_bcast_code_params { + uint8_t id; + uint8_t bcast_code[BT_BASS_BCAST_CODE_SIZE]; +} __packed; + +#define BT_BASS_REMOVE_SRC 0x05 + +struct bt_bass_remove_src_params { + uint8_t id; +} __packed; + +typedef void (*bt_bass_func_t)(struct bt_bass *bass, void *user_data); +typedef void (*bt_bass_destroy_func_t)(void *user_data); +typedef void (*bt_bass_debug_func_t)(const char *str, void *user_data); +typedef void (*bt_bass_src_func_t)(uint8_t id, uint32_t bid, uint8_t enc, + uint32_t bis_sync, void *user_data); + +typedef int (*bt_bass_cp_handler_func_t)(struct bt_bcast_src *bcast_src, + uint8_t op, void *params, void *user_data); + +struct bt_att *bt_bass_get_att(struct bt_bass *bass); +struct bt_gatt_client *bt_bass_get_client(struct bt_bass *bass); +unsigned int bt_bass_register(bt_bass_func_t attached, bt_bass_func_t detached, + void *user_data); +bool bt_bass_unregister(unsigned int id); +bool bt_bass_set_debug(struct bt_bass *bass, bt_bass_debug_func_t func, + void *user_data, bt_bass_destroy_func_t destroy); +struct bt_bass *bt_bass_new(struct gatt_db *ldb, struct gatt_db *rdb, + const bdaddr_t *adapter_bdaddr); +bool bt_bass_set_user_data(struct bt_bass *bass, void *user_data); +void bt_bass_unref(struct bt_bass *bass); +bool bt_bass_attach(struct bt_bass *bass, struct bt_gatt_client *client); +bool bt_bass_set_att(struct bt_bass *bass, struct bt_att *att); +void bt_bass_detach(struct bt_bass *bass); +void bt_bass_add_db(struct gatt_db *db, const bdaddr_t *adapter_bdaddr); +int bt_bass_send(struct bt_bass *bass, + struct bt_bass_bcast_audio_scan_cp_hdr *hdr, + struct iovec *params); +unsigned int bt_bass_src_register(struct bt_bass *bass, bt_bass_src_func_t cb, + void *user_data, bt_bass_destroy_func_t destroy); +bool bt_bass_src_unregister(struct bt_bass *bass, unsigned int id); +unsigned int bt_bass_cp_handler_register(struct bt_bass *bass, + bt_bass_cp_handler_func_t handler, + bt_bass_destroy_func_t destroy, + void *user_data); +bool bt_bass_cp_handler_unregister(struct bt_bass *bass, + unsigned int id); +int bt_bass_set_pa_sync(struct bt_bcast_src *bcast_src, uint8_t sync_state); +int bt_bass_set_bis_sync(struct bt_bcast_src *bcast_src, uint8_t bis); +int bt_bass_clear_bis_sync(struct bt_bcast_src *bcast_src, uint8_t bis); +bool bt_bass_check_bis(struct bt_bcast_src *bcast_src, uint8_t bis); +int bt_bass_set_enc(struct bt_bcast_src *bcast_src, uint8_t enc); diff --git a/src/shared/btsnoop.c b/src/shared/btsnoop.c index 0a68282bc0ad28a2856c264b445578f18e2e6526..bc5f7fcbe84c946c38ccdb23c4fc02e248216d7a 100644 --- a/src/shared/btsnoop.c +++ b/src/shared/btsnoop.c @@ -305,6 +305,9 @@ static uint32_t get_flags_from_opcode(uint16_t opcode) case BTSNOOP_OPCODE_SCO_TX_PKT: case BTSNOOP_OPCODE_SCO_RX_PKT: break; + case BTSNOOP_OPCODE_ISO_TX_PKT: + case BTSNOOP_OPCODE_ISO_RX_PKT: + break; case BTSNOOP_OPCODE_OPEN_INDEX: case BTSNOOP_OPCODE_CLOSE_INDEX: break; @@ -428,6 +431,14 @@ static bool pklg_read_hci(struct btsnoop *btsnoop, struct timeval *tv, *index = 0x0000; *opcode = BTSNOOP_OPCODE_SCO_RX_PKT; break; + case 0x12: + *index = 0x0000; + *opcode = BTSNOOP_OPCODE_ISO_TX_PKT; + break; + case 0x13: + *index = 0x0000; + *opcode = BTSNOOP_OPCODE_ISO_RX_PKT; + break; case 0x0b: *index = 0x0000; *opcode = BTSNOOP_OPCODE_VENDOR_DIAG; @@ -470,6 +481,11 @@ static uint16_t get_opcode_from_flags(uint8_t type, uint32_t flags) return BTSNOOP_OPCODE_SCO_TX_PKT; case 0x04: return BTSNOOP_OPCODE_EVENT_PKT; + case 0x05: + if (flags & 0x01) + return BTSNOOP_OPCODE_ISO_RX_PKT; + else + return BTSNOOP_OPCODE_ISO_TX_PKT; case 0xff: if (flags & 0x02) { if (flags & 0x01) @@ -513,7 +529,7 @@ bool btsnoop_read_hci(struct btsnoop *btsnoop, struct timeval *tv, return false; } - toread = be32toh(pkt.size); + toread = be32toh(pkt.len); if (toread > BTSNOOP_MAX_PACKET_SIZE) { btsnoop->aborted = true; return false; diff --git a/src/shared/ccp.c b/src/shared/ccp.c new file mode 100644 index 0000000000000000000000000000000000000000..8e1b0b58f93be2696a4716a85f78bb2c7c3cf244 --- /dev/null +++ b/src/shared/ccp.c @@ -0,0 +1,1226 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2022 Intel Corporation. All rights reserved. + * + */ + +#define _GNU_SOURCE +#include <inttypes.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> +#include <unistd.h> +#include <errno.h> + +#include "lib/bluetooth.h" +#include "lib/uuid.h" +#include "lib/hci.h" + +#include "src/shared/queue.h" +#include "src/shared/util.h" +#include "src/shared/timeout.h" +#include "src/shared/att.h" +#include "src/shared/gatt-db.h" +#include "src/shared/gatt-server.h" +#include "src/shared/gatt-client.h" +#include "src/shared/ccp.h" + +#define DBG(_ccp, fmt, arg...) \ + ccp_debug(_ccp, "%s:%s() " fmt, __FILE__, __func__, ## arg) + +struct bt_ccp_db { + struct gatt_db *db; + struct bt_ccs *ccs; +}; + +struct bt_ccp_pending { + unsigned int id; + struct bt_ccp *ccp; + bt_gatt_client_read_callback_t func; + void *user_data; +}; + +struct event_callback { + const struct bt_ccp_event_callback *cbs; + void *user_data; +}; + +struct bt_ccp { + int ref_count; + struct bt_gatt_client *client; + struct bt_ccp_db *ldb; + struct bt_ccp_db *rdb; + + unsigned int bearer_name_id; + unsigned int bearer_uci_id; + unsigned int bearer_technology_id; + unsigned int bearer_uri_schemes_list_id; + unsigned int signal_strength_id; + unsigned int signal_reporting_intrvl_id; + unsigned int current_call_list_id; + unsigned int ccid_id; + unsigned int status_flag_id; + unsigned int target_bearer_uri_id; + unsigned int call_state_id; + unsigned int call_control_pt_id; + unsigned int call_control_opt_opcode_id; + unsigned int termination_reason_id; + unsigned int incoming_call_id; + unsigned int friendly_name_id; + + struct event_callback *cb; + struct queue *pending; + + bt_ccp_debug_func_t debug_func; + bt_ccp_destroy_func_t debug_destroy; + void *debug_data; + void *user_data; +}; + +struct bt_ccs { + struct bt_ccp_db *mdb; + struct gatt_db_attribute *service; + struct gatt_db_attribute *bearer_name; + struct gatt_db_attribute *bearer_name_ccc; + struct gatt_db_attribute *bearer_uci; + struct gatt_db_attribute *bearer_technology; + struct gatt_db_attribute *bearer_technology_ccc; + struct gatt_db_attribute *bearer_uri_schemes_list; + struct gatt_db_attribute *signal_strength; + struct gatt_db_attribute *signal_strength_ccc; + struct gatt_db_attribute *signal_reporting_intrvl; + struct gatt_db_attribute *current_call_list; + struct gatt_db_attribute *current_call_list_ccc; + struct gatt_db_attribute *ccid; + struct gatt_db_attribute *status_flag; + struct gatt_db_attribute *status_flag_ccc; + struct gatt_db_attribute *target_bearer_uri; + struct gatt_db_attribute *call_state; + struct gatt_db_attribute *call_state_ccc; + struct gatt_db_attribute *call_ctrl_point; + struct gatt_db_attribute *call_ctrl_point_ccc; + struct gatt_db_attribute *call_ctrl_opt_opcode; + struct gatt_db_attribute *termination_reason; + struct gatt_db_attribute *termination_reason_ccc; + struct gatt_db_attribute *incoming_call; + struct gatt_db_attribute *incoming_call_ccc; + struct gatt_db_attribute *friendly_name; + struct gatt_db_attribute *friendly_name_ccc; +}; + +static struct queue *ccp_db; + +static void ccp_debug(struct bt_ccp *ccp, const char *format, ...) +{ + va_list ap; + + if (!ccp || !format || !ccp->debug_func) + return; + + va_start(ap, format); + util_debug_va(ccp->debug_func, ccp->debug_data, format, ap); + va_end(ap); +} + +static bool ccp_db_match(const void *data, const void *match_data) +{ + const struct bt_ccp_db *mdb = data; + const struct gatt_db *db = match_data; + + return (mdb->db == db); +} + +static void ccp_db_free(void *data) +{ + struct bt_ccp_db *bdb = data; + + if (!bdb) + return; + + gatt_db_unref(bdb->db); + + free(bdb->ccs); + free(bdb); +} + +static void ccp_free(void *data) +{ + struct bt_ccp *ccp = data; + + DBG(ccp, ""); + + bt_ccp_detach(ccp); + ccp_db_free(ccp->rdb); + queue_destroy(ccp->pending, NULL); + + free(ccp); +} + +struct bt_ccp *bt_ccp_ref(struct bt_ccp *ccp) +{ + if (!ccp) + return NULL; + + __sync_fetch_and_add(&ccp->ref_count, 1); + + return ccp; +} + +void bt_ccp_unref(struct bt_ccp *ccp) +{ + if (!ccp) + return; + + if (__sync_sub_and_fetch(&ccp->ref_count, 1)) + return; + + ccp_free(ccp); +} + +bool bt_ccp_set_user_data(struct bt_ccp *ccp, void *user_data) +{ + if (!ccp) + return false; + + ccp->user_data = user_data; + + return true; +} + +void *bt_ccp_get_user_data(struct bt_ccp *ccp) +{ + if (!ccp) + return NULL; + + return ccp->user_data; +} + +bool bt_ccp_set_debug(struct bt_ccp *ccp, bt_ccp_debug_func_t func, + void *user_data, + bt_ccp_destroy_func_t destroy) +{ + if (!ccp) + return false; + + if (ccp->debug_destroy) + ccp->debug_destroy(ccp->debug_data); + + ccp->debug_func = func; + ccp->debug_destroy = destroy; + ccp->debug_data = user_data; + + return true; +} + +static void ccs_call_state_read(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + int call_state = 0; + struct iovec iov; + + iov.iov_base = &call_state; + iov.iov_len = sizeof(int); + + gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base, iov.iov_len); +} + +static void ccs_call_state_write(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + const uint8_t *value, size_t len, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + gatt_db_attribute_write_result(attrib, id, + BT_ATT_ERROR_INSUFFICIENT_RESOURCES); +} + +static struct bt_ccs *ccs_new(struct gatt_db *db) +{ + struct bt_ccs *ccs; + bt_uuid_t uuid; + + if (!db) + return NULL; + + ccs = new0(struct bt_ccs, 1); + + /* Populate DB with ccs attributes */ + bt_uuid16_create(&uuid, GTBS_UUID); + ccs->service = gatt_db_add_service(db, &uuid, true, 42); + + bt_uuid16_create(&uuid, BEARER_PROVIDER_NAME_CHRC_UUID); + ccs->bearer_name = + gatt_db_service_add_characteristic(ccs->service, + &uuid, BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_NOTIFY, + ccs_call_state_read, NULL, + ccs); + + ccs->bearer_name_ccc = gatt_db_service_add_ccc(ccs->service, + BT_ATT_PERM_READ | + BT_ATT_PERM_WRITE); + + bt_uuid16_create(&uuid, BEARER_UCI_CHRC_UUID); + ccs->bearer_uci = + gatt_db_service_add_characteristic(ccs->service, + &uuid, BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ, + ccs_call_state_read, + NULL, ccs); + + bt_uuid16_create(&uuid, BEARER_TECH_CHRC_UUID); + ccs->bearer_technology = + gatt_db_service_add_characteristic(ccs->service, + &uuid, BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_NOTIFY, + ccs_call_state_read, NULL, + ccs); + + ccs->bearer_technology_ccc = gatt_db_service_add_ccc(ccs->service, + BT_ATT_PERM_READ | + BT_ATT_PERM_WRITE); + + bt_uuid16_create(&uuid, BEARER_URI_SCHEME_CHRC_UUID); + ccs->bearer_uri_schemes_list = + gatt_db_service_add_characteristic(ccs->service, + &uuid, BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ, + ccs_call_state_read, NULL, + ccs); + + bt_uuid16_create(&uuid, BEARER_SIGNAL_STR_CHRC_UUID); + ccs->signal_strength = + gatt_db_service_add_characteristic(ccs->service, + &uuid, BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_NOTIFY, + ccs_call_state_read, NULL, + ccs); + + ccs->signal_strength_ccc = gatt_db_service_add_ccc(ccs->service, + BT_ATT_PERM_READ | + BT_ATT_PERM_WRITE); + + bt_uuid16_create(&uuid, BEARER_SIGNAL_INTRVL_CHRC_UUID); + ccs->signal_reporting_intrvl = + gatt_db_service_add_characteristic(ccs->service, + &uuid, BT_ATT_PERM_READ | + BT_ATT_PERM_WRITE, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_WRITE | + BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP, + ccs_call_state_read, + ccs_call_state_write, ccs); + + bt_uuid16_create(&uuid, CURR_CALL_LIST_CHRC_UUID); + ccs->current_call_list = + gatt_db_service_add_characteristic(ccs->service, + &uuid, BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_NOTIFY, + ccs_call_state_read, NULL, + ccs); + + ccs->current_call_list_ccc = gatt_db_service_add_ccc(ccs->service, + BT_ATT_PERM_READ | + BT_ATT_PERM_WRITE); + + bt_uuid16_create(&uuid, BEARER_CCID_CHRC_UUID); + ccs->ccid = gatt_db_service_add_characteristic(ccs->service, + &uuid, BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ, + ccs_call_state_read, + NULL, ccs); + + bt_uuid16_create(&uuid, CALL_STATUS_FLAG_CHRC_UUID); + ccs->status_flag = + gatt_db_service_add_characteristic(ccs->service, + &uuid, BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_NOTIFY, + ccs_call_state_read, NULL, + ccs); + + ccs->status_flag_ccc = gatt_db_service_add_ccc(ccs->service, + BT_ATT_PERM_READ | + BT_ATT_PERM_WRITE); + + bt_uuid16_create(&uuid, INCOM_CALL_TARGET_URI_CHRC_UUID); + ccs->target_bearer_uri = + gatt_db_service_add_characteristic(ccs->service, + &uuid, BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ, + ccs_call_state_read, NULL, + ccs); + + bt_uuid16_create(&uuid, CALL_STATE_CHRC_UUID); + ccs->call_ctrl_point = + gatt_db_service_add_characteristic(ccs->service, + &uuid, BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_NOTIFY, + ccs_call_state_read, NULL, + ccs); + + ccs->call_ctrl_point_ccc = gatt_db_service_add_ccc(ccs->service, + BT_ATT_PERM_READ | + BT_ATT_PERM_WRITE); + + bt_uuid16_create(&uuid, CALL_CTRL_POINT_CHRC_UUID); + ccs->call_ctrl_opt_opcode = + gatt_db_service_add_characteristic(ccs->service, + &uuid, BT_ATT_PERM_WRITE, + BT_GATT_CHRC_PROP_WRITE | + BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP + | BT_GATT_CHRC_PROP_NOTIFY, + NULL, ccs_call_state_write, + ccs); + + bt_uuid16_create(&uuid, CALL_CTRL_POINT_OPT_OPCODE_CHRC_UUID); + ccs->call_ctrl_opt_opcode = + gatt_db_service_add_characteristic(ccs->service, + &uuid, BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ, + ccs_call_state_read, NULL, + ccs); + + bt_uuid16_create(&uuid, TERMINATION_REASON_CHRC_UUID); + ccs->termination_reason = + gatt_db_service_add_characteristic(ccs->service, + &uuid, BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_NOTIFY, + ccs_call_state_read, NULL, + ccs); + + bt_uuid16_create(&uuid, INCOMING_CALL_CHRC_UUID); + ccs->incoming_call = + gatt_db_service_add_characteristic(ccs->service, + &uuid, BT_ATT_PERM_NONE, + BT_GATT_CHRC_PROP_NOTIFY, + NULL, NULL, ccs); + + ccs->incoming_call_ccc = gatt_db_service_add_ccc(ccs->service, + BT_ATT_PERM_READ | + BT_ATT_PERM_WRITE); + + bt_uuid16_create(&uuid, CALL_FRIENDLY_NAME_CHRC_UUID); + ccs->friendly_name = + gatt_db_service_add_characteristic(ccs->service, + &uuid, BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_NOTIFY, + ccs_call_state_read, NULL, + ccs); + + ccs->friendly_name_ccc = gatt_db_service_add_ccc(ccs->service, + BT_ATT_PERM_READ | + BT_ATT_PERM_WRITE); + + gatt_db_service_set_active(ccs->service, false); + + return ccs; +} + +static struct bt_ccs *ccp_get_ccs(struct bt_ccp *ccp) +{ + if (!ccp) + return NULL; + + if (ccp->rdb->ccs) + return ccp->rdb->ccs; + + ccp->rdb->ccs = new0(struct bt_ccs, 1); + ccp->rdb->ccs->mdb = ccp->rdb; + + return ccp->rdb->ccs; +} + +static void ccp_pending_destroy(void *data) +{ + struct bt_ccp_pending *pending = data; + struct bt_ccp *ccp = pending->ccp; + + queue_remove_if(ccp->pending, NULL, pending); +} + +static void ccp_pending_complete(bool success, uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) +{ + struct bt_ccp_pending *pending = user_data; + + if (pending->func) + pending->func(success, att_ecode, value, length, + pending->user_data); +} + +static void ccp_read_value(struct bt_ccp *ccp, uint16_t value_handle, + bt_gatt_client_read_callback_t func, + void *user_data) +{ + struct bt_ccp_pending *pending; + + pending = new0(struct bt_ccp_pending, 1); + pending->ccp = ccp; + pending->func = func; + pending->user_data = user_data; + + pending->id = bt_gatt_client_read_value(ccp->client, value_handle, + ccp_pending_complete, pending, + ccp_pending_destroy); + if (!pending->id) { + DBG(ccp, "Unable to send Read request"); + free(pending); + return; + } + + queue_push_tail(ccp->pending, pending); +} + +static void read_call_back(bool success, uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) +{ + struct bt_ccp *ccp = user_data; + + DBG(ccp, ""); + + if (!success) { + DBG(ccp, "Unable to read call state: error 0x%02x", att_ecode); + return; + } +} + +static void ccp_cb_register(uint16_t att_ecode, void *user_data) +{ + struct bt_ccp *ccp = user_data; + + if (att_ecode) + DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode); + + /* TODO: generic handler for non-mandatory CCP call backs */ +} + +static void ccp_cb_notify(uint16_t value_handle, const uint8_t *value, + uint16_t length, void *user_data) +{ + /* TODO: generic handler for non-mandatory CCP notifications */ +} + +static void ccp_cb_status_flag_register(uint16_t att_ecode, void *user_data) +{ + struct bt_ccp *ccp = user_data; + + if (att_ecode) + DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode); +} + +static void ccp_cb_status_flag_notify(uint16_t value_handle, + const uint8_t *value, + uint16_t length, void *user_data) +{ + struct bt_ccp *ccp = user_data; + + DBG(ccp, ""); + + if (!length) + return; +} + +static void ccp_cb_terminate_register(uint16_t att_ecode, void *user_data) +{ + struct bt_ccp *ccp = user_data; + + if (att_ecode) + DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode); +} + +static void ccp_cb_terminate_notify(uint16_t value_handle, const uint8_t *value, + uint16_t length, void *user_data) +{ + struct bt_ccp *ccp = user_data; + + DBG(ccp, ""); + + if (!length) + return; + + /* TODO: update call state in Local context */ +} + +static void ccp_cb_bearer_name_register(uint16_t att_ecode, void *user_data) +{ + struct bt_ccp *ccp = user_data; + + DBG(ccp, ""); + + if (att_ecode) + DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode); +} + +static void ccp_cb_bearer_name_notify(uint16_t value_handle, + const uint8_t *value, + uint16_t length, void *user_data) +{ + struct bt_ccp *ccp = user_data; + + DBG(ccp, ""); + + if (!length) + return; + + /* TODO: update call details in Local context */ +} + +static void ccp_cb_call_list_register(uint16_t att_ecode, void *user_data) +{ + struct bt_ccp *ccp = user_data; + + DBG(ccp, ""); + + if (att_ecode) + DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode); +} + +static void ccp_cb_call_list_notify(uint16_t value_handle, const uint8_t *value, + uint16_t length, void *user_data) +{ + struct bt_ccp *ccp = user_data; + + DBG(ccp, ""); + + if (!length) + return; + + /* TODO: update call list in Local context */ +} + +static void ccp_cb_call_state_register(uint16_t att_ecode, void *user_data) +{ + struct bt_ccp *ccp = user_data; + + DBG(ccp, ""); + + if (att_ecode) + DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode); +} + +static void ccp_cb_call_state_notify(uint16_t value_handle, + const uint8_t *value, + uint16_t length, void *user_data) +{ + struct bt_ccp *ccp = user_data; + + DBG(ccp, ""); + + if (!length) + return; + + /* TODO: update call state in Local context */ +} + +static void ccp_cb_incom_call_register(uint16_t att_ecode, void *user_data) +{ + struct bt_ccp *ccp = user_data; + + DBG(ccp, ""); + + if (att_ecode) + DBG(ccp, "ccp cb notification failed: 0x%04x", att_ecode); +} + +static void ccp_cb_incom_call_notify(uint16_t value_handle, + const uint8_t *value, + uint16_t length, void *user_data) +{ + struct bt_ccp *ccp = user_data; + + DBG(ccp, ""); + + if (!length) + return; + + /* TODO: Handle incoming call notofiation, Answer/reject etc */ +} + +static void bt_ccp_incom_call_attach(struct bt_ccp *ccp) +{ + uint16_t value_handle; + struct bt_ccs *ccs = ccp_get_ccs(ccp); + + DBG(ccp, ""); + + if (!gatt_db_attribute_get_char_data(ccs->incoming_call, NULL, + &value_handle, + NULL, NULL, NULL)) + return; + + ccp_read_value(ccp, value_handle, read_call_back, ccp); + + ccp->incoming_call_id = + bt_gatt_client_register_notify(ccp->client, + value_handle, + ccp_cb_incom_call_register, + ccp_cb_incom_call_notify, ccp, + NULL); +} + +static void bt_ccp_call_state_attach(struct bt_ccp *ccp) +{ + uint16_t value_handle; + struct bt_ccs *ccs = ccp_get_ccs(ccp); + + DBG(ccp, ""); + + if (!gatt_db_attribute_get_char_data(ccs->call_state, NULL, + &value_handle, + NULL, NULL, NULL)) + return; + + ccp_read_value(ccp, value_handle, read_call_back, ccp); + + ccp->call_state_id = + bt_gatt_client_register_notify(ccp->client, + value_handle, + ccp_cb_call_state_register, + ccp_cb_call_state_notify, ccp, + NULL); +} + +static void bt_ccp_call_list_attach(struct bt_ccp *ccp) +{ + uint16_t value_handle; + struct bt_ccs *ccs = ccp_get_ccs(ccp); + + DBG(ccp, ""); + + if (!gatt_db_attribute_get_char_data(ccs->current_call_list, NULL, + &value_handle, + NULL, NULL, NULL)) + return; + + ccp_read_value(ccp, value_handle, read_call_back, ccp); + + ccp->current_call_list_id = + bt_gatt_client_register_notify(ccp->client, + value_handle, + ccp_cb_call_list_register, + ccp_cb_call_list_notify, ccp, + NULL); +} + +static void bt_ccp_name_attach(struct bt_ccp *ccp) +{ + uint16_t value_handle; + struct bt_ccs *ccs = ccp_get_ccs(ccp); + + DBG(ccp, ""); + + if (!gatt_db_attribute_get_char_data(ccs->bearer_name, NULL, + &value_handle, + NULL, NULL, NULL)) + return; + + ccp_read_value(ccp, value_handle, read_call_back, ccp); + + ccp->bearer_name_id = + bt_gatt_client_register_notify(ccp->client, + value_handle, + ccp_cb_bearer_name_register, + ccp_cb_bearer_name_notify, ccp, + NULL); +} + +static void bt_ccp_term_reason_attach(struct bt_ccp *ccp) +{ + uint16_t value_handle; + struct bt_ccs *ccs = ccp_get_ccs(ccp); + + DBG(ccp, ""); + + if (!gatt_db_attribute_get_char_data(ccs->termination_reason, NULL, + &value_handle, NULL, NULL, NULL)) + return; + + ccp_read_value(ccp, value_handle, read_call_back, ccp); + + ccp->termination_reason_id = + bt_gatt_client_register_notify(ccp->client, + value_handle, + ccp_cb_terminate_register, + ccp_cb_terminate_notify, ccp, + NULL); +} + +static void bt_ccp_status_attach(struct bt_ccp *ccp) +{ + uint16_t value_handle; + struct bt_ccs *ccs = ccp_get_ccs(ccp); + + DBG(ccp, ""); + + if (!gatt_db_attribute_get_char_data(ccs->status_flag, NULL, + &value_handle, + NULL, NULL, NULL)) + return; + + ccp_read_value(ccp, value_handle, read_call_back, ccp); + + ccp->status_flag_id = + bt_gatt_client_register_notify(ccp->client, + value_handle, + ccp_cb_status_flag_register, + ccp_cb_status_flag_notify, ccp, + NULL); +} + +static void bt_ccp_uci_attach(struct bt_ccp *ccp) +{ + uint16_t value_handle; + struct bt_ccs *ccs = ccp_get_ccs(ccp); + + DBG(ccp, ""); + + if (!gatt_db_attribute_get_char_data(ccs->bearer_uci, NULL, + &value_handle, + NULL, NULL, NULL)) + return; + + ccp_read_value(ccp, value_handle, read_call_back, ccp); + + ccp->bearer_uci_id = bt_gatt_client_register_notify(ccp->client, + value_handle, + ccp_cb_register, + ccp_cb_notify, ccp, + NULL); +} + +static void bt_ccp_technology_attach(struct bt_ccp *ccp) +{ + uint16_t value_handle; + struct bt_ccs *ccs = ccp_get_ccs(ccp); + + DBG(ccp, ""); + + if (!gatt_db_attribute_get_char_data(ccs->bearer_technology, NULL, + &value_handle, + NULL, NULL, NULL)) + return; + + ccp_read_value(ccp, value_handle, read_call_back, ccp); + + ccp->bearer_technology_id = + bt_gatt_client_register_notify(ccp->client, + value_handle, ccp_cb_register, + ccp_cb_notify, ccp, NULL); +} + +static void bt_ccp_strength_attach(struct bt_ccp *ccp) +{ + uint16_t value_handle; + struct bt_ccs *ccs = ccp_get_ccs(ccp); + + DBG(ccp, ""); + + if (!gatt_db_attribute_get_char_data(ccs->signal_strength, NULL, + &value_handle, + NULL, NULL, NULL)) + return; + + ccp_read_value(ccp, value_handle, read_call_back, ccp); + + ccp->signal_strength_id = + bt_gatt_client_register_notify(ccp->client, value_handle, + ccp_cb_register, ccp_cb_notify, + ccp, NULL); +} + +static void bt_ccp_ccid_attach(struct bt_ccp *ccp) +{ + uint16_t value_handle; + struct bt_ccs *ccs = ccp_get_ccs(ccp); + + DBG(ccp, ""); + + if (!gatt_db_attribute_get_char_data(ccs->ccid, NULL, &value_handle, + NULL, NULL, NULL)) + return; + + ccp_read_value(ccp, value_handle, read_call_back, ccp); + + ccp->ccid_id = bt_gatt_client_register_notify(ccp->client, + value_handle, + ccp_cb_register, + ccp_cb_notify, ccp, NULL); +} + +static void bt_ccp_tar_uri_attach(struct bt_ccp *ccp) +{ + uint16_t value_handle; + struct bt_ccs *ccs = ccp_get_ccs(ccp); + + DBG(ccp, ""); + + if (!gatt_db_attribute_get_char_data(ccs->target_bearer_uri, NULL, + &value_handle, + NULL, NULL, NULL)) + return; + + ccp_read_value(ccp, value_handle, read_call_back, ccp); + + ccp->target_bearer_uri_id = + bt_gatt_client_register_notify(ccp->client, + value_handle, ccp_cb_register, + ccp_cb_notify, ccp, + NULL); +} + +static void bt_ccp_ctrl_point_attach(struct bt_ccp *ccp) +{ + uint16_t value_handle; + struct bt_ccs *ccs = ccp_get_ccs(ccp); + + DBG(ccp, ""); + + if (!gatt_db_attribute_get_char_data(ccs->call_ctrl_point, NULL, + &value_handle, + NULL, NULL, NULL)) + return; + + ccp_read_value(ccp, value_handle, read_call_back, ccp); + + ccp->call_control_pt_id = + bt_gatt_client_register_notify(ccp->client, + value_handle, ccp_cb_register, + ccp_cb_notify, ccp, NULL); +} + +static void bt_ccp_ctrl_opcode_attach(struct bt_ccp *ccp) +{ + uint16_t value_handle; + struct bt_ccs *ccs = ccp_get_ccs(ccp); + + DBG(ccp, ""); + + if (!gatt_db_attribute_get_char_data(ccs->call_ctrl_opt_opcode, NULL, + &value_handle, + NULL, NULL, NULL)) + return; + + ccp_read_value(ccp, value_handle, read_call_back, ccp); + + ccp->call_control_opt_opcode_id = + bt_gatt_client_register_notify(ccp->client, + value_handle, ccp_cb_register, + ccp_cb_notify, ccp, NULL); +} + +static void bt_ccp_friendly_name_attach(struct bt_ccp *ccp) +{ + uint16_t value_handle; + struct bt_ccs *ccs = ccp_get_ccs(ccp); + + DBG(ccp, ""); + + if (!gatt_db_attribute_get_char_data(ccs->friendly_name, NULL, + &value_handle, + NULL, NULL, NULL)) + return; + + ccp_read_value(ccp, value_handle, read_call_back, ccp); + + ccp->friendly_name_id = + bt_gatt_client_register_notify(ccp->client, + value_handle, ccp_cb_register, + ccp_cb_notify, ccp, NULL); +} + +static void bt_ccp_signal_intrvl_attach(struct bt_ccp *ccp) +{ + uint16_t value_handle; + struct bt_ccs *ccs = ccp_get_ccs(ccp); + + DBG(ccp, ""); + + if (!gatt_db_attribute_get_char_data(ccs->signal_reporting_intrvl, NULL, + &value_handle, + NULL, NULL, NULL)) + return; + + ccp_read_value(ccp, value_handle, read_call_back, ccp); + + ccp->signal_reporting_intrvl_id = + bt_gatt_client_register_notify(ccp->client, + value_handle, ccp_cb_register, + ccp_cb_notify, ccp, NULL); +} + +static void bt_ccp_uri_list_attach(struct bt_ccp *ccp) +{ + uint16_t value_handle; + struct bt_ccs *ccs = ccp_get_ccs(ccp); + + DBG(ccp, ""); + + if (!gatt_db_attribute_get_char_data(ccs->bearer_uri_schemes_list, NULL, + &value_handle, + NULL, NULL, NULL)) + return; + + ccp_read_value(ccp, value_handle, read_call_back, ccp); + + ccp->bearer_uri_schemes_list_id = + bt_gatt_client_register_notify(ccp->client, + value_handle, ccp_cb_register, + ccp_cb_notify, ccp, NULL); +} + +static void foreach_ccs_char(struct gatt_db_attribute *attr, void *user_data) +{ + struct bt_ccp *ccp = user_data; + struct bt_ccs *ccs; + uint16_t value_handle; + bt_uuid_t uuid; + + if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, + NULL, NULL, &uuid)) + return; + + ccs = ccp_get_ccs(ccp); + if (!ccs || ccs->call_state) + return; + + if (bt_uuid16_cmp(&uuid, BEARER_PROVIDER_NAME_CHRC_UUID)) { + DBG(ccp, "Found Bearer Name, handle 0x%04x", value_handle); + + ccs->bearer_name = attr; + bt_ccp_name_attach(ccp); + } + + if (bt_uuid16_cmp(&uuid, BEARER_UCI_CHRC_UUID)) { + DBG(ccp, "Found Bearer Uci, handle 0x%04x", value_handle); + + ccs->bearer_uci = attr; + bt_ccp_uci_attach(ccp); + } + + if (bt_uuid16_cmp(&uuid, BEARER_TECH_CHRC_UUID)) { + DBG(ccp, "Found Bearer Technology, handle %x", value_handle); + + ccs->bearer_technology = attr; + bt_ccp_technology_attach(ccp); + } + + if (bt_uuid16_cmp(&uuid, BEARER_SIGNAL_STR_CHRC_UUID)) { + DBG(ccp, "Found Signal Strength, handle 0x%04x", value_handle); + + ccs->signal_strength = attr; + bt_ccp_strength_attach(ccp); + } + + if (bt_uuid16_cmp(&uuid, BEARER_SIGNAL_INTRVL_CHRC_UUID)) { + DBG(ccp, "Found Signal Interval, handle 0x%04x", value_handle); + + ccs->signal_reporting_intrvl = attr; + bt_ccp_signal_intrvl_attach(ccp); + } + + if (bt_uuid16_cmp(&uuid, CALL_STATUS_FLAG_CHRC_UUID)) { + DBG(ccp, "Found Status Flag, handle 0x%04x", value_handle); + + ccs->status_flag = attr; + bt_ccp_status_attach(ccp); + } + + if (bt_uuid16_cmp(&uuid, BEARER_URI_SCHEME_CHRC_UUID)) { + DBG(ccp, "Found URI Scheme, handle 0x%04x", value_handle); + + ccs->bearer_uri_schemes_list = attr; + bt_ccp_uri_list_attach(ccp); + } + + if (bt_uuid16_cmp(&uuid, CURR_CALL_LIST_CHRC_UUID)) { + DBG(ccp, "Found Call List, handle 0x%04x", value_handle); + + ccs->current_call_list = attr; + bt_ccp_call_list_attach(ccp); + } + + if (bt_uuid16_cmp(&uuid, BEARER_CCID_CHRC_UUID)) { + DBG(ccp, "Found CCID, handle 0x%04x", value_handle); + + ccs->ccid = attr; + bt_ccp_ccid_attach(ccp); + } + + if (bt_uuid16_cmp(&uuid, INCOM_CALL_TARGET_URI_CHRC_UUID)) { + DBG(ccp, "Found Bearer Uri, handle 0x%04x", value_handle); + + ccs->target_bearer_uri = attr; + bt_ccp_tar_uri_attach(ccp); + } + + if (bt_uuid16_cmp(&uuid, CALL_CTRL_POINT_CHRC_UUID)) { + DBG(ccp, "Found Control Point, handle 0x%04x", value_handle); + + ccs->call_ctrl_point = attr; + bt_ccp_ctrl_point_attach(ccp); + } + + if (bt_uuid16_cmp(&uuid, CALL_CTRL_POINT_OPT_OPCODE_CHRC_UUID)) { + DBG(ccp, "Found Control opcode, handle 0x%04x", value_handle); + + ccs->call_ctrl_opt_opcode = attr; + bt_ccp_ctrl_opcode_attach(ccp); + } + + if (bt_uuid16_cmp(&uuid, TERMINATION_REASON_CHRC_UUID)) { + DBG(ccp, "Found Termination Reason, handle %x", value_handle); + + ccs->termination_reason = attr; + bt_ccp_term_reason_attach(ccp); + } + + if (bt_uuid16_cmp(&uuid, INCOMING_CALL_CHRC_UUID)) { + DBG(ccp, "Found Incoming call, handle 0x%04x", value_handle); + + ccs->incoming_call = attr; + bt_ccp_incom_call_attach(ccp); + } + + if (bt_uuid16_cmp(&uuid, CALL_FRIENDLY_NAME_CHRC_UUID)) { + DBG(ccp, "Found Friendly name, handle 0x%04x", value_handle); + + ccs->friendly_name = attr; + bt_ccp_friendly_name_attach(ccp); + } +} + +void bt_ccp_set_event_callbacks(struct bt_ccp *ccp, + const struct bt_ccp_event_callback *cbs, + void *user_data) +{ + struct event_callback *cb; + + if (ccp->cb) + free(ccp->cb); + + cb = new0(struct event_callback, 1); + cb->cbs = cbs; + cb->user_data = user_data; + + ccp->cb = cb; +} + +static void foreach_ccs_service(struct gatt_db_attribute *attr, + void *user_data) +{ + struct bt_ccp *ccp = user_data; + struct bt_ccs *ccs = ccp_get_ccs(ccp); + + ccs->service = attr; + + gatt_db_service_foreach_char(attr, foreach_ccs_char, ccp); +} + +static struct bt_ccp_db *ccp_db_new(struct gatt_db *db) +{ + struct bt_ccp_db *mdb; + + if (!db) + return NULL; + + mdb = new0(struct bt_ccp_db, 1); + mdb->db = gatt_db_ref(db); + + if (!ccp_db) + ccp_db = queue_new(); + + queue_push_tail(ccp_db, mdb); + + mdb->ccs = ccs_new(db); + return mdb; +} + +static struct bt_ccp_db *ccp_get_db(struct gatt_db *db) +{ + struct bt_ccp_db *mdb; + + mdb = queue_find(ccp_db, ccp_db_match, db); + if (mdb) + return mdb; + + return ccp_db_new(db); +} + +struct bt_ccp *bt_ccp_new(struct gatt_db *ldb, struct gatt_db *rdb) +{ + struct bt_ccp *ccp; + struct bt_ccp_db *mdb; + + if (!ldb) + return NULL; + + mdb = ccp_get_db(ldb); + if (!mdb) + return NULL; + + ccp = new0(struct bt_ccp, 1); + ccp->ldb = mdb; + ccp->pending = queue_new(); + + if (!rdb) + goto done; + + mdb = new0(struct bt_ccp_db, 1); + mdb->db = gatt_db_ref(rdb); + + ccp->rdb = mdb; + +done: + bt_ccp_ref(ccp); + + return ccp; +} + +void bt_ccp_register(struct gatt_db *db) +{ + ccp_db_new(db); +} + +bool bt_ccp_attach(struct bt_ccp *ccp, struct bt_gatt_client *client) +{ + bt_uuid_t uuid; + + DBG(ccp, "ccp %p", ccp); + + ccp->client = bt_gatt_client_clone(client); + if (!ccp->client) + return false; + + if (ccp->rdb->ccs) { + bt_ccp_call_state_attach(ccp); + return true; + } + + bt_uuid16_create(&uuid, GTBS_UUID); + gatt_db_foreach_service(ccp->rdb->db, &uuid, foreach_ccs_service, ccp); + + return true; +} + +void bt_ccp_detach(struct bt_ccp *ccp) +{ + DBG(ccp, "%p", ccp); + + bt_gatt_client_unref(ccp->client); + ccp->client = NULL; +} diff --git a/src/shared/ccp.h b/src/shared/ccp.h new file mode 100644 index 0000000000000000000000000000000000000000..28b8b034ece3a80e6a9c8f16c25fbeda242947f5 --- /dev/null +++ b/src/shared/ccp.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + */ + +#include <stdbool.h> +#include <inttypes.h> + +#ifndef __packed +#define __packed __attribute__((packed)) +#endif + +struct bt_ccp; +struct bt_ccp_db; +struct bt_ccp_session_info; + +typedef void (*bt_ccp_debug_func_t)(const char *str, void *user_data); +typedef void (*bt_ccp_destroy_func_t)(void *user_data); + +struct bt_ccp_event_callback { + void (*call_state)(struct bt_ccp *ccp, const uint8_t *value, + uint16_t length); +}; + +void bt_ccp_set_event_callbacks(struct bt_ccp *ccp, + const struct bt_ccp_event_callback *cbs, + void *user_data); + +bool bt_ccp_set_debug(struct bt_ccp *ccp, bt_ccp_debug_func_t cb, + void *user_data, bt_ccp_destroy_func_t destroy); + +void bt_ccp_register(struct gatt_db *db); +bool bt_ccp_attach(struct bt_ccp *ccp, struct bt_gatt_client *client); +void bt_ccp_detach(struct bt_ccp *ccp); + +struct bt_ccp *bt_ccp_new(struct gatt_db *ldb, struct gatt_db *rdb); +struct bt_ccp *bt_ccp_ref(struct bt_ccp *ccp); +void bt_ccp_unref(struct bt_ccp *ccp); + +bool bt_ccp_set_user_data(struct bt_ccp *ccp, void *user_data); +void *bt_ccp_get_user_data(struct bt_ccp *ccp); diff --git a/src/shared/crypto.c b/src/shared/crypto.c index d5efa416dd9966d9012a8ce9d80a69d19939cb8b..5449621b55eade72682aee92f9b7c70f2232f3fc 100644 --- a/src/shared/crypto.c +++ b/src/shared/crypto.c @@ -586,41 +586,55 @@ bool bt_crypto_s1(struct bt_crypto *crypto, const uint8_t k[16], return bt_crypto_e(crypto, k, res, res); } -static bool aes_cmac(struct bt_crypto *crypto, const uint8_t key[16], +static bool aes_cmac_be(struct bt_crypto *crypto, const uint8_t key[16], const uint8_t *msg, size_t msg_len, uint8_t res[16]) { - uint8_t key_msb[16], out[16], msg_msb[CMAC_MSG_MAX]; ssize_t len; int fd; if (msg_len > CMAC_MSG_MAX) return false; - swap_buf(key, key_msb, 16); - fd = alg_new(crypto->cmac_aes, key_msb, 16); + fd = alg_new(crypto->cmac_aes, key, 16); if (fd < 0) return false; - swap_buf(msg, msg_msb, msg_len); - len = send(fd, msg_msb, msg_len, 0); + len = send(fd, msg, msg_len, 0); if (len < 0) { close(fd); return false; } - len = read(fd, out, 16); + len = read(fd, res, 16); if (len < 0) { close(fd); return false; } - swap_buf(out, res, 16); - close(fd); return true; } +static bool aes_cmac(struct bt_crypto *crypto, const uint8_t key[16], + const uint8_t *msg, size_t msg_len, uint8_t res[16]) +{ + uint8_t key_msb[16], out[16], msg_msb[CMAC_MSG_MAX]; + + if (msg_len > CMAC_MSG_MAX) + return false; + + swap_buf(key, key_msb, 16); + swap_buf(msg, msg_msb, msg_len); + + if (!aes_cmac_be(crypto, key_msb, msg_msb, msg_len, out)) + return false; + + swap_buf(out, res, 16); + + return true; +} + bool bt_crypto_f4(struct bt_crypto *crypto, uint8_t u[32], uint8_t v[32], uint8_t x[16], uint8_t z, uint8_t res[16]) { @@ -737,3 +751,218 @@ bool bt_crypto_gatt_hash(struct bt_crypto *crypto, struct iovec *iov, return true; } + +/* + * Resolvable Set Identifier hash function sih + * + * The RSI hash function sih is used to generate a hash value that is used in + * RSIs. + * + * The following variables are the inputs to the RSI hash function sih: + * + * k is 128 bits + * r is 24 bits + * padding is 104 bits, all set to 0 + * + * r is concatenated with padding to generate r', which is used as the 128-bit + * input parameter plaintextData to security function e: + * + * r'=padding||r + * + * The LSO of r becomes the LSO of r', and the MSO of padding becomes the MSO + * of r'. + * + * For example, if the 24-bit value r is 0x3A98B5, then r' is + * 0x000000000000000000000000003A98B5. + * + * The output of the Resolvable Set Identifier function sih is: + * + * sih(k, r)=e(k, r') mod 2^24 + * + * The output of the security function e is truncated to 24 bits by taking the + * least significant 24 bits of the output of e as the result of sih. + */ +bool bt_crypto_sih(struct bt_crypto *crypto, const uint8_t k[16], + const uint8_t r[3], uint8_t hash[3]) +{ + return bt_crypto_ah(crypto, k, r, hash); +} + +static bool aes_cmac_zero(struct bt_crypto *crypto, const uint8_t *msg, + size_t msg_len, uint8_t res[16]) +{ + const uint8_t zero[16] = {}; + + return aes_cmac_be(crypto, zero, msg, msg_len, res); +} + +/* The inputs to function s1 are: + * + * M is a non-zero length octet array or ASCII encoded string + * + * If M is an ASCII encoded string, M shall be converted into an integer number + * by replacing each string character with its ASCII code preserving the order. + * For example, if M is the string “CSISâ€, M is converted into the integer + * number: 0x4353 4953. + * + * ZERO is the 128-bit value: + * + * 0x0000 0000 0000 0000 0000 0000 0000 0000 + * + * The output of the salt generation function s1 shall be calculated as follows: + * + * s1(M)=AESâ€CMACZERO(M) + * + * Where AES-CMACZERO is the CMAC function defined in Section 4.2. + */ +static bool sef_s1(struct bt_crypto *crypto, const uint8_t *m, + size_t m_len, uint8_t res[16]) +{ + /* s1(M)=AESâ€CMACZERO(M) */ + return aes_cmac_zero(crypto, m, m_len, res); +} + +/* The key derivation function k1 is used to derive a key. The derived key is + * used to encrypt and decrypt the value of the Set Identity Resolving Key + * characteristic (see Section 5.1). + * + * The definition of this key generation function uses the MAC function + * AES-CMACT with a 128-bit key T. + * + * The inputs to function k1 are: + * + * N is 0 or more octets + * + * SALT is 128 bits + * + * P is 0 or more octets + * + * The key (T) shall be computed as follows: + * + * T=AESâ€CMACSALT(N) + * + * Where AES-CMACSALT is the CMAC function defined in Section 4.2. + * + * The output of the key generation function k1 shall be calculated as follows: + * + * k1(N, SALT, P)=AESâ€CMACT(P) + * + * Where AES-CMACT is the CMAC function defined in Section 4.2. + */ +static bool sef_k1(struct bt_crypto *crypto, const uint8_t n[16], + uint8_t salt[16], const uint8_t *p, + size_t p_len, uint8_t res[16]) +{ + uint8_t res1[16]; + + /* T=AESâ€CMACSALT(N) */ + if (!aes_cmac_be(crypto, salt, n, 16, res1)) + return false; + + /* k1(N, SALT, P)=AESâ€CMACT(P) */ + return aes_cmac_be(crypto, res1, p, p_len, res); +} + +/* + * SIRK encryption function sef + * + * The SIRK encryption function sef shall be used by the server to encrypt the + * SIRK with a key K. The value of K depends on the transport on which the Set + * Identity Resolving Key characteristic is read or notified. + * + * If the Set Identity Resolving Key characteristic is read or notified on the + * Basic Rate/Enhanced Data Rate (BR/EDR) transport, K shall be equal to the + * Link Key shared by the server and the client. + * + * K=LinkKey + * + * If the Set Identity Resolving Key characteristic is read or notified on the + * Bluetooth Low Energy (LE) transport, K shall be equal to the LTK shared by + * the server and client. That is, + * + * K=LTK + * + * The inputs to the function sef are: + * + * K is the key defined above in this section + * + * SIRK is the value of the SIRK to be encrypted + * + * The output of the SIRK encryption function sef is as follows: + * + * sef(K, SIRK)=k1(K, s1(“SIRKencâ€), “csisâ€)^SIRK + * + * Where ^ is the bitwise exclusive or operation. + */ +bool bt_crypto_sef(struct bt_crypto *crypto, const uint8_t k[16], + const uint8_t sirk[16], uint8_t out[16]) +{ + const uint8_t m[] = {'S', 'I', 'R', 'K', 'e', 'n', 'c'}; + const uint8_t p[] = {'c', 's', 'i', 's'}; + uint8_t k_msb[16]; + uint8_t salt[16]; + uint8_t res_msb[16]; + uint8_t res[16]; + + if (!crypto) + return false; + + /* salt = s1(“SIRKencâ€) */ + if (!sef_s1(crypto, m, sizeof(m), salt)) + return false; + + /* Convert K to MSB/BE format */ + swap_buf(k, k_msb, 16); + + /* res_msb = k1(K, salt, “csisâ€) */ + if (!sef_k1(crypto, k_msb, salt, p, sizeof(p), res_msb)) + return false; + + /* Convert back to LSB/LE format */ + swap_buf(res_msb, res, 16); + + /* res^SIRK */ + u128_xor(res, sirk, out); + + return true; +} + +/* Generates a SIRK from a string using the following steps: + * - Generate a hash (k) using the str as input + * - Generate a hash (sirk) using vendor, product, version and source as input + * - Encrypt sirk using k as LTK with sef function. + */ +bool bt_crypto_sirk(struct bt_crypto *crypto, const char *str, uint16_t vendor, + uint16_t product, uint16_t version, uint16_t source, + uint8_t sirk[16]) +{ + struct iovec iov[4]; + uint8_t k[16]; + uint8_t sirk_plaintext[16]; + + if (!crypto) + return false; + + iov[0].iov_base = (void *)str; + iov[0].iov_len = strlen(str); + + /* Generate a k using the str as input */ + if (!bt_crypto_gatt_hash(crypto, iov, 1, k)) + return false; + + iov[0].iov_base = &vendor; + iov[0].iov_len = sizeof(vendor); + iov[1].iov_base = &product; + iov[1].iov_len = sizeof(product); + iov[2].iov_base = &version; + iov[2].iov_len = sizeof(version); + iov[3].iov_base = &source; + iov[3].iov_len = sizeof(source); + + /* Generate a sirk using vendor, product, version and source as input */ + if (!bt_crypto_gatt_hash(crypto, iov, 4, sirk_plaintext)) + return false; + + /* Encrypt sirk using k as LTK with sef function */ + return bt_crypto_sef(crypto, k, sirk_plaintext, sirk); +} diff --git a/src/shared/crypto.h b/src/shared/crypto.h index 356326d75408f02723afd011dd4e06a8855cb0eb..d45308abf90a1fa470aa156fdd4a2eb7e8c8bcd5 100644 --- a/src/shared/crypto.h +++ b/src/shared/crypto.h @@ -53,3 +53,10 @@ bool bt_crypto_verify_att_sign(struct bt_crypto *crypto, const uint8_t key[16], const uint8_t *pdu, uint16_t pdu_len); bool bt_crypto_gatt_hash(struct bt_crypto *crypto, struct iovec *iov, size_t iov_len, uint8_t res[16]); +bool bt_crypto_sef(struct bt_crypto *crypto, const uint8_t k[16], + const uint8_t sirk[16], uint8_t out[16]); +bool bt_crypto_sih(struct bt_crypto *crypto, const uint8_t k[16], + const uint8_t r[3], uint8_t hash[3]); +bool bt_crypto_sirk(struct bt_crypto *crypto, const char *str, uint16_t vendor, + uint16_t product, uint16_t version, uint16_t source, + uint8_t sirk[16]); diff --git a/src/shared/csip.c b/src/shared/csip.c new file mode 100644 index 0000000000000000000000000000000000000000..a9c57c9bde4e0e7d4f003a0c99183b5bcc780d9e --- /dev/null +++ b/src/shared/csip.c @@ -0,0 +1,845 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2022 Intel Corporation. All rights reserved. + * + */ + +#define _GNU_SOURCE +#include <inttypes.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> +#include <unistd.h> +#include <errno.h> + +#include <glib.h> + +#include "lib/bluetooth.h" +#include "lib/uuid.h" + +#include "src/shared/queue.h" +#include "src/shared/util.h" +#include "src/shared/timeout.h" +#include "src/shared/att.h" +#include "src/shared/gatt-db.h" +#include "src/shared/gatt-server.h" +#include "src/shared/gatt-client.h" +#include "src/shared/crypto.h" +#include "src/shared/csip.h" + +#define DBG(_csip, fmt, arg...) \ + csip_debug(_csip, "%s:%s() " fmt, __FILE__, __func__, ## arg) + +/* SIRK is now hardcoded in the code. This can be moved + * to a configuration file. Since the code is to validate + * the CSIP use case of set member + */ +#define SIRK "761FAE703ED681F0C50B34155B6434FB" +#define CSIS_SIZE 0x02 +#define CSIS_LOCK 0x01 +#define CSIS_RANK 0x01 +#define CSIS_PLAINTEXT 0x01 +#define CSIS_ENC 0x02 + +struct bt_csip_db { + struct gatt_db *db; + struct bt_csis *csis; +}; + +struct csis_sirk { + uint8_t type; + uint8_t val[16]; +} __packed; + +struct bt_csis { + struct bt_csip_db *cdb; + struct csis_sirk *sirk_val; + uint8_t size_val; + uint8_t lock_val; + uint8_t rank_val; + struct gatt_db_attribute *service; + struct gatt_db_attribute *sirk; + struct gatt_db_attribute *size; + struct gatt_db_attribute *lock; + struct gatt_db_attribute *lock_ccc; + struct gatt_db_attribute *rank; + bt_csip_encrypt_func_t encrypt; +}; + +struct bt_csip_cb { + unsigned int id; + bt_csip_func_t attached; + bt_csip_func_t detached; + void *user_data; +}; + +struct bt_csip_ready { + unsigned int id; + bt_csip_ready_func_t func; + bt_csip_destroy_func_t destroy; + void *data; +}; + +struct bt_csip { + int ref_count; + struct bt_csip_db *ldb; + struct bt_csip_db *rdb; + struct bt_gatt_client *client; + struct bt_att *att; + + unsigned int idle_id; + struct queue *ready_cbs; + + bt_csip_debug_func_t debug_func; + bt_csip_destroy_func_t debug_destroy; + void *debug_data; + + bt_csip_sirk_func_t sirk_func; + void *sirk_data; + + void *user_data; +}; + +static struct queue *csip_db; +static struct queue *csip_cbs; +static struct queue *sessions; + +static void csip_detached(void *data, void *user_data) +{ + struct bt_csip_cb *cb = data; + struct bt_csip *csip = user_data; + + cb->detached(csip, cb->user_data); +} + +void bt_csip_detach(struct bt_csip *csip) +{ + if (!queue_remove(sessions, csip)) + return; + + bt_gatt_client_idle_unregister(csip->client, csip->idle_id); + + bt_gatt_client_unref(csip->client); + csip->client = NULL; + + queue_foreach(csip_cbs, csip_detached, csip); +} + +static void csis_free(struct bt_csis *csis) +{ + if (!csis) + return; + + free(csis->sirk_val); + free(csis); +} + +static void csip_db_free(void *data) +{ + struct bt_csip_db *cdb = data; + + if (!cdb) + return; + + gatt_db_unref(cdb->db); + + csis_free(cdb->csis); + free(cdb); +} + +static void csip_ready_free(void *data) +{ + struct bt_csip_ready *ready = data; + + if (ready->destroy) + ready->destroy(ready->data); + + free(ready); +} + +static void csip_free(void *data) +{ + struct bt_csip *csip = data; + + bt_csip_detach(csip); + + csip_db_free(csip->rdb); + + queue_destroy(csip->ready_cbs, csip_ready_free); + + free(csip); +} + +struct bt_att *bt_csip_get_att(struct bt_csip *csip) +{ + if (!csip) + return NULL; + + if (csip->att) + return csip->att; + + return bt_gatt_client_get_att(csip->client); +} + +struct bt_csip *bt_csip_ref(struct bt_csip *csip) +{ + if (!csip) + return NULL; + + __sync_fetch_and_add(&csip->ref_count, 1); + + return csip; +} + +static struct bt_csip *bt_csip_ref_safe(struct bt_csip *csip) +{ + if (!csip || !csip->ref_count) + return NULL; + + return bt_csip_ref(csip); +} + +void bt_csip_unref(struct bt_csip *csip) +{ + if (!csip) + return; + + if (__sync_sub_and_fetch(&csip->ref_count, 1)) + return; + + csip_free(csip); +} + +static void csip_debug(struct bt_csip *csip, const char *format, ...) +{ + va_list ap; + + if (!csip || !format || !csip->debug_func) + return; + + va_start(ap, format); + util_debug_va(csip->debug_func, csip->debug_data, format, ap); + va_end(ap); +} + +static void csis_sirk_read(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct bt_csis *csis = user_data; + struct csis_sirk sirk; + struct iovec iov; + + memcpy(&sirk, csis->sirk_val, sizeof(sirk)); + + if (sirk.type == BT_CSIP_SIRK_ENCRYPT && + !csis->encrypt(att, sirk.val)) { + gatt_db_attribute_read_result(attrib, id, BT_ATT_ERROR_UNLIKELY, + NULL, 0); + return; + } + + iov.iov_base = &sirk; + iov.iov_len = sizeof(sirk); + + gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base, + iov.iov_len); +} + +static void csis_size_read(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct bt_csis *csis = user_data; + struct iovec iov; + + iov.iov_base = &csis->size_val; + iov.iov_len = sizeof(csis->size_val); + + gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base, + iov.iov_len); +} + +static void csis_lock_read_cb(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + uint8_t value = CSIS_LOCK; + + gatt_db_attribute_read_result(attrib, id, 0, &value, sizeof(value)); +} + +static void csis_lock_write_cb(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + const uint8_t *value, size_t len, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + gatt_db_attribute_write_result(attrib, id, 0); +} + +static void csis_rank_read_cb(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct bt_csis *csis = user_data; + struct iovec iov; + + iov.iov_base = &csis->rank_val; + iov.iov_len = sizeof(csis->rank_val); + + gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base, iov.iov_len); +} + +static struct bt_csis *csis_new(struct gatt_db *db) +{ + struct bt_csis *csis; + + if (!db) + return NULL; + + csis = new0(struct bt_csis, 1); + + return csis; +} + +static struct bt_csip_db *csip_db_new(struct gatt_db *db) +{ + struct bt_csip_db *cdb; + + if (!db) + return NULL; + + cdb = new0(struct bt_csip_db, 1); + cdb->db = gatt_db_ref(db); + + if (!csip_db) + csip_db = queue_new(); + + cdb->csis = csis_new(db); + cdb->csis->cdb = cdb; + + queue_push_tail(csip_db, cdb); + + return cdb; +} + +bool bt_csip_set_user_data(struct bt_csip *csip, void *user_data) +{ + if (!csip) + return false; + + csip->user_data = user_data; + + return true; +} + +static bool csip_db_match(const void *data, const void *match_data) +{ + const struct bt_csip_db *cdb = data; + const struct gatt_db *db = match_data; + + return (cdb->db == db); +} + +static struct bt_csip_db *csip_get_db(struct gatt_db *db) +{ + struct bt_csip_db *cdb; + + cdb = queue_find(csip_db, csip_db_match, db); + if (cdb) + return cdb; + + return csip_db_new(db); +} + +bool bt_csip_set_debug(struct bt_csip *csip, bt_csip_debug_func_t func, + void *user_data, bt_csip_destroy_func_t destroy) +{ + if (!csip) + return false; + + if (csip->debug_destroy) + csip->debug_destroy(csip->debug_data); + + csip->debug_func = func; + csip->debug_destroy = destroy; + csip->debug_data = user_data; + + return true; +} + +unsigned int bt_csip_register(bt_csip_func_t attached, bt_csip_func_t detached, + void *user_data) +{ + struct bt_csip_cb *cb; + static unsigned int id; + + if (!attached && !detached) + return 0; + + if (!csip_cbs) + csip_cbs = queue_new(); + + cb = new0(struct bt_csip_cb, 1); + cb->id = ++id ? id : ++id; + cb->attached = attached; + cb->detached = detached; + cb->user_data = user_data; + + queue_push_tail(csip_cbs, cb); + + return cb->id; +} + +static bool match_id(const void *data, const void *match_data) +{ + const struct bt_csip_cb *cb = data; + unsigned int id = PTR_TO_UINT(match_data); + + return (cb->id == id); +} + +bool bt_csip_unregister(unsigned int id) +{ + struct bt_csip_cb *cb; + + cb = queue_remove_if(csip_cbs, match_id, UINT_TO_PTR(id)); + if (!cb) + return false; + + free(cb); + + return true; +} + +struct bt_csip *bt_csip_new(struct gatt_db *ldb, struct gatt_db *rdb) +{ + struct bt_csip *csip; + struct bt_csip_db *db; + + if (!ldb) + return NULL; + + db = csip_get_db(ldb); + if (!db) + return NULL; + + csip = new0(struct bt_csip, 1); + csip->ldb = db; + csip->ready_cbs = queue_new(); + + if (!rdb) + goto done; + + db = new0(struct bt_csip_db, 1); + db->db = gatt_db_ref(rdb); + + csip->rdb = db; + +done: + bt_csip_ref(csip); + + return csip; +} + +static struct bt_csis *csip_get_csis(struct bt_csip *csip) +{ + if (!csip) + return NULL; + + if (csip->rdb->csis) + return csip->rdb->csis; + + csip->rdb->csis = new0(struct bt_csis, 1); + csip->rdb->csis->cdb = csip->rdb; + + return csip->rdb->csis; +} + +static void read_sirk(bool success, uint8_t att_ecode, const uint8_t *value, + uint16_t length, void *user_data) +{ + struct bt_csip *csip = user_data; + struct bt_csis *csis; + struct csis_sirk *sirk; + struct iovec iov = { + .iov_base = (void *)value, + .iov_len = length + }; + + if (!success) { + DBG(csip, "Unable to read SIRK: error 0x%02x", att_ecode); + return; + } + + csis = csip_get_csis(csip); + if (!csis) + return; + + sirk = util_iov_pull_mem(&iov, sizeof(*sirk)); + if (!sirk) { + DBG(csip, "Invalid size for SIRK: len %u", length); + return; + } + + if (!csis->sirk_val) + csis->sirk_val = new0(struct csis_sirk, 1); + + memcpy(csis->sirk_val, sirk, sizeof(*sirk)); +} + +static void read_size(bool success, uint8_t att_ecode, const uint8_t *value, + uint16_t length, void *user_data) +{ + struct bt_csip *csip = user_data; + struct bt_csis *csis; + + if (!success) { + DBG(csip, "Unable to read Size: error 0x%02x", att_ecode); + return; + } + + csis = csip_get_csis(csip); + if (!csis) + return; + + csis->size_val = *value; +} + +static void read_rank(bool success, uint8_t att_ecode, const uint8_t *value, + uint16_t length, void *user_data) +{ + struct bt_csip *csip = user_data; + struct bt_csis *csis; + + if (!success) { + DBG(csip, "Unable to read Rank: error 0x%02x", att_ecode); + return; + } + + csis = csip_get_csis(csip); + if (!csis) + return; + + csis->rank_val = *value; +} + +static void csip_notify_ready(struct bt_csip *csip) +{ + const struct queue_entry *entry; + + if (!bt_csip_ref_safe(csip)) + return; + + for (entry = queue_get_entries(csip->ready_cbs); entry; + entry = entry->next) { + struct bt_csip_ready *ready = entry->data; + + ready->func(csip, ready->data); + } + + bt_csip_unref(csip); +} + +static void foreach_csis_char(struct gatt_db_attribute *attr, void *user_data) +{ + struct bt_csip *csip = user_data; + uint16_t value_handle; + bt_uuid_t uuid, uuid_sirk, uuid_size, uuid_rank; + struct bt_csis *csis; + + if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, + NULL, NULL, &uuid)) + return; + + bt_uuid16_create(&uuid_sirk, CS_SIRK); + bt_uuid16_create(&uuid_size, CS_SIZE); + bt_uuid16_create(&uuid_rank, CS_RANK); + + if (!bt_uuid_cmp(&uuid, &uuid_sirk)) { + DBG(csip, "SIRK found: handle 0x%04x", value_handle); + + csis = csip_get_csis(csip); + if (!csis) + return; + + csis->sirk = attr; + + bt_gatt_client_read_value(csip->client, value_handle, read_sirk, + csip, NULL); + + return; + } + + if (!bt_uuid_cmp(&uuid, &uuid_size)) { + DBG(csip, "Size found: handle 0x%04x", value_handle); + + csis = csip_get_csis(csip); + if (!csis) + return; + + csis->size = attr; + + bt_gatt_client_read_value(csip->client, value_handle, read_size, + csip, NULL); + } + + if (!bt_uuid_cmp(&uuid, &uuid_rank)) { + DBG(csip, "Rank found: handle 0x%04x", value_handle); + + csis = csip_get_csis(csip); + if (!csis) + return; + + csis->rank = attr; + + bt_gatt_client_read_value(csip->client, value_handle, read_rank, + csip, NULL); + } +} +static void foreach_csis_service(struct gatt_db_attribute *attr, + void *user_data) +{ + struct bt_csip *csip = user_data; + struct bt_csis *csis = csip_get_csis(csip); + + if (!csis) + return; + + csis->service = attr; + + gatt_db_service_set_claimed(attr, true); + + gatt_db_service_foreach_char(attr, foreach_csis_char, csip); +} + +static void csip_idle(void *data) +{ + struct bt_csip *csip = data; + + csip->idle_id = 0; + + csip_notify_ready(csip); +} + +bool bt_csip_attach(struct bt_csip *csip, struct bt_gatt_client *client) +{ + bt_uuid_t uuid; + + if (!sessions) + sessions = queue_new(); + + queue_push_tail(sessions, csip); + + if (!client) + return true; + + if (csip->client) + return false; + + csip->client = bt_gatt_client_clone(client); + if (!csip->client) + return false; + + csip->idle_id = bt_gatt_client_idle_register(csip->client, csip_idle, + csip, NULL); + + bt_uuid16_create(&uuid, CSIS_UUID); + gatt_db_foreach_service(csip->rdb->db, &uuid, foreach_csis_service, + csip); + + return true; +} + +static struct csis_sirk *sirk_new(struct bt_csis *csis, struct gatt_db *db, + uint8_t type, uint8_t k[16], + uint8_t size, uint8_t rank) +{ + struct csis_sirk *sirk; + bt_uuid_t uuid; + struct gatt_db_attribute *cas; + + if (!csis) + return NULL; + + if (csis->sirk) + sirk = csis->sirk_val; + else + sirk = new0(struct csis_sirk, 1); + + sirk->type = type; + memcpy(sirk->val, k, sizeof(sirk->val)); + csis->sirk_val = sirk; + csis->size_val = size; + csis->lock_val = 1; + csis->rank_val = rank; + + /* Check if service already active as that means the attributes have + * already been registered. + */ + if (gatt_db_service_get_active(csis->service)) + return sirk; + + /* Populate DB with CSIS attributes */ + bt_uuid16_create(&uuid, CSIS_UUID); + csis->service = gatt_db_add_service(db, &uuid, true, 10); + + bt_uuid16_create(&uuid, CS_SIRK); + csis->sirk = gatt_db_service_add_characteristic(csis->service, + &uuid, + BT_ATT_PERM_READ | + BT_ATT_PERM_READ_ENCRYPT, + BT_GATT_CHRC_PROP_READ, + csis_sirk_read, NULL, + csis); + + bt_uuid16_create(&uuid, CS_SIZE); + csis->size = gatt_db_service_add_characteristic(csis->service, + &uuid, + BT_ATT_PERM_READ | + BT_ATT_PERM_READ_ENCRYPT, + BT_GATT_CHRC_PROP_READ, + csis_size_read, NULL, + csis); + + /* Lock */ + bt_uuid16_create(&uuid, CS_LOCK); + csis->lock = gatt_db_service_add_characteristic(csis->service, &uuid, + BT_ATT_PERM_READ | + BT_ATT_PERM_READ_ENCRYPT | + BT_ATT_PERM_WRITE | + BT_ATT_PERM_WRITE_ENCRYPT, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_WRITE | + BT_GATT_CHRC_PROP_NOTIFY, + csis_lock_read_cb, + csis_lock_write_cb, + csis); + + csis->lock_ccc = gatt_db_service_add_ccc(csis->service, + BT_ATT_PERM_READ | BT_ATT_PERM_WRITE); + + /* Rank */ + bt_uuid16_create(&uuid, CS_RANK); + csis->rank = gatt_db_service_add_characteristic(csis->service, &uuid, + BT_ATT_PERM_READ | + BT_ATT_PERM_READ_ENCRYPT, + BT_GATT_CHRC_PROP_READ, + csis_rank_read_cb, + NULL, csis); + + /* Add the CAS service */ + bt_uuid16_create(&uuid, 0x1853); + cas = gatt_db_add_service(db, &uuid, true, 2); + gatt_db_service_add_included(cas, csis->service); + gatt_db_service_set_active(cas, true); + gatt_db_service_add_included(cas, csis->service); + + gatt_db_service_set_active(csis->service, true); + + return sirk; +} + +bool bt_csip_set_sirk(struct bt_csip *csip, bool encrypt, + uint8_t k[16], uint8_t size, uint8_t rank, + bt_csip_encrypt_func_t func) +{ + uint8_t zero[16] = {}; + uint8_t type; + + if (!csip || !csip->ldb || !memcmp(k, zero, sizeof(zero))) + return false; + + type = encrypt ? BT_CSIP_SIRK_ENCRYPT : BT_CSIP_SIRK_CLEARTEXT; + + /* In case of encrypted type requires sef key function */ + if (type == BT_CSIP_SIRK_ENCRYPT && !func) + return false; + + if (!sirk_new(csip->ldb->csis, csip->ldb->db, type, k, size, rank)) + return false; + + csip->ldb->csis->encrypt = func; + + return true; +} + +bool bt_csip_get_sirk(struct bt_csip *csip, uint8_t *type, + uint8_t k[16], uint8_t *size, uint8_t *rank) +{ + struct bt_csis *csis; + + if (!csip) + return false; + + csis = csip_get_csis(csip); + if (!csis) + return false; + + if (!csis->sirk_val) + return false; + + if (type) + *type = csis->sirk_val->type; + + memcpy(k, csis->sirk_val->val, sizeof(csis->sirk_val->val)); + + if (size) + *size = csis->size_val; + + if (rank) + *rank = csis->rank_val; + + return true; +} + +unsigned int bt_csip_ready_register(struct bt_csip *csip, + bt_csip_ready_func_t func, void *user_data, + bt_csip_destroy_func_t destroy) +{ + struct bt_csip_ready *ready; + static unsigned int id; + + if (!csip) + return 0; + + ready = new0(struct bt_csip_ready, 1); + ready->id = ++id ? id : ++id; + ready->func = func; + ready->destroy = destroy; + ready->data = user_data; + + queue_push_tail(csip->ready_cbs, ready); + + return ready->id; +} + +static bool match_ready_id(const void *data, const void *match_data) +{ + const struct bt_csip_ready *ready = data; + unsigned int id = PTR_TO_UINT(match_data); + + return (ready->id == id); +} + +bool bt_csip_ready_unregister(struct bt_csip *csip, unsigned int id) +{ + struct bt_csip_ready *ready; + + ready = queue_remove_if(csip->ready_cbs, match_ready_id, + UINT_TO_PTR(id)); + if (!ready) + return false; + + csip_ready_free(ready); + + return true; +} diff --git a/src/shared/csip.h b/src/shared/csip.h new file mode 100644 index 0000000000000000000000000000000000000000..81c8954aba8d03f4b4456275aed62d18efbb292e --- /dev/null +++ b/src/shared/csip.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2022 Intel Corporation. All rights reserved. + * + */ + +#include <stdbool.h> +#include <inttypes.h> + +#include "src/shared/io.h" + +#ifndef __packed +#define __packed __attribute__((packed)) +#endif + +struct bt_csip; + +enum { + BT_CSIP_SIRK_ENCRYPT = 0x00, + BT_CSIP_SIRK_CLEARTEXT = 0x01 +}; + +typedef void (*bt_csip_ready_func_t)(struct bt_csip *csip, void *user_data); +typedef void (*bt_csip_destroy_func_t)(void *user_data); +typedef void (*bt_csip_debug_func_t)(const char *str, void *user_data); +typedef void (*bt_csip_func_t)(struct bt_csip *csip, void *user_data); +typedef bool (*bt_csip_encrypt_func_t)(struct bt_att *att, uint8_t k[16]); +typedef bool (*bt_csip_sirk_func_t)(struct bt_csip *csip, uint8_t type, + uint8_t k[16], uint8_t size, uint8_t rank, + void *user_data); + +struct bt_csip *bt_csip_ref(struct bt_csip *csip); +void bt_csip_unref(struct bt_csip *csip); + +bool bt_csip_attach(struct bt_csip *csip, struct bt_gatt_client *client); +void bt_csip_detach(struct bt_csip *csip); + +bool bt_csip_set_debug(struct bt_csip *csip, bt_csip_debug_func_t func, + void *user_data, bt_csip_destroy_func_t destroy); + +struct bt_att *bt_csip_get_att(struct bt_csip *csip); + +bool bt_csip_set_user_data(struct bt_csip *csip, void *user_data); + +/* Session related function */ +unsigned int bt_csip_register(bt_csip_func_t added, bt_csip_func_t removed, + void *user_data); +bool bt_csip_unregister(unsigned int id); +struct bt_csip *bt_csip_new(struct gatt_db *ldb, struct gatt_db *rdb); + +bool bt_csip_set_sirk(struct bt_csip *csip, bool encrypt, + uint8_t k[16], uint8_t size, uint8_t rank, + bt_csip_encrypt_func_t func); + +bool bt_csip_get_sirk(struct bt_csip *csip, uint8_t *type, + uint8_t k[16], uint8_t *size, uint8_t *rank); + +unsigned int bt_csip_ready_register(struct bt_csip *csip, + bt_csip_ready_func_t func, void *user_data, + bt_csip_destroy_func_t destroy); +bool bt_csip_ready_unregister(struct bt_csip *csip, unsigned int id); diff --git a/src/shared/ecc.c b/src/shared/ecc.c index adaae2082e1fde158d2abec58cc5d72a75bde46c..02bccbd430f6f5baa09781842af05b7139c5e82c 100644 --- a/src/shared/ecc.c +++ b/src/shared/ecc.c @@ -870,6 +870,8 @@ bool ecc_make_key(uint8_t public_key[64], uint8_t private_key[32]) uint64_t priv[NUM_ECC_DIGITS]; unsigned int tries = 0; + memset(&pk, 0, sizeof(pk)); + do { if (!get_random_number(priv) || (tries++ >= MAX_TRIES)) return false; diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c index 45b6ed92fde18329e7009fc18c0e66705926026c..9db3f52117ff2183a22ace3e551665df69873790 100644 --- a/src/shared/gatt-client.c +++ b/src/shared/gatt-client.c @@ -38,7 +38,8 @@ #define GATT_SVC_UUID 0x1801 #define SVC_CHNGD_UUID 0x2a05 #define DBG(_client, _format, arg...) \ - gatt_log(_client, "%s:%s() " _format, __FILE__, __func__, ## arg) + gatt_log(_client, "[%p] %s:%s() " _format, _client, __FILE__, \ + __func__, ## arg) struct ready_cb { bt_gatt_client_callback_t callback; @@ -46,6 +47,12 @@ struct ready_cb { void *data; }; +struct idle_cb { + bt_gatt_client_idle_callback_t callback; + bt_gatt_client_destroy_func_t destroy; + void *data; +}; + struct bt_gatt_client { struct bt_att *att; int ref_count; @@ -55,6 +62,7 @@ struct bt_gatt_client { struct queue *clones; struct queue *ready_cbs; + struct queue *idle_cbs; bt_gatt_client_service_changed_callback_t svc_chngd_callback; bt_gatt_client_destroy_func_t svc_chngd_destroy; @@ -146,9 +154,49 @@ static struct request *request_create(struct bt_gatt_client *client) return request_ref(req); } +static void idle_destroy(void *data) +{ + struct idle_cb *idle = data; + + if (idle->destroy) + idle->destroy(idle->data); + + free(idle); +} + +static bool idle_notify(const void *data, const void *user_data) +{ + const struct idle_cb *idle = data; + + idle->callback(idle->data); + + return true; +} + +static struct bt_gatt_client * +bt_gatt_client_ref_safe(struct bt_gatt_client *client) +{ + if (!client || !client->ref_count) + return NULL; + + return bt_gatt_client_ref(client); +} + +static void notify_client_idle(struct bt_gatt_client *client) +{ + client = bt_gatt_client_ref_safe(client); + if (!client) + return; + + queue_remove_all(client->idle_cbs, idle_notify, NULL, idle_destroy); + + bt_gatt_client_unref(client); +} + static void request_unref(void *data) { struct request *req = data; + struct bt_gatt_client *client = req->client; if (__sync_sub_and_fetch(&req->ref_count, 1)) return; @@ -156,8 +204,11 @@ static void request_unref(void *data) if (req->destroy) req->destroy(req->data); - if (!req->removed) - queue_remove(req->client->pending_requests, req); + if (!req->removed) { + queue_remove(client->pending_requests, req); + if (queue_isempty(client->pending_requests)) + notify_client_idle(client); + } free(req); } @@ -357,15 +408,28 @@ static void discovery_op_free(struct discovery_op *op) static bool read_db_hash(struct discovery_op *op); +static void gatt_log_va(struct bt_gatt_client *client, const char *format, + va_list va) +{ + if (!client || !format) + return; + + if (client->debug_callback) + util_debug_va(client->debug_callback, client->debug_data, + format, va); + else + gatt_log_va(client->parent, format, va); +} + static void gatt_log(struct bt_gatt_client *client, const char *format, ...) { va_list ap; - if (!client || !format || !client->debug_callback) + if (!client || !format) return; va_start(ap, format); - util_debug_va(client->debug_callback, client->debug_data, format, ap); + gatt_log_va(client, format, ap); va_end(ap); } @@ -500,6 +564,24 @@ static void discovery_req_clear(struct bt_gatt_client *client) client->discovery_req = NULL; } +static void discover_remove_pending(struct discovery_op *op, + struct gatt_db_attribute *attr) +{ + struct gatt_db_attribute *svc; + + svc = gatt_db_attribute_get_service(attr); + if (!svc) + return; + + if (!queue_remove(op->pending_svcs, svc)) + return; + + gatt_db_service_set_active(svc, true); + + if (op->cur_svc == svc) + op->cur_svc = NULL; +} + static void discover_chrcs_cb(bool success, uint8_t att_ecode, struct bt_gatt_result *result, void *user_data); @@ -576,12 +658,26 @@ static void discover_incl_cb(bool success, uint8_t att_ecode, gatt_db_attribute_get_handle(attr), handle); goto failed; } + + if (!gatt_db_attribute_get_service_data(attr, NULL, &end, + NULL, NULL)) { + DBG(client, "Unable to get service data at 0x%04x", + handle); + goto failed; + } + + /* Skip if there are no attributes */ + if (handle == end) + discover_remove_pending(op, attr); } next: range = queue_pop_head(op->discov_ranges); - if (!range) + if (!range) { + /* Skip if there are no attributes */ + discover_remove_pending(op, op->cur_svc); goto failed; + } client->discovery_req = bt_gatt_discover_characteristics(client->att, range->start, @@ -639,6 +735,7 @@ static bool discover_descs(struct discovery_op *op, bool *discovering) } attr = gatt_db_insert_characteristic(client->db, + chrc_data->start_handle, chrc_data->value_handle, &chrc_data->uuid, 0, chrc_data->properties, @@ -725,11 +822,16 @@ static bool discover_descs(struct discovery_op *op, bool *discovering) goto failed; } + /* Done with the current service */ + discover_remove_pending(op, op->cur_svc); + done: free(chrc_data); return true; failed: + DBG(client, "Failed to discover descriptors"); + free(chrc_data); return false; } @@ -798,9 +900,6 @@ static void ext_prop_read_cb(bool success, uint8_t att_ecode, if (discovering) return; - /* Done with the current service */ - gatt_db_service_set_active(op->cur_svc, true); - goto done; failed: @@ -888,9 +987,6 @@ next: if (discovering) return; - /* Done with the current service */ - gatt_db_service_set_active(op->cur_svc, true); - goto done; failed: @@ -997,9 +1093,6 @@ next: if (discovering) return; - /* Done with the current service */ - gatt_db_service_set_active(op->cur_svc, true); - goto done; failed: @@ -1018,6 +1111,20 @@ static bool match_handle_range(const void *data, const void *match_data) (match_range->start <= range->end); } +static struct handle_range *range_new(uint16_t start, uint16_t end) +{ + struct handle_range *range; + + if (!start || !end || start > end) + return NULL; + + range = new0(struct handle_range, 1); + range->start = start; + range->end = end; + + return range; +} + static void remove_discov_range(struct discovery_op *op, uint16_t start, uint16_t end) { @@ -1034,16 +1141,18 @@ static void remove_discov_range(struct discovery_op *op, uint16_t start, if ((range->start == start) && (range->end == end)) { queue_remove(op->discov_ranges, range); free(range); - } else if (range->start == start) + } else if (range->start == start) { range->start = end + 1; - else if (range->end == end) + if (!range->start || range->start > range->end) { + queue_remove(op->discov_ranges, range); + free(range); + } + } else if (range->end == end) range->end = start - 1; else { - new_range = new0(struct handle_range, 1); - new_range->start = end + 1; - new_range->end = range->end; - - queue_push_after(op->discov_ranges, range, new_range); + new_range = range_new(end + 1, range->end); + if (new_range) + queue_push_after(op->discov_ranges, range, new_range); range->end = start - 1; } @@ -1167,7 +1276,9 @@ next: range = queue_peek_head(op->discov_ranges); - client->discovery_req = bt_gatt_discover_included_services(client->att, + if (range) + client->discovery_req = bt_gatt_discover_included_services( + client->att, range->start, range->end, discover_incl_cb, @@ -1265,10 +1376,13 @@ static void notify_client_ready(struct bt_gatt_client *client, bool success, { const struct queue_entry *entry; - if (client->ready) + client = bt_gatt_client_ref_safe(client); + if (!client) return; - bt_gatt_client_ref(client); + if (client->ready) + goto done; + client->ready = success; if (client->parent) @@ -1291,6 +1405,7 @@ static void notify_client_ready(struct bt_gatt_client *client, bool success, notify_client_ready(clone, success, att_ecode); } +done: bt_gatt_client_unref(client); } @@ -1550,31 +1665,30 @@ static void complete_notify_request(void *data) } static bool notify_data_write_ccc(struct notify_data *notify_data, bool enable, - bt_att_response_func_t callback) + bt_gatt_client_callback_t callback) { - uint8_t pdu[4]; unsigned int att_id; + uint16_t value = 0x0000; uint16_t properties = notify_data->chrc->properties; assert(notify_data->chrc->ccc_handle); - memset(pdu, 0, sizeof(pdu)); - put_le16(notify_data->chrc->ccc_handle, pdu); if (enable) { /* Try to enable notifications or indications based on * whatever the characteristic supports. */ if (properties & BT_GATT_CHRC_PROP_NOTIFY) - pdu[2] = 0x01; + value = cpu_to_le16(0x0001); else if (properties & BT_GATT_CHRC_PROP_INDICATE) - pdu[2] = 0x02; - - if (!pdu[2]) + value = cpu_to_le16(0x0002); + else return false; } - att_id = bt_att_send(notify_data->client->att, BT_ATT_OP_WRITE_REQ, - pdu, sizeof(pdu), callback, + att_id = bt_gatt_client_write_value(notify_data->client, + notify_data->chrc->ccc_handle, + (void *)&value, sizeof(value), + callback, notify_data_ref(notify_data), notify_data_unref); notify_data->chrc->ccc_write_id = notify_data->att_id = att_id; @@ -1604,8 +1718,8 @@ static bool notify_set_ecode(const void *data, const void *match_data) return true; } -static void enable_ccc_callback(uint8_t opcode, const void *pdu, - uint16_t length, void *user_data) +static void enable_ccc_callback(bool success, uint8_t att_ecode, + void *user_data) { struct notify_data *notify_data = user_data; @@ -1613,10 +1727,9 @@ static void enable_ccc_callback(uint8_t opcode, const void *pdu, notify_data->chrc->ccc_write_id = 0; - bt_gatt_client_ref(notify_data->client); + bt_gatt_client_ref_safe(notify_data->client); - if (opcode == BT_ATT_OP_ERROR_RSP) - notify_data->att_ecode = process_error(pdu, length); + notify_data->att_ecode = att_ecode; /* Notify for all remaining requests. */ complete_notify_request(notify_data); @@ -1655,8 +1768,11 @@ static unsigned int register_notify(struct bt_gatt_client *client, * descriptor. */ chrc = notify_chrc_create(client, handle); - if (!chrc) + if (!chrc) { + DBG(client, "Unable to locate characteristic at 0x%04x", + handle); return 0; + } } /* Fail if we've hit the maximum allowed notify sessions */ @@ -1694,9 +1810,10 @@ static unsigned int register_notify(struct bt_gatt_client *client, } /* - * If the ref count > 1, then notifications are already enabled. + * If the ref count > 1, ccc handle cannot be found or registration + * callback is not set consider notifications are already enabled. */ - if (chrc->notify_count > 1 || !chrc->ccc_handle) { + if (chrc->notify_count > 1 || !chrc->ccc_handle || !callback) { complete_notify_request(notify_data); return notify_data->id; } @@ -2051,8 +2168,8 @@ struct value_data { const void *data; }; -static void disable_ccc_callback(uint8_t opcode, const void *pdu, - uint16_t length, void *user_data) +static void disable_ccc_callback(bool success, uint8_t att_ecode, + void *user_data) { struct notify_data *notify_data = user_data; struct notify_data *next_data; @@ -2113,7 +2230,7 @@ static void notify_handler(void *data, void *user_data) value_data->len, notify_data->user_data); } -static void notify_cb(struct bt_att_chan *chan, uint8_t opcode, +static void notify_cb(struct bt_att_chan *chan, uint16_t mtu, uint8_t opcode, const void *pdu, uint16_t length, void *user_data) { @@ -2122,6 +2239,9 @@ static void notify_cb(struct bt_att_chan *chan, uint8_t opcode, bt_gatt_client_ref(client); + if (queue_isempty(client->notify_list)) + goto done; + memset(&data, 0, sizeof(data)); if (opcode == BT_ATT_OP_HANDLE_NFY_MULT) { @@ -2156,6 +2276,7 @@ static void notify_cb(struct bt_att_chan *chan, uint8_t opcode, queue_foreach(client->notify_list, notify_handler, &data); } +done: if (opcode == BT_ATT_OP_HANDLE_IND && !client->parent) bt_att_chan_send(chan, BT_ATT_OP_HANDLE_CONF, NULL, 0, NULL, NULL, NULL); @@ -2171,6 +2292,7 @@ static void bt_gatt_client_free(struct bt_gatt_client *client) queue_destroy(client->notify_list, notify_data_cleanup); queue_destroy(client->ready_cbs, ready_destroy); + queue_destroy(client->idle_cbs, idle_destroy); if (client->debug_destroy) client->debug_destroy(client->debug_data); @@ -2229,6 +2351,7 @@ static struct bt_gatt_client *gatt_client_new(struct gatt_db *db, client->clones = queue_new(); client->ready_cbs = queue_new(); + client->idle_cbs = queue_new(); client->long_write_queue = queue_new(); client->svc_chngd_queue = queue_new(); client->notify_list = queue_new(); @@ -2698,7 +2821,7 @@ unsigned int bt_gatt_client_read_multiple(struct bt_gatt_client *client, void *user_data, bt_gatt_client_destroy_func_t destroy) { - uint8_t pdu[num_handles * 2]; + uint8_t *pdu = newa(uint8_t, num_handles * 2); struct request *req; struct read_op *op; uint8_t opcode; @@ -2735,7 +2858,7 @@ unsigned int bt_gatt_client_read_multiple(struct bt_gatt_client *client, BT_GATT_CHRC_CLI_FEAT_EATT ? BT_ATT_OP_READ_MULT_VL_REQ : BT_ATT_OP_READ_MULT_REQ; - req->att_id = bt_att_send(client->att, opcode, pdu, sizeof(pdu), + req->att_id = bt_att_send(client->att, opcode, pdu, num_handles * 2, read_multiple_cb, req, request_unref); if (!req->att_id) { @@ -2928,7 +3051,7 @@ unsigned int bt_gatt_client_write_without_response( uint16_t value_handle, bool signed_write, const uint8_t *value, uint16_t length) { - uint8_t pdu[2 + length]; + uint8_t *pdu = newa(uint8_t, 2 + length); struct request *req; int security; uint8_t op; @@ -2951,7 +3074,7 @@ unsigned int bt_gatt_client_write_without_response( put_le16(value_handle, pdu); memcpy(pdu + 2, value, length); - req->att_id = bt_att_send(client->att, op, pdu, sizeof(pdu), NULL, req, + req->att_id = bt_att_send(client->att, op, pdu, 2 + length, NULL, req, request_unref); if (!req->att_id) { request_unref(req); @@ -3009,7 +3132,7 @@ unsigned int bt_gatt_client_write_value(struct bt_gatt_client *client, { struct request *req; struct write_op *op; - uint8_t pdu[2 + length]; + uint8_t *pdu = newa(uint8_t, 2 + length); if (!client) return 0; @@ -3033,7 +3156,7 @@ unsigned int bt_gatt_client_write_value(struct bt_gatt_client *client, memcpy(pdu + 2, value, length); req->att_id = bt_att_send(client->att, BT_ATT_OP_WRITE_REQ, - pdu, sizeof(pdu), + pdu, 2 + length, write_cb, req, request_unref); if (!req->att_id) { @@ -3448,7 +3571,7 @@ unsigned int bt_gatt_client_prepare_write(struct bt_gatt_client *client, { struct request *req; struct prep_write_op *op; - uint8_t pdu[4 + length]; + uint8_t *pdu = newa(uint8_t, 4 + length); if (!client) return 0; @@ -3507,7 +3630,7 @@ unsigned int bt_gatt_client_prepare_write(struct bt_gatt_client *client, * Note that request_unref will be done on write execute */ req->att_id = bt_att_send(client->att, BT_ATT_OP_PREP_WRITE_REQ, pdu, - sizeof(pdu), prep_write_cb, req, + length, prep_write_cb, req, NULL); if (!req->att_id) { op->destroy = NULL; @@ -3614,7 +3737,8 @@ unsigned int bt_gatt_client_register_notify(struct bt_gatt_client *client, void *user_data, bt_gatt_client_destroy_func_t destroy) { - if (!client || !client->db || !chrc_value_handle || !callback) + if (!client || !client->db || !chrc_value_handle || + (!callback && !notify)) return 0; if (client->in_svc_chngd) @@ -3663,3 +3787,58 @@ int bt_gatt_client_get_security(struct bt_gatt_client *client) return bt_att_get_security(client->att, NULL); } + +unsigned int bt_gatt_client_idle_register(struct bt_gatt_client *client, + bt_gatt_client_idle_callback_t callback, + void *user_data, + bt_gatt_client_destroy_func_t destroy) +{ + struct idle_cb *idle; + + if (!client) + return 0; + + idle = new0(struct idle_cb, 1); + idle->callback = callback; + idle->destroy = destroy; + idle->data = user_data; + + queue_push_tail(client->idle_cbs, idle); + + return PTR_TO_UINT(idle); +} + +bool bt_gatt_client_idle_unregister(struct bt_gatt_client *client, + unsigned int id) +{ + struct idle_cb *idle = UINT_TO_PTR(id); + + if (!client || !id) + return false; + + if (queue_remove(client->idle_cbs, idle)) { + idle_destroy(idle); + return true; + } + + return false; +} + +bool bt_gatt_client_set_retry(struct bt_gatt_client *client, + unsigned int id, + bool retry) +{ + struct request *req; + + if (!client || !id) + return false; + + req = queue_find(client->pending_requests, match_req_id, + UINT_TO_PTR(id)); + if (!req) + return false; + + bt_att_set_retry(client->att, req->att_id, retry); + + return true; +} diff --git a/src/shared/gatt-client.h b/src/shared/gatt-client.h index dc51023942cac0d347e82288296c3211c08936bd..63cf99500e9ee8a663b23c7b87bcae376b1e9ea3 100644 --- a/src/shared/gatt-client.h +++ b/src/shared/gatt-client.h @@ -26,6 +26,7 @@ struct bt_gatt_client *bt_gatt_client_ref(struct bt_gatt_client *client); void bt_gatt_client_unref(struct bt_gatt_client *client); typedef void (*bt_gatt_client_destroy_func_t)(void *user_data); +typedef void (*bt_gatt_client_idle_callback_t)(void *user_data); typedef void (*bt_gatt_client_callback_t)(bool success, uint8_t att_ecode, void *user_data); typedef void (*bt_gatt_client_debug_func_t)(const char *str, void *user_data); @@ -126,3 +127,13 @@ bool bt_gatt_client_unregister_notify(struct bt_gatt_client *client, bool bt_gatt_client_set_security(struct bt_gatt_client *client, int level); int bt_gatt_client_get_security(struct bt_gatt_client *client); + +unsigned int bt_gatt_client_idle_register(struct bt_gatt_client *client, + bt_gatt_client_idle_callback_t callback, + void *user_data, + bt_gatt_client_destroy_func_t destroy); +bool bt_gatt_client_idle_unregister(struct bt_gatt_client *client, + unsigned int id); +bool bt_gatt_client_set_retry(struct bt_gatt_client *client, + unsigned int id, + bool retry); diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c index ba47c75ff70c9083e421eebb0e5c1615dab27727..b35763410d175f4e97fac84f649607340966bd37 100644 --- a/src/shared/gatt-db.c +++ b/src/shared/gatt-db.c @@ -58,7 +58,7 @@ struct gatt_db { struct bt_crypto *crypto; uint8_t hash[16]; unsigned int hash_id; - uint16_t next_handle; + uint16_t last_handle; struct queue *services; struct queue *notify_list; @@ -255,11 +255,82 @@ struct gatt_db *gatt_db_new(void) db->crypto = bt_crypto_new(); db->services = queue_new(); db->notify_list = queue_new(); - db->next_handle = 0x0001; + db->last_handle = 0x0000; return gatt_db_ref(db); } +static void service_clone(void *data, void *user_data) +{ + struct gatt_db_service *service = data; + struct gatt_db *db = user_data; + struct gatt_db_service *clone; + int i; + + clone = new0(struct gatt_db_service, 1); + clone->db = db; + clone->active = service->active; + clone->num_handles = service->num_handles; + clone->attributes = new0(struct gatt_db_attribute *, + service->num_handles); + + /* Clone attributes */ + for (i = 0; i < service->num_handles; i++) { + struct gatt_db_attribute *attr = service->attributes[i]; + + /* Only clone values for characteristics declaration since that + * is considered when calculating the db hash. + */ + if (bt_uuid_len(&attr->uuid) != 2) { + clone->attributes[i] = new_attribute(clone, + attr->handle, + &attr->uuid, + NULL, 0); + continue; + } + + /* Attribute values that are used for generating the hash needs + * to be cloned as well. + */ + switch (attr->uuid.value.u16) { + case GATT_PRIM_SVC_UUID: + case GATT_SND_SVC_UUID: + case GATT_INCLUDE_UUID: + case GATT_CHARAC_UUID: + clone->attributes[i] = new_attribute(clone, + attr->handle, + &attr->uuid, + attr->value, + attr->value_len); + break; + default: + clone->attributes[i] = new_attribute(clone, + attr->handle, + &attr->uuid, + NULL, 0); + break; + } + } + + queue_push_tail(db->services, clone); +} + +struct gatt_db *gatt_db_clone(struct gatt_db *db) +{ + struct gatt_db *clone; + + if (!db) + return NULL; + + clone = gatt_db_new(); + if (!clone) + return NULL; + + queue_foreach(db->services, service_clone, clone); + + return clone; +} + static void notify_destroy(void *data) { struct notify *notify = data; @@ -356,14 +427,15 @@ static bool db_hash_update(void *user_data) db->hash_id = 0; - if (!db->next_handle) + if (gatt_db_isempty(db)) return false; - hash.iov = new0(struct iovec, db->next_handle); + hash.iov = new0(struct iovec, db->last_handle + 1); hash.i = 0; gatt_db_foreach_service(db, NULL, service_gen_hash_m, &hash); - bt_crypto_gatt_hash(db->crypto, hash.iov, db->next_handle, db->hash); + bt_crypto_gatt_hash(db->crypto, hash.iov, db->last_handle + 1, + db->hash); for (i = 0; i < hash.i; i++) free(hash.iov[i].iov_base); @@ -624,7 +696,7 @@ bool gatt_db_clear_range(struct gatt_db *db, uint16_t start_handle, done: if (gatt_db_isempty(db)) - db->next_handle = 0; + db->last_handle = 0; return true; } @@ -700,7 +772,7 @@ struct gatt_db_attribute *gatt_db_insert_service(struct gatt_db *db, return NULL; if (!handle) - handle = db->next_handle; + handle = db->last_handle + 1; if (num_handles < 1 || (handle + num_handles - 1) > UINT16_MAX) return NULL; @@ -747,8 +819,8 @@ struct gatt_db_attribute *gatt_db_insert_service(struct gatt_db *db, service->attributes[0]->handle = handle; service->num_handles = num_handles; - /* Fast-forward next_handle if the new service was added to the end */ - db->next_handle = MAX(handle + num_handles, db->next_handle); + /* Fast-forward last_handle if the new service was added to the end */ + db->last_handle = MAX(handle + num_handles - 1, db->last_handle); return service->attributes[0]; @@ -824,28 +896,45 @@ bool gatt_db_set_authorize(struct gatt_db *db, gatt_db_authorize_cb_t cb, return true; } -static uint16_t get_attribute_index(struct gatt_db_service *service, +static uint16_t service_get_attribute_index(struct gatt_db_service *service, + uint16_t *handle, int end_offset) { int i = 0; - /* Here we look for first free attribute index with given offset */ - while (i < (service->num_handles - end_offset) && + if (!service || !service->attributes[0] || !handle) + return 0; + + if (*handle) { + /* Check if handle is in within service range */ + if (*handle < service->attributes[0]->handle) + return 0; + + /* Return index based on given handle */ + i = *handle - service->attributes[0]->handle; + } else { + /* Here we look for first free attribute index with given + * offset. + */ + while (i < (service->num_handles - end_offset) && service->attributes[i]) - i++; + i++; + } - return i == (service->num_handles - end_offset) ? 0 : i; -} + if (i >= (service->num_handles - end_offset)) + return 0; -static uint16_t get_handle_at_index(struct gatt_db_service *service, - int index) -{ - return service->attributes[index]->handle; + /* Set handle based on the index */ + if (!(*handle)) + *handle = service->attributes[0]->handle + i; + + return i; } static struct gatt_db_attribute * service_insert_characteristic(struct gatt_db_service *service, uint16_t handle, + uint16_t value_handle, const bt_uuid_t *uuid, uint32_t permissions, uint8_t properties, @@ -853,6 +942,7 @@ service_insert_characteristic(struct gatt_db_service *service, gatt_db_write_t write_func, void *user_data) { + struct gatt_db_attribute **chrc; uint8_t value[MAX_CHAR_DECL_VALUE_LEN]; uint16_t len = 0; int i; @@ -873,37 +963,48 @@ service_insert_characteristic(struct gatt_db_service *service, if (handle == UINT16_MAX) return NULL; - i = get_attribute_index(service, 1); + i = service_get_attribute_index(service, &handle, 1); if (!i) return NULL; - if (!handle) - handle = get_handle_at_index(service, i - 1) + 2; - value[0] = properties; len += sizeof(properties); /* We set handle of characteristic value, which will be added next */ - put_le16(handle, &value[1]); + put_le16(value_handle, &value[1]); len += sizeof(uint16_t); len += uuid_to_le(uuid, &value[3]); - service->attributes[i] = new_attribute(service, handle - 1, + service->attributes[i] = new_attribute(service, handle, &characteristic_uuid, value, len); if (!service->attributes[i]) return NULL; - set_attribute_data(service->attributes[i], NULL, NULL, BT_ATT_PERM_READ, NULL); + chrc = &service->attributes[i]; + set_attribute_data(service->attributes[i], NULL, NULL, BT_ATT_PERM_READ, + NULL); - i++; + i = service_get_attribute_index(service, &value_handle, 0); + if (!i) { + free(*chrc); + *chrc = NULL; + return NULL; + } - service->attributes[i] = new_attribute(service, handle, uuid, NULL, 0); + service->attributes[i] = new_attribute(service, value_handle, uuid, + NULL, 0); if (!service->attributes[i]) { - free(service->attributes[i - 1]); + free(*chrc); + *chrc = NULL; return NULL; } + /* Update handle of characteristic value_handle if it has changed */ + put_le16(value_handle, &value[1]); + if (memcmp((*chrc)->value, value, len)) + memcpy((*chrc)->value, value, len); + set_attribute_data(service->attributes[i], read_func, write_func, permissions, user_data); @@ -913,6 +1014,7 @@ service_insert_characteristic(struct gatt_db_service *service, struct gatt_db_attribute * gatt_db_insert_characteristic(struct gatt_db *db, uint16_t handle, + uint16_t value_handle, const bt_uuid_t *uuid, uint32_t permissions, uint8_t properties, @@ -926,7 +1028,8 @@ gatt_db_insert_characteristic(struct gatt_db *db, if (!attrib) return NULL; - return service_insert_characteristic(attrib->service, handle, uuid, + return service_insert_characteristic(attrib->service, handle, + value_handle, uuid, permissions, properties, read_func, write_func, user_data); @@ -935,6 +1038,7 @@ gatt_db_insert_characteristic(struct gatt_db *db, struct gatt_db_attribute * gatt_db_service_insert_characteristic(struct gatt_db_attribute *attrib, uint16_t handle, + uint16_t value_handle, const bt_uuid_t *uuid, uint32_t permissions, uint8_t properties, @@ -945,7 +1049,8 @@ gatt_db_service_insert_characteristic(struct gatt_db_attribute *attrib, if (!attrib) return NULL; - return service_insert_characteristic(attrib->service, handle, uuid, + return service_insert_characteristic(attrib->service, handle, + value_handle, uuid, permissions, properties, read_func, write_func, user_data); @@ -963,7 +1068,7 @@ gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib, if (!attrib) return NULL; - return service_insert_characteristic(attrib->service, 0, uuid, + return service_insert_characteristic(attrib->service, 0, 0, uuid, permissions, properties, read_func, write_func, user_data); @@ -980,17 +1085,10 @@ service_insert_descriptor(struct gatt_db_service *service, { int i; - i = get_attribute_index(service, 0); + i = service_get_attribute_index(service, &handle, 0); if (!i) return NULL; - /* Check if handle is in within service range */ - if (handle && handle <= service->attributes[0]->handle) - return NULL; - - if (!handle) - handle = get_handle_at_index(service, i - 1) + 1; - service->attributes[i] = new_attribute(service, handle, uuid, NULL, 0); if (!service->attributes[i]) return NULL; @@ -1150,17 +1248,10 @@ service_insert_included(struct gatt_db_service *service, uint16_t handle, len += include->value_len; } - index = get_attribute_index(service, 0); + index = service_get_attribute_index(service, &handle, 0); if (!index) return NULL; - /* Check if handle is in within service range */ - if (handle && handle <= service->attributes[0]->handle) - return NULL; - - if (!handle) - handle = get_handle_at_index(service, index - 1) + 1; - service->attributes[index] = new_attribute(service, handle, &included_service_uuid, value, len); @@ -1549,7 +1640,7 @@ static int gatt_db_attribute_get_index(const struct gatt_db_attribute *attrib) return -1; } -static struct gatt_db_attribute * +struct gatt_db_attribute * gatt_db_attribute_get_value(struct gatt_db_attribute *attrib) { struct gatt_db_service *service; @@ -1559,18 +1650,18 @@ gatt_db_attribute_get_value(struct gatt_db_attribute *attrib) return NULL; index = gatt_db_attribute_get_index(attrib); - if (index < 0) + if (index <= 0) return NULL; service = attrib->service; if (!bt_uuid_cmp(&characteristic_uuid, &attrib->uuid)) - index++; - else if (bt_uuid_cmp(&characteristic_uuid, + return service->attributes[index + 1]; + else if (!bt_uuid_cmp(&characteristic_uuid, &service->attributes[index - 1]->uuid)) - return NULL; + return service->attributes[index]; - return service->attributes[index]; + return gatt_db_attribute_get_value(service->attributes[index - 1]); } void gatt_db_service_foreach_desc(struct gatt_db_attribute *attrib, @@ -1712,6 +1803,15 @@ uint16_t gatt_db_attribute_get_handle(const struct gatt_db_attribute *attrib) return attrib->handle; } +struct gatt_db_attribute * +gatt_db_attribute_get_service(const struct gatt_db_attribute *attrib) +{ + if (!attrib) + return NULL; + + return attrib->service->attributes[0]; +} + bool gatt_db_attribute_get_service_uuid(const struct gatt_db_attribute *attrib, bt_uuid_t *uuid) { @@ -2095,7 +2195,7 @@ bool gatt_db_attribute_write(struct gatt_db_attribute *attrib, uint16_t offset, { uint8_t err = 0; - if (!attrib || !func) + if (!attrib || (!func && attrib->write_func)) return false; if (attrib->write_func) { @@ -2158,7 +2258,8 @@ bool gatt_db_attribute_write(struct gatt_db_attribute *attrib, uint16_t offset, memcpy(&attrib->value[offset], value, len); done: - func(attrib, err, user_data); + if (func) + func(attrib, err, user_data); return true; } diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h index 41464ad3e7e021cc918212259049b121449b22eb..dc2daf7fc1ba4f41d8306e38e1786e06e4a07161 100644 --- a/src/shared/gatt-db.h +++ b/src/shared/gatt-db.h @@ -12,6 +12,7 @@ struct gatt_db; struct gatt_db_attribute; struct gatt_db *gatt_db_new(void); +struct gatt_db *gatt_db_clone(struct gatt_db *db); struct gatt_db *gatt_db_ref(struct gatt_db *db); void gatt_db_unref(struct gatt_db *db); @@ -63,6 +64,7 @@ gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib, struct gatt_db_attribute * gatt_db_service_insert_characteristic(struct gatt_db_attribute *attrib, uint16_t handle, + uint16_t value_handle, const bt_uuid_t *uuid, uint32_t permissions, uint8_t properties, @@ -73,6 +75,7 @@ gatt_db_service_insert_characteristic(struct gatt_db_attribute *attrib, struct gatt_db_attribute * gatt_db_insert_characteristic(struct gatt_db *db, uint16_t handle, + uint16_t value_handle, const bt_uuid_t *uuid, uint32_t permissions, uint8_t properties, @@ -225,6 +228,9 @@ const bt_uuid_t *gatt_db_attribute_get_type( uint16_t gatt_db_attribute_get_handle(const struct gatt_db_attribute *attrib); +struct gatt_db_attribute * +gatt_db_attribute_get_service(const struct gatt_db_attribute *attrib); + bool gatt_db_attribute_get_service_uuid(const struct gatt_db_attribute *attrib, bt_uuid_t *uuid); @@ -281,6 +287,8 @@ bool gatt_db_attribute_write(struct gatt_db_attribute *attrib, uint16_t offset, bool gatt_db_attribute_write_result(struct gatt_db_attribute *attrib, unsigned int id, int err); +struct gatt_db_attribute * +gatt_db_attribute_get_value(struct gatt_db_attribute *attrib); struct gatt_db_attribute * gatt_db_attribute_get_ccc(struct gatt_db_attribute *attrib); diff --git a/src/shared/gatt-server.c b/src/shared/gatt-server.c index 85cff30eca8893c79555af46c00a4de40f2dccfb..b30ec8c6acc944453500de7dc67605013e4fa56c 100644 --- a/src/shared/gatt-server.c +++ b/src/shared/gatt-server.c @@ -4,6 +4,7 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2014 Google Inc. + * Copyright 2023 NXP * * */ @@ -49,6 +50,7 @@ struct async_read_op { struct bt_gatt_server *server; uint8_t opcode; bool done; + uint16_t mtu; uint8_t *pdu; size_t pdu_len; size_t value_len; @@ -105,6 +107,7 @@ struct bt_gatt_server { unsigned int read_multiple_vl_id; unsigned int prep_write_id; unsigned int exec_write_id; + unsigned int signed_write_cmd_id; uint8_t min_enc_size; @@ -154,6 +157,7 @@ static void bt_gatt_server_free(struct bt_gatt_server *server) bt_att_unregister(server->att, server->read_multiple_vl_id); bt_att_unregister(server->att, server->prep_write_id); bt_att_unregister(server->att, server->exec_write_id); + bt_att_unregister(server->att, server->signed_write_cmd_id); queue_destroy(server->prep_queue, prep_write_data_destroy); @@ -225,7 +229,7 @@ static bool encode_read_by_grp_type_rsp(struct gatt_db *db, struct queue *q, * value is seen. */ if (iter == 0) { - data_val_len = MIN(MIN((unsigned)mtu - 6, 251), + data_val_len = MIN(MIN((unsigned int)mtu - 6, 251), value.iov_len); pdu[0] = data_val_len + 4; iter++; @@ -263,15 +267,14 @@ static void gatt_log(struct bt_gatt_server *server, const char *format, ...) va_end(ap); } -static void read_by_grp_type_cb(struct bt_att_chan *chan, uint8_t opcode, - const void *pdu, uint16_t length, - void *user_data) +static void read_by_grp_type_cb(struct bt_att_chan *chan, uint16_t mtu, + uint8_t opcode, const void *pdu, + uint16_t length, void *user_data) { struct bt_gatt_server *server = user_data; uint16_t start, end; bt_uuid_t type; bt_uuid_t prim, snd; - uint16_t mtu = bt_att_get_mtu(server->att); uint8_t rsp_pdu[mtu]; uint16_t rsp_len; uint8_t ecode = 0; @@ -356,11 +359,8 @@ static void read_by_type_read_complete_cb(struct gatt_db_attribute *attr, size_t len, void *user_data) { struct async_read_op *op = user_data; - struct bt_gatt_server *server = op->server; - uint16_t mtu; uint16_t handle; - mtu = bt_att_get_mtu(server->att); handle = gatt_db_attribute_get_handle(attr); /* Terminate the operation if there was an error */ @@ -372,7 +372,7 @@ static void read_by_type_read_complete_cb(struct gatt_db_attribute *attr, } if (op->pdu_len == 0) { - op->value_len = MIN(MIN((unsigned) mtu - 4, 253), len); + op->value_len = MIN(MIN((unsigned int)op->mtu - 4, 253), len); op->pdu[0] = op->value_len + 2; op->pdu_len++; } else if (len != op->value_len) { @@ -381,7 +381,7 @@ static void read_by_type_read_complete_cb(struct gatt_db_attribute *attr, } /* Stop if this would surpass the MTU */ - if (op->pdu_len + op->value_len + 2 > (unsigned) mtu - 1) { + if (op->pdu_len + op->value_len + 2 > (unsigned int) op->mtu - 1) { op->done = true; goto done; } @@ -392,7 +392,7 @@ static void read_by_type_read_complete_cb(struct gatt_db_attribute *attr, op->pdu_len += op->value_len + 2; - if (op->pdu_len == (unsigned) mtu - 1) + if (op->pdu_len == (unsigned int) op->mtu - 1) op->done = true; done: @@ -488,9 +488,9 @@ error: async_read_op_destroy(op); } -static void read_by_type_cb(struct bt_att_chan *chan, uint8_t opcode, - const void *pdu, uint16_t length, - void *user_data) +static void read_by_type_cb(struct bt_att_chan *chan, uint16_t mtu, + uint8_t opcode, const void *pdu, + uint16_t length, void *user_data) { struct bt_gatt_server *server = user_data; uint16_t start, end; @@ -533,7 +533,8 @@ static void read_by_type_cb(struct bt_att_chan *chan, uint8_t opcode, } op = new0(struct async_read_op, 1); - op->pdu = malloc(bt_att_get_mtu(server->att)); + op->mtu = mtu; + op->pdu = malloc(mtu); if (!op->pdu) { free(op); ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES; @@ -608,13 +609,12 @@ static bool encode_find_info_rsp(struct gatt_db *db, struct queue *q, return true; } -static void find_info_cb(struct bt_att_chan *chan, uint8_t opcode, +static void find_info_cb(struct bt_att_chan *chan, uint16_t mtu, uint8_t opcode, const void *pdu, uint16_t length, void *user_data) { struct bt_gatt_server *server = user_data; uint16_t start, end; - uint16_t mtu = bt_att_get_mtu(server->att); uint8_t rsp_pdu[mtu]; uint16_t rsp_len; uint8_t ecode = 0; @@ -706,14 +706,13 @@ static void find_by_type_val_att_cb(struct gatt_db_attribute *attrib, data->len += 4; } -static void find_by_type_val_cb(struct bt_att_chan *chan, uint8_t opcode, - const void *pdu, uint16_t length, - void *user_data) +static void find_by_type_val_cb(struct bt_att_chan *chan, uint16_t mtu, + uint8_t opcode, const void *pdu, + uint16_t length, void *user_data) { struct bt_gatt_server *server = user_data; uint16_t start, end, uuid16; struct find_by_type_val_data data; - uint16_t mtu = bt_att_get_mtu(server->att); uint8_t rsp_pdu[mtu]; uint16_t ehandle = 0; bt_uuid_t uuid; @@ -776,7 +775,8 @@ static void write_complete_cb(struct gatt_db_attribute *attr, int err, struct bt_gatt_server *server = op->server; uint16_t handle; - if (op->opcode == BT_ATT_OP_WRITE_CMD) { + if (op->opcode == BT_ATT_OP_WRITE_CMD || + op->opcode == BT_ATT_OP_SIGNED_WRITE_CMD) { async_write_op_destroy(op); return; } @@ -817,8 +817,8 @@ static uint8_t check_length(uint16_t length, uint16_t offset) return 0; } -static void write_cb(struct bt_att_chan *chan, uint8_t opcode, const void *pdu, - uint16_t length, void *user_data) +static void write_cb(struct bt_att_chan *chan, uint16_t mtu, uint8_t opcode, + const void *pdu, uint16_t length, void *user_data) { struct bt_gatt_server *server = user_data; struct gatt_db_attribute *attr; @@ -845,7 +845,7 @@ static void write_cb(struct bt_att_chan *chan, uint8_t opcode, const void *pdu, DBG(server, "Write %s - handle: 0x%04x", (opcode == BT_ATT_OP_WRITE_REQ) ? "Req" : "Cmd", handle); - ecode = check_length(length, 0); + ecode = check_length(length - 2, 0); if (ecode) goto error; @@ -904,12 +904,10 @@ static void read_complete_cb(struct gatt_db_attribute *attr, int err, struct async_read_op *op = user_data; struct bt_gatt_server *server = op->server; uint8_t rsp_opcode; - uint16_t mtu; uint16_t handle; DBG(server, "Read Complete: err %d", err); - mtu = bt_att_get_mtu(server->att); handle = gatt_db_attribute_get_handle(attr); if (err) { @@ -921,13 +919,14 @@ static void read_complete_cb(struct gatt_db_attribute *attr, int err, rsp_opcode = get_read_rsp_opcode(op->opcode); bt_att_chan_send_rsp(op->chan, rsp_opcode, len ? value : NULL, - MIN((unsigned int) mtu - 1, len)); + MIN((unsigned int) op->mtu - 1, len)); async_read_op_destroy(op); } static void handle_read_req(struct bt_att_chan *chan, - struct bt_gatt_server *server, uint8_t opcode, - uint16_t handle, uint16_t offset) + struct bt_gatt_server *server, uint16_t mtu, + uint8_t opcode, uint16_t handle, + uint16_t offset) { struct gatt_db_attribute *attr; uint8_t ecode; @@ -954,6 +953,7 @@ static void handle_read_req(struct bt_att_chan *chan, op->chan = chan; op->opcode = opcode; op->server = bt_gatt_server_ref(server); + op->mtu = mtu; if (gatt_db_attribute_read(attr, offset, opcode, server->att, read_complete_cb, op)) @@ -968,8 +968,8 @@ error: bt_att_chan_send_error_rsp(chan, opcode, handle, ecode); } -static void read_cb(struct bt_att_chan *chan, uint8_t opcode, const void *pdu, - uint16_t length, void *user_data) +static void read_cb(struct bt_att_chan *chan, uint16_t mtu, uint8_t opcode, + const void *pdu, uint16_t length, void *user_data) { struct bt_gatt_server *server = user_data; uint16_t handle; @@ -982,10 +982,10 @@ static void read_cb(struct bt_att_chan *chan, uint8_t opcode, const void *pdu, handle = get_le16(pdu); - handle_read_req(chan, server, opcode, handle, 0); + handle_read_req(chan, server, mtu, opcode, handle, 0); } -static void read_blob_cb(struct bt_att_chan *chan, uint8_t opcode, +static void read_blob_cb(struct bt_att_chan *chan, uint16_t mtu, uint8_t opcode, const void *pdu, uint16_t length, void *user_data) { @@ -1001,7 +1001,7 @@ static void read_blob_cb(struct bt_att_chan *chan, uint8_t opcode, handle = get_le16(pdu); offset = get_le16(pdu + 2); - handle_read_req(chan, server, opcode, handle, offset); + handle_read_req(chan, server, mtu, opcode, handle, offset); } struct read_mult_data { @@ -1101,6 +1101,7 @@ error: static struct read_mult_data *read_mult_data_new(struct bt_gatt_server *server, struct bt_att_chan *chan, + uint16_t mtu, uint8_t opcode, uint16_t num_handles) { @@ -1114,16 +1115,16 @@ static struct read_mult_data *read_mult_data_new(struct bt_gatt_server *server, data->server = server; data->num_handles = num_handles; data->cur_handle = 0; - data->mtu = bt_att_get_mtu(server->att); + data->mtu = mtu; data->length = 0; data->rsp_data = new0(uint8_t, data->mtu - 1); return data; } -static void read_multiple_cb(struct bt_att_chan *chan, uint8_t opcode, - const void *pdu, uint16_t length, - void *user_data) +static void read_multiple_cb(struct bt_att_chan *chan, uint16_t mtu, + uint8_t opcode, const void *pdu, + uint16_t length, void *user_data) { struct bt_gatt_server *server = user_data; struct gatt_db_attribute *attr; @@ -1137,7 +1138,7 @@ static void read_multiple_cb(struct bt_att_chan *chan, uint8_t opcode, goto error; } - data = read_mult_data_new(server, chan, opcode, length / 2); + data = read_mult_data_new(server, chan, mtu, opcode, length / 2); for (i = 0; i < data->num_handles; i++) data->handles[i] = get_le16(pdu + i * 2); @@ -1300,9 +1301,9 @@ static void prep_write_complete_cb(struct gatt_db_attribute *attr, int err, free(pwcd); } -static void prep_write_cb(struct bt_att_chan *chan, uint8_t opcode, - const void *pdu, uint16_t length, - void *user_data) +static void prep_write_cb(struct bt_att_chan *chan, uint16_t mtu, + uint8_t opcode, const void *pdu, + uint16_t length, void *user_data) { struct bt_gatt_server *server = user_data; uint16_t handle = 0; @@ -1332,7 +1333,7 @@ static void prep_write_cb(struct bt_att_chan *chan, uint8_t opcode, DBG(server, "Prep Write Req - handle: 0x%04x", handle); - ecode = check_length(length, offset); + ecode = check_length(length - 4, offset); if (ecode) goto error; @@ -1432,9 +1433,9 @@ static bool find_no_reliable_characteristic(const void *data, return !prep_data->reliable_supported; } -static void exec_write_cb(struct bt_att_chan *chan, uint8_t opcode, - const void *pdu, uint16_t length, - void *user_data) +static void exec_write_cb(struct bt_att_chan *chan, uint16_t mtu, + uint8_t opcode, const void *pdu, + uint16_t length, void *user_data) { struct bt_gatt_server *server = user_data; struct exec_data *data; @@ -1495,9 +1496,9 @@ error: bt_att_chan_send_error_rsp(chan, opcode, ehandle, ecode); } -static void exchange_mtu_cb(struct bt_att_chan *chan, uint8_t opcode, - const void *pdu, uint16_t length, - void *user_data) +static void exchange_mtu_cb(struct bt_att_chan *chan, uint16_t mtu, + uint8_t opcode, const void *pdu, + uint16_t length, void *user_data) { struct bt_gatt_server *server = user_data; uint16_t client_rx_mtu; @@ -1627,6 +1628,14 @@ static bool gatt_server_register_att_handlers(struct bt_gatt_server *server) if (!server->exec_write_id) return NULL; + /* Signed Write Command */ + server->signed_write_cmd_id = bt_att_register(server->att, + BT_ATT_OP_SIGNED_WRITE_CMD, + write_cb, + server, NULL); + if (!server->signed_write_cmd_id) + return false; + return true; } @@ -1785,7 +1794,9 @@ bool bt_gatt_server_send_notification(struct bt_gatt_server *server, length = MIN(data->len - data->offset, length); } - memcpy(data->pdu + data->offset, value, length); + if (value) + memcpy(data->pdu + data->offset, value, length); + data->offset += length; if (multiple) { @@ -1808,8 +1819,10 @@ bool bt_gatt_server_send_notification(struct bt_gatt_server *server, return result; error: - if (data) + if (data) { + free(data->pdu); free(data); + } return false; } diff --git a/src/shared/lc3.h b/src/shared/lc3.h index fd9eb15a73eaeed36db127c099b288a4b36e1c57..e7a9277ec349107732606fd28a2a974dfd7d5ee8 100644 --- a/src/shared/lc3.h +++ b/src/shared/lc3.h @@ -4,21 +4,17 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2022 Intel Corporation. All rights reserved. + * Copyright 2024 NXP * */ -#define LTV(_type, _bytes...) \ - { \ - .len = 1 + sizeof((uint8_t []) { _bytes }), \ - .type = _type, \ - .data = { _bytes }, \ - } +#include "src/shared/bap-defs.h" #define LC3_ID 0x06 -#define LC3_BASE 0x01 +#define LC3_TYPE_BASE 0x01 -#define LC3_FREQ (LC3_BASE) +#define LC3_FREQ LC3_TYPE_BASE #define LC3_FREQ_8KHZ BIT(0) #define LC3_FREQ_11KHZ BIT(1) #define LC3_FREQ_16KHZ BIT(2) @@ -36,7 +32,7 @@ LC3_FREQ_44KHZ | \ LC3_FREQ_48KHZ) -#define LC3_DURATION (LC3_BASE + 1) +#define LC3_DURATION (LC3_TYPE_BASE + 1) #define LC3_DURATION_7_5 BIT(0) #define LC3_DURATION_10 BIT(1) #define LC3_DURATION_ANY (LC3_DURATION_7_5 | LC3_DURATION_10) @@ -44,21 +40,19 @@ #define LC3_DURATION_PREFER_10 BIT(5) -#define LC3_CHAN_COUNT (LC3_BASE + 2) +#define LC3_CHAN_COUNT (LC3_TYPE_BASE + 2) #define LC3_CHAN_COUNT_SUPPORT BIT(0) -#define LC3_FRAME_LEN (LC3_BASE + 3) +#define LC3_FRAME_LEN (LC3_TYPE_BASE + 3) -#define LC3_FRAME_COUNT (LC3_BASE + 4) +#define LC3_FRAME_COUNT (LC3_TYPE_BASE + 4) #define LC3_CAPABILITIES(_freq, _duration, _chan_count, _len_min, _len_max) \ - { \ - LTV(LC3_FREQ, _freq), \ - LTV(LC3_DURATION, _duration), \ - LTV(LC3_CHAN_COUNT, _chan_count), \ - LTV(LC3_FRAME_LEN, _len_min, _len_min >> 8, \ - _len_max, _len_max >> 8), \ - } + UTIL_IOV_INIT(0x02, LC3_FREQ, _freq, _freq >> 8, \ + 0x02, LC3_DURATION, _duration, \ + 0x02, LC3_CHAN_COUNT, _chan_count, \ + 0x05, LC3_FRAME_LEN, _len_min, _len_min >> 8, \ + _len_max, _len_max >> 8) #define LC3_CONFIG_BASE 0x01 @@ -76,37 +70,1128 @@ #define LC3_CONFIG_DURATION_7_5 0x00 #define LC3_CONFIG_DURATION_10 0x01 -#define LC3_CONFIG_CHAN_ALLOC (LC3_CONFIG_BASE + 2) +#define LC3_CONFIG_CHAN_ALLOC (LC3_CONFIG_BASE + 2) +#define LC3_CONFIG_CHAN_ALLOC_LEN 0x05 #define LC3_CONFIG_FRAME_LEN (LC3_CONFIG_BASE + 3) #define LC3_CONFIG(_freq, _duration, _len) \ - { \ - LTV(LC3_CONFIG_FREQ, _freq), \ - LTV(LC3_CONFIG_DURATION, _duration), \ - LTV(LC3_CONFIG_FRAME_LEN, _len, _len >> 8), \ - } + UTIL_IOV_INIT(0x02, LC3_CONFIG_FREQ, _freq, \ + 0x02, LC3_CONFIG_DURATION, _duration, \ + 0x03, LC3_CONFIG_FRAME_LEN, _len, _len >> 8) -#define LC3_CONFIG_8KHZ(_duration, _len) \ +#define LC3_AC_BITS(_ac) (BIT(_ac) - 1) + +#define LC3_CONFIG_AC(_freq, _duration, _len, _ac) \ + UTIL_IOV_INIT(0x02, LC3_CONFIG_FREQ, _freq, \ + 0x02, LC3_CONFIG_DURATION, _duration, \ + 0x03, LC3_CONFIG_FRAME_LEN, _len, _len >> 8, \ + 0x05, LC3_CONFIG_CHAN_ALLOC, LC3_AC_BITS(_ac), \ + LC3_AC_BITS(_ac) >> 8 & 0xff, \ + LC3_AC_BITS(_ac) >> 16 & 0xff, \ + LC3_AC_BITS(_ac) >> 24 & 0xff) + +#define LC3_CONFIG_8(_duration, _len) \ LC3_CONFIG(LC3_CONFIG_FREQ_8KHZ, _duration, _len) -#define LC3_CONFIG_11KHZ(_duration, _len) \ +#define LC3_CONFIG_8_AC(_duration, _len, _ac) \ + LC3_CONFIG_AC(LC3_CONFIG_FREQ_8KHZ, _duration, _len, _ac) + +#define LC3_CONFIG_11(_duration, _len) \ LC3_CONFIG(LC3_CONFIG_FREQ_11KHZ, _duration, _len) -#define LC3_CONFIG_16KHZ(_duration, _len) \ +#define LC3_CONFIG_11_AC(_duration, _len, _ac) \ + LC3_CONFIG_AC(LC3_CONFIG_FREQ_11KHZ, _duration, _len, _ac) + +#define LC3_CONFIG_16(_duration, _len) \ LC3_CONFIG(LC3_CONFIG_FREQ_16KHZ, _duration, _len) -#define LC3_CONFIG_22KHZ(_duration, _len) \ +#define LC3_CONFIG_16_AC(_duration, _len, _ac) \ + LC3_CONFIG_AC(LC3_CONFIG_FREQ_16KHZ, _duration, _len, _ac) + +#define LC3_CONFIG_22(_duration, _len) \ LC3_CONFIG(LC3_CONFIG_FREQ_22KHZ, _duration, _len) -#define LC3_CONFIG_24KHZ(_duration, _len) \ +#define LC3_CONFIG_22_AC(_duration, _len) \ + LC3_CONFIG(LC3_CONFIG_FREQ_22KHZ, _duration, _len, _ac) + +#define LC3_CONFIG_24(_duration, _len) \ LC3_CONFIG(LC3_CONFIG_FREQ_24KHZ, _duration, _len) -#define LC3_CONFIG_32KHZ(_duration, _len) \ +#define LC3_CONFIG_24_AC(_duration, _len, _ac) \ + LC3_CONFIG_AC(LC3_CONFIG_FREQ_24KHZ, _duration, _len, _ac) + +#define LC3_CONFIG_32(_duration, _len) \ LC3_CONFIG(LC3_CONFIG_FREQ_32KHZ, _duration, _len) -#define LC3_CONFIG_44KHZ(_duration, _len) \ +#define LC3_CONFIG_32_AC(_duration, _len, _ac) \ + LC3_CONFIG_AC(LC3_CONFIG_FREQ_32KHZ, _duration, _len, _ac) + +#define LC3_CONFIG_44(_duration, _len) \ LC3_CONFIG(LC3_CONFIG_FREQ_44KHZ, _duration, _len) -#define LC3_CONFIG_48KHZ(_duration, _len) \ +#define LC3_CONFIG_44_AC(_duration, _len, _ac) \ + LC3_CONFIG_AC(LC3_CONFIG_FREQ_44KHZ, _duration, _len, _ac) + +#define LC3_CONFIG_48(_duration, _len) \ LC3_CONFIG(LC3_CONFIG_FREQ_48KHZ, _duration, _len) + +#define LC3_CONFIG_48_AC(_duration, _len, _ac) \ + LC3_CONFIG_AC(LC3_CONFIG_FREQ_48KHZ, _duration, _len, _ac) + +#define LC3_CONFIG_FRAME_LEN_8_1 26u + +#define LC3_CONFIG_8_1 \ + LC3_CONFIG_8(LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_8_1) + +#define LC3_CONFIG_8_1_AC(_ac) \ + LC3_CONFIG_8_AC(LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_8_1, _ac) + +#define LC3_CONFIG_FRAME_LEN_8_2 30u + +#define LC3_CONFIG_8_2 \ + LC3_CONFIG_8(LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_8_2 ) + +#define LC3_CONFIG_8_2_AC(_ac) \ + LC3_CONFIG_8_AC(LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_8_2, _ac) + +#define LC3_CONFIG_FRAME_LEN_16_1 30u + +#define LC3_CONFIG_16_1 \ + LC3_CONFIG_16(LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_16_1) + +#define LC3_CONFIG_16_1_AC(_ac) \ + LC3_CONFIG_16_AC(LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_16_1, \ + _ac) + +#define LC3_CONFIG_FRAME_LEN_16_2 40u + +#define LC3_CONFIG_16_2 \ + LC3_CONFIG_16(LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_16_2) + +#define LC3_CONFIG_16_2_AC(_ac) \ + LC3_CONFIG_16_AC(LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_16_2, _ac) + +#define LC3_CONFIG_FRAME_LEN_24_1 45u + +#define LC3_CONFIG_24_1 \ + LC3_CONFIG_24(LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_24_1) + +#define LC3_CONFIG_24_1_AC(_ac) \ + LC3_CONFIG_24_AC(LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_24_1, \ + _ac) + +#define LC3_CONFIG_FRAME_LEN_24_2 60u + +#define LC3_CONFIG_24_2 \ + LC3_CONFIG_24(LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_24_2) + +#define LC3_CONFIG_24_2_AC(_ac) \ + LC3_CONFIG_24_AC(LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_24_2, _ac) + +#define LC3_CONFIG_FRAME_LEN_32_1 60u + +#define LC3_CONFIG_32_1 \ + LC3_CONFIG_32(LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_32_1) + +#define LC3_CONFIG_32_1_AC(_ac) \ + LC3_CONFIG_32_AC(LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_32_1, \ + _ac) + +#define LC3_CONFIG_FRAME_LEN_32_2 80u + +#define LC3_CONFIG_32_2 \ + LC3_CONFIG_32(LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_32_2) + +#define LC3_CONFIG_32_2_AC(_ac) \ + LC3_CONFIG_32_AC(LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_32_2, _ac) + +#define LC3_CONFIG_FRAME_LEN_44_1 98u + +#define LC3_CONFIG_44_1 \ + LC3_CONFIG_44(LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_44_1) + +#define LC3_CONFIG_44_1_AC(_ac) \ + LC3_CONFIG_44_AC(LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_44_1, \ + _ac) + +#define LC3_CONFIG_FRAME_LEN_44_2 130u + +#define LC3_CONFIG_44_2 \ + LC3_CONFIG_44(LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_44_2) + +#define LC3_CONFIG_44_2_AC(_ac) \ + LC3_CONFIG_44_AC(LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_44_2, _ac) + +#define LC3_CONFIG_FRAME_LEN_48_1 75u + +#define LC3_CONFIG_48_1 \ + LC3_CONFIG_48(LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_48_1) + +#define LC3_CONFIG_48_1_AC(_ac) \ + LC3_CONFIG_48_AC(LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_48_1, \ + _ac) + +#define LC3_CONFIG_FRAME_LEN_48_2 100u + +#define LC3_CONFIG_48_2 \ + LC3_CONFIG_48(LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_48_2) + +#define LC3_CONFIG_48_2_AC(_ac) \ + LC3_CONFIG_48_AC(LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_48_2, _ac) + +#define LC3_CONFIG_FRAME_LEN_48_3 90u + +#define LC3_CONFIG_48_3 \ + LC3_CONFIG_48(LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_48_3) + +#define LC3_CONFIG_48_3_AC(_ac) \ + LC3_CONFIG_48_AC(LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_48_3, \ + _ac) + +#define LC3_CONFIG_FRAME_LEN_48_4 120u + +#define LC3_CONFIG_48_4 \ + LC3_CONFIG_48(LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_48_4) + +#define LC3_CONFIG_48_4_AC(_ac) \ + LC3_CONFIG_48_AC(LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_48_4, _ac) + +#define LC3_CONFIG_FRAME_LEN_48_5 117u + +#define LC3_CONFIG_48_5 \ + LC3_CONFIG_48(LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_48_5) + +#define LC3_CONFIG_48_5_AC(_ac) \ + LC3_CONFIG_48_AC(LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_48_5, \ + _ac) + +#define LC3_CONFIG_FRAME_LEN_48_6 155u + +#define LC3_CONFIG_48_6 \ + LC3_CONFIG_48(LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_48_6) + +#define LC3_CONFIG_48_6_AC(_ac) \ + LC3_CONFIG_48_AC(LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_48_6, \ + _ac) + +#define BASE(_pd, _sgrp, _nbis, _cfg...) \ + _pd & 0xff, _pd >> 8, _pd >> 16, \ + _sgrp, \ + _nbis, \ + _cfg + +#define BASE_LC3(_pd, _sgrp, _nbis, _cc...) \ + BASE(_pd, _sgrp, _nbis, \ + 0x06, 0x00, 0x00, 0x00, 0x00, \ + _cc) + +#define LC3_CFG(_freq, _dur, _len) \ + 0x0a, \ + 0x02, LC3_CONFIG_FREQ, _freq, \ + 0x02, LC3_CONFIG_DURATION, _dur, \ + 0x03, LC3_CONFIG_FRAME_LEN, _len, _len >> 8 + +#define LC3_CFG_8_1 \ + LC3_CFG(LC3_CONFIG_FREQ_8KHZ, \ + LC3_CONFIG_DURATION_7_5, \ + LC3_CONFIG_FRAME_LEN_8_1) + +#define BASE_LC3_8_1 \ + BASE_LC3(40000, 1, 1, LC3_CFG_8_1, 0x00, 0x01, 0x00) + +#define LC3_CFG_8_2 \ + LC3_CFG(LC3_CONFIG_FREQ_8KHZ, \ + LC3_CONFIG_DURATION_10, \ + LC3_CONFIG_FRAME_LEN_8_2) + +#define BASE_LC3_8_2 \ + BASE_LC3(40000, 1, 1, LC3_CFG_8_2, 0x00, 0x01, 0x00) + +#define LC3_CFG_16_1 \ + LC3_CFG(LC3_CONFIG_FREQ_16KHZ, \ + LC3_CONFIG_DURATION_7_5, \ + LC3_CONFIG_FRAME_LEN_16_1) + +#define BASE_LC3_16_1 \ + BASE_LC3(40000, 1, 1, LC3_CFG_16_1, 0x00, 0x01, 0x00) + +#define LC3_CFG_16_2 \ + LC3_CFG(LC3_CONFIG_FREQ_16KHZ, \ + LC3_CONFIG_DURATION_10, \ + LC3_CONFIG_FRAME_LEN_16_2) + +#define BASE_LC3_16_2 \ + BASE_LC3(40000, 1, 1, LC3_CFG_16_2, 0x00, 0x01, 0x00) + +#define LC3_CFG_24_1 \ + LC3_CFG(LC3_CONFIG_FREQ_24KHZ, \ + LC3_CONFIG_DURATION_7_5, \ + LC3_CONFIG_FRAME_LEN_24_1) + +#define BASE_LC3_24_1 \ + BASE_LC3(40000, 1, 1, LC3_CFG_24_1, 0x00, 0x01, 0x00) + +#define LC3_CFG_24_2 \ + LC3_CFG(LC3_CONFIG_FREQ_24KHZ, \ + LC3_CONFIG_DURATION_10, \ + LC3_CONFIG_FRAME_LEN_24_2) + +#define BASE_LC3_24_2 \ + BASE_LC3(40000, 1, 1, LC3_CFG_24_2, 0x00, 0x01, 0x00) + +#define LC3_CFG_32_1 \ + LC3_CFG(LC3_CONFIG_FREQ_32KHZ, \ + LC3_CONFIG_DURATION_7_5, \ + LC3_CONFIG_FRAME_LEN_32_1) + +#define BASE_LC3_32_1 \ + BASE_LC3(40000, 1, 1, LC3_CFG_32_1, 0x00, 0x01, 0x00) + +#define LC3_CFG_32_2 \ + LC3_CFG(LC3_CONFIG_FREQ_32KHZ, \ + LC3_CONFIG_DURATION_10, \ + LC3_CONFIG_FRAME_LEN_32_2) + +#define BASE_LC3_32_2 \ + BASE_LC3(40000, 1, 1, LC3_CFG_32_2, 0x00, 0x01, 0x00) + +#define LC3_CFG_44_1 \ + LC3_CFG(LC3_CONFIG_FREQ_44KHZ, \ + LC3_CONFIG_DURATION_7_5, \ + LC3_CONFIG_FRAME_LEN_44_1) + +#define BASE_LC3_44_1 \ + BASE_LC3(40000, 1, 1, LC3_CFG_44_1, 0x00, 0x01, 0x00) + +#define LC3_CFG_44_2 \ + LC3_CFG(LC3_CONFIG_FREQ_44KHZ, \ + LC3_CONFIG_DURATION_10, \ + LC3_CONFIG_FRAME_LEN_44_2) + +#define BASE_LC3_44_2 \ + BASE_LC3(40000, 1, 1, LC3_CFG_44_2, 0x00, 0x01, 0x00) + +#define LC3_CFG_48_1 \ + LC3_CFG(LC3_CONFIG_FREQ_48KHZ, \ + LC3_CONFIG_DURATION_7_5, \ + LC3_CONFIG_FRAME_LEN_48_1) + +#define BASE_LC3_48_1 \ + BASE_LC3(40000, 1, 1, LC3_CFG_48_1, 0x00, 0x01, 0x00) + +#define LC3_CFG_48_2 \ + LC3_CFG(LC3_CONFIG_FREQ_48KHZ, \ + LC3_CONFIG_DURATION_10, \ + LC3_CONFIG_FRAME_LEN_48_2) + +#define BASE_LC3_48_2 \ + BASE_LC3(40000, 1, 1, LC3_CFG_48_2, 0x00, 0x01, 0x00) + +#define LC3_CFG_48_3 \ + LC3_CFG(LC3_CONFIG_FREQ_48KHZ, \ + LC3_CONFIG_DURATION_7_5, \ + LC3_CONFIG_FRAME_LEN_48_3) + +#define BASE_LC3_48_3 \ + BASE_LC3(40000, 1, 1, LC3_CFG_48_3, 0x00, 0x01, 0x00) + +#define LC3_CFG_48_4 \ + LC3_CFG(LC3_CONFIG_FREQ_48KHZ, \ + LC3_CONFIG_DURATION_10, \ + LC3_CONFIG_FRAME_LEN_48_4) + +#define BASE_LC3_48_4 \ + BASE_LC3(40000, 1, 1, LC3_CFG_48_4, 0x00, 0x01, 0x00) + +#define LC3_CFG_48_5 \ + LC3_CFG(LC3_CONFIG_FREQ_48KHZ, \ + LC3_CONFIG_DURATION_7_5, \ + LC3_CONFIG_FRAME_LEN_48_5) + +#define BASE_LC3_48_5 \ + BASE_LC3(40000, 1, 1, LC3_CFG_48_5, 0x00, 0x01, 0x00) + +#define LC3_CFG_48_6 \ + LC3_CFG(LC3_CONFIG_FREQ_48KHZ, \ + LC3_CONFIG_DURATION_10, \ + LC3_CONFIG_FRAME_LEN_48_6) + +#define BASE_LC3_48_6 \ + BASE_LC3(40000, 1, 1, LC3_CFG_48_6, 0x00, 0x01, 0x00) + +#define BASE_VS(_cc) \ + BASE(40000, 1, 1, \ + 0xFF, 0x00, 0x00, 0x00, 0x00, \ + _cc, 0x00, 0x01, 0x00) + +#define BASE_LC3_8_1_MBIS \ + BASE_LC3(40000, 1, 2, LC3_CFG_8_1, 0x00, 0x01, 0x00, 0x02, 0x00) + +#define BASE_LC3_8_2_MBIS \ + BASE_LC3(40000, 1, 2, LC3_CFG_8_2, 0x00, 0x01, 0x00, 0x02, 0x00) + +#define BASE_LC3_16_1_MBIS \ + BASE_LC3(40000, 1, 2, LC3_CFG_16_1, 0x00, 0x01, 0x00, 0x02, 0x00) + +#define BASE_LC3_16_2_MBIS \ + BASE_LC3(40000, 1, 2, LC3_CFG_16_2, 0x00, 0x01, 0x00, 0x02, 0x00) + +#define BASE_LC3_24_1_MBIS \ + BASE_LC3(40000, 1, 2, LC3_CFG_24_1, 0x00, 0x01, 0x00, 0x02, 0x00) + +#define BASE_LC3_24_2_MBIS \ + BASE_LC3(40000, 1, 2, LC3_CFG_24_2, 0x00, 0x01, 0x00, 0x02, 0x00) + +#define BASE_LC3_32_1_MBIS \ + BASE_LC3(40000, 1, 2, LC3_CFG_32_1, 0x00, 0x01, 0x00, 0x02, 0x00) + +#define BASE_LC3_32_2_MBIS \ + BASE_LC3(40000, 1, 2, LC3_CFG_32_2, 0x00, 0x01, 0x00, 0x02, 0x00) + +#define BASE_LC3_44_1_MBIS \ + BASE_LC3(40000, 1, 2, LC3_CFG_44_1, 0x00, 0x01, 0x00, 0x02, 0x00) + +#define BASE_LC3_44_2_MBIS \ + BASE_LC3(40000, 1, 2, LC3_CFG_44_2, 0x00, 0x01, 0x00, 0x02, 0x00) + +#define BASE_LC3_48_1_MBIS \ + BASE_LC3(40000, 1, 2, LC3_CFG_48_1, 0x00, 0x01, 0x00, 0x02, 0x00) + +#define BASE_LC3_48_2_MBIS \ + BASE_LC3(40000, 1, 2, LC3_CFG_48_2, 0x00, 0x01, 0x00, 0x02, 0x00) + +#define BASE_LC3_48_3_MBIS \ + BASE_LC3(40000, 1, 2, LC3_CFG_48_3, 0x00, 0x01, 0x00, 0x02, 0x00) + +#define BASE_LC3_48_4_MBIS \ + BASE_LC3(40000, 1, 2, LC3_CFG_48_4, 0x00, 0x01, 0x00, 0x02, 0x00) + +#define BASE_LC3_48_5_MBIS \ + BASE_LC3(40000, 1, 2, LC3_CFG_48_5, 0x00, 0x01, 0x00, 0x02, 0x00) + +#define BASE_LC3_48_6_MBIS \ + BASE_LC3(40000, 1, 2, LC3_CFG_48_6, 0x00, 0x01, 0x00, 0x02, 0x00) + +#define BASE_VS_MBIS(_cc) \ + BASE(40000, 1, 2, \ + 0xFF, 0x00, 0x00, 0x00, 0x00, \ + _cc, 0x00, 0x01, 0x00, 0x02, 0x00) + +#define LC3_QOS_UNFRAMED 0x00 +#define LC3_QOS_FRAMED 0x01 + +#define LC3_QOS_UCAST(_frame, _pd, _t_lat, _interval, _lat, _sdu, _rtn) \ +{ \ + .ucast.cig_id = 0x00, \ + .ucast.cis_id = 0x00, \ + .ucast.framing = _frame, \ + .ucast.delay = _pd, \ + .ucast.target_latency = _t_lat, \ + .ucast.io_qos.interval = _interval, \ + .ucast.io_qos.latency = _lat, \ + .ucast.io_qos.sdu = _sdu, \ + .ucast.io_qos.phy = BT_BAP_CONFIG_PHY_2M, \ + .ucast.io_qos.rtn = _rtn, \ +} + +#define LC3_QOS_UCAST_7_5_UNFRAMED(_pd, _t_lat, _lat, _sdu, _rtn) \ + LC3_QOS_UCAST(LC3_QOS_UNFRAMED, _pd, _t_lat, 7500u, _lat, _sdu, _rtn) + +#define LC3_QOS_UCAST_10_UNFRAMED(_pd, _t_lat, _lat, _sdu, _rtn) \ + LC3_QOS_UCAST(LC3_QOS_UNFRAMED, _pd, _t_lat, 10000u, _lat, _sdu, _rtn) + +#define LC3_QOS_UCAST_FRAMED(_pd, _t_lat, _interval, _lat, _sdu, _rtn) \ + LC3_QOS_UCAST(LC3_QOS_FRAMED, _pd, _t_lat, _interval, _lat, _sdu, _rtn) + +#define LC3_QOS_8_1_1_LATENCY 8u +#define LC3_QOS_8_1_1_RTN 2u + +#define LC3_QOS_8_1_1_AC(_ac) \ + LC3_QOS_UCAST_7_5_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_8_1_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_8_1, \ + LC3_QOS_8_1_1_RTN) +#define LC3_QOS_8_1_1 LC3_QOS_8_1_1_AC(1) + +#define LC3_QOS_8_1_2_LATENCY 75u +#define LC3_QOS_8_1_2_RTN 13u + +#define LC3_QOS_8_1_2_AC(_ac) \ + LC3_QOS_UCAST_7_5_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_8_1_2_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_8_1, \ + LC3_QOS_8_1_2_RTN) +#define LC3_QOS_8_1_2 LC3_QOS_8_1_2_AC(1) + +#define LC3_QOS_8_2_1_LATENCY 10u +#define LC3_QOS_8_2_1_RTN 2u + +#define LC3_QOS_8_2_1_AC(_ac) \ + LC3_QOS_UCAST_10_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_8_2_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_8_2, \ + LC3_QOS_8_2_1_RTN) +#define LC3_QOS_8_2_1 LC3_QOS_8_2_1_AC(1) + +#define LC3_QOS_8_2_2_LATENCY 95u +#define LC3_QOS_8_2_2_RTN 13u + +#define LC3_QOS_8_2_2_AC(_ac) \ + LC3_QOS_UCAST_10_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_8_2_2_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_8_2, \ + LC3_QOS_8_2_2_RTN) +#define LC3_QOS_8_2_2 LC3_QOS_8_2_2_AC(1) + +#define LC3_QOS_16_1_1_LATENCY 8u +#define LC3_QOS_16_1_1_RTN 2u + +#define LC3_QOS_16_1_1_AC(_ac) \ + LC3_QOS_UCAST_7_5_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_16_1_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_16_1, \ + LC3_QOS_16_1_1_RTN) +#define LC3_QOS_16_1_1 LC3_QOS_16_1_1_AC(1) + +#define LC3_QOS_16_1_2_LATENCY 75u +#define LC3_QOS_16_1_2_RTN 13u + +#define LC3_QOS_16_1_2_AC(_ac) \ + LC3_QOS_UCAST_7_5_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_16_1_2_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_16_1, \ + LC3_QOS_16_1_2_RTN) +#define LC3_QOS_16_1_2 LC3_QOS_16_1_2_AC(1) + +#define LC3_QOS_16_1_GS_LATENCY 15u +#define LC3_QOS_16_1_GS_RTN 1u +#define LC3_QOS_16_1_GS \ + LC3_QOS_UCAST_7_5_UNFRAMED(60000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_16_1_GS_LATENCY, \ + LC3_CONFIG_FRAME_LEN_16_1, \ + LC3_QOS_16_1_GS_RTN) + +#define LC3_QOS_16_2_1_LATENCY 10u +#define LC3_QOS_16_2_1_RTN 2u + +#define LC3_QOS_16_2_1_AC(_ac) \ + LC3_QOS_UCAST_10_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_16_2_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_16_2, \ + LC3_QOS_16_2_1_RTN) +#define LC3_QOS_16_2_1 LC3_QOS_16_2_1_AC(1) + +#define LC3_QOS_16_2_2_LATENCY 95u +#define LC3_QOS_16_2_2_RTN 13u + +#define LC3_QOS_16_2_2_AC(_ac) \ + LC3_QOS_UCAST_10_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_16_2_2_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_16_2, \ + LC3_QOS_16_2_2_RTN) +#define LC3_QOS_16_2_2 LC3_QOS_16_2_2_AC(1) + +#define LC3_QOS_16_2_GS_LATENCY 20u +#define LC3_QOS_16_2_GS_RTN 1u +#define LC3_QOS_16_2_GS \ + LC3_QOS_UCAST_10_UNFRAMED(60000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_16_2_GS_LATENCY, \ + LC3_CONFIG_FRAME_LEN_16_2, \ + LC3_QOS_16_2_GS_RTN) + +#define LC3_QOS_24_1_1_LATENCY 8u +#define LC3_QOS_24_1_1_RTN 2u + +#define LC3_QOS_24_1_1_AC(_ac) \ + LC3_QOS_UCAST_7_5_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_24_1_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_24_1, \ + LC3_QOS_24_1_1_RTN) +#define LC3_QOS_24_1_1 LC3_QOS_24_1_1_AC(1) + +#define LC3_QOS_24_1_2_LATENCY 75u +#define LC3_QOS_24_1_2_RTN 13u + +#define LC3_QOS_24_1_2_AC(_ac) \ + LC3_QOS_UCAST_7_5_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_24_1_2_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_24_1, \ + LC3_QOS_24_1_2_RTN) +#define LC3_QOS_24_1_2 LC3_QOS_24_1_2_AC(1) + +#define LC3_QOS_24_2_1_LATENCY 10u +#define LC3_QOS_24_2_1_RTN 2u + +#define LC3_QOS_24_2_1_AC(_ac) \ + LC3_QOS_UCAST_10_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_24_2_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_24_2, \ + LC3_QOS_24_2_1_RTN) +#define LC3_QOS_24_2_1 LC3_QOS_24_2_1_AC(1) + +#define LC3_QOS_24_2_2_LATENCY 95u +#define LC3_QOS_24_2_2_RTN 13u + +#define LC3_QOS_24_2_2_AC(_ac) \ + LC3_QOS_UCAST_10_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_24_2_2_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_24_2, \ + LC3_QOS_24_2_2_RTN) +#define LC3_QOS_24_2_2 LC3_QOS_24_2_2_AC(1) + +#define LC3_QOS_32_1_1_LATENCY 8u +#define LC3_QOS_32_1_1_RTN 2u + +#define LC3_QOS_32_1_1_AC(_ac) \ + LC3_QOS_UCAST_7_5_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_32_1_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_32_1, \ + LC3_QOS_32_1_1_RTN) +#define LC3_QOS_32_1_1 LC3_QOS_32_1_1_AC(1) + +#define LC3_QOS_32_1_2_LATENCY 75u +#define LC3_QOS_32_1_2_RTN 13u + +#define LC3_QOS_32_1_2_AC(_ac) \ + LC3_QOS_UCAST_7_5_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_32_1_2_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_32_1, \ + LC3_QOS_32_1_2_RTN) +#define LC3_QOS_32_1_2 LC3_QOS_32_1_2_AC(1) + +#define LC3_QOS_32_1_GS_LATENCY 15u +#define LC3_QOS_32_1_GS_RTN 1u +#define LC3_QOS_32_1_GS \ + LC3_QOS_UCAST_7_5_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_32_1_GS_LATENCY, \ + LC3_CONFIG_FRAME_LEN_32_1, \ + LC3_QOS_32_1_GS_RTN) + +#define LC3_QOS_32_1_GR_LATENCY 15u +#define LC3_QOS_32_1_GR_RTN 1u +#define LC3_QOS_32_1_GR_AC(_ac) \ + LC3_QOS_UCAST_7_5_UNFRAMED(10000u, BT_BAP_CONFIG_LATENCY_LOW, \ + LC3_QOS_32_1_GS_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_32_1, \ + LC3_QOS_32_1_GS_RTN) +#define LC3_QOS_32_1_GR LC3_QOS_32_1_GR_AC(1) + +#define LC3_QOS_32_2_1_LATENCY 10u +#define LC3_QOS_32_2_1_RTN 2u + +#define LC3_QOS_32_2_1_AC(_ac) \ + LC3_QOS_UCAST_10_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_32_2_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_32_2, \ + LC3_QOS_32_2_1_RTN) +#define LC3_QOS_32_2_1 LC3_QOS_32_2_1_AC(1) + +#define LC3_QOS_32_2_2_LATENCY 95u +#define LC3_QOS_32_2_2_RTN 13u + +#define LC3_QOS_32_2_2_AC(_ac) \ + LC3_QOS_UCAST_10_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_32_2_2_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_32_2, \ + LC3_QOS_32_2_2_RTN) +#define LC3_QOS_32_2_2 LC3_QOS_32_2_2_AC(1) + +#define LC3_QOS_32_2_GS_LATENCY 20u +#define LC3_QOS_32_2_GS_RTN 1u +#define LC3_QOS_32_2_GS \ + LC3_QOS_UCAST_10_UNFRAMED(60000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_32_2_GS_LATENCY, \ + LC3_CONFIG_FRAME_LEN_32_2, \ + LC3_QOS_32_2_GS_RTN) + +#define LC3_QOS_32_2_GR_LATENCY 20u +#define LC3_QOS_32_2_GR_RTN 1u +#define LC3_QOS_32_2_GR_AC(_ac) \ + LC3_QOS_UCAST_10_UNFRAMED(10000u, BT_BAP_CONFIG_LATENCY_LOW, \ + LC3_QOS_32_2_GR_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_32_2, \ + LC3_QOS_32_2_GR_RTN) +#define LC3_QOS_32_2_GR LC3_QOS_32_2_GR_AC(1) + +#define LC3_QOS_44_1_INTERVAL 8163u +#define LC3_QOS_44_1_1_LATENCY 24u +#define LC3_QOS_44_1_1_RTN 5u + +#define LC3_QOS_44_1_1_AC(_ac) \ + LC3_QOS_UCAST_FRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_44_1_INTERVAL, \ + LC3_QOS_44_1_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_44_1, \ + LC3_QOS_44_1_1_RTN) +#define LC3_QOS_44_1_1 LC3_QOS_44_1_1_AC(1) + +#define LC3_QOS_44_1_2_LATENCY 80u +#define LC3_QOS_44_1_2_RTN 13u + +#define LC3_QOS_44_1_2_AC(_ac) \ + LC3_QOS_UCAST_FRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_44_1_INTERVAL, \ + LC3_QOS_44_1_2_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_44_1, \ + LC3_QOS_44_1_2_RTN) +#define LC3_QOS_44_1_2 LC3_QOS_44_1_2_AC(1) + +#define LC3_QOS_44_2_INTERVAL 10884u +#define LC3_QOS_44_2_1_LATENCY 31u +#define LC3_QOS_44_2_1_RTN 5u + +#define LC3_QOS_44_2_1_AC(_ac) \ + LC3_QOS_UCAST_FRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_44_2_INTERVAL, \ + LC3_QOS_44_2_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_44_2, \ + LC3_QOS_44_2_1_RTN) +#define LC3_QOS_44_2_1 LC3_QOS_44_2_1_AC(1) + +#define LC3_QOS_44_2_2_LATENCY 85u +#define LC3_QOS_44_2_2_RTN 13u + +#define LC3_QOS_44_2_2_AC(_ac) \ + LC3_QOS_UCAST_FRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_44_2_INTERVAL, \ + LC3_QOS_44_2_2_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_44_2, \ + LC3_QOS_44_2_2_RTN) +#define LC3_QOS_44_2_2 LC3_QOS_44_2_2_AC(1) + +#define LC3_QOS_48_1_1_LATENCY 15u +#define LC3_QOS_48_1_1_RTN 5u + +#define LC3_QOS_48_1_1_AC(_ac) \ + LC3_QOS_UCAST_7_5_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_48_1_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_1,\ + LC3_QOS_48_1_1_RTN) +#define LC3_QOS_48_1_1 LC3_QOS_48_1_1_AC(1) + +#define LC3_QOS_48_1_2_LATENCY 75u +#define LC3_QOS_48_1_2_RTN 13u + +#define LC3_QOS_48_1_2_AC(_ac) \ + LC3_QOS_UCAST_7_5_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_48_1_2_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_1, \ + LC3_QOS_48_1_2_RTN) +#define LC3_QOS_48_1_2 LC3_QOS_48_1_2_AC(1) + +#define LC3_QOS_48_1_GS_LATENCY 15u +#define LC3_QOS_48_1_GS_RTN 1u + +#define LC3_QOS_48_1_GS \ + LC3_QOS_UCAST_7_5_UNFRAMED(60000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_48_1_GS_LATENCY, \ + LC3_CONFIG_FRAME_LEN_48_1, \ + LC3_QOS_48_1_GS_RTN) + +#define LC3_QOS_48_1_GR_LATENCY 15u +#define LC3_QOS_48_1_GR_RTN 1u + +#define LC3_QOS_48_1_GR_AC(_ac) \ + LC3_QOS_UCAST_7_5_UNFRAMED(10000u, BT_BAP_CONFIG_LATENCY_LOW, \ + LC3_QOS_48_1_GR_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_1, \ + LC3_QOS_48_1_GR_RTN) +#define LC3_QOS_48_1_GR LC3_QOS_48_1_GR_AC(1) + +#define LC3_QOS_48_2_1_LATENCY 20u +#define LC3_QOS_48_2_1_RTN 5u + +#define LC3_QOS_48_2_1_AC(_ac) \ + LC3_QOS_UCAST_10_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_48_2_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_2, \ + LC3_QOS_48_2_1_RTN) +#define LC3_QOS_48_2_1 LC3_QOS_48_2_1_AC(1) + +#define LC3_QOS_48_2_2_LATENCY 95u +#define LC3_QOS_48_2_2_RTN 13u + +#define LC3_QOS_48_2_2_AC(_ac) \ + LC3_QOS_UCAST_10_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_48_2_2_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_2, \ + LC3_QOS_48_2_2_RTN) +#define LC3_QOS_48_2_2 LC3_QOS_48_2_2_AC(1) + +#define LC3_QOS_48_2_GS_LATENCY 20u +#define LC3_QOS_48_2_GS_RTN 1u + +#define LC3_QOS_48_2_GS \ + LC3_QOS_UCAST_10_UNFRAMED(60000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_48_2_GS_LATENCY, \ + LC3_CONFIG_FRAME_LEN_48_2, \ + LC3_QOS_48_2_GS_RTN) + +#define LC3_QOS_48_2_GR_LATENCY 20u +#define LC3_QOS_48_2_GR_RTN 1u + +#define LC3_QOS_48_2_GR_AC(_ac) \ + LC3_QOS_UCAST_10_UNFRAMED(10000u, BT_BAP_CONFIG_LATENCY_LOW, \ + LC3_QOS_48_2_GR_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_2, \ + LC3_QOS_48_2_GR_RTN) +#define LC3_QOS_48_2_GR LC3_QOS_48_2_GR_AC(1) + +#define LC3_QOS_48_3_1_LATENCY 15u +#define LC3_QOS_48_3_1_RTN 5u + +#define LC3_QOS_48_3_1_AC(_ac) \ + LC3_QOS_UCAST_7_5_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_48_3_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_3, \ + LC3_QOS_48_3_1_RTN) +#define LC3_QOS_48_3_1 LC3_QOS_48_3_1_AC(1) + +#define LC3_QOS_48_3_2_LATENCY 75u +#define LC3_QOS_48_3_2_RTN 13u + +#define LC3_QOS_48_3_2_AC(_ac) \ + LC3_QOS_UCAST_7_5_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_48_3_2_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_3, \ + LC3_QOS_48_3_2_RTN) +#define LC3_QOS_48_3_2 LC3_QOS_48_3_2_AC(1) + +#define LC3_QOS_48_3_GR_LATENCY 15u +#define LC3_QOS_48_3_GR_RTN 1u + +#define LC3_QOS_48_3_GR_AC(_ac) \ + LC3_QOS_UCAST_7_5_UNFRAMED(10000u, BT_BAP_CONFIG_LATENCY_LOW, \ + LC3_QOS_48_3_GR_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_3, \ + LC3_QOS_48_3_GR_RTN) +#define LC3_QOS_48_3_GR LC3_QOS_48_3_GR_AC(1) + +#define LC3_QOS_48_4_1_LATENCY 20u +#define LC3_QOS_48_4_1_RTN 5u + +#define LC3_QOS_48_4_1_AC(_ac) \ + LC3_QOS_UCAST_10_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_48_4_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_4, \ + LC3_QOS_48_4_1_RTN) +#define LC3_QOS_48_4_1 LC3_QOS_48_4_1_AC(1) + +#define LC3_QOS_48_4_2_LATENCY 100u +#define LC3_QOS_48_4_2_RTN 13u + +#define LC3_QOS_48_4_2_AC(_ac) \ + LC3_QOS_UCAST_10_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_48_4_2_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_4, \ + LC3_QOS_48_4_2_RTN) +#define LC3_QOS_48_4_2 LC3_QOS_48_4_2_AC(1) + +#define LC3_QOS_48_4_GR_LATENCY 20u +#define LC3_QOS_48_4_GR_RTN 1u + +#define LC3_QOS_48_4_GR_AC(_ac) \ + LC3_QOS_UCAST_10_UNFRAMED(10000u, BT_BAP_CONFIG_LATENCY_LOW, \ + LC3_QOS_48_4_GR_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_4, \ + LC3_QOS_48_4_GR_RTN) +#define LC3_QOS_48_4_GR LC3_QOS_48_4_GR_AC(1) + +#define LC3_QOS_48_5_1_LATENCY 15u +#define LC3_QOS_48_5_1_RTN 5u + +#define LC3_QOS_48_5_1_AC(_ac) \ + LC3_QOS_UCAST_7_5_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_48_5_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_5, \ + LC3_QOS_48_5_1_RTN) +#define LC3_QOS_48_5_1 LC3_QOS_48_5_1_AC(1) + +#define LC3_QOS_48_5_2_LATENCY 75u +#define LC3_QOS_48_5_2_RTN 13u + +#define LC3_QOS_48_5_2_AC(_ac) \ + LC3_QOS_UCAST_7_5_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_48_5_2_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_5, \ + LC3_QOS_48_5_2_RTN) +#define LC3_QOS_48_5_2 LC3_QOS_48_5_2_AC(1) + +#define LC3_QOS_48_6_1_LATENCY 20u +#define LC3_QOS_48_6_1_RTN 5u + +#define LC3_QOS_48_6_1_AC(_ac) \ + LC3_QOS_UCAST_10_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_48_6_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_6, \ + LC3_QOS_48_6_1_RTN) +#define LC3_QOS_48_6_1 LC3_QOS_48_6_1_AC(1) + +#define LC3_QOS_48_6_2_LATENCY 100u +#define LC3_QOS_48_6_2_RTN 13u + +#define LC3_QOS_48_6_2_AC(_ac) \ + LC3_QOS_UCAST_10_UNFRAMED(40000u, BT_BAP_CONFIG_LATENCY_BALANCED, \ + LC3_QOS_48_6_2_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_6, \ + LC3_QOS_48_6_2_RTN) +#define LC3_QOS_48_6_2 LC3_QOS_48_6_2_AC(1) + +#define LC3_QOS_BCAST(_frame, _pd, _interval, _lat, _sdu, _rtn) \ +{ \ + .bcast.big = 0x00, \ + .bcast.bis = 0x00, \ + .bcast.framing = _frame, \ + .bcast.delay = _pd, \ + .bcast.io_qos.interval = _interval, \ + .bcast.io_qos.latency = _lat, \ + .bcast.io_qos.sdu = _sdu, \ + .bcast.io_qos.phy = BT_BAP_CONFIG_PHY_2M, \ + .bcast.io_qos.rtn = _rtn, \ +} + +#define LC3_QOS_BCAST_7_5_UNFRAMED(_pd, _lat, _sdu, _rtn) \ + LC3_QOS_BCAST(LC3_QOS_UNFRAMED, _pd, 7500u, _lat, _sdu, _rtn) + +#define LC3_QOS_BCAST_10_UNFRAMED(_pd, _lat, _sdu, _rtn) \ + LC3_QOS_BCAST(LC3_QOS_UNFRAMED, _pd, 10000u, _lat, _sdu, _rtn) + +#define LC3_QOS_BCAST_FRAMED(_pd, _interval, _lat, _sdu, _rtn) \ + LC3_QOS_BCAST(LC3_QOS_FRAMED, _pd, _interval, _lat, _sdu, _rtn) + +#define LC3_QOS_8_1_1_B_AC(_ac) \ + LC3_QOS_BCAST_7_5_UNFRAMED(40000u, LC3_QOS_8_1_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_8_1, \ + LC3_QOS_8_1_1_RTN) +#define LC3_QOS_8_1_1_B LC3_QOS_8_1_1_B_AC(1) + +#define LC3_QOS_8_1_2_B_LATENCY 75u +#define LC3_QOS_8_1_2_B_RTN 4u +#define LC3_QOS_8_1_2_B_AC(_ac) \ + LC3_QOS_BCAST_7_5_UNFRAMED(40000u, LC3_QOS_8_1_2_B_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_8_1, \ + LC3_QOS_8_1_2_B_RTN) +#define LC3_QOS_8_1_2_B LC3_QOS_8_1_2_B_AC(1) + +#define LC3_QOS_8_2_1_B_AC(_ac) \ + LC3_QOS_BCAST_10_UNFRAMED(40000u, LC3_QOS_8_2_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_8_2, \ + LC3_QOS_8_2_1_RTN) +#define LC3_QOS_8_2_1_B LC3_QOS_8_2_1_B_AC(1) + +#define LC3_QOS_8_2_2_B_LATENCY 60u +#define LC3_QOS_8_2_2_B_RTN 4u +#define LC3_QOS_8_2_2_B_AC(_ac) \ + LC3_QOS_BCAST_10_UNFRAMED(40000u, LC3_QOS_8_2_2_B_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_8_2, \ + LC3_QOS_8_2_2_B_RTN) +#define LC3_QOS_8_2_2_B LC3_QOS_8_2_2_B_AC(1) + +#define LC3_QOS_16_1_1_B_AC(_ac) \ + LC3_QOS_BCAST_7_5_UNFRAMED(40000u, LC3_QOS_16_1_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_16_1, \ + LC3_QOS_16_1_1_RTN) +#define LC3_QOS_16_1_1_B LC3_QOS_16_1_1_B_AC(1) + +#define LC3_QOS_16_1_2_B_LATENCY 45u +#define LC3_QOS_16_1_2_B_RTN 4u +#define LC3_QOS_16_1_2_B_AC(_ac) \ + LC3_QOS_BCAST_7_5_UNFRAMED(40000u, LC3_QOS_16_1_2_B_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_16_1, \ + LC3_QOS_16_1_2_B_RTN) +#define LC3_QOS_16_1_2_B LC3_QOS_16_1_2_B_AC(1) + +#define LC3_QOS_16_2_1_B_AC(_ac) \ + LC3_QOS_BCAST_10_UNFRAMED(40000u, LC3_QOS_16_2_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_16_2, \ + LC3_QOS_16_2_1_RTN) +#define LC3_QOS_16_2_1_B LC3_QOS_16_2_1_B_AC(1) + +#define LC3_QOS_16_2_2_B_LATENCY 60u +#define LC3_QOS_16_2_2_B_RTN 4u +#define LC3_QOS_16_2_2_B_AC(_ac) \ + LC3_QOS_BCAST_10_UNFRAMED(40000u, LC3_QOS_16_2_2_B_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_16_2, \ + LC3_QOS_16_2_2_B_RTN) +#define LC3_QOS_16_2_2_B LC3_QOS_16_2_2_B_AC(1) + +#define LC3_QOS_24_1_1_B_AC(_ac) \ + LC3_QOS_BCAST_7_5_UNFRAMED(40000u, LC3_QOS_24_1_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_24_1, \ + LC3_QOS_24_1_1_RTN) +#define LC3_QOS_24_1_1_B LC3_QOS_24_1_1_B_AC(1) + +#define LC3_QOS_24_1_2_B_LATENCY 45u +#define LC3_QOS_24_1_2_B_RTN 4u +#define LC3_QOS_24_1_2_B_AC(_ac) \ + LC3_QOS_BCAST_7_5_UNFRAMED(40000u, LC3_QOS_24_1_2_B_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_24_1, \ + LC3_QOS_24_1_2_B_RTN) +#define LC3_QOS_24_1_2_B LC3_QOS_24_1_2_B_AC(1) + +#define LC3_QOS_24_2_1_B_AC(_ac) \ + LC3_QOS_BCAST_10_UNFRAMED(40000u, LC3_QOS_24_2_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_24_2, \ + LC3_QOS_24_2_1_RTN) +#define LC3_QOS_24_2_1_B LC3_QOS_24_2_1_B_AC(1) + +#define LC3_QOS_24_2_2_B_LATENCY 60u +#define LC3_QOS_24_2_2_B_RTN 4u +#define LC3_QOS_24_2_2_B_AC(_ac) \ + LC3_QOS_BCAST_10_UNFRAMED(40000u, LC3_QOS_24_2_2_B_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_24_2, \ + LC3_QOS_24_2_2_B_RTN) +#define LC3_QOS_24_2_2_B LC3_QOS_24_2_2_B_AC(1) + +#define LC3_QOS_32_1_1_B_AC(_ac) \ + LC3_QOS_BCAST_7_5_UNFRAMED(40000u, LC3_QOS_32_1_1_LATENCY, \ + LC3_CONFIG_FRAME_LEN_32_1, \ + LC3_QOS_32_1_1_RTN) +#define LC3_QOS_32_1_1_B LC3_QOS_32_1_1_B_AC(1) + +#define LC3_QOS_32_1_2_B_LATENCY 45u +#define LC3_QOS_32_1_2_B_RTN 4u +#define LC3_QOS_32_1_2_B_AC(_ac) \ + LC3_QOS_BCAST_7_5_UNFRAMED(40000u, LC3_QOS_32_1_2_B_LATENCY, \ + LC3_CONFIG_FRAME_LEN_32_1, \ + LC3_QOS_32_1_2_B_RTN) +#define LC3_QOS_32_1_2_B LC3_QOS_32_1_2_B_AC(1) + +#define LC3_QOS_32_2_1_B_AC(_ac) \ + LC3_QOS_BCAST_10_UNFRAMED(40000u, LC3_QOS_32_2_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_32_2, \ + LC3_QOS_32_2_1_RTN) +#define LC3_QOS_32_2_1_B LC3_QOS_32_2_1_B_AC(1) + +#define LC3_QOS_32_2_2_B_LATENCY 60u +#define LC3_QOS_32_2_2_B_RTN 4u +#define LC3_QOS_32_2_2_B_AC(_ac) \ + LC3_QOS_BCAST_10_UNFRAMED(40000u, LC3_QOS_32_2_2_B_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_32_2, \ + LC3_QOS_32_2_2_B_RTN) +#define LC3_QOS_32_2_2_B LC3_QOS_32_2_2_B_AC(1) + +#define LC3_QOS_44_1_1_B_RTN 4u +#define LC3_QOS_44_1_1_B_AC(_ac) \ + LC3_QOS_BCAST_FRAMED(40000u, LC3_QOS_44_1_INTERVAL, \ + LC3_QOS_44_1_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_44_1, \ + LC3_QOS_44_1_1_B_RTN) +#define LC3_QOS_44_1_1_B LC3_QOS_44_1_1_B_AC(1) + +#define LC3_QOS_44_1_2_B_LATENCY 54u +#define LC3_QOS_44_1_2_B_RTN 4u +#define LC3_QOS_44_1_2_B_AC(_ac) \ + LC3_QOS_BCAST_FRAMED(40000u, LC3_QOS_44_1_INTERVAL, \ + LC3_QOS_44_1_2_B_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_44_1, \ + LC3_QOS_44_1_2_B_RTN) +#define LC3_QOS_44_1_2_B LC3_QOS_44_1_2_B_AC(1) + +#define LC3_QOS_44_2_1_B_RTN 4u +#define LC3_QOS_44_2_1_B_AC(_ac) \ + LC3_QOS_BCAST_FRAMED(40000u, LC3_QOS_44_2_INTERVAL, \ + LC3_QOS_44_2_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_44_2, \ + LC3_QOS_44_2_1_B_RTN) +#define LC3_QOS_44_2_1_B LC3_QOS_44_2_1_B_AC(1) + +#define LC3_QOS_44_2_2_B_LATENCY 60u +#define LC3_QOS_44_2_2_B_RTN 4u +#define LC3_QOS_44_2_2_B_AC(_ac) \ + LC3_QOS_BCAST_FRAMED(40000u, LC3_QOS_44_2_INTERVAL, \ + LC3_QOS_44_2_2_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_44_2, \ + LC3_QOS_44_2_2_RTN) +#define LC3_QOS_44_2_2_B LC3_QOS_44_2_2_B_AC(1) + +#define LC3_QOS_48_1_1_B_RTN 4u +#define LC3_QOS_48_1_1_B_AC(_ac) \ + LC3_QOS_BCAST_7_5_UNFRAMED(40000u, LC3_QOS_48_1_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_1,\ + LC3_QOS_48_1_1_B_RTN) +#define LC3_QOS_48_1_1_B LC3_QOS_48_1_1_B_AC(1) + +#define LC3_QOS_48_1_2_B_LATENCY 50u +#define LC3_QOS_48_1_2_B_RTN 4u +#define LC3_QOS_48_1_2_B_AC(_ac) \ + LC3_QOS_BCAST_7_5_UNFRAMED(40000u, LC3_QOS_48_1_2_B_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_1, \ + LC3_QOS_48_1_2_B_RTN) +#define LC3_QOS_48_1_2_B LC3_QOS_48_1_2_B_AC(1) + +#define LC3_QOS_48_2_1_B_RTN 4u +#define LC3_QOS_48_2_1_B_AC(_ac) \ + LC3_QOS_BCAST_10_UNFRAMED(40000u, LC3_QOS_48_2_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_2, \ + LC3_QOS_48_2_1_B_RTN) +#define LC3_QOS_48_2_1_B LC3_QOS_48_2_1_B_AC(1) + +#define LC3_QOS_48_2_2_B_LATENCY 65u +#define LC3_QOS_48_2_2_B_RTN 4u +#define LC3_QOS_48_2_2_B_AC(_ac) \ + LC3_QOS_BCAST_10_UNFRAMED(40000u, LC3_QOS_48_2_2_B_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_2, \ + LC3_QOS_48_2_2_B_RTN) +#define LC3_QOS_48_2_2_B LC3_QOS_48_2_2_B_AC(1) + +#define LC3_QOS_48_3_1_B_RTN 4u +#define LC3_QOS_48_3_1_B_AC(_ac) \ + LC3_QOS_BCAST_7_5_UNFRAMED(40000u, LC3_QOS_48_3_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_3, \ + LC3_QOS_48_3_1_B_RTN) +#define LC3_QOS_48_3_1_B LC3_QOS_48_3_1_B_AC(1) + +#define LC3_QOS_48_3_2_B_LATENCY 50u +#define LC3_QOS_48_3_2_B_RTN 4u +#define LC3_QOS_48_3_2_B_AC(_ac) \ + LC3_QOS_BCAST_7_5_UNFRAMED(40000u, LC3_QOS_48_3_2_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_3, \ + LC3_QOS_48_3_2_RTN) +#define LC3_QOS_48_3_2_B LC3_QOS_48_3_2_B_AC(1) + +#define LC3_QOS_48_4_1_B_RTN 4u +#define LC3_QOS_48_4_1_B_AC(_ac) \ + LC3_QOS_BCAST_10_UNFRAMED(40000u, LC3_QOS_48_4_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_4, \ + LC3_QOS_48_4_1_B_RTN) +#define LC3_QOS_48_4_1_B LC3_QOS_48_4_1_B_AC(1) + +#define LC3_QOS_48_4_2_B_LATENCY 65u +#define LC3_QOS_48_4_2_B_RTN 4u +#define LC3_QOS_48_4_2_B_AC(_ac) \ + LC3_QOS_BCAST_10_UNFRAMED(40000u, LC3_QOS_48_4_2_B_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_4, \ + LC3_QOS_48_4_2_B_RTN) +#define LC3_QOS_48_4_2_B LC3_QOS_48_4_2_B_AC(1) + +#define LC3_QOS_48_5_1_B_RTN 4u +#define LC3_QOS_48_5_1_B_AC(_ac) \ + LC3_QOS_BCAST_7_5_UNFRAMED(40000u, LC3_QOS_48_5_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_5, \ + LC3_QOS_48_5_1_B_RTN) +#define LC3_QOS_48_5_1_B LC3_QOS_48_5_1_B_AC(1) + +#define LC3_QOS_48_5_2_B_LATENCY 50u +#define LC3_QOS_48_5_2_B_RTN 4u +#define LC3_QOS_48_5_2_B_AC(_ac) \ + LC3_QOS_BCAST_7_5_UNFRAMED(40000u, LC3_QOS_48_5_2_B_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_5, \ + LC3_QOS_48_5_2_B_RTN) +#define LC3_QOS_48_5_2_B LC3_QOS_48_5_2_B_AC(1) + +#define LC3_QOS_48_6_1_B_RTN 5u +#define LC3_QOS_48_6_1_B_AC(_ac) \ + LC3_QOS_BCAST_10_UNFRAMED(40000u, LC3_QOS_48_6_1_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_6, \ + LC3_QOS_48_6_1_B_RTN) +#define LC3_QOS_48_6_1_B LC3_QOS_48_6_1_B_AC(1) + +#define LC3_QOS_48_6_2_B_LATENCY 65u +#define LC3_QOS_48_6_2_B_RTN 4u +#define LC3_QOS_48_6_2_B_AC(_ac) \ + LC3_QOS_BCAST_10_UNFRAMED(40000u, LC3_QOS_48_6_2_B_LATENCY, \ + (_ac) * LC3_CONFIG_FRAME_LEN_48_6, \ + LC3_QOS_48_6_2_B_RTN) +#define LC3_QOS_48_6_2_B LC3_QOS_48_6_2_B_AC(1) diff --git a/src/shared/log.c b/src/shared/log.c index 3f18e803d8e939de51ff24c9a74460f6112ae115..22b9850f6f110f1cacbd01b4b6f438c4ae38afc9 100644 --- a/src/shared/log.c +++ b/src/shared/log.c @@ -135,7 +135,7 @@ int bt_log_vprintf(uint16_t index, const char *label, int level, int len; len = vasprintf(&str, format, ap); - if (len < 0) + if (len < 0 || !str) return errno; len = strlen(str); diff --git a/src/shared/mainloop-notify.c b/src/shared/mainloop-notify.c index 33be3cf8d78ef339c6e2d93f2747f8f870842c4d..11989512e0138162cc3e6701a5aa4ddc0c68e748 100644 --- a/src/shared/mainloop-notify.c +++ b/src/shared/mainloop-notify.c @@ -15,6 +15,7 @@ #define _GNU_SOURCE #include <stdio.h> #include <errno.h> +#include <limits.h> #include <unistd.h> #include <stdlib.h> #include <stddef.h> @@ -130,7 +131,7 @@ static bool signal_read(struct io *io, void *user_data) fd = io_get_fd(io); result = read(fd, &si, sizeof(si)); - if (result != sizeof(si)) + if (result != sizeof(si) || si.ssi_signo > INT_MAX) return false; if (data && data->func) diff --git a/src/shared/mcp.c b/src/shared/mcp.c index b3726ebae5d71a1303fb09907047f36740678ec3..20a540a70bcc20cb6eeddb9e45449b553d4aacca 100644 --- a/src/shared/mcp.c +++ b/src/shared/mcp.c @@ -600,6 +600,9 @@ static unsigned int mcp_send(struct bt_mcp *mcp, uint8_t operation) unsigned int bt_mcp_play(struct bt_mcp *mcp) { + if (!mcp) + return 0; + if (!(mcp->session.cp_op_supported & BT_MCS_CMD_PLAY_SUPPORTED)) return -ENOTSUP; @@ -610,6 +613,9 @@ unsigned int bt_mcp_play(struct bt_mcp *mcp) unsigned int bt_mcp_pause(struct bt_mcp *mcp) { + if (!mcp) + return 0; + if (!(mcp->session.cp_op_supported & BT_MCS_CMD_PAUSE_SUPPORTED)) return -ENOTSUP; @@ -620,6 +626,9 @@ unsigned int bt_mcp_pause(struct bt_mcp *mcp) unsigned int bt_mcp_stop(struct bt_mcp *mcp) { + if (!mcp) + return 0; + if (!(mcp->session.cp_op_supported & BT_MCS_CMD_STOP_SUPPORTED)) return -ENOTSUP; @@ -628,10 +637,41 @@ unsigned int bt_mcp_stop(struct bt_mcp *mcp) return mcp_send(mcp, BT_MCS_CMD_STOP); } +unsigned int bt_mcp_next_track(struct bt_mcp *mcp) +{ + if (!mcp) + return 0; + + if (!(mcp->session.cp_op_supported & BT_MCS_CMD_NEXT_TRACK_SUPPORTED)) + return -ENOTSUP; + + DBG(mcp, "mcp %p", mcp); + + return mcp_send(mcp, BT_MCS_CMD_NEXT_TRACK); +} + +unsigned int bt_mcp_previous_track(struct bt_mcp *mcp) +{ + if (!mcp) + return 0; + + if (!(mcp->session.cp_op_supported & BT_MCS_CMD_PREV_TRACK_SUPPORTED)) + return -ENOTSUP; + + DBG(mcp, "mcp %p", mcp); + + return mcp_send(mcp, BT_MCS_CMD_PREV_TRACK); +} + static void mcp_mp_set_player_name(struct bt_mcp *mcp, const uint8_t *value, uint16_t length) { - struct event_callback *cb = mcp->cb; + struct event_callback *cb; + + if (!mcp) + return; + + cb = mcp->cb; if (cb && cb->cbs && cb->cbs->player_name) cb->cbs->player_name(mcp, value, length); @@ -640,7 +680,12 @@ static void mcp_mp_set_player_name(struct bt_mcp *mcp, const uint8_t *value, static void mcp_mp_set_track_title(struct bt_mcp *mcp, const uint8_t *value, uint16_t length) { - struct event_callback *cb = mcp->cb; + struct event_callback *cb; + + if (!mcp) + return; + + cb = mcp->cb; if (cb && cb->cbs && cb->cbs->track_title) cb->cbs->track_title(mcp, value, length); @@ -648,7 +693,12 @@ static void mcp_mp_set_track_title(struct bt_mcp *mcp, const uint8_t *value, static void mcp_mp_set_title_duration(struct bt_mcp *mcp, int32_t duration) { - struct event_callback *cb = mcp->cb; + struct event_callback *cb; + + if (!mcp) + return; + + cb = mcp->cb; DBG(mcp, "Track Duration 0x%08x", duration); @@ -658,7 +708,12 @@ static void mcp_mp_set_title_duration(struct bt_mcp *mcp, int32_t duration) static void mcp_mp_set_title_position(struct bt_mcp *mcp, int32_t position) { - struct event_callback *cb = mcp->cb; + struct event_callback *cb; + + if (!mcp) + return; + + cb = mcp->cb; DBG(mcp, "Track Position 0x%08x", position); @@ -668,7 +723,12 @@ static void mcp_mp_set_title_position(struct bt_mcp *mcp, int32_t position) static void mcp_mp_set_media_state(struct bt_mcp *mcp, uint8_t state) { - struct event_callback *cb = mcp->cb; + struct event_callback *cb; + + if (!mcp) + return; + + cb = mcp->cb; DBG(mcp, "Media State 0x%02x", state); @@ -1292,6 +1352,9 @@ void bt_mcp_set_event_callbacks(struct bt_mcp *mcp, { struct event_callback *cb; + if (!mcp) + return; + if (mcp->cb) free(mcp->cb); @@ -1377,6 +1440,9 @@ done: void bt_mcp_register(struct gatt_db *db) { + if (!db) + return; + mcp_db_new(db); } @@ -1384,6 +1450,9 @@ bool bt_mcp_attach(struct bt_mcp *mcp, struct bt_gatt_client *client) { bt_uuid_t uuid; + if (!mcp) + return false; + DBG(mcp, "mcp %p", mcp); mcp->client = bt_gatt_client_clone(client); @@ -1412,6 +1481,9 @@ bool bt_mcp_attach(struct bt_mcp *mcp, struct bt_gatt_client *client) void bt_mcp_detach(struct bt_mcp *mcp) { + if (!mcp) + return; + DBG(mcp, "%p", mcp); bt_gatt_client_unref(mcp->client); diff --git a/src/shared/mcp.h b/src/shared/mcp.h index a2cd6fc455e86bb90edebce3f25fe8c8f86057bf..ee57ed4bf6f54efb4b86a283820a0cac3ff5c85d 100644 --- a/src/shared/mcp.h +++ b/src/shared/mcp.h @@ -59,3 +59,5 @@ void *bt_mcp_get_user_data(struct bt_mcp *mcp); unsigned int bt_mcp_play(struct bt_mcp *mcp); unsigned int bt_mcp_pause(struct bt_mcp *mcp); unsigned int bt_mcp_stop(struct bt_mcp *mcp); +unsigned int bt_mcp_next_track(struct bt_mcp *mcp); +unsigned int bt_mcp_previous_track(struct bt_mcp *mcp); diff --git a/src/shared/micp.c b/src/shared/micp.c new file mode 100644 index 0000000000000000000000000000000000000000..1c34e9d0079f400be257c0e4a83342ece7d9878a --- /dev/null +++ b/src/shared/micp.c @@ -0,0 +1,894 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2023 NXP Semiconductors. All rights reserved. + * + */ +#define _GNU_SOURCE +#include <inttypes.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> +#include <unistd.h> +#include <errno.h> + +#include "lib/bluetooth.h" +#include "lib/uuid.h" + +#include "src/shared/queue.h" +#include "src/shared/util.h" +#include "src/shared/timeout.h" +#include "src/shared/att.h" +#include "src/shared/gatt-db.h" +#include "src/shared/gatt-server.h" +#include "src/shared/gatt-helpers.h" +#include "src/shared/micp.h" + +#define DBG(_micp, fmt, arg...) \ + micp_debug(_micp, "%s:%s() " fmt, __FILE__, __func__, ##arg) + +/* Application error codes */ +#define MICP_ERROR_MUTE_DISABLED 0x80 +#define MICP_ERROR_VALUE_NOT_ALLOWED 0x13 +#define BT_ATT_ERROR_OPCODE_NOT_SUPPORTED 0x81 + +/* Mute char values */ +#define MICS_NOT_MUTED 0x00 +#define MICS_MUTED 0x01 +#define MICS_DISABLED 0x02 + +static struct queue *micp_db; +static struct queue *micp_cbs; +static struct queue *sessions; + +struct bt_micp_cb { + unsigned int id; + bt_micp_func_t attached; + bt_micp_func_t detached; + void *user_data; +}; + +typedef void (*micp_func_t)(struct bt_micp *micp, bool success, + uint8_t att_ecode, const uint8_t *value, + uint16_t length, void *user_data); + +struct bt_micp_pending { + unsigned int id; + struct bt_micp *micp; + micp_func_t func; + void *userdata; +}; + +struct bt_micp_ready { + unsigned int id; + bt_micp_ready_func_t func; + bt_micp_destroy_func_t destroy; + void *data; +}; + +typedef void (*micp_notify_t)(struct bt_micp *micp, uint16_t value_handle, + const uint8_t *value, uint16_t length, + void *user_data); + +struct bt_micp_notify { + unsigned int id; + struct bt_micp *micp; + micp_notify_t func; + void *user_data; +}; + +static void *iov_pull_mem(struct iovec *iov, size_t len) +{ + void *data = iov->iov_base; + + if (iov->iov_len < len) + return NULL; + + iov->iov_base += len; + iov->iov_len -= len; + + return data; +} + +static struct bt_micp_db *micp_get_mdb(struct bt_micp *micp) +{ + if (!micp) + return NULL; + + if (micp->ldb) + return micp->ldb; + + return NULL; +} + +static uint8_t *mdb_get_mute_state(struct bt_micp_db *vdb) +{ + if (!vdb->mics) + return NULL; + + return &(vdb->mics->mute_stat); +} + +struct bt_mics *micp_get_mics(struct bt_micp *micp) +{ + if (!micp) + return NULL; + + if (micp->rdb->mics) + return micp->rdb->mics; + + micp->rdb->mics = new0(struct bt_mics, 1); + micp->rdb->mics->mdb = micp->rdb; + + return micp->rdb->mics; +} + +static void micp_detached(void *data, void *user_data) +{ + struct bt_micp_cb *cb = data; + struct bt_micp *micp = user_data; + + cb->detached(micp, cb->user_data); +} + +void bt_micp_detach(struct bt_micp *micp) +{ + if (!queue_remove(sessions, micp)) + return; + + bt_gatt_client_idle_unregister(micp->client, micp->idle_id); + bt_gatt_client_unref(micp->client); + micp->client = NULL; + + queue_foreach(micp_cbs, micp_detached, micp); +} + +static void micp_db_free(void *data) +{ + struct bt_micp_db *mdb = data; + + if (!mdb) + return; + + gatt_db_unref(mdb->db); + + free(mdb->mics); + free(mdb); +} + +static void micp_ready_free(void *data) +{ + struct bt_micp_ready *ready = data; + + if (ready->destroy) + ready->destroy(ready->data); + + free(ready); +} + +static void micp_free(void *data) +{ + struct bt_micp *micp = data; + + bt_micp_detach(micp); + + micp_db_free(micp->rdb); + + queue_destroy(micp->notify, free); + queue_destroy(micp->pending, NULL); + queue_destroy(micp->ready_cbs, micp_ready_free); + + free(micp); +} + +bool bt_micp_set_user_data(struct bt_micp *micp, void *user_data) +{ + + if (!micp) + return false; + + micp->user_data = user_data; + + return true; +} + +static bool micp_db_match(const void *data, const void *match_data) +{ + const struct bt_micp_db *mdb = data; + const struct gatt_db *db = match_data; + + return (mdb->db == db); +} + +struct bt_att *bt_micp_get_att(struct bt_micp *micp) +{ + if (!micp) + return NULL; + + if (micp->att) + return micp->att; + + return bt_gatt_client_get_att(micp->client); +} + +struct bt_micp *bt_micp_ref(struct bt_micp *micp) +{ + if (!micp) + return NULL; + + __sync_fetch_and_add(&micp->ref_count, 1); + + return micp; +} + +void bt_micp_unref(struct bt_micp *micp) +{ + if (!micp) + return; + + if (__sync_sub_and_fetch(&micp->ref_count, 1)) + return; + + micp_free(micp); +} + +static void micp_debug(struct bt_micp *micp, const char *format, ...) +{ + va_list ap; + + if (!micp || !format || !micp->debug_func) + return; + + va_start(ap, format); + util_debug_va(micp->debug_func, micp->debug_data, format, ap); + va_end(ap); +} + +static void micp_disconnected(int err, void *user_data) +{ + struct bt_micp *micp = user_data; + + DBG(micp, "micp %p disconnected err %d", micp, err); + + bt_micp_detach(micp); +} + +static struct bt_micp *micp_get_session(struct bt_att *att, struct gatt_db *db) +{ + const struct queue_entry *entry; + struct bt_micp *micp; + + for (entry = queue_get_entries(sessions); entry; entry = entry->next) { + struct bt_micp *micp = entry->data; + + if (att == bt_micp_get_att(micp)) + return micp; + } + + micp = bt_micp_new(db, NULL); + micp->att = att; + + bt_att_register_disconnect(att, micp_disconnected, micp, NULL); + + bt_micp_attach(micp, NULL); + + return micp; +} + +static void mics_mute_read(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct bt_mics *mics = user_data; + struct iovec iov; + + iov.iov_base = &mics->mute_stat; + iov.iov_len = sizeof(mics->mute_stat); + + gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base, + iov.iov_len); +} + +static uint8_t mics_not_muted(struct bt_mics *mics, struct bt_micp *micp, + struct iovec *iov) +{ + struct bt_micp_db *mdb; + uint8_t *mute_state; + + DBG(micp, "Mute state OP: Not Muted"); + + mdb = micp_get_mdb(micp); + if (!mdb) { + DBG(micp, "error: MDB not available"); + return 0; + } + + mute_state = mdb_get_mute_state(mdb); + if (!mute_state) { + DBG(micp, "Error : Mute State not available"); + return 0; + } + + *mute_state = MICS_NOT_MUTED; + + gatt_db_attribute_notify(mdb->mics->ms, (void *)mute_state, + sizeof(uint8_t), bt_micp_get_att(micp)); + + return 0; +} + +static uint8_t mics_muted(struct bt_mics *mics, struct bt_micp *micp, + struct iovec *iov) +{ + struct bt_micp_db *mdb; + uint8_t *mute_state; + + DBG(micp, "Mute state OP: Muted"); + + mdb = micp_get_mdb(micp); + if (!mdb) { + DBG(micp, "error: MDB not available"); + return 0; + } + + mute_state = mdb_get_mute_state(mdb); + + *mute_state = MICS_MUTED; + + gatt_db_attribute_notify(mdb->mics->ms, (void *)mute_state, + sizeof(uint8_t), bt_micp_get_att(micp)); + + return 0; +} + +#define MICS_OP(_str, _op, _size, _func) \ + { \ + .str = _str, \ + .op = _op, \ + .size = _size, \ + .func = _func, \ + } + +struct mics_op_handler { + const char *str; + uint8_t op; + size_t size; + uint8_t (*func)(struct bt_mics *mics, struct bt_micp *micp, + struct iovec *iov); +} micp_handlers[] = { + MICS_OP("Not Muted", MICS_NOT_MUTED, + sizeof(uint8_t), mics_not_muted), + MICS_OP("Muted", MICS_MUTED, + sizeof(uint8_t), mics_muted), + {}}; + +static void mics_mute_write(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + const uint8_t *value, size_t len, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct bt_mics *mics = user_data; + struct bt_micp *micp = micp_get_session(att, mics->mdb->db); + struct iovec iov = { + .iov_base = (void *)value, + .iov_len = len, + }; + uint8_t *micp_op, *mute_state; + struct mics_op_handler *handler; + uint8_t ret = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED; + struct bt_micp_db *mdb; + + DBG(micp, "MICS Mute Char write: len: %ld: %ld", len, iov.iov_len); + + if (offset) { + DBG(micp, "invalid offset: %d", offset); + ret = BT_ATT_ERROR_INVALID_OFFSET; + goto respond; + } + + if (len < sizeof(*micp_op)) { + DBG(micp, "invalid length: %ld < %ld sizeof(param)", len, + sizeof(*micp_op)); + ret = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN; + goto respond; + } + + micp_op = iov_pull_mem(&iov, sizeof(*micp_op)); + if (!micp_op) { + DBG(micp, "iov_pull_mem() returned NULL"); + goto respond; + } + + if ((*micp_op == MICS_DISABLED) || (*micp_op != MICS_NOT_MUTED + && *micp_op != MICS_MUTED)) { + DBG(micp, "Invalid operation - MICS DISABLED/RFU mics op:%d", + micp_op); + ret = MICP_ERROR_VALUE_NOT_ALLOWED; + goto respond; + } + + mdb = micp_get_mdb(micp); + if (!mdb) { + DBG(micp, "error: MDB not available"); + goto respond; + } + + mute_state = mdb_get_mute_state(mdb); + if (*mute_state == MICS_DISABLED) { + DBG(micp, "state: MICS DISABLED , can not write value: %d", + *micp_op); + ret = MICP_ERROR_MUTE_DISABLED; + goto respond; + } + + for (handler = micp_handlers; handler && handler->str; handler++) { + DBG(micp, "handler->op: %d micp_op: %d iov.iov_len: %ld", + handler->op, *micp_op, iov.iov_len); + if (handler->op != *micp_op) + continue; + + if (len < handler->size) { + DBG(micp, "invalid len %ld : %ld < %ld handler->size", + len, iov.iov_len, handler->size); + ret = BT_ATT_ERROR_OPCODE_NOT_SUPPORTED; + goto respond; + } + + break; + } + + if (handler && handler->str) { + DBG(micp, "%s", handler->str); + + ret = handler->func(mics, micp, &iov); + } else { + DBG(micp, "unknown opcode 0x%02x", *micp_op); + ret = BT_ATT_ERROR_OPCODE_NOT_SUPPORTED; + } + +respond: + gatt_db_attribute_write_result(attrib, id, ret); +} + +static struct bt_mics *mics_new(struct gatt_db *db) +{ + struct bt_mics *mics; + bt_uuid_t uuid; + + if (!db) + return NULL; + + mics = new0(struct bt_mics, 1); + + mics->mute_stat = MICS_MUTED; + + /* Populate DB with MICS attributes */ + bt_uuid16_create(&uuid, MICS_UUID); + mics->service = gatt_db_add_service(db, &uuid, true, 4); + + bt_uuid16_create(&uuid, MUTE_CHRC_UUID); + mics->ms = gatt_db_service_add_characteristic(mics->service, + &uuid, + BT_ATT_PERM_READ | BT_ATT_PERM_WRITE, + BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_WRITE + | BT_GATT_CHRC_PROP_NOTIFY, + mics_mute_read, mics_mute_write, + mics); + + mics->ms_ccc = gatt_db_service_add_ccc(mics->service, + BT_ATT_PERM_READ | BT_ATT_PERM_WRITE); + + gatt_db_service_set_active(mics->service, true); + + return mics; +} + +static struct bt_micp_db *micp_db_new(struct gatt_db *db) +{ + struct bt_micp_db *mdb; + + if (!db) + return NULL; + + mdb = new0(struct bt_micp_db, 1); + mdb->db = gatt_db_ref(db); + + if (!micp_db) + micp_db = queue_new(); + + mdb->mics = mics_new(db); + mdb->mics->mdb = mdb; + + queue_push_tail(micp_db, mdb); + + return mdb; +} + +static struct bt_micp_db *micp_get_db(struct gatt_db *db) +{ + struct bt_micp_db *mdb; + + mdb = queue_find(micp_db, micp_db_match, db); + if (mdb) + return mdb; + + return micp_db_new(db); +} + +void bt_micp_add_db(struct gatt_db *db) +{ + micp_db_new(db); +} + +bool bt_micp_set_debug(struct bt_micp *micp, bt_micp_debug_func_t func, + void *user_data, bt_micp_destroy_func_t destroy) +{ + if (!micp) + return false; + + if (micp->debug_destroy) + micp->debug_destroy(micp->debug_data); + + micp->debug_func = func; + micp->debug_destroy = destroy; + micp->debug_data = user_data; + + return true; +} + +unsigned int bt_micp_register(bt_micp_func_t attached, bt_micp_func_t detached, + void *user_data) +{ + struct bt_micp_cb *cb; + static unsigned int id; + + if (!attached && !detached) + return 0; + + if (!micp_cbs) + micp_cbs = queue_new(); + + cb = new0(struct bt_micp_cb, 1); + cb->id = ++id ? id : ++id; + cb->attached = attached; + cb->detached = detached; + cb->user_data = user_data; + + queue_push_tail(micp_cbs, cb); + + return cb->id; +} + +static bool match_id(const void *data, const void *match_data) +{ + const struct bt_micp_cb *cb = data; + unsigned int id = PTR_TO_UINT(match_data); + + return (cb->id == id); +} + +bool bt_micp_unregister(unsigned int id) +{ + struct bt_micp_cb *cb; + + cb = queue_remove_if(micp_cbs, match_id, UINT_TO_PTR(id)); + if (!cb) + return false; + + free(cb); + + return true; +} + +struct bt_micp *bt_micp_new(struct gatt_db *ldb, struct gatt_db *rdb) +{ + struct bt_micp *micp; + struct bt_micp_db *mdb; + + if (!ldb) + return NULL; + + mdb = micp_get_db(ldb); + if (!mdb) + return NULL; + + micp = new0(struct bt_micp, 1); + micp->ldb = mdb; + micp->pending = queue_new(); + micp->ready_cbs = queue_new(); + micp->notify = queue_new(); + + if (!rdb) + goto done; + + mdb = new0(struct bt_micp_db, 1); + mdb->db = gatt_db_ref(rdb); + + micp->rdb = mdb; + +done: + bt_micp_ref(micp); + + return micp; +} + +static void micp_pending_destroy(void *data) +{ + struct bt_micp_pending *pending = data; + struct bt_micp *micp = pending->micp; + + if (queue_remove_if(micp->pending, NULL, pending)) + free(pending); +} + +static void micp_pending_complete(bool success, uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) +{ + struct bt_micp_pending *pending = user_data; + + if (pending->func) + pending->func(pending->micp, success, att_ecode, value, length, + pending->userdata); +} + +static void micp_read_value(struct bt_micp *micp, uint16_t value_handle, + micp_func_t func, void *user_data) +{ + struct bt_micp_pending *pending; + + pending = new0(struct bt_micp_pending, 1); + pending->micp = micp; + pending->func = func; + pending->userdata = user_data; + + pending->id = bt_gatt_client_read_value(micp->client, value_handle, + micp_pending_complete, pending, + micp_pending_destroy); + + if (!pending->id) { + DBG(micp, "unable to send read request"); + free(pending); + return; + } + + queue_push_tail(micp->pending, pending); +} + +static void micp_register(uint16_t att_ecode, void *user_data) +{ + struct bt_micp_notify *notify = user_data; + + if (att_ecode) + DBG(notify->micp, "MICP register failed 0x%04x", att_ecode); +} + +static void micp_notify(uint16_t value_handle, const uint8_t *value, + uint16_t length, void *user_data) +{ + struct bt_micp_notify *notify = user_data; + + if (notify->func) + notify->func(notify->micp, value_handle, value, length, + notify->user_data); +} + +static void micp_notify_destroy(void *data) +{ + struct bt_micp_notify *notify = data; + struct bt_micp *micp = notify->micp; + + if (queue_remove_if(micp->notify, NULL, notify)) + free(notify); +} + +static unsigned int micp_register_notify(struct bt_micp *micp, + uint16_t value_handle, + micp_notify_t func, + void *user_data) +{ + struct bt_micp_notify *notify; + + notify = new0(struct bt_micp_notify, 1); + notify->micp = micp; + notify->func = func; + notify->user_data = user_data; + + notify->id = bt_gatt_client_register_notify(micp->client, + value_handle, micp_register, + micp_notify, notify, + micp_notify_destroy); + if (!notify->id) { + DBG(micp, "Unable to register for notifications"); + free(notify); + return 0; + } + + queue_push_tail(micp->notify, notify); + + return notify->id; +} + +static void micp_mute_state_notify(struct bt_micp *micp, uint16_t value_handle, + const uint8_t *value, uint16_t length, + void *user_data) +{ + uint8_t mute_state; + + memcpy(&mute_state, value, sizeof(mute_state)); + + DBG(micp, "Mute state: 0x%x", mute_state); +} + +static void read_mute_state(struct bt_micp *micp, bool success, + uint8_t att_ecode, const uint8_t *value, + uint16_t length, void *user_data) +{ + uint8_t *mute_state; + struct iovec iov = { + .iov_base = (void *)value, + .iov_len = length, + }; + + if (!success) { + DBG(micp, "Unable to read Mute state: error 0x%02x", att_ecode); + return; + } + + mute_state = iov_pull_mem(&iov, sizeof(uint8_t)); + if (mute_state == NULL) { + DBG(micp, "Unable to get Mute state"); + return; + } + + DBG(micp, "Mute state: %x", *mute_state); +} + +static void foreach_mics_char(struct gatt_db_attribute *attr, void *user_data) +{ + struct bt_micp *micp = user_data; + uint16_t value_handle; + bt_uuid_t uuid, uuid_mute; + struct bt_mics *mics; + + if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, + NULL, NULL, &uuid)) + return; + + bt_uuid16_create(&uuid_mute, MUTE_CHRC_UUID); + if (!bt_uuid_cmp(&uuid, &uuid_mute)) { + DBG(micp, "MICS Mute characteristic found: handle 0x%04x", + value_handle); + + mics = micp_get_mics(micp); + if (!mics || mics->ms) + return; + + mics->ms = attr; + + micp_read_value(micp, value_handle, read_mute_state, micp); + + micp->mute_id = micp_register_notify(micp, value_handle, + micp_mute_state_notify, NULL); + } +} + +static void foreach_mics_service(struct gatt_db_attribute *attr, + void *user_data) +{ + struct bt_micp *micp = user_data; + struct bt_mics *mics = micp_get_mics(micp); + + mics->service = attr; + + gatt_db_service_set_claimed(attr, true); + gatt_db_service_foreach_char(attr, foreach_mics_char, micp); +} + +unsigned int bt_micp_ready_register(struct bt_micp *micp, + bt_micp_ready_func_t func, void *user_data, + bt_micp_destroy_func_t destroy) +{ + struct bt_micp_ready *ready; + static unsigned int id; + + DBG(micp, "bt_micp_ready_register_Entry\n"); + if (!micp) + return 0; + + ready = new0(struct bt_micp_ready, 1); + ready->id = ++id ? id : ++id; + ready->func = func; + ready->destroy = destroy; + ready->data = user_data; + + queue_push_tail(micp->ready_cbs, ready); + + return ready->id; +} + +static bool match_ready_id(const void *data, const void *match_data) +{ + const struct bt_micp_ready *ready = data; + unsigned int id = PTR_TO_UINT(match_data); + + return (ready->id == id); +} + +bool bt_micp_ready_unregister(struct bt_micp *micp, unsigned int id) +{ + struct bt_micp_ready *ready; + + ready = queue_remove_if(micp->ready_cbs, match_ready_id, + UINT_TO_PTR(id)); + if (!ready) + return false; + + micp_ready_free(ready); + + return true; +} + +static struct bt_micp *bt_micp_ref_safe(struct bt_micp *micp) +{ + if (!micp || !micp->ref_count) + return NULL; + + return bt_micp_ref(micp); +} + +static void micp_notify_ready(struct bt_micp *micp) +{ + const struct queue_entry *entry; + + if (!bt_micp_ref_safe(micp)) + return; + + for (entry = queue_get_entries(micp->ready_cbs); entry; + entry = entry->next) { + struct bt_micp_ready *ready = entry->data; + + ready->func(micp, ready->data); + } + + bt_micp_unref(micp); +} + +static void micp_idle(void *data) +{ + struct bt_micp *micp = data; + + micp->idle_id = 0; + micp_notify_ready(micp); +} + +bool bt_micp_attach(struct bt_micp *micp, struct bt_gatt_client *client) +{ + bt_uuid_t uuid; + + if (!sessions) + sessions = queue_new(); + + queue_push_tail(sessions, micp); + + if (!client) + return true; + + if (micp->client) + return false; + + micp->client = bt_gatt_client_clone(client); + if (!micp->client) + return false; + + bt_gatt_client_idle_register(micp->client, micp_idle, micp, NULL); + + bt_uuid16_create(&uuid, MICS_UUID); + gatt_db_foreach_service(micp->ldb->db, &uuid, foreach_mics_service, + micp); + return true; +} diff --git a/src/shared/micp.h b/src/shared/micp.h new file mode 100644 index 0000000000000000000000000000000000000000..c881aded911b6e4953d87b6e40f358938accc8cd --- /dev/null +++ b/src/shared/micp.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2023 NXP Semiconductors. All rights reserved. + * + */ +#include <stdbool.h> +#include <inttypes.h> + +#include "src/shared/io.h" +#include "src/shared/gatt-client.h" + +struct bt_mics; +struct bt_micp; + +typedef void (*bt_micp_ready_func_t)(struct bt_micp *micp, void *user_data); +typedef void (*bt_micp_destroy_func_t)(void *user_data); +typedef void (*bt_micp_debug_func_t)(const char *str, void *user_data); +typedef void (*bt_micp_func_t)(struct bt_micp *micp, void *user_data); + +struct bt_micp_db { + struct gatt_db *db; + struct bt_mics *mics; +}; + +struct bt_mics { + struct bt_micp_db *mdb; + uint8_t mute_stat; + struct gatt_db_attribute *service; + struct gatt_db_attribute *ms; + struct gatt_db_attribute *ms_ccc; +}; + +struct bt_micp { + int ref_count; + struct bt_micp_db *ldb; + struct bt_micp_db *rdb; + struct bt_gatt_client *client; + struct bt_att *att; + unsigned int mute_id; + + unsigned int idle_id; + uint8_t mute; + + struct queue *notify; + struct queue *pending; + struct queue *ready_cbs; + + bt_micp_debug_func_t debug_func; + bt_micp_destroy_func_t debug_destroy; + + void *debug_data; + void *user_data; +}; + +struct bt_micp *bt_micp_ref(struct bt_micp *micp); +void bt_micp_unref(struct bt_micp *micp); + +void bt_micp_add_db(struct gatt_db *db); + +bool bt_micp_attach(struct bt_micp *micp, struct bt_gatt_client *client); +void bt_micp_detach(struct bt_micp *micp); + +bool bt_micp_set_debug(struct bt_micp *micp, bt_micp_debug_func_t func, + void *user_data, bt_micp_destroy_func_t destroy); + +struct bt_att *bt_micp_get_att(struct bt_micp *micp); + +bool bt_micp_set_user_data(struct bt_micp *micp, void *user_data); + +/* session related functions */ +unsigned int bt_micp_register(bt_micp_func_t attached, bt_micp_func_t detached, + void *user_data); +unsigned int bt_micp_ready_register(struct bt_micp *micp, + bt_micp_ready_func_t func, void *user_data, + bt_micp_destroy_func_t destroy); +bool bt_micp_ready_unregister(struct bt_micp *micp, unsigned int id); + +bool bt_micp_unregister(unsigned int id); +struct bt_micp *bt_micp_new(struct gatt_db *ldb, struct gatt_db *rdb); +struct bt_mics *micp_get_mics(struct bt_micp *micp); diff --git a/src/shared/ringbuf.c b/src/shared/ringbuf.c index 3dc7ed71b2b2766ab5f932d3b5d2771fda038581..1b7adbb4f513563626e25576ba0e20009f1ac7d7 100644 --- a/src/shared/ringbuf.c +++ b/src/shared/ringbuf.c @@ -237,7 +237,7 @@ int ringbuf_vprintf(struct ringbuf *ringbuf, const char *format, va_list ap) ringbuf->in_tracing(ringbuf->buffer + offset, end, ringbuf->in_data); - if (len - end > 0) { + if ((size_t) len > end) { /* Put the remainder of string at the beginning */ memcpy(ringbuf->buffer, str + end, len - end); diff --git a/src/shared/shell.c b/src/shared/shell.c index 0639c786d98304c690173ab99414475ba86e3d49..a8fa8769608827a7dd47bcf774129ccea937a5fa 100644 --- a/src/shared/shell.c +++ b/src/shared/shell.c @@ -4,7 +4,7 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2017 Intel Corporation. All rights reserved. - * + * Copyright 2024 NXP * */ @@ -24,6 +24,7 @@ #include <sys/signalfd.h> #include <wordexp.h> #include <getopt.h> +#include <fcntl.h> #include <readline/readline.h> #include <readline/history.h> @@ -59,6 +60,11 @@ struct bt_shell_prompt_input { void *user_data; }; +struct input { + struct io *io; + FILE *f; +}; + static struct { bool init; char *name; @@ -69,7 +75,11 @@ static struct { bool zsh; bool monitor; int timeout; - struct io *input; + int init_fd; + struct queue *inputs; + + char *line; + struct queue *queue; bool saved_prompt; bt_shell_prompt_input_func saved_func; @@ -252,6 +262,162 @@ static void cmd_export(int argc, char *argv[]) } } +static int bt_shell_queue_exec(char *line) +{ + int err; + + /* Ignore comments */ + if (line[0] == '#') + return 0; + + /* Queue if already executing */ + if (data.line) { + /* Check if prompt is being held then release using the line */ + if (!bt_shell_release_prompt(line)) { + bt_shell_printf("%s\n", line); + return 0; + } + + queue_push_tail(data.queue, strdup(line)); + return 0; + } + + bt_shell_printf("%s\n", line); + + err = bt_shell_exec(line); + if (!err) + data.line = strdup(line); + + return err; +} + +static bool bt_shell_input_line(struct input *input) +{ + int fd; + char *line = NULL; + size_t len = 0; + ssize_t nread; + + fd = io_get_fd(input->io); + + if (fd < 0) { + printf("io_get_fd() returned %d\n", fd); + return false; + } + + if (fd == STDIN_FILENO) { + rl_callback_read_char(); + return true; + } + + if (!input->f) { + input->f = fdopen(fd, "r"); + if (!input->f) { + printf("fdopen: %s (%d)\n", strerror(errno), errno); + return false; + } + } + + nread = getline(&line, &len, input->f); + if (nread > 0) { + int err; + + if (line[nread - 1] == '\n') + line[nread - 1] = '\0'; + + err = bt_shell_queue_exec(line); + if (err < 0) + printf("%s: %s (%d)\n", line, strerror(-err), -err); + } else if (input->f) { + fclose(input->f); + input->f = NULL; + } + + free(line); + + return input->f ? true : false; +} + +static bool input_read(struct io *io, void *user_data) +{ + return bt_shell_input_line(user_data); +} + +static bool input_hup(struct io *io, void *user_data) +{ + if (queue_remove(data.inputs, user_data)) { + if (!queue_isempty(data.inputs)) + return false; + } + + mainloop_quit(); + + return false; +} + +static struct input *input_new(int fd) +{ + struct input *input; + struct io *io; + + io = io_new(fd); + if (!io) + return false; + + input = new0(struct input, 1); + input->io = io; + + queue_push_tail(data.inputs, input); + + return input; +} + +static bool bt_shell_input_attach(int fd) +{ + struct input *input; + struct queue *queue; + + input = input_new(fd); + if (!input) + return false; + + /* Save executing queue so input lines can be placed in the correct + * order. + */ + queue = data.queue; + data.queue = queue_new(); + + while (bt_shell_input_line(input)); + + /* Push existing input lines back into the executing queue */ + while (!queue_isempty(queue)) + queue_push_tail(data.queue, queue_pop_head(queue)); + + queue_destroy(queue, free); + + return true; +} + +static void cmd_script(int argc, char *argv[]) +{ + int fd; + + fd = open(argv[1], O_RDONLY); + if (fd < 0) { + printf("Unable to open %s: %s (%d)\n", argv[1], + strerror(errno), errno); + bt_shell_noninteractive_quit(EXIT_FAILURE); + return; + } + + printf("Running script %s...\n", argv[1]); + + if (!bt_shell_input_attach(fd)) + return bt_shell_noninteractive_quit(EXIT_FAILURE); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + static const struct bt_shell_menu_entry default_menu[] = { { "back", NULL, cmd_back, "Return to main menu", NULL, NULL, cmd_back_exists }, @@ -265,6 +431,7 @@ static const struct bt_shell_menu_entry default_menu[] = { "Display help about this program" }, { "export", NULL, cmd_export, "Print environment variables" }, + { "script", "<filename>", cmd_script, "Run script" }, { } }; @@ -535,7 +702,7 @@ void bt_shell_printf(const char *fmt, ...) char *saved_line; int saved_point; - if (!data.input) + if (queue_isempty(data.inputs)) return; if (data.mode) { @@ -552,8 +719,7 @@ void bt_shell_printf(const char *fmt, ...) saved_line = rl_copy_text(0, rl_end); if (!data.saved_prompt) rl_save_prompt(); - rl_replace_line("", 0); - rl_redisplay(); + rl_reset_line_state(); } va_start(args, fmt); @@ -571,11 +737,29 @@ void bt_shell_printf(const char *fmt, ...) rl_restore_prompt(); rl_replace_line(saved_line, 0); rl_point = saved_point; - rl_forced_update_display(); + rl_redisplay(); free(saved_line); } } +void bt_shell_echo(const char *fmt, ...) +{ + va_list args; + char *str; + int ret; + + va_start(args, fmt); + ret = vasprintf(&str, fmt, args); + va_end(args); + + if (ret < 0) + return; + + rl_save_prompt(); + bt_shell_set_prompt(str, COLOR_HIGHLIGHT); + rl_restore_prompt(); +} + static void print_string(const char *str, void *user_data) { bt_shell_printf("%s\n", str); @@ -586,7 +770,7 @@ void bt_shell_hexdump(const unsigned char *buf, size_t len) util_hexdump(' ', buf, len, print_string, NULL); } -void bt_shell_usage() +void bt_shell_usage(void) { if (!data.exec) return; @@ -595,6 +779,40 @@ void bt_shell_usage() data.exec->arg ? data.exec->arg : ""); } +static void bt_shell_dequeue_exec(void) +{ + int err; + + if (!data.line) + return; + + free(data.line); + data.line = NULL; + + data.line = queue_pop_head(data.queue); + if (!data.line) + return; + + bt_shell_printf("%s\n", data.line); + + if (!bt_shell_release_prompt(data.line)) { + /* If a prompt was released with this line, + * try to release all the other prompts, + * if any are left. Otherwise, the next + * line will be executed on + * bt_shell_noninteractive_quit. + */ + if (data.saved_prompt) + bt_shell_dequeue_exec(); + + return; + } + + err = bt_shell_exec(data.line); + if (err) + bt_shell_dequeue_exec(); +} + static void prompt_input(const char *str, bt_shell_prompt_input_func func, void *user_data) { @@ -603,7 +821,7 @@ static void prompt_input(const char *str, bt_shell_prompt_input_func func, data.saved_user_data = user_data; rl_save_prompt(); - bt_shell_set_prompt(str); + bt_shell_set_prompt(str, COLOR_HIGHLIGHT); } void bt_shell_prompt_input(const char *label, const char *msg, @@ -641,6 +859,13 @@ void bt_shell_prompt_input(const char *label, const char *msg, prompt_input(str, func, user_data); free(str); + + if (data.line && !queue_isempty(data.queue)) + /* If a prompt was set to receive input and + * data is already available, try to execute + * the line and release the prompt. + */ + bt_shell_dequeue_exec(); } static void prompt_free(void *data) @@ -686,8 +911,6 @@ int bt_shell_release_prompt(const char *input) static void rl_handler(char *input) { - HIST_ENTRY *last; - if (!input) { rl_insert_text("quit"); rl_redisplay(); @@ -696,20 +919,13 @@ static void rl_handler(char *input) return; } - if (!strlen(input)) + /* Ignore empty/comment lines */ + if (!strlen(input) || input[0] == '#') goto done; if (!bt_shell_release_prompt(input)) goto done; - last = history_get(history_length + history_base - 1); - /* append only if input is different from previous command */ - if (!last || strcmp(input, last->line)) - add_history(input); - - if (data.monitor) - bt_log_printf(0xffff, data.name, LOG_INFO, "%s", input); - bt_shell_exec(input); done: @@ -966,20 +1182,13 @@ static char **shell_completion(const char *text, int start, int end) return matches; } -static bool io_hup(struct io *io, void *user_data) -{ - mainloop_quit(); - - return false; -} - static void signal_callback(int signum, void *user_data) { static bool terminated = false; switch (signum) { case SIGINT: - if (data.input && !data.mode) { + if (!queue_isempty(data.inputs) && !data.mode) { rl_replace_line("", 0); rl_crlf(); rl_on_new_line(); @@ -1071,6 +1280,7 @@ static void rl_init(void) static const struct option main_options[] = { { "version", no_argument, 0, 'v' }, { "help", no_argument, 0, 'h' }, + { "init-script", required_argument, 0, 's' }, { "timeout", required_argument, 0, 't' }, { "monitor", no_argument, 0, 'm' }, { "zsh-complete", no_argument, 0, 'z' }, @@ -1092,6 +1302,7 @@ static void usage(int argc, char **argv, const struct bt_shell_opt *opt) printf("\t--monitor \tEnable monitor output\n" "\t--timeout \tTimeout in seconds for non-interactive mode\n" "\t--version \tDisplay version\n" + "\t--init-script \tInit script file\n" "\t--help \t\tDisplay help\n"); } @@ -1110,9 +1321,9 @@ void bt_shell_init(int argc, char **argv, const struct bt_shell_opt *opt) if (opt) { memcpy(options + offset, opt->options, sizeof(struct option) * opt->optno); - snprintf(optstr, sizeof(optstr), "+mhvt:%s", opt->optstr); + snprintf(optstr, sizeof(optstr), "+mhvs:t:%s", opt->optstr); } else - snprintf(optstr, sizeof(optstr), "+mhvt:"); + snprintf(optstr, sizeof(optstr), "+mhvs:t:"); data.name = strrchr(argv[0], '/'); if (!data.name) @@ -1120,6 +1331,8 @@ void bt_shell_init(int argc, char **argv, const struct bt_shell_opt *opt) else data.name = strdup(++data.name); + data.init_fd = -1; + while ((c = getopt_long(argc, argv, optstr, options, &index)) != -1) { switch (c) { case 'v': @@ -1132,6 +1345,14 @@ void bt_shell_init(int argc, char **argv, const struct bt_shell_opt *opt) data.argv = &cmplt; data.mode = 1; goto done; + case 's': + if (optarg && data.init_fd < 0) { + data.init_fd = open(optarg, O_RDONLY); + if (data.init_fd < 0) + printf("Unable to open %s: %s (%d)\n", + optarg, strerror(errno), errno); + } + break; case 't': if (optarg) data.timeout = strtol(optarg, &endptr, 0); @@ -1157,13 +1378,15 @@ void bt_shell_init(int argc, char **argv, const struct bt_shell_opt *opt) } } - if (c != opt->options[index - offset].val) { - usage(argc, argv, opt); - exit(EXIT_SUCCESS); - return; - } + if (opt && index >= 0 && (size_t)index >= offset) { + if (c != opt->options[index - offset].val) { + usage(argc, argv, opt); + exit(EXIT_SUCCESS); + return; + } - *opt->optarg[index - offset] = optarg ? : ""; + *opt->optarg[index - offset] = optarg ? : ""; + } } index = -1; @@ -1185,6 +1408,8 @@ done: rl_init(); data.init = true; + data.inputs = queue_new(); + data.queue = queue_new(); data.prompts = queue_new(); } @@ -1221,14 +1446,35 @@ int bt_shell_run(void) int bt_shell_exec(const char *input) { + HIST_ENTRY *last; wordexp_t w; int err; if (!input) return 0; - if (wordexp(input, &w, WRDE_NOCMD)) - return -ENOEXEC; + last = history_get(history_length + history_base - 1); + /* append only if input is different from previous command */ + if (!last || strcmp(input, last->line)) + add_history(input); + + if (data.monitor) + bt_log_printf(0xffff, data.name, LOG_INFO, "%s", input); + + err = wordexp(input, &w, WRDE_NOCMD); + switch (err) { + case WRDE_BADCHAR: + return -EBADMSG; + case WRDE_BADVAL: + case WRDE_SYNTAX: + return -EINVAL; + case WRDE_NOSPACE: + return -ENOMEM; + case WRDE_CMDSUB: + if (wordexp(input, &w, 0)) + return -ENOEXEC; + break; + }; if (w.we_wordc == 0) { wordfree(&w); @@ -1242,6 +1488,17 @@ int bt_shell_exec(const char *input) return err; } +static void input_destroy(void *data) +{ + struct input *input = data; + + if (input->f) + fclose(input->f); + + io_destroy(input->io); + free(input); +} + void bt_shell_cleanup(void) { bt_shell_release_prompt(""); @@ -1257,6 +1514,10 @@ void bt_shell_cleanup(void) rl_cleanup(); + queue_destroy(data.inputs, input_destroy); + data.inputs = NULL; + queue_destroy(data.queue, free); + data.queue = NULL; queue_destroy(data.prompts, prompt_free); data.prompts = NULL; @@ -1274,8 +1535,10 @@ void bt_shell_quit(int status) void bt_shell_noninteractive_quit(int status) { - if (!data.mode || data.timeout) + if (!data.mode || data.timeout) { + bt_shell_dequeue_exec(); return; + } bt_shell_quit(status); } @@ -1309,19 +1572,26 @@ bool bt_shell_add_submenu(const struct bt_shell_menu *menu) return true; } -void bt_shell_set_prompt(const char *string) +void bt_shell_set_prompt(const char *string, const char *color) { + char *prompt; + if (!data.init || data.mode) return; - rl_set_prompt(string); - rl_redisplay(); -} + /* Envelope color within RL_PROMPT_START_IGNORE (\001) and + * RL_PROMPT_END_IGNORE (\002) so readline can properly calculate the + * prompt length. + */ + if (!color || asprintf(&prompt, "\001%s\002%s\001%s\002", color, string, + COLOR_OFF) < 0) { + rl_set_prompt(string); + } else { + rl_set_prompt(prompt); + free(prompt); + } -static bool input_read(struct io *io, void *user_data) -{ - rl_callback_read_char(); - return true; + rl_redisplay(); } static bool shell_quit(void *data) @@ -1333,21 +1603,17 @@ static bool shell_quit(void *data) bool bt_shell_attach(int fd) { - struct io *io; + struct input *input; - /* TODO: Allow more than one input? */ - if (data.input) + input = input_new(fd); + if (!input) return false; - io = io_new(fd); - if (!data.mode) { - io_set_read_handler(io, input_read, NULL, NULL); - io_set_disconnect_handler(io, io_hup, NULL, NULL); + io_set_read_handler(input->io, input_read, input, NULL); + io_set_disconnect_handler(input->io, input_hup, input, NULL); } - data.input = io; - if (data.mode) { if (shell_exec(data.argc, data.argv) < 0) { bt_shell_noninteractive_quit(EXIT_FAILURE); @@ -1357,6 +1623,12 @@ bool bt_shell_attach(int fd) if (data.timeout) timeout_add(data.timeout * 1000, shell_quit, NULL, NULL); + } else if (data.init_fd >= 0) { + int fd = data.init_fd; + + data.init_fd = -1; + if (!bt_shell_attach(fd)) + return false; } return true; @@ -1364,11 +1636,10 @@ bool bt_shell_attach(int fd) bool bt_shell_detach(void) { - if (!data.input) + if (queue_isempty(data.inputs)) return false; - io_destroy(data.input); - data.input = NULL; + queue_remove_all(data.inputs, NULL, NULL, input_destroy); return true; } @@ -1421,3 +1692,8 @@ void *bt_shell_get_env(const char *name) return env->value; } + +int bt_shell_get_timeout(void) +{ + return data.timeout; +} diff --git a/src/shared/shell.h b/src/shared/shell.h index 8baa2854a2502ab648aa1c32015b3faf208ca789..e431db9f5821181a295dd26421b52f29f6887bb4 100644 --- a/src/shared/shell.h +++ b/src/shared/shell.h @@ -10,14 +10,14 @@ #include <getopt.h> #include <stdbool.h> -#define COLOR_OFF "\001\x1B[0m\002" -#define COLOR_RED "\001\x1B[0;91m\002" -#define COLOR_GREEN "\001\x1B[0;92m\002" -#define COLOR_YELLOW "\001\x1B[0;93m\002" -#define COLOR_BLUE "\001\x1B[0;94m\002" -#define COLOR_BOLDGRAY "\001\x1B[1;30m\002" -#define COLOR_BOLDWHITE "\001\x1B[1;37m\002" -#define COLOR_HIGHLIGHT "\001\x1B[1;39m\002" +#define COLOR_OFF "\x1B[0m" +#define COLOR_RED "\x1B[0;91m" +#define COLOR_GREEN "\x1B[0;92m" +#define COLOR_YELLOW "\x1B[0;93m" +#define COLOR_BLUE "\x1B[0;94m" +#define COLOR_BOLDGRAY "\x1B[1;30m" +#define COLOR_BOLDWHITE "\x1B[1;37m" +#define COLOR_HIGHLIGHT "\x1B[1;39m" struct bt_shell_menu; @@ -66,10 +66,12 @@ bool bt_shell_add_submenu(const struct bt_shell_menu *menu); bool bt_shell_remove_submenu(const struct bt_shell_menu *menu); -void bt_shell_set_prompt(const char *string); +void bt_shell_set_prompt(const char *string, const char *color); void bt_shell_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); +void bt_shell_echo(const char *fmt, + ...) __attribute__((format(printf, 1, 2))); void bt_shell_hexdump(const unsigned char *buf, size_t len); void bt_shell_usage(void); @@ -83,4 +85,6 @@ bool bt_shell_detach(void); void bt_shell_set_env(const char *name, void *value); void *bt_shell_get_env(const char *name); +int bt_shell_get_timeout(void); + void bt_shell_cleanup(void); diff --git a/src/shared/tester.c b/src/shared/tester.c index e88dfabdc37c8ecd54de8c79f3aa6a28c46b7a47..56c8cba6f57871033476124c90daaf2717fa062c 100644 --- a/src/shared/tester.c +++ b/src/shared/tester.c @@ -89,6 +89,7 @@ struct test_case { tester_data_func_t test_func; tester_data_func_t teardown_func; tester_data_func_t post_teardown_func; + tester_data_func_t io_complete_func; gdouble start_time; gdouble end_time; unsigned int timeout; @@ -562,6 +563,38 @@ void tester_pre_setup_failed(void) g_idle_add(done_callback, test); } +void tester_pre_setup_abort(void) +{ + struct test_case *test; + + if (!test_current) + return; + + test = test_current->data; + + if (test->stage != TEST_STAGE_PRE_SETUP) + return; + + if (test->timeout_id > 0) { + timeout_remove(test->timeout_id); + test->timeout_id = 0; + } + + print_progress(test->name, COLOR_YELLOW, "not run"); + + g_idle_add(done_callback, test); +} + +bool tester_pre_setup_skip_by_default(void) +{ + if (!option_prefix && !option_string) { + tester_pre_setup_abort(); + return true; + } + + return false; +} + void tester_setup_complete(void) { struct test_case *test; @@ -621,6 +654,9 @@ static void test_result(enum test_result result) test->timeout_id = 0; } + if (test->result == TEST_RESULT_FAILED) + result = TEST_RESULT_FAILED; + test->result = result; switch (result) { case TEST_RESULT_PASSED: @@ -913,6 +949,13 @@ static bool test_io_send(struct io *io, void *user_data) g_assert_cmpint(len, ==, iov->iov_len); + if (!test->iovcnt && test->io_complete_func) { + test->io_complete_func(test->test_data); + } else if (test->iovcnt && !test->iov->iov_base) { + test_get_iov(test); + return test_io_send(io, user_data); + } + return false; } @@ -937,10 +980,15 @@ static bool test_io_recv(struct io *io, void *user_data) g_assert_cmpint(len, ==, iov->iov_len); + if (memcmp(buf, iov->iov_base, len)) + tester_monitor('!', 0x0004, 0x0000, iov->iov_base, len); + g_assert(memcmp(buf, iov->iov_base, len) == 0); if (test->iovcnt) io_set_write_handler(io, test_io_send, NULL, NULL); + else if (test->io_complete_func) + test->io_complete_func(test->test_data); return true; } @@ -1004,6 +1052,13 @@ void tester_io_send(void) io_set_write_handler(ios[1], test_io_send, NULL, NULL); } +void tester_io_set_complete_func(tester_data_func_t func) +{ + struct test_case *test = tester_get_test(); + + test->io_complete_func = func; +} + int tester_run(void) { int ret; diff --git a/src/shared/tester.h b/src/shared/tester.h index c28f61e7fd6b8d45fa497cc9d54f39c361dcaf80..1f81384343def86f12531a97fc21686c6aa5d8c3 100644 --- a/src/shared/tester.h +++ b/src/shared/tester.h @@ -21,6 +21,8 @@ .iov_len = sizeof(data(args)), \ } +#define IOV_NULL {} + void tester_init(int *argc, char ***argv); int tester_run(void); @@ -57,6 +59,8 @@ void *tester_get_data(void); void tester_pre_setup_complete(void); void tester_pre_setup_failed(void); +void tester_pre_setup_abort(void); +bool tester_pre_setup_skip_by_default(void); void tester_setup_complete(void); void tester_setup_failed(void); @@ -78,3 +82,4 @@ void tester_wait(unsigned int seconds, tester_wait_func_t func, struct io *tester_setup_io(const struct iovec *iov, int iovcnt); void tester_io_send(void); +void tester_io_set_complete_func(tester_data_func_t func); diff --git a/src/shared/uhid.c b/src/shared/uhid.c index 1f15443cd6d008b7db6719674e7097624485df7a..20bd26781799b42884141e646325c3c7df32e014 100644 --- a/src/shared/uhid.c +++ b/src/shared/uhid.c @@ -26,11 +26,30 @@ #define UHID_DEVICE_FILE "/dev/uhid" +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#endif + +struct uhid_replay { + bool active; + struct queue *out; + struct queue *in; + struct queue *rout; + struct queue *rin; +}; + struct bt_uhid { int ref_count; struct io *io; unsigned int notify_id; + bool notifying; struct queue *notify_list; + struct queue *input; + uint8_t type; + bool created; + unsigned int start_id; + bool started; + struct uhid_replay *replay; }; struct uhid_notify { @@ -38,8 +57,21 @@ struct uhid_notify { uint32_t event; bt_uhid_callback_t func; void *user_data; + bool removed; }; +static void uhid_replay_free(struct uhid_replay *replay) +{ + if (!replay) + return; + + queue_destroy(replay->rin, NULL); + queue_destroy(replay->in, free); + queue_destroy(replay->rout, NULL); + queue_destroy(replay->out, free); + free(replay); +} + static void uhid_free(struct bt_uhid *uhid) { if (uhid->io) @@ -48,6 +80,11 @@ static void uhid_free(struct bt_uhid *uhid) if (uhid->notify_list) queue_destroy(uhid->notify_list, free); + if (uhid->input) + queue_destroy(uhid->input, free); + + uhid_replay_free(uhid->replay); + free(uhid); } @@ -63,6 +100,64 @@ static void notify_handler(void *data, void *user_data) notify->func(ev, notify->user_data); } +static struct uhid_replay *uhid_replay_new(void) +{ + struct uhid_replay *replay = new0(struct uhid_replay, 1); + + replay->out = queue_new(); + replay->in = queue_new(); + + return replay; +} + +static int bt_uhid_record(struct bt_uhid *uhid, bool input, + struct uhid_event *ev) +{ + if (!uhid) + return -EINVAL; + + /* Capture input events in replay mode and send the next replay event */ + if (uhid->replay && uhid->replay->active && input) { + queue_pop_head(uhid->replay->rin); + bt_uhid_replay(uhid); + return -EALREADY; + } + + if (!uhid->replay) + uhid->replay = uhid_replay_new(); + + if (input) + queue_push_tail(uhid->replay->in, + util_memdup(ev, sizeof(*ev))); + else + queue_push_tail(uhid->replay->out, + util_memdup(ev, sizeof(*ev))); + + return 0; +} + +static bool match_removed(const void *a, const void *b) +{ + const struct uhid_notify *notify = a; + + return notify->removed; +} + +static void uhid_notify(struct bt_uhid *uhid, struct uhid_event *ev) +{ + /* Add a reference to the uhid to ensure it doesn't get freed while at + * notify_handler. + */ + bt_uhid_ref(uhid); + + uhid->notifying = true; + queue_foreach(uhid->notify_list, notify_handler, ev); + uhid->notifying = false; + queue_remove_all(uhid->notify_list, match_removed, NULL, free); + + bt_uhid_unref(uhid); +} + static bool uhid_read_handler(struct io *io, void *user_data) { struct bt_uhid *uhid = user_data; @@ -83,7 +178,14 @@ static bool uhid_read_handler(struct io *io, void *user_data) if ((size_t) len < sizeof(ev.type)) return false; - queue_foreach(uhid->notify_list, notify_handler, &ev); + switch (ev.type) { + case UHID_GET_REPORT: + case UHID_SET_REPORT: + bt_uhid_record(uhid, false, &ev); + break; + } + + uhid_notify(uhid, &ev); return true; } @@ -169,7 +271,7 @@ unsigned int bt_uhid_register(struct bt_uhid *uhid, uint32_t event, return 0; notify = new0(struct uhid_notify, 1); - notify->id = uhid->notify_id++; + notify->id = ++uhid->notify_id ? uhid->notify_id : ++uhid->notify_id; notify->event = event; notify->func = func; notify->user_data = user_data; @@ -206,23 +308,47 @@ bool bt_uhid_unregister(struct bt_uhid *uhid, unsigned int id) return true; } +static bool match_not_id(const void *a, const void *b) +{ + const struct uhid_notify *notify = a; + unsigned int id = PTR_TO_UINT(b); + + return notify->id != id; +} + +static void uhid_notify_removed(void *data, void *user_data) +{ + struct uhid_notify *notify = data; + struct bt_uhid *uhid = user_data; + + /* Skip marking start_id as removed since that is not removed with + * unregister all. + */ + if (notify->id == uhid->start_id) + return; + + notify->removed = true; +} + bool bt_uhid_unregister_all(struct bt_uhid *uhid) { if (!uhid) return false; - queue_remove_all(uhid->notify_list, NULL, NULL, free); + if (!uhid->notifying) + queue_remove_all(uhid->notify_list, match_not_id, + UINT_TO_PTR(uhid->start_id), free); + else + queue_foreach(uhid->notify_list, uhid_notify_removed, uhid); + return true; } -int bt_uhid_send(struct bt_uhid *uhid, const struct uhid_event *ev) +static int uhid_send(struct bt_uhid *uhid, const struct uhid_event *ev) { ssize_t len; struct iovec iov; - if (!uhid->io) - return -ENOTCONN; - iov.iov_base = (void *) ev; iov.iov_len = sizeof(*ev); @@ -233,3 +359,277 @@ int bt_uhid_send(struct bt_uhid *uhid, const struct uhid_event *ev) /* uHID kernel driver does not handle partial writes */ return len != sizeof(*ev) ? -EIO : 0; } + +int bt_uhid_send(struct bt_uhid *uhid, const struct uhid_event *ev) +{ + if (!uhid || !ev) + return -EINVAL; + + if (!uhid->io) + return -ENOTCONN; + + return uhid_send(uhid, ev); +} + +static bool input_dequeue(const void *data, const void *match_data) +{ + struct uhid_event *ev = (void *)data; + struct bt_uhid *uhid = (void *)match_data; + + return bt_uhid_send(uhid, ev) == 0; +} + +static void uhid_start(struct uhid_event *ev, void *user_data) +{ + struct bt_uhid *uhid = user_data; + + uhid->started = true; + + /* dequeue input events send while UHID_CREATE2 was in progress */ + queue_remove_all(uhid->input, input_dequeue, uhid, free); +} + +int bt_uhid_create(struct bt_uhid *uhid, const char *name, bdaddr_t *src, + bdaddr_t *dst, uint32_t vendor, uint32_t product, + uint32_t version, uint32_t country, uint8_t type, + void *rd_data, size_t rd_size) +{ + struct uhid_event ev; + int err; + + if (!uhid || !name || rd_size > sizeof(ev.u.create2.rd_data)) + return -EINVAL; + + if (uhid->created) + return 0; + + /* Register callback for UHID_START if not registered yet */ + if (!uhid->start_id) { + uhid->start_id = bt_uhid_register(uhid, UHID_START, uhid_start, + uhid); + if (!uhid->start_id) + return -ENOMEM; + } + + memset(&ev, 0, sizeof(ev)); + ev.type = UHID_CREATE2; + strncpy((char *) ev.u.create2.name, name, + sizeof(ev.u.create2.name) - 1); + if (src) + sprintf((char *)ev.u.create2.phys, + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", + src->b[5], src->b[4], src->b[3], src->b[2], src->b[1], + src->b[0]); + if (dst) + sprintf((char *)ev.u.create2.uniq, + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", + dst->b[5], dst->b[4], dst->b[3], dst->b[2], dst->b[1], + dst->b[0]); + ev.u.create2.vendor = vendor; + ev.u.create2.product = product; + ev.u.create2.version = version; + ev.u.create2.country = country; + ev.u.create2.bus = BUS_BLUETOOTH; + if (rd_size) + memcpy(ev.u.create2.rd_data, rd_data, rd_size); + ev.u.create2.rd_size = rd_size; + + err = bt_uhid_send(uhid, &ev); + if (err) + return err; + + uhid->created = true; + uhid->started = false; + uhid->type = type; + + return 0; +} + +bool bt_uhid_created(struct bt_uhid *uhid) +{ + if (!uhid) + return false; + + return uhid->created; +} + +bool bt_uhid_started(struct bt_uhid *uhid) +{ + if (!uhid) + return false; + + return uhid->started; +} + +int bt_uhid_input(struct bt_uhid *uhid, uint8_t number, const void *data, + size_t size) +{ + struct uhid_event ev; + struct uhid_input2_req *req = &ev.u.input2; + size_t len = 0; + + if (!uhid) + return -EINVAL; + + memset(&ev, 0, sizeof(ev)); + ev.type = UHID_INPUT2; + + if (number) { + req->data[len++] = number; + req->size = 1 + MIN(size, sizeof(req->data) - 1); + } else + req->size = MIN(size, sizeof(req->data)); + + if (data && size) + memcpy(&req->data[len], data, req->size - len); + + /* Queue events if UHID_START has not been received yet */ + if (!uhid->started) { + if (!uhid->input) + uhid->input = queue_new(); + + queue_push_tail(uhid->input, util_memdup(&ev, sizeof(ev))); + return 0; + } + + return bt_uhid_send(uhid, &ev); +} + +int bt_uhid_set_report_reply(struct bt_uhid *uhid, uint8_t id, uint8_t status) +{ + struct uhid_event ev; + struct uhid_set_report_reply_req *rsp = &ev.u.set_report_reply; + + if (!uhid) + return false; + + memset(&ev, 0, sizeof(ev)); + ev.type = UHID_SET_REPORT_REPLY; + rsp->id = id; + rsp->err = status; + + if (bt_uhid_record(uhid, true, &ev) == -EALREADY) + return 0; + + return bt_uhid_send(uhid, &ev); +} + +int bt_uhid_get_report_reply(struct bt_uhid *uhid, uint8_t id, uint8_t number, + uint8_t status, const void *data, size_t size) +{ + struct uhid_event ev; + struct uhid_get_report_reply_req *rsp = &ev.u.get_report_reply; + size_t len = 0; + + if (!uhid) + return false; + + memset(&ev, 0, sizeof(ev)); + ev.type = UHID_GET_REPORT_REPLY; + rsp->id = id; + rsp->err = status; + + if (!data || !size) + goto done; + + if (number) { + rsp->data[len++] = number; + rsp->size += MIN(size, sizeof(rsp->data) - 1); + } else + rsp->size = MIN(size, sizeof(ev.u.input.data)); + + memcpy(&rsp->data[len], data, rsp->size - len); + +done: + if (bt_uhid_record(uhid, true, &ev) == -EALREADY) + return 0; + + return bt_uhid_send(uhid, &ev); +} + +int bt_uhid_destroy(struct bt_uhid *uhid, bool force) +{ + struct uhid_event ev; + int err; + + if (!uhid) + return -EINVAL; + + /* Cleanup input queue */ + queue_destroy(uhid->input, free); + uhid->input = NULL; + + /* Force destroy for non-keyboard devices - keyboards are not destroyed + * on disconnect since they can glitch on reconnection losing + * keypresses. + */ + if (!force && uhid->type != BT_UHID_KEYBOARD) + force = true; + + if (!uhid->created || !force) + return 0; + + memset(&ev, 0, sizeof(ev)); + ev.type = UHID_DESTROY; + + err = bt_uhid_send(uhid, &ev); + if (err < 0) + return err; + + uhid->created = false; + uhid_replay_free(uhid->replay); + uhid->replay = NULL; + + return err; +} + +static void queue_append(void *data, void *user_data) +{ + queue_push_tail(user_data, data); +} + +static struct queue *queue_dup(struct queue *q) +{ + struct queue *dup; + + if (!q || queue_isempty(q)) + return NULL; + + dup = queue_new(); + + queue_foreach(q, queue_append, dup); + + return dup; +} + +int bt_uhid_replay(struct bt_uhid *uhid) +{ + struct uhid_event *ev; + + if (!uhid || !uhid->started) + return -EINVAL; + + if (!uhid->replay) + return 0; + + if (uhid->replay->active) + goto resend; + + uhid->replay->active = true; + queue_destroy(uhid->replay->rin, NULL); + uhid->replay->rin = queue_dup(uhid->replay->in); + + queue_destroy(uhid->replay->rout, NULL); + uhid->replay->rout = queue_dup(uhid->replay->out); + +resend: + ev = queue_pop_head(uhid->replay->rout); + if (!ev) { + uhid->replay->active = false; + return 0; + } + + uhid_notify(uhid, ev); + + return 0; +} diff --git a/src/shared/uhid.h b/src/shared/uhid.h index 55ae839f3017ca34fa5c32619d7c3717aced3203..e76a6e22bd8eed64229c195fd1cb58da64ac541d 100644 --- a/src/shared/uhid.h +++ b/src/shared/uhid.h @@ -11,9 +11,35 @@ #include <stdbool.h> #include <stdint.h> #include <linux/uhid.h> +#include <bluetooth/bluetooth.h> struct bt_uhid; +enum { + BT_UHID_NONE = 0, + BT_UHID_KEYBOARD, + BT_UHID_MOUSE, + BT_UHID_GAMING, + BT_UHID_TABLET +}; + +static inline uint8_t bt_uhid_icon_to_type(const char *icon) +{ + if (!icon) + return BT_UHID_NONE; + + if (!strcmp(icon, "input-keyboard")) + return BT_UHID_KEYBOARD; + else if (!strcmp(icon, "input-mouse")) + return BT_UHID_MOUSE; + else if (!strcmp(icon, "input-gaming")) + return BT_UHID_GAMING; + else if (!strcmp(icon, "input-tablet")) + return BT_UHID_TABLET; + else + return BT_UHID_NONE; +} + struct bt_uhid *bt_uhid_new_default(void); struct bt_uhid *bt_uhid_new(int fd); @@ -29,3 +55,16 @@ bool bt_uhid_unregister(struct bt_uhid *uhid, unsigned int id); bool bt_uhid_unregister_all(struct bt_uhid *uhid); int bt_uhid_send(struct bt_uhid *uhid, const struct uhid_event *ev); +int bt_uhid_create(struct bt_uhid *uhid, const char *name, bdaddr_t *src, + bdaddr_t *dst, uint32_t vendor, uint32_t product, + uint32_t version, uint32_t country, uint8_t type, + void *rd_data, size_t rd_size); +bool bt_uhid_created(struct bt_uhid *uhid); +bool bt_uhid_started(struct bt_uhid *uhid); +int bt_uhid_input(struct bt_uhid *uhid, uint8_t number, const void *data, + size_t size); +int bt_uhid_set_report_reply(struct bt_uhid *uhid, uint8_t id, uint8_t status); +int bt_uhid_get_report_reply(struct bt_uhid *uhid, uint8_t id, uint8_t number, + uint8_t status, const void *data, size_t size); +int bt_uhid_destroy(struct bt_uhid *uhid, bool force); +int bt_uhid_replay(struct bt_uhid *uhid); diff --git a/src/shared/util.c b/src/shared/util.c index 0a0308cb07861bea390e9ab220a7e07b90469ac9..6e7634ad109f1454ab4ee1bffed45445b8f209f5 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -4,6 +4,7 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2012-2014 Intel Corporation. All rights reserved. + * Copyright 2023-2024 NXP * * */ @@ -28,6 +29,13 @@ #include <sys/random.h> #endif +#include <lib/bluetooth.h> + +/* define MAX_INPUT for musl */ +#ifndef MAX_INPUT +#define MAX_INPUT _POSIX_MAX_INPUT +#endif + #include "src/shared/util.h" void *util_malloc(size_t size) @@ -130,6 +138,148 @@ void util_hexdump(const char dir, const unsigned char *buf, size_t len, } } +/* Helper to print debug information of bitfields */ +uint64_t util_debug_bit(const char *label, uint64_t val, + const struct util_bit_debugger *table, + util_debug_func_t function, void *user_data) +{ + uint64_t mask = val; + int i; + + for (i = 0; table[i].str; i++) { + if (val & (((uint64_t) 1) << table[i].bit)) { + util_debug(function, user_data, "%s%s", label, + table[i].str); + mask &= ~(((uint64_t) 1) << table[i].bit); + } + } + + return mask; +} + +static const struct util_ltv_debugger* +ltv_debugger(const struct util_ltv_debugger *debugger, size_t num, uint8_t type) +{ + size_t i; + + if (!debugger || !num) + return NULL; + + for (i = 0; i < num; i++) { + const struct util_ltv_debugger *debug = &debugger[i]; + + if (debug->type == type) + return debug; + } + + return NULL; +} + +/* Helper to itertate over LTV entries */ +bool util_ltv_foreach(const uint8_t *data, uint8_t len, uint8_t *type, + util_ltv_func_t func, void *user_data) +{ + struct iovec iov; + int i; + + if (!func || !data) + return false; + + iov.iov_base = (void *) data; + iov.iov_len = len; + + for (i = 0; iov.iov_len; i++) { + uint8_t l, t, *v; + + if (!util_iov_pull_u8(&iov, &l)) + return false; + + if (!l) { + func(i, l, 0, NULL, user_data); + continue; + } + + if (!util_iov_pull_u8(&iov, &t)) + return false; + + l--; + + if (l) { + v = util_iov_pull_mem(&iov, l); + if (!v) + return false; + } else + v = NULL; + + if (!type || *type == t) + func(i, l, t, v, user_data); + } + + return true; +} + +/* Helper to add l,t,v data in an iovec struct */ +void util_ltv_push(struct iovec *output, uint8_t l, uint8_t t, void *v) +{ + output->iov_base = realloc(output->iov_base, output->iov_len + l + 2); + util_iov_push_u8(output, l + 1); + util_iov_push_u8(output, t); + util_iov_push_mem(output, l, v); +} + +/* Helper to print debug information of LTV entries */ +bool util_debug_ltv(const uint8_t *data, uint8_t len, + const struct util_ltv_debugger *debugger, size_t num, + util_debug_func_t function, void *user_data) +{ + struct iovec iov; + int i; + + iov.iov_base = (void *) data; + iov.iov_len = len; + + for (i = 0; iov.iov_len; i++) { + uint8_t l, t, *v; + const struct util_ltv_debugger *debug; + + if (!util_iov_pull_u8(&iov, &l)) { + util_debug(function, user_data, + "Unable to pull length"); + return false; + } + + if (!l) { + util_debug(function, user_data, "#%d: len 0x%02x", + i, l); + continue; + } + + if (!util_iov_pull_u8(&iov, &t)) { + util_debug(function, user_data, "Unable to pull type"); + return false; + } + + util_debug(function, user_data, "#%d: len 0x%02x type 0x%02x", + i, l, t); + + l--; + + v = util_iov_pull_mem(&iov, l); + if (!v) { + util_debug(function, user_data, "Unable to pull value"); + return false; + } + + debug = ltv_debugger(debugger, num, t); + if (debug) + debug->func(v, l, function, user_data); + else + util_hexdump(' ', (void *)v, l, function, user_data); + } + + return true; +} + /* Helper for getting the dirent type in case readdir returns DT_UNKNOWN */ unsigned char util_get_dt(const char *parent, const char *name) { @@ -189,6 +339,351 @@ void util_clear_uid(uint64_t *bitmap, uint8_t id) *bitmap &= ~(((uint64_t)1) << (id - 1)); } +struct iovec *util_iov_dup(const struct iovec *iov, size_t cnt) +{ + struct iovec *dup; + size_t i; + + if (!iov) + return NULL; + + dup = new0(struct iovec, cnt); + + for (i = 0; i < cnt; i++) + util_iov_memcpy(&dup[i], iov[i].iov_base, iov[i].iov_len); + + return dup; +} + +int util_iov_memcmp(const struct iovec *iov1, const struct iovec *iov2) +{ + if (!iov1) + return 1; + + if (!iov2) + return -1; + + if (iov1->iov_len != iov2->iov_len) + return iov1->iov_len - iov2->iov_len; + + return memcmp(iov1->iov_base, iov2->iov_base, iov1->iov_len); +} + +void util_iov_memcpy(struct iovec *iov, void *src, size_t len) +{ + if (!iov || !src || !len) + return; + + iov->iov_base = realloc(iov->iov_base, len); + iov->iov_len = len; + memcpy(iov->iov_base, src, len); +} + +void util_iov_free(struct iovec *iov, size_t cnt) +{ + size_t i; + + if (!iov) + return; + + for (i = 0; i < cnt; i++) + free(iov[i].iov_base); + + free(iov); +} + +void *util_iov_push(struct iovec *iov, size_t len) +{ + void *data; + + if (!iov) + return NULL; + + data = iov->iov_base + iov->iov_len; + iov->iov_len += len; + + return data; +} + +void *util_iov_push_mem(struct iovec *iov, size_t len, const void *data) +{ + void *p; + + p = util_iov_push(iov, len); + if (!p) + return NULL; + + if (data) + memcpy(p, data, len); + + return p; +} + +void *util_iov_push_le64(struct iovec *iov, uint64_t val) +{ + void *p; + + p = util_iov_push(iov, sizeof(val)); + if (!p) + return NULL; + + put_le64(val, p); + + return p; +} + +void *util_iov_push_be64(struct iovec *iov, uint64_t val) +{ + void *p; + + p = util_iov_push(iov, sizeof(val)); + if (!p) + return NULL; + + put_be64(val, p); + + return p; +} + +void *util_iov_push_le32(struct iovec *iov, uint32_t val) +{ + void *p; + + p = util_iov_push(iov, sizeof(val)); + if (!p) + return NULL; + + put_le32(val, p); + + return p; +} + +void *util_iov_push_be32(struct iovec *iov, uint32_t val) +{ + void *p; + + p = util_iov_push(iov, sizeof(val)); + if (!p) + return NULL; + + put_be32(val, p); + + return p; +} + +void *util_iov_push_le24(struct iovec *iov, uint32_t val) +{ + void *p; + + p = util_iov_push(iov, sizeof(uint24_t)); + if (!p) + return NULL; + + put_le24(val, p); + + return p; +} + +void *util_iov_push_be24(struct iovec *iov, uint32_t val) +{ + void *p; + + p = util_iov_push(iov, sizeof(uint24_t)); + if (!p) + return NULL; + + put_le24(val, p); + + return p; +} + +void *util_iov_push_le16(struct iovec *iov, uint16_t val) +{ + void *p; + + p = util_iov_push(iov, sizeof(val)); + if (!p) + return NULL; + + put_le16(val, p); + + return p; +} + +void *util_iov_push_be16(struct iovec *iov, uint16_t val) +{ + void *p; + + p = util_iov_push(iov, sizeof(val)); + if (!p) + return NULL; + + put_be16(val, p); + + return p; +} + +void *util_iov_push_u8(struct iovec *iov, uint8_t val) +{ + void *p; + + p = util_iov_push(iov, sizeof(val)); + if (!p) + return NULL; + + put_u8(val, p); + + return p; +} + +void *util_iov_append(struct iovec *iov, const void *data, size_t len) +{ + iov->iov_base = realloc(iov->iov_base, iov->iov_len + len); + return util_iov_push_mem(iov, len, data); +} + +struct iovec *util_iov_new(void *data, size_t len) +{ + struct iovec *iov; + + iov = new0(struct iovec, 1); + util_iov_append(iov, data, len); + + return iov; +} + +void *util_iov_pull(struct iovec *iov, size_t len) +{ + if (!iov) + return NULL; + + if (iov->iov_len < len) + return NULL; + + iov->iov_base += len; + iov->iov_len -= len; + + return iov->iov_base; +} + +void *util_iov_pull_mem(struct iovec *iov, size_t len) +{ + void *data = iov->iov_base; + + if (util_iov_pull(iov, len)) + return data; + + return NULL; +} + +void *util_iov_pull_le64(struct iovec *iov, uint64_t *val) +{ + void *data = iov->iov_base; + + if (util_iov_pull(iov, sizeof(*val))) { + *val = get_le64(data); + return data; + } + + return NULL; +} + +void *util_iov_pull_be64(struct iovec *iov, uint64_t *val) +{ + void *data = iov->iov_base; + + if (util_iov_pull(iov, sizeof(*val))) { + *val = get_be64(data); + return data; + } + + return NULL; +} + +void *util_iov_pull_le32(struct iovec *iov, uint32_t *val) +{ + void *data = iov->iov_base; + + if (util_iov_pull(iov, sizeof(*val))) { + *val = get_le32(data); + return data; + } + + return NULL; +} + +void *util_iov_pull_be32(struct iovec *iov, uint32_t *val) +{ + void *data = iov->iov_base; + + if (util_iov_pull(iov, sizeof(*val))) { + *val = get_be32(data); + return data; + } + + return NULL; +} + +void *util_iov_pull_le24(struct iovec *iov, uint32_t *val) +{ + void *data = iov->iov_base; + + if (util_iov_pull(iov, sizeof(uint24_t))) { + *val = get_le24(data); + return data; + } + + return NULL; +} + +void *util_iov_pull_be24(struct iovec *iov, uint32_t *val) +{ + void *data = iov->iov_base; + + if (util_iov_pull(iov, sizeof(uint24_t))) { + *val = get_be24(data); + return data; + } + + return NULL; +} + +void *util_iov_pull_le16(struct iovec *iov, uint16_t *val) +{ + void *data = iov->iov_base; + + if (util_iov_pull(iov, sizeof(*val))) { + *val = get_le16(data); + return data; + } + + return NULL; +} + +void *util_iov_pull_be16(struct iovec *iov, uint16_t *val) +{ + void *data = iov->iov_base; + + if (util_iov_pull(iov, sizeof(*val))) { + *val = get_be16(data); + return data; + } + + return NULL; +} + +void *util_iov_pull_u8(struct iovec *iov, uint8_t *val) +{ + void *data = iov->iov_base; + + if (util_iov_pull(iov, sizeof(*val))) { + *val = get_u8(data); + return data; + } + + return NULL; +} + static const struct { uint16_t uuid; const char *str; @@ -344,7 +839,12 @@ static const struct { { 0x1850, "Published Audio Capabilities" }, { 0x1851, "Basic Audio Announcement" }, { 0x1852, "Broadcast Audio Announcement" }, - /* 0x1853 to 0x27ff undefined */ + { 0x1853, "Common Audio" }, + { 0x1854, "Hearing Aid" }, + { 0x1855, "Telephony and Media Audio" }, + { 0x1856, "Public Broadcast Announcement" }, + { 0x1858, "Gaming Audio" }, + /* 0x1857 to 0x27ff undefined */ { 0x2800, "Primary Service" }, { 0x2801, "Secondary Service" }, { 0x2802, "Include" }, @@ -578,6 +1078,7 @@ static const struct { { 0x2b29, "Client Supported Features" }, { 0x2b2A, "Database Hash" }, { 0x2b3a, "Server Supported Features" }, + { 0x2b51, "Telephony and Media Audio Profile Role" }, { 0x2b77, "Audio Input State" }, { 0x2b78, "Gain Settings Attribute" }, { 0x2b79, "Audio Input Type" }, @@ -592,6 +1093,9 @@ static const struct { { 0x2b82, "Volume Offset Control Point" }, { 0x2b83, "Audio Output Description" }, { 0x2b84, "Set Identity Resolving Key" }, + { 0x2b85, "Coordinated Set Size" }, + { 0x2b86, "Set Member Lock" }, + { 0x2b87, "Set Member Rank" }, { 0x2b93, "Media Player Name" }, { 0x2b94, "Media Player Icon Object ID" }, { 0x2b95, "Media Player Icon URL" }, @@ -645,6 +1149,14 @@ static const struct { { 0x2bcc, "Source Audio Locations" }, { 0x2bcd, "Available Audio Contexts" }, { 0x2bce, "Supported Audio Contexts" }, + { 0x2bda, "Hearing Aid Features" }, + { 0x2bdb, "Hearing Aid Preset Control Point" }, + { 0x2bdc, "Active Preset Index" }, + { 0x2c00, "GMAP Role" }, + { 0x2c01, "UGG Features" }, + { 0x2c02, "UGT Features" }, + { 0x2c03, "BGS Features" }, + { 0x2c03, "BGR Features" }, /* vendor defined */ { 0xfeff, "GN Netcom" }, { 0xfefe, "GN ReSound A/S" }, @@ -1064,9 +1576,23 @@ static const struct { { 0xfd60, "Sercomm Corporation" }, { 0xfd5f, "Oculus VR, LLC" }, /* SDO defined */ - { 0xfffc, "AirFuel Alliance" }, - { 0xfffe, "Alliance for Wireless Power (A4WP)" }, - { 0xfffd, "Fast IDentity Online Alliance (FIDO)" }, + { 0xfccc, "Wi-Fi Easy Connect Specification" }, + { 0xffef, "Wi-Fi Direct Specification" }, + { 0xfff0, "Public Key Open Credential (PKOC)" }, + { 0xfff1, "ICCE Digital Key" }, + { 0xfff2, "Aliro" }, + { 0xfff3, "FiRa Consortium" }, + { 0xfff4, "FiRa Consortium" }, + { 0xfff5, "Car Connectivity Consortium, LLC" }, + { 0xfff6, "Matter Profile ID" }, + { 0xfff7, "Zigbee Direct" }, + { 0xfff8, "Mopria Alliance BLE" }, + { 0xfff9, "FIDO2 Secure Client-To-Authenticator Transport" }, + { 0xfffa, "ASTM Remote ID" }, + { 0xfffb, "Direct Thread Commissioning" }, + { 0xfffc, "Wireless Power Transfer (WPT)" }, + { 0xfffd, "Universal Second Factor Authenticator" }, + { 0xfffe, "Wireless Power Transfer" }, { } }; @@ -1151,6 +1677,8 @@ static const struct { { "a6695ace-ee7f-4fb9-881a-5fac66c629af", "BlueZ Offload Codecs"}, { "6fbaf188-05e0-496a-9885-d6ddfdb4e03e", "BlueZ Experimental ISO Socket"}, + { "69518c4c-b69f-4679-8bc1-c021b47b5733", + "BlueZ Experimental Poll Errqueue"}, { } }; @@ -1357,3 +1885,65 @@ int strsuffix(const char *str, const char *suffix) return strncmp(str + len - suffix_len, suffix, suffix_len); } + +char *strstrip(char *str) +{ + size_t size; + char *end; + + if (!str) + return NULL; + + size = strlen(str); + if (!size) + return str; + + end = str + size - 1; + while (end >= str && isspace(*end)) + end--; + *(end + 1) = '\0'; + + while (*str && isspace(*str)) + str++; + + return str; +} + +bool strisutf8(const char *str, size_t len) +{ + size_t i = 0; + + while (i < len) { + unsigned char c = str[i]; + size_t size = 0; + + /* Check the first byte to determine the number of bytes in the + * UTF-8 character. + */ + if ((c & 0x80) == 0x00) + size = 1; + else if ((c & 0xE0) == 0xC0) + size = 2; + else if ((c & 0xF0) == 0xE0) + size = 3; + else if ((c & 0xF8) == 0xF0) + size = 4; + else + /* Invalid UTF-8 sequence */ + return false; + + /* Check the following bytes to ensure they have the correct + * format. + */ + for (size_t j = 1; j < size; ++j) { + if (i + j > len || (str[i + j] & 0xC0) != 0x80) + /* Invalid UTF-8 sequence */ + return false; + } + + /* Move to the next character */ + i += size; + } + + return true; +} diff --git a/src/shared/util.h b/src/shared/util.h index 554481e1e1ea0e562dc3ed0009a8afccb3276255..f2ca4f29f102a275729732659f14dbab54f4da1f 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -4,6 +4,7 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2012-2014 Intel Corporation. All rights reserved. + * Copyright 2023-2024 NXP * * */ @@ -11,10 +12,12 @@ #include <stdint.h> #include <stdlib.h> #include <stdarg.h> +#include <stdbool.h> #include <alloca.h> #include <byteswap.h> #include <string.h> #include <sys/types.h> +#include <sys/uio.h> #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #define BIT(n) (1 << (n)) @@ -82,10 +85,12 @@ do { \ })) #define newa(t, n) ((t*) alloca(sizeof(t)*(n))) -#define malloc0(n) (calloc((n), 1)) +#define malloc0(n) (calloc(1, (n))) char *strdelimit(char *str, char *del, char c); int strsuffix(const char *str, const char *suffix); +char *strstrip(char *str); +bool strisutf8(const char *str, size_t length); void *util_malloc(size_t size); void *util_memdup(const void *src, size_t size); @@ -102,6 +107,45 @@ void util_debug(util_debug_func_t function, void *user_data, void util_hexdump(const char dir, const unsigned char *buf, size_t len, util_debug_func_t function, void *user_data); +#define UTIL_BIT_DEBUG(_bit, _str) \ +{ \ + .bit = _bit, \ + .str = _str, \ +} + +struct util_bit_debugger { + uint64_t bit; + const char *str; +}; + +uint64_t util_debug_bit(const char *label, uint64_t val, + const struct util_bit_debugger *table, + util_debug_func_t func, void *user_data); + +#define UTIL_LTV_DEBUG(_type, _func) \ +{ \ + .type = _type, \ + .func = _func, \ +} + +struct util_ltv_debugger { + uint8_t type; + void (*func)(const uint8_t *data, uint8_t len, + util_debug_func_t func, void *user_data); +}; + +void util_ltv_push(struct iovec *output, uint8_t l, uint8_t t, void *v); + +bool util_debug_ltv(const uint8_t *data, uint8_t len, + const struct util_ltv_debugger *debugger, size_t num, + util_debug_func_t function, void *user_data); + +typedef void (*util_ltv_func_t)(size_t i, uint8_t l, uint8_t t, uint8_t *v, + void *user_data); + +bool util_ltv_foreach(const uint8_t *data, uint8_t len, uint8_t *type, + util_ltv_func_t func, void *user_data); + unsigned char util_get_dt(const char *parent, const char *name); ssize_t util_getrandom(void *buf, size_t buflen, unsigned int flags); @@ -109,6 +153,43 @@ ssize_t util_getrandom(void *buf, size_t buflen, unsigned int flags); uint8_t util_get_uid(uint64_t *bitmap, uint8_t max); void util_clear_uid(uint64_t *bitmap, uint8_t id); +#define util_data(args...) ((const unsigned char[]) { args }) + +#define UTIL_IOV_INIT(args...) \ +{ \ + .iov_base = (void *)util_data(args), \ + .iov_len = sizeof(util_data(args)), \ +} + +struct iovec *util_iov_dup(const struct iovec *iov, size_t cnt); +int util_iov_memcmp(const struct iovec *iov1, const struct iovec *iov2); +void util_iov_memcpy(struct iovec *iov, void *src, size_t len); +void *util_iov_push(struct iovec *iov, size_t len); +void *util_iov_push_mem(struct iovec *iov, size_t len, const void *data); +void *util_iov_push_le64(struct iovec *iov, uint64_t val); +void *util_iov_push_be64(struct iovec *iov, uint64_t val); +void *util_iov_push_le32(struct iovec *iov, uint32_t val); +void *util_iov_push_be32(struct iovec *iov, uint32_t val); +void *util_iov_push_le24(struct iovec *iov, uint32_t val); +void *util_iov_push_be24(struct iovec *iov, uint32_t val); +void *util_iov_push_le16(struct iovec *iov, uint16_t val); +void *util_iov_push_be16(struct iovec *iov, uint16_t val); +void *util_iov_push_u8(struct iovec *iov, uint8_t val); +void *util_iov_append(struct iovec *iov, const void *data, size_t len); +struct iovec *util_iov_new(void *data, size_t len); +void *util_iov_pull(struct iovec *iov, size_t len); +void *util_iov_pull_mem(struct iovec *iov, size_t len); +void *util_iov_pull_le64(struct iovec *iov, uint64_t *val); +void *util_iov_pull_be64(struct iovec *iov, uint64_t *val); +void *util_iov_pull_le32(struct iovec *iov, uint32_t *val); +void *util_iov_pull_be32(struct iovec *iov, uint32_t *val); +void *util_iov_pull_le24(struct iovec *iov, uint32_t *val); +void *util_iov_pull_be24(struct iovec *iov, uint32_t *val); +void *util_iov_pull_le16(struct iovec *iov, uint16_t *val); +void *util_iov_pull_be16(struct iovec *iov, uint16_t *val); +void *util_iov_pull_u8(struct iovec *iov, uint8_t *val); +void util_iov_free(struct iovec *iov, size_t cnt); + const char *bt_uuid16_to_str(uint16_t uuid); const char *bt_uuid32_to_str(uint32_t uuid); const char *bt_uuid128_to_str(const uint8_t uuid[16]); @@ -169,6 +250,11 @@ static inline uint64_t get_be64(const void *ptr) return be64_to_cpu(get_unaligned((const uint64_t *) ptr)); } +static inline void put_u8(uint8_t val, void *dst) +{ + put_unaligned(val, (uint8_t *) dst); +} + static inline void put_le16(uint16_t val, void *dst) { put_unaligned(cpu_to_le16(val), (uint16_t *) dst); diff --git a/src/shared/vcp.c b/src/shared/vcp.c index 5459cf892a7da218d554fbf0d81f648bb1efa512..cfc4266248756ef183ce7e1945d2b6971cb9c2b0 100644 --- a/src/shared/vcp.c +++ b/src/shared/vcp.c @@ -32,13 +32,93 @@ #define VCP_STEP_SIZE 1 +#define VOCS_VOL_OFFSET_UPPER_LIMIT 255 +#define VOCS_VOL_OFFSET_LOWER_LIMIT -255 + /* Apllication Error Code */ #define BT_ATT_ERROR_INVALID_CHANGE_COUNTER 0x80 #define BT_ATT_ERROR_OPCODE_NOT_SUPPORTED 0x81 +#define BT_ATT_ERROR_VALUE_OUT_OF_RANGE 0x82 +#define BT_ATT_AICS_ERROR_VALUE_OUT_OF_RANGE 0x83 +#define BT_ATT_AICS_ERROR_MUTE_DISABLED 0x82 +#define BT_ATT_AICS_ERROR_GAIN_MODE_CHANGE_NOT_ALLOWED 0x84 + +#define BT_VCP_NA BIT(0) +#define BT_VCP_FRONT_LEFT BIT(1) +#define BT_VCP_FRONT_RIGHT BIT(2) +#define BT_VCP_FRONT_CENTER BIT(3) +#define BT_VCP_LOW_FRQ_EFF_1 BIT(4) +#define BT_VCP_BACK_LEFT BIT(5) +#define BT_VCP_BACK_RIGHT BIT(6) +#define BT_VCP_FRONT_LEFT_CENTER BIT(7) +#define BT_VCP_FRONT_RIGHT_CENTER BIT(8) +#define BT_VCP_BACK_CENTER BIT(9) +#define BT_VCP_LOW_FRQ_EFF_2 BIT(10) +#define BT_VCP_SIDE_LEFT BIT(11) +#define BT_VCP_SIDE_RIGHT BIT(12) +#define BT_VCP_TOP_FRONT_LEFT BIT(13) +#define BT_VCP_TOP_FRONT_RIGHT BIT(14) +#define BT_VCP_TOP_FRONT_CENTER BIT(15) +#define BT_VCP_TOP_CENTER BIT(16) +#define BT_VCP_TOP_BACK_LEFT BIT(17) +#define BT_VCP_TOP_BACK_RIGHT BIT(18) +#define BT_VCP_TOP_SIDE_LEFT BIT(19) +#define BT_VCP_TOP_SIDE_RIGHT BIT(20) +#define BT_VCP_TOP_BACK_CENTER BIT(21) +#define BT_VCP_BOTTOM_FRONT_CENTER BIT(22) +#define BT_VCP_BOTTOM_FRONT_LEFT BIT(23) +#define BT_VCP_BOTTOM_FRONT_RIGHT BIT(24) +#define BT_VCP_FRONT_LEFT_WIDE BIT(25) +#define BT_VCP_FRONT_RIGHT_WIDE BIT(26) +#define BT_VCP_LEFT_SURROUND BIT(27) +#define BT_VCP_RIGHT_SURROUND BIT(28) + +#define VCS_TOTAL_NUM_HANDLES 11 +#define AICS_TOTAL_NUM_HANDLES 16 + +/* AICS Audio Input Type Values */ +#define AICS_AUD_IP_TYPE_UNSPECIFIED 0x00 +#define AICS_AUD_IP_TYPE_BLUETOOTH 0x01 +#define AICS_AUD_IP_TYPE_MICROPHONE 0x02 +#define AICS_AUD_IP_TYPE_ANALOG 0x03 +#define AICS_AUD_IP_TYPE_DIGITAL 0x04 +#define AICS_AUD_IP_TYPE_RADIO 0x05 +#define AICS_AUD_IP_TYPE_STREAMING 0x06 +#define AICS_AUD_IP_TYPE_AMBIENT 0x07 + +/* AICS Audio Input Status Values */ +#define AICS_AUD_IP_STATUS_INACTIVE 0x00 +#define AICS_AUD_IP_STATUS_ACTIVE 0x01 + +/* AICS Audio Input Control Point Opcodes */ +#define BT_AICS_SET_GAIN_SETTING 0x01 +#define BT_AICS_UNMUTE 0x02 +#define BT_AICS_MUTE 0x03 +#define BT_AICS_SET_MANUAL_GAIN_MODE 0x04 +#define BT_AICS_SET_AUTO_GAIN_MODE 0x05 + +/* AICS Gain Mode Field Value */ +#define AICS_GAIN_MODE_MANUAL_ONLY 0x00 +#define AICS_GAIN_MODE_AUTO_ONLY 0x01 +#define AICS_GAIN_MODE_MANUAL 0x02 +#define AICS_GAIN_MODE_AUTO 0x03 + +/* AICS Mute Field Values */ +#define AICS_NOT_MUTED 0x00 +#define AICS_MUTED 0x01 +#define AICS_DISABLED 0x02 + +#define AICS_GAIN_SETTING_UNITS 1 +#define AICS_GAIN_SETTING_MAX_VALUE 127 +#define AICS_GAIN_SETTING_MIN_VALUE -128 + +#define AICS_GAIN_SETTING_DEFAULT_VALUE 88 struct bt_vcp_db { struct gatt_db *db; struct bt_vcs *vcs; + struct bt_vocs *vocs; + struct bt_aics *aics; }; typedef void (*vcp_func_t)(struct bt_vcp *vcp, bool success, uint8_t att_ecode, @@ -57,11 +137,21 @@ struct bt_vcs_param { uint8_t change_counter; } __packed; +struct bt_vocs_param { + uint8_t op; + uint8_t change_counter; +} __packed; + struct bt_vcs_ab_vol { uint8_t change_counter; uint8_t vol_set; } __packed; +struct bt_vocs_set_vol_off { + uint8_t change_counter; + int16_t set_vol_offset; +} __packed; + struct bt_vcp_cb { unsigned int id; bt_vcp_func_t attached; @@ -89,6 +179,14 @@ struct bt_vcp { unsigned int vstate_id; unsigned int vflag_id; + unsigned int state_id; + unsigned int audio_loc_id; + unsigned int ao_dec_id; + + unsigned int aics_ip_state_id; + unsigned int aics_ip_status_id; + unsigned int aics_ip_descr_id; + struct queue *notify; struct queue *pending; @@ -120,6 +218,64 @@ struct bt_vcs { struct gatt_db_attribute *vf_ccc; }; +/* Contains local bt_vcp_db */ +struct vol_offset_state { + int16_t vol_offset; + uint8_t counter; +} __packed; + +struct bt_vocs { + struct bt_vcp_db *vdb; + struct vol_offset_state *vostate; + uint32_t vocs_audio_loc; + char *vocs_ao_dec; + struct gatt_db_attribute *service; + struct gatt_db_attribute *vos; + struct gatt_db_attribute *vos_ccc; + struct gatt_db_attribute *voal; + struct gatt_db_attribute *voal_ccc; + struct gatt_db_attribute *vo_cp; + struct gatt_db_attribute *voaodec; + struct gatt_db_attribute *voaodec_ccc; +}; + +struct aud_ip_st { + int8_t gain_setting; + uint8_t mute; + uint8_t gain_mode; + uint8_t chg_counter; +} __packed; + +struct gain_setting_prop { + uint8_t gain_setting_units; + int8_t gain_setting_min; + int8_t gain_setting_max; +} __packed; + +struct bt_aics_set_gain_setting { + uint8_t change_counter; + int8_t gain_setting; +} __packed; + +struct bt_aics { + struct bt_vcp_db *vdb; + struct aud_ip_st *aud_ipst; + struct gain_setting_prop *gain_settingprop; + uint8_t aud_input_type; + uint8_t aud_input_status; + char *aud_input_descr; + struct gatt_db_attribute *service; + struct gatt_db_attribute *aud_ip_state; + struct gatt_db_attribute *aud_ip_state_ccc; + struct gatt_db_attribute *gain_stting_prop; + struct gatt_db_attribute *aud_ip_type; + struct gatt_db_attribute *aud_ip_status; + struct gatt_db_attribute *aud_ip_status_ccc; + struct gatt_db_attribute *aud_ip_cp; + struct gatt_db_attribute *aud_ip_dscrptn; + struct gatt_db_attribute *aud_ip_dscrptn_ccc; +}; + static struct queue *vcp_db; static struct queue *vcp_cbs; static struct queue *sessions; @@ -159,6 +315,17 @@ static struct vol_state *vdb_get_vstate(struct bt_vcp_db *vdb) return NULL; } +static struct vol_offset_state *vdb_get_vostate(struct bt_vcp_db *vdb) +{ + if (!vdb->vocs) + return NULL; + + if (vdb->vocs->vostate) + return vdb->vocs->vostate; + + return NULL; +} + static struct bt_vcs *vcp_get_vcs(struct bt_vcp *vcp) { if (!vcp) @@ -173,6 +340,34 @@ static struct bt_vcs *vcp_get_vcs(struct bt_vcp *vcp) return vcp->rdb->vcs; } +static struct bt_vocs *vcp_get_vocs(struct bt_vcp *vcp) +{ + if (!vcp) + return NULL; + + if (vcp->rdb->vocs) + return vcp->rdb->vocs; + + vcp->rdb->vocs = new0(struct bt_vocs, 1); + vcp->rdb->vocs->vdb = vcp->rdb; + + return vcp->rdb->vocs; +} + +static struct bt_aics *vcp_get_aics(struct bt_vcp *vcp) +{ + if (!vcp) + return NULL; + + if (vcp->rdb->aics) + return vcp->rdb->aics; + + vcp->rdb->aics = new0(struct bt_aics, 1); + vcp->rdb->aics->vdb = vcp->rdb; + + return vcp->rdb->aics; +} + static void vcp_detached(void *data, void *user_data) { struct bt_vcp_cb *cb = data; @@ -202,6 +397,8 @@ static void vcp_db_free(void *data) gatt_db_unref(vdb->db); free(vdb->vcs); + free(vdb->vocs); + free(vdb->aics); free(vdb); } @@ -583,6 +780,57 @@ static uint8_t vcs_mute(struct bt_vcs *vcs, struct bt_vcp *vcp, return 0; } +static uint8_t vocs_set_vol_offset(struct bt_vocs *vocs, struct bt_vcp *vcp, + struct iovec *iov) +{ + struct bt_vcp_db *vdb; + struct vol_offset_state *vstate, state; + struct bt_vocs_set_vol_off *req; + + DBG(vcp, "Set Volume Offset"); + + vdb = vcp_get_vdb(vcp); + if (!vdb) { + DBG(vcp, "error: VDB not available"); + return 0; + } + + vstate = vdb_get_vostate(vdb); + if (!vstate) { + DBG(vcp, "error: VSTATE not available"); + return 0; + } + + req = iov_pull_mem(iov, sizeof(*req)); + if (!req) + return 0; + + if (req->change_counter != vstate->counter) { + DBG(vcp, "Change Counter Mismatch Volume not decremented!"); + return BT_ATT_ERROR_INVALID_CHANGE_COUNTER; + } + + vstate->vol_offset = le16_to_cpu(req->set_vol_offset); + + if (vstate->vol_offset > VOCS_VOL_OFFSET_UPPER_LIMIT || + vstate->vol_offset < VOCS_VOL_OFFSET_LOWER_LIMIT) { + DBG(vcp, "error: Value Out of Range"); + return BT_ATT_ERROR_VALUE_OUT_OF_RANGE; + } + + /* Increment Change Counter */ + vstate->counter = -~vstate->counter; + + /* Notify change */ + state.vol_offset = req->set_vol_offset; + state.counter = vstate->counter; + + gatt_db_attribute_notify(vdb->vocs->vos, (void *)&state, sizeof(state), + bt_vcp_get_att(vcp)); + + return 0; +} + #define BT_VCS_REL_VOL_DOWN 0x00 #define BT_VCS_REL_VOL_UP 0x01 #define BT_VCS_UNMUTE_REL_VOL_DOWN 0x02 @@ -591,6 +839,8 @@ static uint8_t vcs_mute(struct bt_vcs *vcs, struct bt_vcp *vcp, #define BT_VCS_UNMUTE 0x05 #define BT_VCS_MUTE 0x06 +#define BT_VOCS_SET_VOL_OFFSET 0x01 + #define VCS_OP(_str, _op, _size, _func) \ { \ .str = _str, \ @@ -623,6 +873,26 @@ struct vcs_op_handler { {} }; +#define VOCS_OP(_str, _op, _size, _func) \ + { \ + .str = _str, \ + .op = _op, \ + .size = _size, \ + .func = _func, \ + } + +struct vocs_op_handler { + const char *str; + uint8_t op; + size_t size; + uint8_t (*func)(struct bt_vocs *vocs, struct bt_vcp *vcp, + struct iovec *iov); +} vocp_handlers[] = { + VOCS_OP("Set Volume Offset", BT_VOCS_SET_VOL_OFFSET, + sizeof(uint8_t), vocs_set_vol_offset), + {} +}; + static void vcs_cp_write(struct gatt_db_attribute *attrib, unsigned int id, uint16_t offset, const uint8_t *value, size_t len, @@ -655,6 +925,10 @@ static void vcs_cp_write(struct gatt_db_attribute *attrib, } vcp_op = iov_pull_mem(&iov, sizeof(*vcp_op)); + if (!vcp_op) { + DBG(vcp, "iov_pull_mem() returned NULL"); + goto respond; + } for (handler = vcp_handlers; handler && handler->str; handler++) { if (handler->op != *vcp_op) @@ -683,6 +957,70 @@ respond: gatt_db_attribute_write_result(attrib, id, ret); } +static void vocs_cp_write(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + const uint8_t *value, size_t len, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct bt_vocs *vocs = user_data; + struct bt_vcp *vcp = vcp_get_session(att, vocs->vdb->db); + struct iovec iov = { + .iov_base = (void *) value, + .iov_len = len, + }; + uint8_t *vcp_op; + struct vocs_op_handler *handler; + uint8_t ret = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED; + + DBG(vcp, "VOCP Control Point Write"); + + if (offset) { + DBG(vcp, "invalid offset %d", offset); + ret = BT_ATT_ERROR_INVALID_OFFSET; + goto respond; + } + + if (len < sizeof(*vcp_op)) { + DBG(vcp, "invalid len %ld < %ld sizeof(*param)", len, + sizeof(*vcp_op)); + ret = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN; + goto respond; + } + + vcp_op = iov_pull_mem(&iov, sizeof(*vcp_op)); + if (!vcp_op) { + DBG(vcp, "iov_pull_mem() returned NULL"); + goto respond; + } + + for (handler = vocp_handlers; handler && handler->str; handler++) { + if (handler->op != *vcp_op) + continue; + + if (iov.iov_len < handler->size) { + DBG(vcp, "invalid len %ld < %ld handler->size", len, + handler->size); + ret = BT_ATT_ERROR_OPCODE_NOT_SUPPORTED; + goto respond; + } + + break; + } + + if (handler && handler->str) { + DBG(vcp, "%s", handler->str); + + ret = handler->func(vocs, vcp, &iov); + } else { + DBG(vcp, "Unknown opcode 0x%02x", *vcp_op); + ret = BT_ATT_ERROR_OPCODE_NOT_SUPPORTED; + } + +respond: + gatt_db_attribute_write_result(attrib, id, ret); +} + static void vcs_state_read(struct gatt_db_attribute *attrib, unsigned int id, uint16_t offset, uint8_t opcode, struct bt_att *att, @@ -698,6 +1036,21 @@ static void vcs_state_read(struct gatt_db_attribute *attrib, iov.iov_len); } +static void vocs_state_read(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct bt_vocs *vocs = user_data; + struct vol_offset_state state; + + state.vol_offset = cpu_to_le16(vocs->vostate->vol_offset); + state.counter = vocs->vostate->counter; + + gatt_db_attribute_read_result(attrib, id, 0, (void *)&state, + sizeof(state)); +} + static void vcs_flag_read(struct gatt_db_attribute *attrib, unsigned int id, uint16_t offset, uint8_t opcode, struct bt_att *att, @@ -713,78 +1066,775 @@ static void vcs_flag_read(struct gatt_db_attribute *attrib, iov.iov_len); } -static struct bt_vcs *vcs_new(struct gatt_db *db) +static void vocs_voal_read(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) { - struct bt_vcs *vcs; - struct vol_state *vstate; - bt_uuid_t uuid; + struct bt_vocs *vocs = user_data; + uint32_t loc; - if (!db) - return NULL; + loc = cpu_to_le32(vocs->vocs_audio_loc); - vcs = new0(struct bt_vcs, 1); + gatt_db_attribute_read_result(attrib, id, 0, (void *)&loc, + sizeof(loc)); +} - vstate = new0(struct vol_state, 1); +static void vocs_voaodec_read(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct bt_vocs *vocs = user_data; + struct iovec iov; - vcs->vstate = vstate; - vcs->vol_flag = USERSET_VOLUME_SETTING; + iov.iov_base = vocs->vocs_ao_dec; + iov.iov_len = strlen(vocs->vocs_ao_dec); - /* Populate DB with VCS attributes */ - bt_uuid16_create(&uuid, VCS_UUID); - vcs->service = gatt_db_add_service(db, &uuid, true, 9); + gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base, + iov.iov_len); +} - bt_uuid16_create(&uuid, VOL_STATE_CHRC_UUID); - vcs->vs = gatt_db_service_add_characteristic(vcs->service, - &uuid, - BT_ATT_PERM_READ, - BT_GATT_CHRC_PROP_READ | - BT_GATT_CHRC_PROP_NOTIFY, - vcs_state_read, NULL, - vcs); +static void aics_input_state_read(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct bt_aics *aics = user_data; + struct iovec iov; - vcs->vs_ccc = gatt_db_service_add_ccc(vcs->service, - BT_ATT_PERM_READ | BT_ATT_PERM_WRITE); + iov.iov_base = aics->aud_ipst; + iov.iov_len = sizeof(*aics->aud_ipst); - bt_uuid16_create(&uuid, VOL_CP_CHRC_UUID); - vcs->vol_cp = gatt_db_service_add_characteristic(vcs->service, - &uuid, - BT_ATT_PERM_WRITE, - BT_GATT_CHRC_PROP_WRITE, - NULL, vcs_cp_write, - vcs); + gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base, + iov.iov_len); +} - bt_uuid16_create(&uuid, VOL_FLAG_CHRC_UUID); - vcs->vf = gatt_db_service_add_characteristic(vcs->service, - &uuid, - BT_ATT_PERM_READ, - BT_GATT_CHRC_PROP_READ | - BT_GATT_CHRC_PROP_NOTIFY, - vcs_flag_read, NULL, - vcs); +static void aics_gain_setting_prop_read(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct bt_aics *aics = user_data; + struct iovec iov; - vcs->vf_ccc = gatt_db_service_add_ccc(vcs->service, - BT_ATT_PERM_READ | BT_ATT_PERM_WRITE); + iov.iov_base = aics->gain_settingprop; + iov.iov_len = sizeof(*aics->gain_settingprop); + gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base, + iov.iov_len); +} - gatt_db_service_set_active(vcs->service, true); +static void aics_audio_input_type_read(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct bt_aics *aics = user_data; + struct iovec iov; - return vcs; + iov.iov_base = &aics->aud_input_type; + iov.iov_len = sizeof(aics->aud_input_type); + + gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base, + iov.iov_len); } -static struct bt_vcp_db *vcp_db_new(struct gatt_db *db) +static void aics_input_status_read(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) { - struct bt_vcp_db *vdb; + struct bt_aics *aics = user_data; + struct iovec iov; - if (!db) - return NULL; + iov.iov_base = &aics->aud_input_status; + iov.iov_len = sizeof(aics->aud_input_status); - vdb = new0(struct bt_vcp_db, 1); - vdb->db = gatt_db_ref(db); + gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base, + iov.iov_len); +} + +static struct aud_ip_st *vdb_get_audipst(struct bt_vcp_db *vdb) +{ + if (!vdb->aics) + return NULL; + + if (vdb->aics->aud_ipst) + return vdb->aics->aud_ipst; + + return NULL; +} + +static struct gain_setting_prop *vdb_get_gainsettingprop( + struct bt_vcp_db *vdb) +{ + if (!vdb->aics) + return NULL; + + if (vdb->aics->gain_settingprop) + return vdb->aics->gain_settingprop; + + return NULL; +} + +static uint8_t aics_set_gain_setting(struct bt_aics *aics, + struct bt_vcp *vcp, struct iovec *iov) +{ + struct bt_vcp_db *vdb; + struct aud_ip_st *audipst; + struct bt_aics_set_gain_setting *req; + struct gain_setting_prop *gainsettngprop; + uint8_t ret = 1; + + vdb = vcp_get_vdb(vcp); + if (!vdb) { + DBG(vcp, "error: VDB not available"); + ret = 0; + goto respond; + } + + audipst = vdb_get_audipst(vdb); + if (!audipst) { + DBG(vcp, "error: Audio Input State value is not available"); + ret = 0; + goto respond; + + } + + req = iov_pull_mem(iov, sizeof(*req)); + if (!req) { + ret = 0; + goto respond; + + } + + if (req->change_counter != audipst->chg_counter) { + DBG(vcp, "Change Counter Mismatch Audio Input State!"); + ret = BT_ATT_ERROR_INVALID_CHANGE_COUNTER; + goto respond; + } + + if (audipst->gain_mode != AICS_GAIN_MODE_MANUAL_ONLY && + audipst->gain_mode != AICS_GAIN_MODE_MANUAL) { + DBG(vcp, "Gain Mode is not Manual only or Manual"); + ret = BT_ATT_AICS_ERROR_GAIN_MODE_CHANGE_NOT_ALLOWED; + goto respond; + } + + gainsettngprop = vdb_get_gainsettingprop(vdb); + if (req->gain_setting > gainsettngprop->gain_setting_max || + req->gain_setting < gainsettngprop->gain_setting_min) { + DBG(vcp, "error: Value Out of Range"); + ret = BT_ATT_AICS_ERROR_VALUE_OUT_OF_RANGE; + goto respond; + } + + audipst->gain_setting = req->gain_setting; + /*Increment Change Counter*/ + audipst->chg_counter = -~audipst->chg_counter; + gatt_db_attribute_notify(vdb->aics->aud_ip_state, (void *)audipst, + sizeof(struct aud_ip_st), + bt_vcp_get_att(vcp)); + ret = 0; + +respond: + return ret; +} + +static uint8_t aics_unmute(struct bt_aics *aics, struct bt_vcp *vcp, + struct iovec *iov) +{ + struct bt_vcp_db *vdb; + struct aud_ip_st *audipst; + uint8_t *change_counter; + uint8_t ret = 1; + + vdb = vcp_get_vdb(vcp); + if (!vdb) { + DBG(vcp, "error: VDB not available"); + ret = 0; + goto respond; + + } + + audipst = vdb_get_audipst(vdb); + if (!audipst) { + DBG(vcp, "error: Audio Input State value is not available"); + ret = 0; + goto respond; + + } + change_counter = iov_pull_mem(iov, sizeof(*change_counter)); + if (!change_counter) { + ret = 0; + goto respond; + + } + + if (*change_counter != audipst->chg_counter) { + DBG(vcp, "Change Counter Mismatch Audio Input State!"); + ret = BT_ATT_ERROR_INVALID_CHANGE_COUNTER; + goto respond; + } + + if (audipst->mute == AICS_DISABLED) { + DBG(vcp, "Mute state is Disabled!"); + ret = BT_ATT_AICS_ERROR_MUTE_DISABLED; + goto respond; + } + + audipst->mute = AICS_NOT_MUTED; + /*Increment Change Counter*/ + audipst->chg_counter = -~audipst->chg_counter; + gatt_db_attribute_notify(vdb->aics->aud_ip_state, (void *)audipst, + sizeof(struct aud_ip_st), + bt_vcp_get_att(vcp)); + ret = 0; + +respond: + return ret; +} + +static uint8_t aics_mute(struct bt_aics *aics, struct bt_vcp *vcp, + struct iovec *iov) +{ + struct bt_vcp_db *vdb; + struct aud_ip_st *audipst; + uint8_t *change_counter; + uint8_t ret = 1; + + vdb = vcp_get_vdb(vcp); + if (!vdb) { + DBG(vcp, "error: VDB not available"); + ret = 0; + goto respond; + } + + audipst = vdb_get_audipst(vdb); + if (!audipst) { + DBG(vcp, "error: Audio Input State value is not available"); + ret = 0; + goto respond; + } + change_counter = iov_pull_mem(iov, sizeof(*change_counter)); + if (!change_counter) { + ret = 0; + goto respond; + } + + if (*change_counter != audipst->chg_counter) { + DBG(vcp, "Change Counter Mismatch Audio Input State!"); + ret = BT_ATT_ERROR_INVALID_CHANGE_COUNTER; + goto respond; + } + + if (audipst->mute == AICS_DISABLED) { + DBG(vcp, "Mute state is Disabled!"); + ret = BT_ATT_AICS_ERROR_MUTE_DISABLED; + goto respond; + } + + audipst->mute = AICS_MUTED; + /*Increment Change Counter*/ + audipst->chg_counter = -~audipst->chg_counter; + gatt_db_attribute_notify(vdb->aics->aud_ip_state, (void *)audipst, + sizeof(struct aud_ip_st), + bt_vcp_get_att(vcp)); + ret = 0; + +respond: + return ret; +} + +static uint8_t aics_set_manual_gain_mode(struct bt_aics *aics, + struct bt_vcp *vcp, struct iovec *iov) +{ + struct bt_vcp_db *vdb; + struct aud_ip_st *audipst; + uint8_t *change_counter; + uint8_t ret = 1; + + vdb = vcp_get_vdb(vcp); + if (!vdb) { + DBG(vcp, "error: VDB not available"); + ret = 0; + goto respond; + } + + audipst = vdb_get_audipst(vdb); + if (!audipst) { + DBG(vcp, "error: Audio Input State value is not available"); + ret = 0; + goto respond; + } + + change_counter = iov_pull_mem(iov, sizeof(*change_counter)); + if (!change_counter) { + ret = 0; + goto respond; + } + + if (*change_counter != audipst->chg_counter) { + DBG(vcp, "Change Counter Mismatch Audio Input State!"); + ret = BT_ATT_ERROR_INVALID_CHANGE_COUNTER; + goto respond; + } + + if (audipst->gain_mode == AICS_GAIN_MODE_AUTO_ONLY || + audipst->gain_mode == AICS_GAIN_MODE_MANUAL_ONLY) { + DBG(vcp, "error!! gain mode is Automatic only or Manual only"); + ret = BT_ATT_AICS_ERROR_GAIN_MODE_CHANGE_NOT_ALLOWED; + goto respond; + } + + if (audipst->gain_mode == AICS_GAIN_MODE_AUTO) { + audipst->gain_mode = AICS_GAIN_MODE_MANUAL; + /*Increment Change Counter*/ + audipst->chg_counter = -~audipst->chg_counter; + gatt_db_attribute_notify(vdb->aics->aud_ip_state, + (void *)audipst, + sizeof(struct aud_ip_st), + bt_vcp_get_att(vcp)); + ret = 0; + } else { + DBG(vcp, + "error!! Gain mode field value not Automatic"); + ret = BT_ATT_AICS_ERROR_GAIN_MODE_CHANGE_NOT_ALLOWED; + } + +respond: + return ret; +} + +static uint8_t aics_set_auto_gain_mode(struct bt_aics *aics, struct bt_vcp *vcp, + struct iovec *iov) +{ + struct bt_vcp_db *vdb; + struct aud_ip_st *audipst; + uint8_t *change_counter; + uint8_t ret = 1; + + vdb = vcp_get_vdb(vcp); + if (!vdb) { + DBG(vcp, "error: VDB not available"); + ret = 0; + goto respond; + } + + audipst = vdb_get_audipst(vdb); + if (!audipst) { + DBG(vcp, "error: Audio Input State value is not available"); + ret = 0; + goto respond; + } + change_counter = iov_pull_mem(iov, sizeof(*change_counter)); + if (!change_counter) { + ret = 0; + goto respond; + } + + if (*change_counter != audipst->chg_counter) { + DBG(vcp, "Change Counter Mismatch Audio Input State!"); + ret = BT_ATT_ERROR_INVALID_CHANGE_COUNTER; + goto respond; + } + + if (audipst->gain_mode == AICS_GAIN_MODE_AUTO_ONLY || + audipst->gain_mode == AICS_GAIN_MODE_MANUAL_ONLY) { + DBG(vcp, "error!! gain mode is Automatic only or Manual only"); + ret = BT_ATT_AICS_ERROR_GAIN_MODE_CHANGE_NOT_ALLOWED; + goto respond; + } + + if (audipst->gain_mode == AICS_GAIN_MODE_MANUAL) { + audipst->gain_mode = AICS_GAIN_MODE_AUTO; + /*Increment Change Counter*/ + audipst->chg_counter = -~audipst->chg_counter; + gatt_db_attribute_notify(vdb->aics->aud_ip_state, + (void *)audipst, + sizeof(struct aud_ip_st), bt_vcp_get_att(vcp)); + ret = 0; + } else { + DBG(vcp, "error!! Gain mode field value is not Manual"); + ret = BT_ATT_AICS_ERROR_GAIN_MODE_CHANGE_NOT_ALLOWED; + } + +respond: + return ret; +} + +#define AICS_OP(_str, _op, _size, _func) \ + { \ + .str = _str, \ + .op = _op, \ + .size = _size, \ + .func = _func, \ + } + +struct aics_op_handler { + const char *str; + uint8_t op; + size_t size; + uint8_t (*func)(struct bt_aics *aics, struct bt_vcp *vcp, + struct iovec *iov); +} aics_handlers[] = { + AICS_OP("Set Gain Setting", BT_AICS_SET_GAIN_SETTING, + sizeof(struct bt_aics_set_gain_setting), + aics_set_gain_setting), + AICS_OP("Unmute", BT_AICS_UNMUTE, + sizeof(uint8_t), aics_unmute), + AICS_OP("Mute", BT_AICS_MUTE, + sizeof(uint8_t), aics_mute), + AICS_OP("Set Manual Gain Mode", BT_AICS_SET_MANUAL_GAIN_MODE, + sizeof(uint8_t), aics_set_manual_gain_mode), + AICS_OP("Set Automatic Gain Mode", BT_AICS_SET_AUTO_GAIN_MODE, + sizeof(uint8_t), aics_set_auto_gain_mode), + {} +}; + +static void aics_ip_cp_write(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + const uint8_t *value, size_t len, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct bt_aics *aics = user_data; + struct bt_vcp *vcp = vcp_get_session(att, aics->vdb->db); + struct iovec iov = { + .iov_base = (void *) value, + .iov_len = len, + }; + uint8_t *aics_op; + struct aics_op_handler *handler; + uint8_t ret = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED; + + DBG(vcp, "AICS Control Point Write"); + + if (offset) { + DBG(vcp, "invalid offset %d", offset); + ret = BT_ATT_ERROR_INVALID_OFFSET; + goto respond; + } + + if (len < sizeof(*aics_op)) { + DBG(vcp, "invalid len %ld < %ld sizeof(*param)", len, + sizeof(*aics_op)); + ret = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN; + goto respond; + } + + aics_op = iov_pull_mem(&iov, sizeof(*aics_op)); + if (!aics_op) { + DBG(vcp, "iov_pull_mem() returned NULL"); + goto respond; + } + + for (handler = aics_handlers; handler && handler->str; handler++) { + if (handler->op != *aics_op) + continue; + + if (iov.iov_len < handler->size) { + DBG(vcp, "invalid len %ld < %ld handler->size", len, + handler->size); + ret = BT_ATT_ERROR_OPCODE_NOT_SUPPORTED; + goto respond; + } + + break; + } + + if (handler && handler->str) { + DBG(vcp, "%s", handler->str); + + ret = handler->func(aics, vcp, &iov); + } else { + DBG(vcp, "Unknown opcode 0x%02x", *aics_op); + ret = BT_ATT_ERROR_OPCODE_NOT_SUPPORTED; + } + +respond: + gatt_db_attribute_write_result(attrib, id, ret); +} + +static void aics_input_descr_read(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct bt_aics *aics = user_data; + struct iovec iov; + + iov.iov_base = aics->aud_input_descr; + iov.iov_len = strlen(aics->aud_input_descr); + + gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base, + iov.iov_len); +} + +static void aics_input_descr_write(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + const uint8_t *value, size_t len, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + /* TODO : AICS optional feature */ +} + +static struct bt_vcs *vcs_new(struct gatt_db *db, struct bt_vcp_db *vdb) +{ + struct bt_vcs *vcs; + struct vol_state *vstate; + bt_uuid_t uuid; + + if (!db) + return NULL; + + vcs = new0(struct bt_vcs, 1); + + vstate = new0(struct vol_state, 1); + + vcs->vstate = vstate; + vcs->vol_flag = USERSET_VOLUME_SETTING; + + /* Populate DB with VCS attributes */ + bt_uuid16_create(&uuid, VCS_UUID); + vcs->service = gatt_db_add_service(db, &uuid, true, + VCS_TOTAL_NUM_HANDLES); + gatt_db_service_add_included(vcs->service, vdb->vocs->service); + gatt_db_service_set_active(vdb->vocs->service, true); + gatt_db_service_add_included(vcs->service, vdb->aics->service); + gatt_db_service_set_active(vdb->aics->service, true); + + bt_uuid16_create(&uuid, VOL_STATE_CHRC_UUID); + vcs->vs = gatt_db_service_add_characteristic(vcs->service, + &uuid, + BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_NOTIFY, + vcs_state_read, NULL, + vcs); + + vcs->vs_ccc = gatt_db_service_add_ccc(vcs->service, + BT_ATT_PERM_READ | BT_ATT_PERM_WRITE); + + bt_uuid16_create(&uuid, VOL_CP_CHRC_UUID); + vcs->vol_cp = gatt_db_service_add_characteristic(vcs->service, + &uuid, + BT_ATT_PERM_WRITE, + BT_GATT_CHRC_PROP_WRITE, + NULL, vcs_cp_write, + vcs); + + bt_uuid16_create(&uuid, VOL_FLAG_CHRC_UUID); + vcs->vf = gatt_db_service_add_characteristic(vcs->service, + &uuid, + BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_NOTIFY, + vcs_flag_read, NULL, + vcs); + + vcs->vf_ccc = gatt_db_service_add_ccc(vcs->service, + BT_ATT_PERM_READ | BT_ATT_PERM_WRITE); + + + gatt_db_service_set_active(vcs->service, true); + + return vcs; +} + +static struct bt_vocs *vocs_new(struct gatt_db *db) +{ + struct bt_vocs *vocs; + struct vol_offset_state *vostate; + bt_uuid_t uuid; + + if (!db) + return NULL; + + vocs = new0(struct bt_vocs, 1); + + vostate = new0(struct vol_offset_state, 1); + + vocs->vostate = vostate; + vocs->vocs_audio_loc = BT_VCP_FRONT_LEFT; + vocs->vocs_ao_dec = "Left Speaker"; + + /* Populate DB with VOCS attributes */ + bt_uuid16_create(&uuid, VOL_OFFSET_CS_UUID); + + vocs->service = gatt_db_add_service(db, &uuid, false, 12); + + bt_uuid16_create(&uuid, VOCS_STATE_CHAR_UUID); + vocs->vos = gatt_db_service_add_characteristic(vocs->service, + &uuid, + BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_NOTIFY, + vocs_state_read, NULL, + vocs); + + vocs->vos_ccc = gatt_db_service_add_ccc(vocs->service, + BT_ATT_PERM_READ | BT_ATT_PERM_WRITE); + + bt_uuid16_create(&uuid, VOCS_AUDIO_LOC_CHRC_UUID); + vocs->voal = gatt_db_service_add_characteristic(vocs->service, + &uuid, + BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_NOTIFY, + vocs_voal_read, NULL, + vocs); + + vocs->voal_ccc = gatt_db_service_add_ccc(vocs->service, + BT_ATT_PERM_READ | BT_ATT_PERM_WRITE); + + bt_uuid16_create(&uuid, VOCS_CP_CHRC_UUID); + vocs->vo_cp = gatt_db_service_add_characteristic(vocs->service, + &uuid, + BT_ATT_PERM_WRITE, + BT_GATT_CHRC_PROP_WRITE, + NULL, vocs_cp_write, + vocs); + + bt_uuid16_create(&uuid, VOCS_AUDIO_OP_DESC_CHAR_UUID); + vocs->voaodec = gatt_db_service_add_characteristic(vocs->service, + &uuid, + BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_NOTIFY, + vocs_voaodec_read, NULL, + vocs); + + vocs->voaodec_ccc = gatt_db_service_add_ccc(vocs->service, + BT_ATT_PERM_READ | BT_ATT_PERM_WRITE); + + return vocs; +} + +static struct bt_aics *aics_new(struct gatt_db *db) +{ + struct bt_aics *aics; + struct aud_ip_st *aics_aud_ip_st; + struct gain_setting_prop *aics_gain_settng_prop; + char *ip_descr; + char ip_descr_str[] = "Blueooth"; + bt_uuid_t uuid; + + if (!db) + return NULL; + + aics = new0(struct bt_aics, 1); + + aics_aud_ip_st = new0(struct aud_ip_st, 1); + aics_gain_settng_prop = new0(struct gain_setting_prop, 1); + ip_descr = malloc(256); + memset(ip_descr, 0, 256); + + aics_aud_ip_st->mute = AICS_NOT_MUTED; + aics_aud_ip_st->gain_mode = AICS_GAIN_MODE_MANUAL; + aics_aud_ip_st->gain_setting = AICS_GAIN_SETTING_DEFAULT_VALUE; + aics->aud_ipst = aics_aud_ip_st; + aics_gain_settng_prop->gain_setting_units = AICS_GAIN_SETTING_UNITS; + aics_gain_settng_prop->gain_setting_max = AICS_GAIN_SETTING_MAX_VALUE; + aics_gain_settng_prop->gain_setting_min = AICS_GAIN_SETTING_MIN_VALUE; + aics->gain_settingprop = aics_gain_settng_prop; + aics->aud_input_type = AICS_AUD_IP_TYPE_BLUETOOTH; + aics->aud_input_status = AICS_AUD_IP_STATUS_ACTIVE; + memcpy(ip_descr, ip_descr_str, strlen(ip_descr_str)); + aics->aud_input_descr = ip_descr; + + /* Populate DB with AICS attributes */ + bt_uuid16_create(&uuid, AUDIO_INPUT_CS_UUID); + aics->service = gatt_db_add_service(db, &uuid, false, + AICS_TOTAL_NUM_HANDLES); + + bt_uuid16_create(&uuid, AICS_INPUT_STATE_CHAR_UUID); + aics->aud_ip_state = gatt_db_service_add_characteristic(aics->service, + &uuid, + BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_NOTIFY, + aics_input_state_read, + NULL, + aics); + aics->aud_ip_state_ccc = gatt_db_service_add_ccc(aics->service, + BT_ATT_PERM_READ | BT_ATT_PERM_WRITE); + + bt_uuid16_create(&uuid, AICS_GAIN_SETTING_PROP_CHAR_UUID); + aics->gain_stting_prop = gatt_db_service_add_characteristic( + aics->service, + &uuid, + BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ, + aics_gain_setting_prop_read, NULL, + aics); + + bt_uuid16_create(&uuid, AICS_AUDIO_INPUT_TYPE_CHAR_UUID); + aics->aud_ip_type = gatt_db_service_add_characteristic(aics->service, + &uuid, + BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ, + aics_audio_input_type_read, NULL, + aics); + + bt_uuid16_create(&uuid, AICS_INPUT_STATUS_CHAR_UUID); + aics->aud_ip_status = gatt_db_service_add_characteristic(aics->service, + &uuid, + BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_NOTIFY, + aics_input_status_read, NULL, + aics); + aics->aud_ip_status_ccc = gatt_db_service_add_ccc(aics->service, + BT_ATT_PERM_READ | BT_ATT_PERM_WRITE); + + bt_uuid16_create(&uuid, AICS_AUDIO_INPUT_CP_CHRC_UUID); + aics->aud_ip_cp = gatt_db_service_add_characteristic(aics->service, + &uuid, + BT_ATT_PERM_WRITE, + BT_GATT_CHRC_PROP_WRITE, + NULL, aics_ip_cp_write, + aics); + + bt_uuid16_create(&uuid, AICS_INPUT_DESCR_CHAR_UUID); + aics->aud_ip_dscrptn = gatt_db_service_add_characteristic(aics->service, + &uuid, + BT_ATT_PERM_READ | + BT_ATT_PERM_WRITE, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP | + BT_GATT_CHRC_PROP_NOTIFY, + aics_input_descr_read, + aics_input_descr_write, + aics); + aics->aud_ip_dscrptn_ccc = gatt_db_service_add_ccc(aics->service, + BT_ATT_PERM_READ | BT_ATT_PERM_WRITE); + + return aics; +} + +static struct bt_vcp_db *vcp_db_new(struct gatt_db *db) +{ + struct bt_vcp_db *vdb; + + if (!db) + return NULL; + + vdb = new0(struct bt_vcp_db, 1); + vdb->db = gatt_db_ref(db); if (!vcp_db) vcp_db = queue_new(); - vdb->vcs = vcs_new(db); + vdb->vocs = vocs_new(db); + vdb->vocs->vdb = vdb; + + vdb->aics = aics_new(db); + vdb->aics->vdb = vdb; + + vdb->vcs = vcs_new(db, vdb); vdb->vcs->vdb = vdb; queue_push_tail(vcp_db, vdb); @@ -902,13 +1952,54 @@ static void vcp_vstate_notify(struct bt_vcp *vcp, uint16_t value_handle, const uint8_t *value, uint16_t length, void *user_data) { - struct vol_state vstate; + struct vol_state vstate; + + memcpy(&vstate, value, sizeof(struct vol_state)); + + DBG(vcp, "Vol Settings 0x%x", vstate.vol_set); + DBG(vcp, "Mute Status 0x%x", vstate.mute); + DBG(vcp, "Vol Counter 0x%x", vstate.counter); +} + +static void vcp_voffset_state_notify(struct bt_vcp *vcp, uint16_t value_handle, + const uint8_t *value, uint16_t length, + void *user_data) +{ + struct vol_offset_state vostate; + + memcpy(&vostate, value, sizeof(struct vol_offset_state)); + + DBG(vcp, "Vol Offset 0x%x", vostate.vol_offset); + DBG(vcp, "Vol Offset Counter 0x%x", vostate.counter); +} + +static void vcp_audio_loc_notify(struct bt_vcp *vcp, uint16_t value_handle, + const uint8_t *value, uint16_t length, + void *user_data) +{ + uint32_t *vocs_audio_loc_n = malloc(sizeof(uint32_t)); + *vocs_audio_loc_n = 0; + + if (value != NULL) + memcpy(vocs_audio_loc_n, value, sizeof(uint32_t)); + + DBG(vcp, "VOCS Audio Location 0x%x", *vocs_audio_loc_n); + + free(vocs_audio_loc_n); +} + + +static void vcp_audio_descriptor_notify(struct bt_vcp *vcp, + uint16_t value_handle, + const uint8_t *value, + uint16_t length, + void *user_data) +{ + char vocs_audio_dec_n[256] = {'\0'}; - memcpy(&vstate, value, sizeof(struct vol_state)); + memcpy(vocs_audio_dec_n, value, length); - DBG(vcp, "Vol Settings 0x%x", vstate.vol_set); - DBG(vcp, "Mute Status 0x%x", vstate.mute); - DBG(vcp, "Vol Counter 0x%x", vstate.counter); + DBG(vcp, "VOCS Audio Descriptor 0x%s", *vocs_audio_dec_n); } static void vcp_vflag_notify(struct bt_vcp *vcp, uint16_t value_handle, @@ -972,6 +2063,90 @@ static void read_vol_state(struct bt_vcp *vcp, bool success, uint8_t att_ecode, DBG(vcp, "Vol Counter:%x", vs->counter); } +static void read_vol_offset_state(struct bt_vcp *vcp, bool success, + uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) +{ + struct vol_offset_state *vos; + struct iovec iov = { + .iov_base = (void *) value, + .iov_len = length, + }; + + if (!success) { + DBG(vcp, "Unable to read Vol Offset State: error 0x%02x", + att_ecode); + return; + } + + vos = iov_pull_mem(&iov, sizeof(*vos)); + if (!vos) { + DBG(vcp, "Unable to get Vol Offset State"); + return; + } + + DBG(vcp, "Vol Offset: 0x%04x", le16_to_cpu(vos->vol_offset)); + DBG(vcp, "Vol Counter: 0x%02x", vos->counter); +} + +static void read_vocs_audio_location(struct bt_vcp *vcp, bool success, + uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) +{ + uint32_t vocs_audio_loc; + struct iovec iov; + + if (!value) { + DBG(vcp, "Unable to get VOCS Audio Location"); + return; + } + + if (!success) { + DBG(vcp, "Unable to read VOCS Audio Location: error 0x%02x", + att_ecode); + return; + } + + iov.iov_base = (void *)value; + iov.iov_len = length; + + if (!util_iov_pull_le32(&iov, &vocs_audio_loc)) { + DBG(vcp, "Invalid size for VOCS Audio Location"); + return; + } + + DBG(vcp, "VOCS Audio Loc: 0x%8x", vocs_audio_loc); +} + + +static void read_vocs_audio_descriptor(struct bt_vcp *vcp, bool success, + uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) +{ + char *vocs_ao_dec_r; + + if (!value) { + DBG(vcp, "Unable to get VOCS Audio Location"); + return; + } + + if (!success) { + DBG(vcp, "Unable to read VOCS Audio Descriptor: error 0x%02x", + att_ecode); + return; + } + + vocs_ao_dec_r = util_memdup(value, length + 1); + memset(vocs_ao_dec_r + length, 0, 1); + + DBG(vcp, "VOCS Audio Descriptor: %s", vocs_ao_dec_r); + free(vocs_ao_dec_r); + vocs_ao_dec_r = NULL; +} + static void vcp_pending_destroy(void *data) { struct bt_vcp_pending *pending = data; @@ -1128,6 +2303,385 @@ static void foreach_vcs_char(struct gatt_db_attribute *attr, void *user_data) } } +static void foreach_vocs_char(struct gatt_db_attribute *attr, void *user_data) +{ + struct bt_vcp *vcp = user_data; + uint16_t value_handle; + bt_uuid_t uuid, uuid_vostate, uuid_audio_loc, uuid_vo_cp, + uuid_audio_op_decs; + struct bt_vocs *vocs; + + if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, + NULL, NULL, &uuid)) + return; + + bt_uuid16_create(&uuid_vostate, VOCS_STATE_CHAR_UUID); + bt_uuid16_create(&uuid_audio_loc, VOCS_AUDIO_LOC_CHRC_UUID); + bt_uuid16_create(&uuid_vo_cp, VOCS_CP_CHRC_UUID); + bt_uuid16_create(&uuid_audio_op_decs, VOCS_AUDIO_OP_DESC_CHAR_UUID); + + if (!bt_uuid_cmp(&uuid, &uuid_vostate)) { + DBG(vcp, "VOCS Vol state found: handle 0x%04x", value_handle); + + vocs = vcp_get_vocs(vcp); + if (!vocs || vocs->vos) + return; + + vocs->vos = attr; + + vcp_read_value(vcp, value_handle, read_vol_offset_state, vcp); + + vcp->state_id = vcp_register_notify(vcp, value_handle, + vcp_voffset_state_notify, NULL); + + return; + } + + if (!bt_uuid_cmp(&uuid, &uuid_audio_loc)) { + DBG(vcp, "VOCS Volume Audio Location found: handle 0x%04x", + value_handle); + + vocs = vcp_get_vocs(vcp); + if (!vocs || vocs->voal) + return; + + vocs->voal = attr; + + vcp_read_value(vcp, value_handle, read_vocs_audio_location, + vcp); + + vcp->audio_loc_id = vcp_register_notify(vcp, value_handle, + vcp_audio_loc_notify, NULL); + + return; + } + + if (!bt_uuid_cmp(&uuid, &uuid_vo_cp)) { + DBG(vcp, "VOCS Volume CP found: handle 0x%04x", value_handle); + + vocs = vcp_get_vocs(vcp); + if (!vocs || vocs->vo_cp) + return; + + vocs->vo_cp = attr; + + return; + } + + if (!bt_uuid_cmp(&uuid, &uuid_audio_op_decs)) { + DBG(vcp, "VOCS Vol Audio Descriptor found: handle 0x%04x", + value_handle); + + vocs = vcp_get_vocs(vcp); + if (!vocs || vocs->voaodec) + return; + + vocs->voaodec = attr; + + vcp_read_value(vcp, value_handle, read_vocs_audio_descriptor, + vcp); + vcp->ao_dec_id = vcp_register_notify(vcp, value_handle, + vcp_audio_descriptor_notify, NULL); + + } + +} + +static void read_aics_audio_ip_state(struct bt_vcp *vcp, bool success, + uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) +{ + struct aud_ip_st *ip_st; + struct iovec iov = { + .iov_base = (void *) value, + .iov_len = length, + }; + + if (!success) { + DBG(vcp, "Unable to read Audio Input State: error 0x%02x", + att_ecode); + return; + } + + ip_st = iov_pull_mem(&iov, sizeof(*ip_st)); + if (!ip_st) { + DBG(vcp, "Unable to get Audio Input State"); + return; + } + + DBG(vcp, "Audio Input State, Gain Setting:%d", ip_st->gain_setting); + DBG(vcp, "Audio Input State, Mute:%x", ip_st->mute); + DBG(vcp, "Audio Input State, Gain Mode:%x", ip_st->gain_mode); + DBG(vcp, "Audio Input State, Change Counter:%x", ip_st->chg_counter); +} + +static void aics_ip_state_notify(struct bt_vcp *vcp, uint16_t value_handle, + const uint8_t *value, uint16_t length, + void *user_data) +{ + struct aud_ip_st ip_st; + + memcpy(&ip_st, value, sizeof(struct aud_ip_st)); + + DBG(vcp, "Audio Input State, Gain Setting:%d", ip_st.gain_setting); + DBG(vcp, "Audio Input State, Mute:%x", ip_st.mute); + DBG(vcp, "Audio Input State, Gain Mode:%x", ip_st.gain_mode); + DBG(vcp, "Audio Input State, Change Counter:%x", ip_st.chg_counter); +} + +static void read_aics_gain_setting_prop(struct bt_vcp *vcp, bool success, + uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) +{ + struct gain_setting_prop *aics_gain_setting_prop; + struct iovec iov = { + .iov_base = (void *) value, + .iov_len = length, + }; + + if (!value) { + DBG(vcp, "Unable to get Gain Setting Properties Char"); + return; + } + + if (!success) { + DBG(vcp, + "Unable to read Gain Setting Properties Char: 0x%02x", + att_ecode); + return; + } + + aics_gain_setting_prop = iov_pull_mem(&iov, + sizeof(*aics_gain_setting_prop)); + if (!aics_gain_setting_prop) { + DBG(vcp, "Unable to get Gain Setting Properties Char"); + return; + } + + DBG(vcp, "Gain Setting Properties, Units: %x", + aics_gain_setting_prop->gain_setting_units); + DBG(vcp, "Gain Setting Properties, Min Value: %d", + aics_gain_setting_prop->gain_setting_min); + DBG(vcp, "Gain Setting Properties, Max Value: %d", + aics_gain_setting_prop->gain_setting_max); +} + +static void read_aics_aud_ip_type(struct bt_vcp *vcp, bool success, + uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) +{ + uint8_t ip_type; + + if (!success) { + DBG(vcp, + "Unable to read Audio Input Type Char: error 0x%02x", + att_ecode); + return; + } + + memcpy(&ip_type, value, length); + + DBG(vcp, "Audio Input Type : %x", ip_type); +} + +static void read_aics_audio_ip_status(struct bt_vcp *vcp, bool success, + uint8_t att_ecode, + const uint8_t *value, uint16_t length, + void *user_data) +{ + uint8_t ip_status; + + if (!success) { + DBG(vcp, + "Unable to read Audio Input Status Char: 0x%02x", att_ecode); + return; + } + + memcpy(&ip_status, value, length); + + DBG(vcp, "Audio Input Status : %x", ip_status); +} + +static void aics_ip_status_notify(struct bt_vcp *vcp, uint16_t value_handle, + const uint8_t *value, + uint16_t length, + void *user_data) +{ + uint8_t ip_status; + + memcpy(&ip_status, value, length); + + DBG(vcp, "Audio Input Status, %x", ip_status); +} + +static void read_aics_audio_ip_description(struct bt_vcp *vcp, bool success, + uint8_t att_ecode, + const uint8_t *value, + uint16_t length, + void *user_data) +{ + char *ip_descrptn; + + if (!value) { + DBG(vcp, "Unable to get Audio Input Description"); + return; + } + + if (!success) { + DBG(vcp, + "Unable to read Audio Input Description Char: error 0x%02x", + att_ecode); + return; + } + + ip_descrptn = util_memdup(value, length + 1); + memset(ip_descrptn + length, 0, 1); + + DBG(vcp, "Audio Input Description: %s", ip_descrptn); + free(ip_descrptn); + ip_descrptn = NULL; +} + +static void aics_audio_ip_desr_notify(struct bt_vcp *vcp, uint16_t value_handle, + const uint8_t *value, uint16_t length, + void *user_data) +{ + char *aud_ip_desr; + + aud_ip_desr = malloc(length+1); + memset(aud_ip_desr, 0, length+1); + memcpy(aud_ip_desr, value, length); + + DBG(vcp, "Audio Input Description Notify, %s", aud_ip_desr); + free(aud_ip_desr); + aud_ip_desr = NULL; +} + +static void foreach_aics_char(struct gatt_db_attribute *attr, void *user_data) +{ + struct bt_vcp *vcp = user_data; + uint16_t value_handle; + bt_uuid_t uuid, uuid_ipstate, uuid_gain_setting_prop, uuid_ip_type, + uuid_ip_status, uuid_ip_cp, uuid_ip_decs; + struct bt_aics *aics; + + if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, + NULL, NULL, &uuid)) + return; + + bt_uuid16_create(&uuid_ipstate, AICS_INPUT_STATE_CHAR_UUID); + bt_uuid16_create(&uuid_gain_setting_prop, + AICS_GAIN_SETTING_PROP_CHAR_UUID); + bt_uuid16_create(&uuid_ip_type, AICS_AUDIO_INPUT_TYPE_CHAR_UUID); + bt_uuid16_create(&uuid_ip_status, AICS_INPUT_STATUS_CHAR_UUID); + bt_uuid16_create(&uuid_ip_cp, AICS_AUDIO_INPUT_CP_CHRC_UUID); + bt_uuid16_create(&uuid_ip_decs, AICS_INPUT_DESCR_CHAR_UUID); + + + if (!bt_uuid_cmp(&uuid, &uuid_ipstate)) { + DBG(vcp, + "AICS Audio Input State Char found: handle 0x%04x", + value_handle); + + aics = vcp_get_aics(vcp); + if (!aics || aics->aud_ip_state) + return; + + aics->aud_ip_state = attr; + + vcp_read_value(vcp, value_handle, + read_aics_audio_ip_state, vcp); + + vcp->aics_ip_state_id = vcp_register_notify(vcp, value_handle, + aics_ip_state_notify, NULL); + + return; + } + + if (!bt_uuid_cmp(&uuid, &uuid_gain_setting_prop)) { + DBG(vcp, + "AICS Gain Setting Properties Char found: handle 0x%04x", + value_handle); + + aics = vcp_get_aics(vcp); + if (!aics || aics->gain_stting_prop) + return; + + aics->gain_stting_prop = attr; + + vcp_read_value(vcp, value_handle, read_aics_gain_setting_prop, + vcp); + return; + } + + if (!bt_uuid_cmp(&uuid, &uuid_ip_type)) { + DBG(vcp, "AICS Audio Input Type Char found: handle 0x%04x", + value_handle); + + aics = vcp_get_aics(vcp); + if (!aics || aics->aud_ip_type) + return; + + aics->aud_ip_type = attr; + + vcp_read_value(vcp, value_handle, read_aics_aud_ip_type, + vcp); + return; + } + + if (!bt_uuid_cmp(&uuid, &uuid_ip_status)) { + DBG(vcp, + "AICS Audio Input Status Char found: handle 0x%04x", + value_handle); + + aics = vcp_get_aics(vcp); + if (!aics || aics->aud_ip_status) + return; + + aics->aud_ip_status = attr; + + vcp_read_value(vcp, value_handle, + read_aics_audio_ip_status, vcp); + + vcp->aics_ip_status_id = vcp_register_notify(vcp, value_handle, + aics_ip_status_notify, NULL); + + return; + } + + if (!bt_uuid_cmp(&uuid, &uuid_ip_cp)) { + DBG(vcp, "AICS Input CP found: handle 0x%04x", value_handle); + + aics = vcp_get_aics(vcp); + if (!aics || aics->aud_ip_cp) + return; + + aics->aud_ip_cp = attr; + + return; + } + + if (!bt_uuid_cmp(&uuid, &uuid_ip_decs)) { + DBG(vcp, + "AICS Audio Input Description Char found: handle 0x%04x", + value_handle); + + aics = vcp_get_aics(vcp); + if (!aics || aics->aud_ip_dscrptn) + return; + + aics->aud_ip_dscrptn = attr; + + vcp_read_value(vcp, value_handle, + read_aics_audio_ip_description, vcp); + vcp->aics_ip_descr_id = vcp_register_notify(vcp, value_handle, + aics_audio_ip_desr_notify, NULL); + } +} + static void foreach_vcs_service(struct gatt_db_attribute *attr, void *user_data) { @@ -1141,6 +2695,38 @@ static void foreach_vcs_service(struct gatt_db_attribute *attr, gatt_db_service_foreach_char(attr, foreach_vcs_char, vcp); } +static void foreach_vocs_service(struct gatt_db_attribute *attr, + void *user_data) +{ + struct bt_vcp *vcp = user_data; + struct bt_vocs *vocs = vcp_get_vocs(vcp); + + if (!vocs || !attr) + return; + + vocs->service = attr; + + gatt_db_service_set_claimed(attr, true); + + gatt_db_service_foreach_char(attr, foreach_vocs_char, vcp); +} + +static void foreach_aics_service(struct gatt_db_attribute *attr, + void *user_data) +{ + struct bt_vcp *vcp = user_data; + struct bt_aics *aics = vcp_get_aics(vcp); + + if (!aics || !attr) + return; + + aics->service = attr; + + gatt_db_service_set_claimed(attr, true); + + gatt_db_service_foreach_char(attr, foreach_aics_char, vcp); +} + bool bt_vcp_attach(struct bt_vcp *vcp, struct bt_gatt_client *client) { bt_uuid_t uuid; @@ -1161,7 +2747,13 @@ bool bt_vcp_attach(struct bt_vcp *vcp, struct bt_gatt_client *client) return false; bt_uuid16_create(&uuid, VCS_UUID); - gatt_db_foreach_service(vcp->ldb->db, &uuid, foreach_vcs_service, vcp); + gatt_db_foreach_service(vcp->rdb->db, &uuid, foreach_vcs_service, vcp); + + bt_uuid16_create(&uuid, VOL_OFFSET_CS_UUID); + gatt_db_foreach_service(vcp->rdb->db, &uuid, foreach_vocs_service, vcp); + + bt_uuid16_create(&uuid, AUDIO_INPUT_CS_UUID); + gatt_db_foreach_service(vcp->rdb->db, &uuid, foreach_aics_service, vcp); return true; } diff --git a/src/storage.c b/src/storage.c index 6e69be978b4692a6189b454fe6c0046110a52d9a..187ba156ce6c4c9b23a4d310ade41ec1606828e7 100644 --- a/src/storage.c +++ b/src/storage.c @@ -21,6 +21,7 @@ #include <unistd.h> #include <stdlib.h> #include <time.h> +#include <limits.h> #include <sys/file.h> #include <sys/stat.h> diff --git a/src/textfile.c b/src/textfile.c index a5b9e73a64218ff09dcb37c7ca87f89c187dc98a..8188d2ebe9dbbb04c8e2469c2545ab49b4b976c2 100644 --- a/src/textfile.c +++ b/src/textfile.c @@ -21,6 +21,7 @@ #include <stdlib.h> #include <stdarg.h> #include <string.h> +#include <limits.h> #include <sys/file.h> #include <sys/stat.h> #include <sys/mman.h> @@ -126,10 +127,10 @@ static inline char *find_key(char *map, size_t size, const char *key, size_t len while (ptrlen > len + 1) { int cmp = (icase) ? strncasecmp(ptr, key, len) : strncmp(ptr, key, len); if (cmp == 0) { - if (ptr == map && *(ptr + len) == ' ') - return ptr; - - if ((*(ptr - 1) == '\r' || *(ptr - 1) == '\n') && + if (ptr == map) { + if (*(ptr + len) == ' ') + return ptr; + } else if ((*(ptr - 1) == '\r' || *(ptr - 1) == '\n') && *(ptr + len) == ' ') return ptr; } diff --git a/test-driver b/test-driver new file mode 100755 index 0000000000000000000000000000000000000000..be73b80adf95515f3fc7cdc504facb29bc12e6b3 --- /dev/null +++ b/test-driver @@ -0,0 +1,153 @@ +#! /bin/sh +# test-driver - basic testsuite driver script. + +scriptversion=2018-03-07.03; # UTC + +# Copyright (C) 2011-2021 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, see <https://www.gnu.org/licenses/>. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to <bug-automake@gnu.org> or send patches to +# <automake-patches@gnu.org>. + +# Make unconditional expansion of undefined variables an error. This +# helps a lot in preventing typo-related bugs. +set -u + +usage_error () +{ + echo "$0: $*" >&2 + print_usage >&2 + exit 2 +} + +print_usage () +{ + cat <<END +Usage: + test-driver --test-name NAME --log-file PATH --trs-file PATH + [--expect-failure {yes|no}] [--color-tests {yes|no}] + [--enable-hard-errors {yes|no}] [--] + TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS] + +The '--test-name', '--log-file' and '--trs-file' options are mandatory. +See the GNU Automake documentation for information. +END +} + +test_name= # Used for reporting. +log_file= # Where to save the output of the test script. +trs_file= # Where to save the metadata of the test run. +expect_failure=no +color_tests=no +enable_hard_errors=yes +while test $# -gt 0; do + case $1 in + --help) print_usage; exit $?;; + --version) echo "test-driver $scriptversion"; exit $?;; + --test-name) test_name=$2; shift;; + --log-file) log_file=$2; shift;; + --trs-file) trs_file=$2; shift;; + --color-tests) color_tests=$2; shift;; + --expect-failure) expect_failure=$2; shift;; + --enable-hard-errors) enable_hard_errors=$2; shift;; + --) shift; break;; + -*) usage_error "invalid option: '$1'";; + *) break;; + esac + shift +done + +missing_opts= +test x"$test_name" = x && missing_opts="$missing_opts --test-name" +test x"$log_file" = x && missing_opts="$missing_opts --log-file" +test x"$trs_file" = x && missing_opts="$missing_opts --trs-file" +if test x"$missing_opts" != x; then + usage_error "the following mandatory options are missing:$missing_opts" +fi + +if test $# -eq 0; then + usage_error "missing argument" +fi + +if test $color_tests = yes; then + # Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'. + red='[0;31m' # Red. + grn='[0;32m' # Green. + lgn='[1;32m' # Light green. + blu='[1;34m' # Blue. + mgn='[0;35m' # Magenta. + std='[m' # No color. +else + red= grn= lgn= blu= mgn= std= +fi + +do_exit='rm -f $log_file $trs_file; (exit $st); exit $st' +trap "st=129; $do_exit" 1 +trap "st=130; $do_exit" 2 +trap "st=141; $do_exit" 13 +trap "st=143; $do_exit" 15 + +# Test script is run here. We create the file first, then append to it, +# to ameliorate tests themselves also writing to the log file. Our tests +# don't, but others can (automake bug#35762). +: >"$log_file" +"$@" >>"$log_file" 2>&1 +estatus=$? + +if test $enable_hard_errors = no && test $estatus -eq 99; then + tweaked_estatus=1 +else + tweaked_estatus=$estatus +fi + +case $tweaked_estatus:$expect_failure in + 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; + 0:*) col=$grn res=PASS recheck=no gcopy=no;; + 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; + 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; + *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; + *:*) col=$red res=FAIL recheck=yes gcopy=yes;; +esac + +# Report the test outcome and exit status in the logs, so that one can +# know whether the test passed or failed simply by looking at the '.log' +# file, without the need of also peaking into the corresponding '.trs' +# file (automake bug#11814). +echo "$res $test_name (exit status: $estatus)" >>"$log_file" + +# Report outcome to console. +echo "${col}${res}${std}: $test_name" + +# Register the test result, and other relevant metadata. +echo ":test-result: $res" > $trs_file +echo ":global-test-result: $res" >> $trs_file +echo ":recheck: $recheck" >> $trs_file +echo ":copy-in-global-log: $gcopy" >> $trs_file + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/test/agent.py b/test/agent.py index 57a74183df25961fefacbfd45811a435f22665cb..450fb20a33aae213a1aae3533b964badb02e9d5f 100755 --- a/test/agent.py +++ b/test/agent.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later import sys diff --git a/test/example-adv-monitor b/test/example-adv-monitor deleted file mode 100644 index a405fc7b0e11fa69a333cd6e5ecec76f14cf6b4f..0000000000000000000000000000000000000000 --- a/test/example-adv-monitor +++ /dev/null @@ -1,403 +0,0 @@ -#!/usr/bin/python -# SPDX-License-Identifier: LGPL-2.1-or-later - -import argparse -import dbus -import dbus.mainloop.glib -import dbus.service -import json -import time - -from threading import Thread - -try: - from gi.repository import GObject # python3 -except ImportError: - import gobject as GObject # python2 - -DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager' -DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties' - -BLUEZ_SERVICE_NAME = 'org.bluez' - -ADV_MONITOR_MANAGER_IFACE = 'org.bluez.AdvertisementMonitorManager1' -ADV_MONITOR_IFACE = 'org.bluez.AdvertisementMonitor1' -ADV_MONITOR_APP_BASE_PATH = '/org/bluez/example/adv_monitor_app' - - -class AdvMonitor(dbus.service.Object): - - # Indexes of the Monitor object parameters in a monitor data list. - MONITOR_TYPE = 0 - RSSI_FILTER = 1 - PATTERNS = 2 - - # Indexes of the RSSI filter parameters in a monitor data list. - RSSI_H_THRESH = 0 - RSSI_H_TIMEOUT = 1 - RSSI_L_THRESH = 2 - RSSI_L_TIMEOUT = 3 - - # Indexes of the Patterns filter parameters in a monitor data list. - PATTERN_START_POS = 0 - PATTERN_AD_TYPE = 1 - PATTERN_DATA = 2 - - def __init__(self, bus, app_path, monitor_id, monitor_data): - self.path = app_path + '/monitor' + str(monitor_id) - self.bus = bus - - self._set_type(monitor_data[self.MONITOR_TYPE]) - self._set_rssi(monitor_data[self.RSSI_FILTER]) - self._set_patterns(monitor_data[self.PATTERNS]) - - super(AdvMonitor, self).__init__(self.bus, self.path) - - - def get_path(self): - return dbus.ObjectPath(self.path) - - - def get_properties(self): - properties = dict() - properties['Type'] = dbus.String(self.monitor_type) - properties['RSSIHighThreshold'] = dbus.Int16(self.rssi_h_thresh) - properties['RSSIHighTimeout'] = dbus.UInt16(self.rssi_h_timeout) - properties['RSSILowThreshold'] = dbus.Int16(self.rssi_l_thresh) - properties['RSSILowTimeout'] = dbus.UInt16(self.rssi_l_timeout) - properties['Patterns'] = dbus.Array(self.patterns, signature='(yyay)') - return {ADV_MONITOR_IFACE: properties} - - - def _set_type(self, monitor_type): - self.monitor_type = monitor_type - - - def _set_rssi(self, rssi): - self.rssi_h_thresh = rssi[self.RSSI_H_THRESH] - self.rssi_h_timeout = rssi[self.RSSI_H_TIMEOUT] - self.rssi_l_thresh = rssi[self.RSSI_L_THRESH] - self.rssi_l_timeout = rssi[self.RSSI_L_TIMEOUT] - - - def _set_patterns(self, patterns): - self.patterns = [] - for pattern in patterns: - start_pos = dbus.Byte(pattern[self.PATTERN_START_POS]) - ad_type = dbus.Byte(pattern[self.PATTERN_AD_TYPE]) - ad_data = [] - for byte in pattern[self.PATTERN_DATA]: - ad_data.append(dbus.Byte(byte)) - adv_pattern = dbus.Struct((start_pos, ad_type, ad_data), - signature='yyay') - self.patterns.append(adv_pattern) - - - def remove_monitor(self): - self.remove_from_connection() - - - @dbus.service.method(DBUS_PROP_IFACE, - in_signature='s', - out_signature='a{sv}') - def GetAll(self, interface): - print('{}: {} GetAll'.format(self.path, interface)) - if interface != ADV_MONITOR_IFACE: - print('{}: GetAll: Invalid arg {}'.format(self.path, interface)) - return {} - - return self.get_properties()[ADV_MONITOR_IFACE] - - - @dbus.service.method(ADV_MONITOR_IFACE, - in_signature='', - out_signature='') - def Activate(self): - print('{}: Monitor Activated'.format(self.path)) - - - @dbus.service.method(ADV_MONITOR_IFACE, - in_signature='', - out_signature='') - def Release(self): - print('{}: Monitor Released'.format(self.path)) - - - @dbus.service.method(ADV_MONITOR_IFACE, - in_signature='o', - out_signature='') - def DeviceFound(self, device): - print('{}: {} Device Found'.format(self.path, device)) - - - @dbus.service.method(ADV_MONITOR_IFACE, - in_signature='o', - out_signature='') - def DeviceLost(self, device): - print('{}: {} Device Lost'.format(self.path, device)) - - -class AdvMonitorApp(dbus.service.Object): - - def __init__(self, bus, advmon_manager, app_id): - self.bus = bus - self.advmon_mgr = advmon_manager - self.app_path = ADV_MONITOR_APP_BASE_PATH + str(app_id) - - self.monitors = dict() - - super(AdvMonitorApp, self).__init__(self.bus, self.app_path) - - - def get_app_path(self): - return dbus.ObjectPath(self.app_path) - - - def add_monitor(self, monitor_data): - monitor_id = 0 - while monitor_id in self.monitors: - monitor_id += 1 - - monitor = AdvMonitor(self.bus, self.app_path, monitor_id, monitor_data) - - # Emit the InterfacesAdded signal once the Monitor object is created. - self.InterfacesAdded(monitor.get_path(), monitor.get_properties()) - - self.monitors[monitor_id] = monitor - - return monitor_id - - - def remove_monitor(self, monitor_id): - monitor = self.monitors.pop(monitor_id, None) - if not monitor: - return False - - # Emit the InterfacesRemoved signal before removing the Monitor object. - self.InterfacesRemoved(monitor.get_path(), - monitor.get_properties().keys()) - - monitor.remove_monitor() - - return True - - - def register_app(self): - self.register_successful = None - - def register_cb(): - print('{}: RegisterMonitor successful'.format(self.app_path)) - self.register_successful = True - - def register_error_cb(error): - print('{}: RegisterMonitor failed: {}'.format(self.app_path, - str(error))) - self.register_successful = False - - self.advmon_mgr.RegisterMonitor(self.get_app_path(), - reply_handler=register_cb, - error_handler=register_error_cb) - - # Wait for the reply. - while self.register_successful is None: - pass - - return self.register_successful - - - def unregister_app(self): - self.unregister_successful = None - - def unregister_cb(): - print('{}: UnregisterMonitor successful'.format(self.app_path)) - self.unregister_successful = True - - def unregister_error_cb(error): - print('{}: UnregisterMonitor failed: {}'.format(self.app_path, - str(error))) - self.unregister_successful = False - - self.advmon_mgr.UnregisterMonitor(self.get_app_path(), - reply_handler=unregister_cb, - error_handler=unregister_error_cb) - - # Wait for the reply. - while self.unregister_successful is None: - pass - - return self.unregister_successful - - - @dbus.service.method(DBUS_OM_IFACE, out_signature='a{oa{sa{sv}}}') - def GetManagedObjects(self): - print('{}: GetManagedObjects'.format(self.app_path)) - objects = dict() - for monitor_id in self.monitors: - monitor = self.monitors[monitor_id] - objects[monitor.get_path()] = monitor.get_properties() - - return objects - - - @dbus.service.signal(DBUS_OM_IFACE, signature='oa{sa{sv}}') - def InterfacesAdded(self, object_path, interfaces_and_properties): - # Invoking this method emits the InterfacesAdded signal, - # nothing needs to be done here. - return - - - @dbus.service.signal(DBUS_OM_IFACE, signature='oas') - def InterfacesRemoved(self, object_path, interfaces): - # Invoking this method emits the InterfacesRemoved signal, - # nothing needs to be done here. - return - - -def read_adapter_supported_monitor_types(adapter_props): - types = json.dumps(adapter_props.Get(ADV_MONITOR_MANAGER_IFACE, - 'SupportedMonitorTypes', - dbus_interface=DBUS_PROP_IFACE)) - return json.loads(types) - - -def read_adapter_supported_monitor_features(adapter_props): - features = json.dumps(adapter_props.Get(ADV_MONITOR_MANAGER_IFACE, - 'SupportedFeatures', - dbus_interface=DBUS_PROP_IFACE)) - return json.loads(features) - - -def print_supported_types_and_features(adapter_props): - supported_types = read_adapter_supported_monitor_types(adapter_props) - for supported_type in supported_types: - print(supported_type) - - supported_features = read_adapter_supported_monitor_features(adapter_props) - for supported_feature in supported_features: - print(supported_feature) - - -def find_advmon_mgr(bus, adapter): - return dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, adapter), - ADV_MONITOR_MANAGER_IFACE) - - -def find_adapter(bus): - remote_om = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, '/'), - DBUS_OM_IFACE) - objects = remote_om.GetManagedObjects() - - adapter = None - adapter_props = None - - for o, props in objects.items(): - if ADV_MONITOR_MANAGER_IFACE in props: - adapter = o - break - - if adapter: - # Turn on the bluetooth adapter. - adapter_props = dbus.Interface( - bus.get_object(BLUEZ_SERVICE_NAME, adapter), - DBUS_PROP_IFACE) - adapter_props.Set('org.bluez.Adapter1', 'Powered', dbus.Boolean(1)) - - return adapter, adapter_props - - -def test(bus, mainloop, advmon_mgr, app_id): - # Create an App instance. - app = AdvMonitorApp(bus, advmon_mgr, app_id) - - # Create two monitor objects before registering the app. No Activate() or - # Release() should get called yet as the app is not registered. - data0 = [ - 'invalid_patterns', - [-50, 1, -70, 1], - [[0, 0x03, [0x12, 0x18]]] # Service Class UUID is 0x1812 (HOG) - ] - data1 = [ - 'or_patterns', - [127, 0, 127, 0], - [[5, 0x09, [ord('_')]]] # 5th character of the Local Name is '_' - ] - monitor0 = app.add_monitor(data0) - monitor1 = app.add_monitor(data1) - - # Register the app root path to expose advertisement monitors. - # Release() should get called on monitor0 - incorrect monitor type. - # Activate() should get called on monitor1. - ret = app.register_app() - if not ret: - print('RegisterMonitor failed.') - mainloop.quit() - exit(-1) - - # Create two more monitor objects. - # Release() should get called on monitor2 - incorrect RSSI Filter values. - # Activate() should get called on monitor3. - data2 = [ - 'or_patterns', - [-50, 1, -30, 1], - [[0, 0x19, [0xC2, 0x03]]] # Appearance is 0xC203 (Mouse) - ] - data3 = [ - 'or_patterns', - [-50, 1, -70, 1], - [[0, 0x03, [0x12, 0x18]], [0, 0x19, [0xC2, 0x03]]] - ] - monitor2 = app.add_monitor(data2) - monitor3 = app.add_monitor(data3) - - # Run until user hits the 'Enter' key. If any peer device is advertising - # during this time, DeviceFound() should get triggered for monitors - # matching the advertisements. - raw_input('Press "Enter" key to quit...\n') - - # Remove a monitor. DeviceFound() for this monitor should not get - # triggered any more. - app.remove_monitor(monitor1) - - # Unregister the app. Release() should get invoked on active monitors, - # monitor3 in this case. - app.unregister_app() - - mainloop.quit() - - -def main(app_id): - # Initialize threads in gobject/dbus-glib before creating local threads. - GObject.threads_init() - dbus.mainloop.glib.threads_init() - - # Arrange for the GLib main loop to be the default. - dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) - - bus = dbus.SystemBus() - mainloop = GObject.MainLoop() - - # Find bluetooth adapter and power it on. - adapter, adapter_props = find_adapter(bus) - if not adapter or not adapter_props: - print('Bluetooth adapter not found.') - exit(-1) - - # Read supported types and find AdvertisementMonitorManager1 interface. - print_supported_types_and_features(adapter_props) - advmon_mgr = find_advmon_mgr(bus, adapter) - if not advmon_mgr : - print('AdvertisementMonitorManager1 interface not found.') - exit(-1) - - Thread(target=test, args=(bus, mainloop, advmon_mgr, app_id)).start() - - mainloop.run() # blocks until mainloop.quit() is called - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--app_id', default=0, type=int, help='use this App-ID ' - 'for creating dbus objects (default: 0)') - args = parser.parse_args() - - main(args.app_id) diff --git a/test/example-advertisement b/test/example-advertisement index 5f022ee676970ff0aceb29c5854c8d604fc79703..9107012200b99a3d5fc21731b39684da163353e4 100755 --- a/test/example-advertisement +++ b/test/example-advertisement @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import print_function diff --git a/test/example-battery-provider b/test/example-battery-provider deleted file mode 100755 index 1522a5e075ca2f0441cf752c553a5d4b10d8f7f4..0000000000000000000000000000000000000000 --- a/test/example-battery-provider +++ /dev/null @@ -1,232 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: LGPL-2.1-or-later - -import dbus -import dbus.exceptions -import dbus.mainloop.glib -import dbus.service - -try: - from gi.repository import GObject -except ImportError: - import gobject as GObject -import sys - -mainloop = None -app = None -bus = None - -BLUEZ_SERVICE_NAME = 'org.bluez' -DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager' -DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties' - -BATTERY_PROVIDER_MANAGER_IFACE = 'org.bluez.BatteryProviderManager1' -BATTERY_PROVIDER_IFACE = 'org.bluez.BatteryProvider1' -BATTERY_PROVIDER_PATH = '/path/to/provider' - -BATTERY_PATH1 = '11_11_11_11_11_11' -BATTERY_PATH2 = '22_22_22_22_22_22' -BATTERY_PATH3 = '33_33_33_33_33_33' - -class InvalidArgsException(dbus.exceptions.DBusException): - _dbus_error_name = 'org.freedesktop.DBus.Error.InvalidArgs' - - -class Application(dbus.service.Object): - def __init__(self, bus): - self.path = BATTERY_PROVIDER_PATH - self.services = [] - self.batteries = [] - dbus.service.Object.__init__(self, bus, self.path) - - def get_path(self): - return dbus.ObjectPath(self.path) - - def add_battery(self, battery): - self.batteries.append(battery) - self.InterfacesAdded(battery.get_path(), battery.get_properties()) - GObject.timeout_add(1000, drain_battery, battery) - - def remove_battery(self, battery): - self.batteries.remove(battery) - self.InterfacesRemoved(battery.get_path(), [BATTERY_PROVIDER_IFACE]) - - @dbus.service.method(DBUS_OM_IFACE, out_signature='a{oa{sa{sv}}}') - def GetManagedObjects(self): - response = {} - print('GetManagedObjects called') - - for battery in self.batteries: - response[battery.get_path()] = battery.get_properties() - - return response - - @dbus.service.signal(DBUS_OM_IFACE, signature='oa{sa{sv}}') - def InterfacesAdded(self, object_path, interfaces_and_properties): - return - - @dbus.service.signal(DBUS_OM_IFACE, signature='oas') - def InterfacesRemoved(self, object_path, interfaces): - return - - -class Battery(dbus.service.Object): - """ - org.bluez.BatteryProvider1 interface implementation - """ - def __init__(self, bus, dev, percentage, source = None): - self.path = BATTERY_PROVIDER_PATH + '/dev_' + dev - self.dev_path = '/org/bluez/hci0/dev_' + dev - self.bus = bus - self.percentage = percentage - self.source = source - dbus.service.Object.__init__(self, bus, self.path) - - def get_battery_properties(self): - properties = {} - if self.percentage != None: - properties['Percentage'] = dbus.Byte(self.percentage) - if self.source != None: - properties['Source'] = self.source - properties['Device'] = dbus.ObjectPath(self.dev_path) - return properties - - def get_properties(self): - return { BATTERY_PROVIDER_IFACE: self.get_battery_properties() } - - def get_path(self): - return dbus.ObjectPath(self.path) - - def set_percentage(self, percentage): - if percentage < 0 or percentage > 100: - print('percentage not valid') - return - - self.percentage = percentage - print('battery %s percentage %d' % (self.path, self.percentage)) - self.PropertiesChanged( - BATTERY_PROVIDER_IFACE, self.get_battery_properties()) - - @dbus.service.method(DBUS_PROP_IFACE, - in_signature='s', - out_signature='a{sv}') - def GetAll(self, interface): - if interface != BATTERY_PROVIDER_IFACE: - raise InvalidArgsException() - - return self.get_properties()[BATTERY_PROVIDER_IFACE] - - @dbus.service.signal(DBUS_PROP_IFACE, signature='sa{sv}') - def PropertiesChanged(self, interface, properties): - return - - -def add_late_battery(): - app.add_battery(Battery(bus, BATTERY_PATH3, 70, 'Protocol 2')) - - -def drain_battery(battery): - new_percentage = 100 - if battery.percentage != None: - new_percentage = battery.percentage - 5 - if new_percentage < 0: - new_percentage = 0 - - battery.set_percentage(new_percentage) - - if new_percentage <= 0: - return False - - return True - -def register_provider_cb(): - print('Battery Provider registered') - - # Battery added early right after RegisterBatteryProvider succeeds - app.add_battery(Battery(bus, BATTERY_PATH2, None)) - # Battery added later - GObject.timeout_add(5000, add_late_battery) - - -def register_provider_error_cb(error): - print('Failed to register Battery Provider: ' + str(error)) - mainloop.quit() - - -def find_manager(bus): - remote_om = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, '/'), - DBUS_OM_IFACE) - objects = remote_om.GetManagedObjects() - - for o, props in objects.items(): - if BATTERY_PROVIDER_MANAGER_IFACE in props.keys(): - return o - - return None - - -def unregister_provider_cb(): - print('Battery Provider unregistered') - - -def unregister_provider_error_cb(error): - print('Failed to unregister Battery Provider: ' + str(error)) - - -def unregister_battery_provider(battery_provider_manager): - battery_provider_manager.UnregisterBatteryProvider(BATTERY_PROVIDER_PATH, - reply_handler=unregister_provider_cb, - error_handler=unregister_provider_error_cb) - - -def remove_battery(app, battery): - app.remove_battery(battery) - - -""" -Simulates an application registering to BlueZ as a Battery Provider providing -fake batteries drained periodically. -""" -def main(): - global mainloop, bus, app - - dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) - - bus = dbus.SystemBus() - - manager_path = find_manager(bus) - if not manager_path: - print('BatteryProviderManager1 interface not found') - return - - print('BatteryProviderManager1 path = ', manager_path) - - battery_provider_manager = dbus.Interface( - bus.get_object(BLUEZ_SERVICE_NAME, manager_path), - BATTERY_PROVIDER_MANAGER_IFACE) - - app = Application(bus) - - # Battery pre-added before RegisterBatteryProvider - battery1 = Battery(bus, BATTERY_PATH1, 87, 'Protocol 1') - app.add_battery(battery1) - - mainloop = GObject.MainLoop() - - print('Registering Battery Provider...') - - battery_provider_manager.RegisterBatteryProvider(BATTERY_PROVIDER_PATH, - reply_handler=register_provider_cb, - error_handler=register_provider_error_cb) - - # Unregister the Battery Provider after an arbitrary amount of time - GObject.timeout_add( - 12000, unregister_battery_provider, battery_provider_manager) - # Simulate battery removal by a provider - GObject.timeout_add(8000, remove_battery, app, battery1) - - mainloop.run() - - -if __name__ == '__main__': - main() diff --git a/test/example-endpoint b/test/example-endpoint deleted file mode 100644 index 16651c683a7ff2efba360aff1bdd15dade85419d..0000000000000000000000000000000000000000 --- a/test/example-endpoint +++ /dev/null @@ -1,187 +0,0 @@ -#!/usr/bin/python -# SPDX-License-Identifier: LGPL-2.1-or-later - -from __future__ import absolute_import, print_function, unicode_literals - -import sys -import dbus -import dbus.exceptions -import dbus.service -import dbus.mainloop.glib - -import array -try: - from gi.repository import GObject -except ImportError: - import gobject as GObject -import bluezutils - -ENDPOINT_IFACE = 'org.bluez.MediaEndpoint1' -DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager' -DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties' - -A2DP_SOURCE_UUID = '0000110A-0000-1000-8000-00805F9B34FB' -A2DP_SINK_UUID = '0000110B-0000-1000-8000-00805F9B34FB' - -SBC_CODEC = dbus.Byte(0x00) -#Channel Modes: Mono DualChannel Stereo JointStereo -#Frequencies: 16Khz 32Khz 44.1Khz 48Khz -#Subbands: 4 8 -#Blocks: 4 8 12 16 -#Bitpool Range: 2-64 -SBC_CAPABILITIES = dbus.Array([dbus.Byte(0xff), dbus.Byte(0xff), dbus.Byte(2), dbus.Byte(64)]) -# JointStereo 44.1Khz Subbands: Blocks: 16 Bitpool Range: 2-32 -SBC_CONFIGURATION = dbus.Array([dbus.Byte(0x21), dbus.Byte(0x15), dbus.Byte(2), dbus.Byte(32)]) - -MP3_CODEC = dbus.Byte(0x01) -#Channel Modes: Mono DualChannel Stereo JointStereo -#Frequencies: 32Khz 44.1Khz 48Khz -#CRC: YES -#Layer: 3 -#Bit Rate: All except Free format -#VBR: Yes -#Payload Format: RFC-2250 -MP3_CAPABILITIES = dbus.Array([dbus.Byte(0x3f), dbus.Byte(0x07), dbus.Byte(0xff), dbus.Byte(0xfe)]) -# JointStereo 44.1Khz Layer: 3 Bit Rate: VBR Format: RFC-2250 -MP3_CONFIGURATION = dbus.Array([dbus.Byte(0x21), dbus.Byte(0x02), dbus.Byte(0x00), dbus.Byte(0x80)]) - -PCM_CODEC = dbus.Byte(0x00) -PCM_CONFIGURATION = dbus.Array([], signature="ay") - -CVSD_CODEC = dbus.Byte(0x01) - -class Rejected(dbus.DBusException): - _dbus_error_name = "org.bluez.Error.Rejected" - -class InvalidArgsException(dbus.exceptions.DBusException): - _dbus_error_name = 'org.freedesktop.DBus.Error.InvalidArgs' - -class Endpoint(dbus.service.Object): - def __init__(self, bus, path, properties, configuration): - self.path = path - self.bus = bus - self.properties = properties - self.configuration = configuration - self.exit_on_release = True - dbus.service.Object.__init__(self, bus, self.path) - - def get_properties(self): - return self.properties - - def get_path(self): - return dbus.ObjectPath(self.path) - - @dbus.service.method(DBUS_PROP_IFACE, in_signature='s', - out_signature='a{sv}') - def GetAll(self, interface): - if interface != ENDPOINT_IFACE: - raise InvalidArgsException() - - return self.get_properties() - - def set_exit_on_release(self, exit_on_release): - self.exit_on_release = exit_on_release - - def default_configuration(self, configuration): - self.configuration = configuration - - @dbus.service.method(ENDPOINT_IFACE, in_signature="", out_signature="") - def Release(self): - print("Release") - if self.exit_on_release: - mainloop.quit() - - @dbus.service.method(ENDPOINT_IFACE, in_signature="o", out_signature="") - def ClearConfiguration(self, transport): - print("ClearConfiguration (%s)" % (transport)) - - @dbus.service.method(ENDPOINT_IFACE, in_signature="oay", out_signature="") - def SetConfiguration(self, transport, config): - print("SetConfiguration (%s, %s)" % (transport, config)) - return - - @dbus.service.method(ENDPOINT_IFACE, in_signature="ay", out_signature="ay") - def SelectConfiguration(self, caps): - print("SelectConfiguration (%s)" % (caps)) - return self.configuration - -class Application(dbus.service.Object): - def __init__(self, bus, path, properties, configuration): - self.path = '/' - self.endpoints = [] - dbus.service.Object.__init__(self, bus, self.path) - self.add_endpoint(Endpoint(bus, path, properties, configuration)) - - def get_path(self): - return dbus.ObjectPath(self.path) - - def add_endpoint(self, endpoint): - self.endpoints.append(endpoint) - - @dbus.service.method(DBUS_OM_IFACE, out_signature='a{oa{sa{sv}}}') - def GetManagedObjects(self): - response = {} - print('GetManagedObjects') - - for endpoint in self.endpoints: - response[endpoint.get_path()] = { ENDPOINT_IFACE: - endpoint.get_properties() } - - return response - -def register_app_cb(): - print('Media application registered') - - -def register_app_error_cb(error): - print('Failed to register application: ' + str(error)) - mainloop.quit() - -if __name__ == '__main__': - dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) - - bus = dbus.SystemBus() - - if len(sys.argv) > 1: - path = bluezutils.find_adapter(sys.argv[1]).object_path - else: - path = bluezutils.find_adapter().object_path - - media = dbus.Interface(bus.get_object("org.bluez", path), - "org.bluez.Media1") - - - properties = dbus.Dictionary({ "UUID" : A2DP_SOURCE_UUID, - "Codec" : SBC_CODEC, - "DelayReporting" : True, - "Capabilities" : SBC_CAPABILITIES }) - - configuration = SBC_CONFIGURATION - - if len(sys.argv) > 2: - if sys.argv[2] == "sbcsink": - properties = dbus.Dictionary({ "UUID" : A2DP_SINK_UUID, - "Codec" : SBC_CODEC, - "DelayReporting" : True, - "Capabilities" : SBC_CAPABILITIES }) - if sys.argv[2] == "mp3source": - properties = dbus.Dictionary({ "UUID" : A2DP_SOURCE_UUID, - "Codec" : MP3_CODEC, - "Capabilities" : MP3_CAPABILITIES }) - configuration = MP3_CONFIGURATION - if sys.argv[2] == "mp3sink": - properties = dbus.Dictionary({ "UUID" : A2DP_SINK_UUID, - "Codec" : MP3_CODEC, - "Capabilities" : MP3_CAPABILITIES }) - configuration = MP3_CONFIGURATION - - print(properties) - - path = "/test/endpoint" - app = Application(bus, path, properties, configuration) - mainloop = GObject.MainLoop() - - media.RegisterApplication(app.get_path(), {}, - reply_handler=register_app_cb, - error_handler=register_app_error_cb) - mainloop.run() diff --git a/test/example-gatt-client b/test/example-gatt-client index 5e6bef9d7b92b3b9c1e38d37b2421b1373afd29b..38ca97eae58080f5dec99afaeca23e9c663be2a7 100755 --- a/test/example-gatt-client +++ b/test/example-gatt-client @@ -2,10 +2,7 @@ # SPDX-License-Identifier: LGPL-2.1-or-later import dbus -try: - from gi.repository import GObject -except ImportError: - import gobject as GObject +from gi.repository import GLib import sys from dbus.mainloop.glib import DBusGMainLoop @@ -189,7 +186,7 @@ def main(): global bus bus = dbus.SystemBus() global mainloop - mainloop = GObject.MainLoop() + mainloop = GLib.MainLoop() om = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, '/'), DBUS_OM_IFACE) om.connect_to_signal('InterfacesRemoved', interfaces_removed_cb) diff --git a/test/example-gatt-server b/test/example-gatt-server index 77231c3ad102a25b41517f9b417c371b7ba034b0..83b700901b9f18b44d314185985cca8b74cd9aa7 100755 --- a/test/example-gatt-server +++ b/test/example-gatt-server @@ -7,10 +7,7 @@ import dbus.mainloop.glib import dbus.service import array -try: - from gi.repository import GObject -except ImportError: - import gobject as GObject +from gi.repository import GLib import sys from random import randint @@ -305,7 +302,7 @@ class HeartRateMeasurementChrc(Characteristic): if not self.notifying: return - GObject.timeout_add(1000, self.hr_msrmt_cb) + GLib.timeout_add(1000, self.hr_msrmt_cb) def StartNotify(self): if self.notifying: @@ -392,7 +389,7 @@ class BatteryLevelCharacteristic(Characteristic): service) self.notifying = False self.battery_lvl = 100 - GObject.timeout_add(5000, self.drain_battery) + GLib.timeout_add(5000, self.drain_battery) def notify_battery_level(self): if not self.notifying: @@ -649,7 +646,7 @@ def main(): app = Application(bus) - mainloop = GObject.MainLoop() + mainloop = GLib.MainLoop() print('Registering GATT application...') diff --git a/test/example-player b/test/example-player deleted file mode 100644 index 1497d1107a168148352f3008fc09a110d6ba0c0b..0000000000000000000000000000000000000000 --- a/test/example-player +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/python -# SPDX-License-Identifier: LGPL-2.1-or-later - -from __future__ import print_function - -import os -import sys -import dbus -import dbus.service -import dbus.mainloop.glib -try: - from gi.repository import GObject -except ImportError: - import gobject as GObject -import bluezutils - -PLAYER_IFACE = 'org.mpris.MediaPlayer2.Player' -DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager' -DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties' - -class InvalidArgsException(dbus.exceptions.DBusException): - _dbus_error_name = 'org.freedesktop.DBus.Error.InvalidArgs' - -class Player(dbus.service.Object): - def __init__(self, bus, path, obj): - self.path = path - dbus.service.Object.__init__(self, bus, self.path) - - if obj != None: - mp = dbus.Interface(bus.get_object("org.bluez", obj), - "org.bluez.MediaPlayer1") - prop = dbus.Interface(bus.get_object("org.bluez", obj), - "org.freedesktop.DBus.Properties") - - self.properties = prop.GetAll("org.bluez.MediaPlayer1") - - bus.add_signal_receiver(self.properties_changed, path = obj, - dbus_interface = "org.freedesktop.DBus.Properties", - signal_name = "PropertiesChanged") - else: - self.track = dbus.Dictionary({"xesam:title" : "Title", - "xesam:artist" : ["Artist"], - "xesam:album" : "Album", - "xesam:genre" : ["Genre"], - "xesam:trackNumber" : dbus.Int32(1), - "mpris:length" : dbus.Int64(10000) }, - signature="sv") - - self.properties = dbus.Dictionary({"PlaybackStatus" : "playing", - "Identity" : "SimplePlayer", - "LoopStatus" : "None", - "Rate" : dbus.Double(1.0), - "Shuffle" : dbus.Boolean(False), - "Metadata" : self.track, - "Volume" : dbus.Double(1.0), - "Position" : dbus.Int64(0), - "MinimumRate" : dbus.Double(1.0), - "MaximumRate" : dbus.Double(1.0), - "CanGoNext" : dbus.Boolean(False), - "CanGoPrevious" : dbus.Boolean(False), - "CanPlay" : dbus.Boolean(False), - "CanSeek" : dbus.Boolean(False), - "CanControl" : dbus.Boolean(False), - }, - signature="sv") - - print('Register media player with:\n\tProperties: %s' \ - % (self.properties)) - handler = InputHandler(self) - GObject.io_add_watch(sys.stdin, GObject.IO_IN, handler.handle) - - @dbus.service.method("org.freedesktop.DBus.Properties", - in_signature="ssv", out_signature="") - def Set(self, interface, key, value): - print("Set (%s, %s)" % (key, value), file=sys.stderr) - return - - def get_properties(self): - return self.properties - - def get_path(self): - return dbus.ObjectPath(self.path) - - @dbus.service.method("org.freedesktop.DBus.Properties", - in_signature='s', out_signature='a{sv}') - def GetAll(self, interface): - if interface != PLAYER_IFACE: - raise InvalidArgsException() - - return self.get_properties() - - @dbus.service.signal("org.freedesktop.DBus.Properties", - signature="sa{sv}as") - def PropertiesChanged(self, interface, properties, - invalidated = dbus.Array()): - """PropertiesChanged(interface, properties, invalidated) - - Send a PropertiesChanged signal. 'properties' is a dictionary - containing string parameters as specified in doc/media-api.txt. - """ - pass - - def help(self, func): - help(self.__class__.__dict__[func]) - - def properties_changed(self, interface, properties, invalidated): - print("properties_changed(%s, %s)" % (properties, invalidated)) - - self.PropertiesChanged(interface, properties, invalidated) - -class InputHandler: - commands = { 'PropertiesChanged': '(interface, properties)', - 'help': '(cmd)' } - def __init__(self, player): - self.player = player - print('\n\nAvailable commands:') - for cmd in self.commands: - print('\t', cmd, self.commands[cmd], sep='') - - print("\nUse python syntax to pass arguments to available methods.\n" \ - "E.g.: PropertiesChanged({'Metadata' : {'Title': 'My title', \ - 'Album': 'my album' }})") - self.prompt() - - def prompt(self): - print('\n>>> ', end='') - sys.stdout.flush() - - def handle(self, fd, condition): - s = os.read(fd.fileno(), 1024).strip() - try: - cmd = s[:s.find('(')] - if not cmd in self.commands: - print("Unknown command ", cmd) - except ValueError: - print("Malformed command") - return True - try: - exec "self.player.%s" % s - except Exception as e: - print(e) - pass - self.prompt() - return True - -class Application(dbus.service.Object): - def __init__(self, bus, path, obj): - self.path = '/' - self.players = [] - dbus.service.Object.__init__(self, bus, self.path) - self.add_player(Player(bus, path, obj)) - - def get_path(self): - return dbus.ObjectPath(self.path) - - def add_player(self, player): - self.players.append(player) - - @dbus.service.method(DBUS_OM_IFACE, out_signature='a{oa{sa{sv}}}') - def GetManagedObjects(self): - response = {} - print('GetManagedObjects') - - for player in self.players: - response[player.get_path()] = { PLAYER_IFACE: - player.get_properties() } - - return response - -def register_app_cb(): - print('Media application registered') - - -def register_app_error_cb(error): - print('Failed to register application: ' + str(error)) - mainloop.quit() - -if __name__ == '__main__': - dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) - - bus = dbus.SystemBus() - - if len(sys.argv) > 1: - path = bluezutils.find_adapter(sys.argv[1]).object_path - else: - path = bluezutils.find_adapter().object_path - - media = dbus.Interface(bus.get_object("org.bluez", path), - "org.bluez.Media1") - - path = "/test/player" - - if len(sys.argv) > 2: - app = Application(bus, path, sys.argv[2]) - else: - app = Application(bus, path, None) - - mainloop = GObject.MainLoop() - - media.RegisterApplication(app.get_path(), {}, - reply_handler=register_app_cb, - error_handler=register_app_error_cb) - - mainloop.run() diff --git a/test/exchange-business-cards b/test/exchange-business-cards deleted file mode 100755 index 9a3aa29fb47626a515362d42b20c414206374316..0000000000000000000000000000000000000000 --- a/test/exchange-business-cards +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/python -# SPDX-License-Identifier: LGPL-2.1-or-later - -import sys -import dbus - -bus = dbus.SessionBus() -client = dbus.Interface(bus.get_object("org.bluez.obex", "/org/bluez/obex"), - "org.bluez.obex.Client") - -if (len(sys.argv) < 4): - print "Usage: %s <device> <clientfile> <file>" % (sys.argv[0]) - sys.exit(1) - -print "Creating Session" -path = client.CreateSession(sys.argv[1], { "Target": "OPP" }) -opp = dbus.Interface(bus.get_object("org.bluez.obex", path), - "org.bluez.obex.ObjectPush") - -opp.ExchangeBusinessCards(sys.argv[2], sys.argv[3]) diff --git a/test/ftp-client b/test/ftp-client index ef756ab2b30d92732a92eb28428c02b74caafb63..e37c027f4ac8418b5cb1d76b138b9bffe5f8a484 100755 --- a/test/ftp-client +++ b/test/ftp-client @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/get-managed-objects b/test/get-managed-objects deleted file mode 100755 index 5125ee5247d887c7b30a746151af53eec13d7b95..0000000000000000000000000000000000000000 --- a/test/get-managed-objects +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/python -# SPDX-License-Identifier: LGPL-2.1-or-later - -from __future__ import absolute_import, print_function, unicode_literals - -import dbus - -bus = dbus.SystemBus() - -manager = dbus.Interface(bus.get_object("org.bluez", "/"), - "org.freedesktop.DBus.ObjectManager") - -objects = manager.GetManagedObjects() - -for path in objects.keys(): - print("[ %s ]" % (path)) - - interfaces = objects[path] - - for interface in interfaces.keys(): - if interface in ["org.freedesktop.DBus.Introspectable", - "org.freedesktop.DBus.Properties"]: - continue - - print(" %s" % (interface)) - - properties = interfaces[interface] - - for key in properties.keys(): - print(" %s = %s" % (key, properties[key])) diff --git a/test/get-obex-capabilities b/test/get-obex-capabilities deleted file mode 100755 index a7980a44259569d42010fc866151dc3402cb47e5..0000000000000000000000000000000000000000 --- a/test/get-obex-capabilities +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/python -# SPDX-License-Identifier: LGPL-2.1-or-later - -import sys -import dbus - -bus = dbus.SessionBus() -client = dbus.Interface(bus.get_object("org.bluez.obex", "/org/bluez/obex"), - "org.bluez.obex.Client") - -if (len(sys.argv) < 3): - print "Usage: %s <device> <target>" % (sys.argv[0]) - sys.exit(1) - -print "Creating Session" -session_path = client.CreateSession(sys.argv[1], { "Target": sys.argv[2] }) -session = dbus.Interface(bus.get_object("org.bluez.obex", session_path), - "org.bluez.obex.Session") - -print session.GetCapabilities() diff --git a/test/list-devices b/test/list-devices index 618d2867b08a446365551016885be7a7ce601530..a24c31c7d271a81ae903d47a53a5dee28d41dd13 100755 --- a/test/list-devices +++ b/test/list-devices @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/list-folders b/test/list-folders deleted file mode 100755 index b4e3f100b09626da7fa57bbb1d59ad6e346ce363..0000000000000000000000000000000000000000 --- a/test/list-folders +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/python -# SPDX-License-Identifier: LGPL-2.1-or-later - -import sys -import dbus - - -def list_folder(folder): - bus = dbus.SessionBus() - client = dbus.Interface(bus.get_object("org.bluez.obex", - "/org/bluez/obex"), - "org.bluez.obex.Client") - - path = client.CreateSession(sys.argv[1], { "Target": "ftp" }) - - ftp = dbus.Interface(bus.get_object("org.bluez.obex", path), - "org.bluez.obex.FileTransfer") - - if folder: - for node in folder.split("/"): - ftp.ChangeFolder(node) - - for i in ftp.ListFolder(): - if i["Type"] == "folder": - print "%s/" % (i["Name"]) - else: - print "%s" % (i["Name"]) - - -if __name__ == '__main__': - - if len(sys.argv) < 2: - print "Usage: %s <device> [folder]" % (sys.argv[0]) - sys.exit(1) - - folder = None - if len(sys.argv) == 3: - folder = sys.argv[2] - - list_folder(folder) diff --git a/test/map-client b/test/map-client index f44f512bdef896d4f88d9e5fe5a5fc2ef711bda1..b7369b0681c85e3267241012c6369eb854e3e23f 100755 --- a/test/map-client +++ b/test/map-client @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/monitor-bluetooth b/test/monitor-bluetooth index 99f3c857c4f0c32779c6b69fc8f8714f8ee86d67..347c91ac3c81df6e35fe912f118544e2ab61498c 100755 --- a/test/monitor-bluetooth +++ b/test/monitor-bluetooth @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/opp-client b/test/opp-client index 4f00a41c0129ea3f1448440ef1b1bf0df6be2cc6..deb02c77cd76d6ceeb2d3027f686d4daf326bb36 100755 --- a/test/opp-client +++ b/test/opp-client @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/pbap-client b/test/pbap-client index e6cafdd30142215ef616ad3fdefb504fe3032930..6dada4a118f7baa422aa6d22eb3158c685291344 100755 --- a/test/pbap-client +++ b/test/pbap-client @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/sap_client.py b/test/sap_client.py index fed13aedc840169159f6fbab1864df615ba200b4..2da46eee36bc6a4003f42d975e0e764f20c61e65 100644 --- a/test/sap_client.py +++ b/test/sap_client.py @@ -165,7 +165,7 @@ class SAPParam_ConnectionStatus(SAPParam): def __validate(self): if self.value is not None and self.value not in (0x00, 0x01, 0x02, 0x03, 0x04): - print "Warning. ConnectionStatus value in reserved range (0x%x)" % self.value + print("Warning. ConnectionStatus value in reserved range (0x%x)" % self.value) def deserialize(self, buf): ret = SAPParam.deserialize(self, buf) @@ -183,7 +183,7 @@ class SAPParam_ResultCode(SAPParam): def __validate(self): if self.value is not None and self.value not in (0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07): - print "Warning. ResultCode value in reserved range (0x%x)" % self.value + print("Warning. ResultCode value in reserved range (0x%x)" % self.value) def deserialize(self, buf): ret = SAPParam.deserialize(self, buf) @@ -201,7 +201,7 @@ class SAPParam_DisconnectionType(SAPParam): def __validate(self): if self.value is not None and self.value not in (0x00, 0x01): - print "Warning. DisconnectionType value in reserved range (0x%x)" % self.value + print("Warning. DisconnectionType value in reserved range (0x%x)" % self.value) def deserialize(self, buf): ret = SAPParam.deserialize(self, buf) @@ -227,7 +227,7 @@ class SAPParam_StatusChange(SAPParam): def __validate(self): if self.value is not None and self.value not in (0x00, 0x01, 0x02, 0x03, 0x04, 0x05): - print "Warning. StatusChange value in reserved range (0x%x)" % self.value + print("Warning. StatusChange value in reserved range (0x%x)" % self.value) def deserialize(self, buf): ret = SAPParam.deserialize(self, buf) @@ -245,7 +245,7 @@ class SAPParam_TransportProtocol(SAPParam): def __validate(self): if self.value is not None and self.value not in (0x00, 0x01): - print "Warning. TransportProtoco value in reserved range (0x%x)" % self.value + print("Warning. TransportProtoco value in reserved range (0x%x)" % self.value) def deserialize(self, buf): ret = SAPParam.deserialize(self, buf) @@ -728,7 +728,7 @@ class SAPClient: self.port = first_match["port"] self.host = first_match["host"] - print "SAP Service found on %s(%s)" % first_match["name"] % self.host + print("SAP Service found on %s(%s)" % first_match["name"] % self.host) def __connectRFCOMM(self): self.sock=BluetoothSocket( RFCOMM ) @@ -739,19 +739,19 @@ class SAPClient: def __sendMsg(self, msg): if isinstance(msg, SAPMessage): s = msg.serialize() - print "\tTX: " + msg.getContent() + print("\tTX: " + msg.getContent()) return self.sock.send(s.tostring()) def __rcvMsg(self, msg): if isinstance(msg, SAPMessage): - print "\tRX Wait: %s(id = 0x%.2x)" % (msg.name, msg.id) + print("\tRX Wait: %s(id = 0x%.2x)" % (msg.name, msg.id)) data = self.sock.recv(self.bufsize) if data: if msg.deserialize(array('B',data)): - print "\tRX: len(%d) %s" % (len(data), msg.getContent()) + print("\tRX: len(%d) %s" % (len(data), msg.getContent())) return msg else: - print "msg: %s" % array('B',data) + print("msg: %s" % array('B',data)) raise BluetoothError ("Message deserialization failed.") else: raise BluetoothError ("Timeout. No data received.") @@ -797,8 +797,8 @@ class SAPClient: return False else: return False - except BluetoothError , e: - print "Error. " +str(e) + except BluetoothError as e: + print("Error. " +str(e)) return False def proc_disconnectByClient(self, timeout=0): @@ -808,8 +808,8 @@ class SAPClient: time.sleep(timeout) # let srv to close rfcomm self.__disconnectRFCOMM() return True - except BluetoothError , e: - print "Error. " +str(e) + except BluetoothError as e: + print("Error. " +str(e)) return False def proc_disconnectByServer(self, timeout=0): @@ -823,8 +823,8 @@ class SAPClient: return self.proc_disconnectByClient(timeout) - except BluetoothError , e: - print "Error. " +str(e) + except BluetoothError as e: + print("Error. " +str(e)) return False def proc_transferAPDU(self, apdu = "Sample APDU command"): @@ -832,8 +832,8 @@ class SAPClient: self.__sendMsg(SAPMessage_TRANSFER_APDU_REQ(apdu)) params = self.__rcvMsg(SAPMessage_TRANSFER_APDU_RESP()).getParams() return True - except BluetoothError , e: - print "Error. " +str(e) + except BluetoothError as e: + print("Error. " +str(e)) return False def proc_transferATR(self): @@ -841,8 +841,8 @@ class SAPClient: self.__sendMsg(SAPMessage_TRANSFER_ATR_REQ()) params = self.__rcvMsg(SAPMessage_TRANSFER_ATR_RESP()).getParams() return True - except BluetoothError , e: - print "Error. " +str(e) + except BluetoothError as e: + print("Error. " +str(e)) return False def proc_powerSimOff(self): @@ -850,8 +850,8 @@ class SAPClient: self.__sendMsg(SAPMessage_POWER_SIM_OFF_REQ()) params = self.__rcvMsg(SAPMessage_POWER_SIM_OFF_RESP()).getParams() return True - except BluetoothError , e: - print "Error. " +str(e) + except BluetoothError as e: + print("Error. " +str(e)) return False def proc_powerSimOn(self): @@ -862,8 +862,8 @@ class SAPClient: return self.proc_transferATR() return True - except BluetoothError , e: - print "Error. " +str(e) + except BluetoothError as e: + print("Error. " +str(e)) return False def proc_resetSim(self): @@ -874,23 +874,23 @@ class SAPClient: return self.proc_transferATR() return True - except BluetoothError , e: - print "Error. " +str(e) + except BluetoothError as e: + print("Error. " +str(e)) return False def proc_reportStatus(self): try: params = self.__rcvMsg(SAPMessage_STATUS_IND()).getParams() - except BluetoothError , e: - print "Error. " +str(e) + except BluetoothError as e: + print("Error. " +str(e)) return False def proc_transferCardReaderStatus(self): try: self.__sendMsg(SAPMessage_TRANSFER_CARD_READER_STATUS_REQ()) params = self.__rcvMsg(SAPMessage_TRANSFER_CARD_READER_STATUS_RESP()).getParams() - except BluetoothError , e: - print "Error. " +str(e) + except BluetoothError as e: + print("Error. " +str(e)) return False def proc_errorResponse(self): @@ -899,8 +899,8 @@ class SAPClient: self.__sendMsg(SAPMessage_CONNECT_REQ()) params = self.__rcvMsg(SAPMessage_ERROR_RESP()).getParams() - except BluetoothError , e: - print "Error. " +str(e) + except BluetoothError as e: + print("Error. " +str(e)) return False def proc_setTransportProtocol(self, protocol = 0): @@ -922,8 +922,8 @@ class SAPClient: else: return False - except BluetoothError , e: - print "Error. " +str(e) + except BluetoothError as e: + print("Error. " +str(e)) return False if __name__ == "__main__": diff --git a/test/simple-agent b/test/simple-agent index 4fdaff1eb765a4966ba50d30c269733e4406218c..09437eb22bd5eed29ff6b206f4e4a8aab45fe179 100755 --- a/test/simple-agent +++ b/test/simple-agent @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/simple-endpoint b/test/simple-endpoint index 463f124d1b6e458db24a6d93fa4985ee50b31df7..eace4286d0ef392a0011a4ab1f6c0775ffe78e68 100755 --- a/test/simple-endpoint +++ b/test/simple-endpoint @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/simple-obex-agent b/test/simple-obex-agent deleted file mode 100755 index 064f6d30b9ebb2845091aec9ccbeadc2219808c7..0000000000000000000000000000000000000000 --- a/test/simple-obex-agent +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/python -# SPDX-License-Identifier: LGPL-2.1-or-later - -from __future__ import absolute_import, print_function, unicode_literals - -import sys -import dbus -import dbus.service -import dbus.mainloop.glib -try: - from gi.repository import GObject -except ImportError: - import gobject as GObject - -BUS_NAME = 'org.bluez.obex' -PATH = '/org/bluez/obex' -AGENT_MANAGER_INTERFACE = 'org.bluez.obex.AgentManager1' -AGENT_INTERFACE = 'org.bluez.obex.Agent1' -TRANSFER_INTERFACE = 'org.bluez.obex.Transfer1' - -def ask(prompt): - try: - return raw_input(prompt) - except: - return input(prompt) - -class Agent(dbus.service.Object): - def __init__(self, conn=None, obj_path=None): - dbus.service.Object.__init__(self, conn, obj_path) - self.pending_auth = False - - @dbus.service.method(AGENT_INTERFACE, in_signature="o", - out_signature="s") - def AuthorizePush(self, path): - transfer = dbus.Interface(bus.get_object(BUS_NAME, path), - 'org.freedesktop.DBus.Properties') - properties = transfer.GetAll(TRANSFER_INTERFACE); - - self.pending_auth = True - auth = ask("Authorize (%s, %s) (Y/n):" % (path, - properties['Name'])) - - if auth == "n" or auth == "N": - self.pending_auth = False - raise dbus.DBusException( - "org.bluez.obex.Error.Rejected: " - "Not Authorized") - - self.pending_auth = False - - return properties['Name'] - - @dbus.service.method(AGENT_INTERFACE, in_signature="", - out_signature="") - def Cancel(self): - print("Authorization Canceled") - self.pending_auth = False - -if __name__ == '__main__': - dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) - - bus = dbus.SessionBus() - manager = dbus.Interface(bus.get_object(BUS_NAME, PATH), - AGENT_MANAGER_INTERFACE) - - path = "/test/agent" - agent = Agent(bus, path) - - mainloop = GObject.MainLoop() - - manager.RegisterAgent(path) - print("Agent registered") - - cont = True - while cont: - try: - mainloop.run() - except KeyboardInterrupt: - if agent.pending_auth: - agent.Cancel() - elif len(transfers) > 0: - for a in transfers: - a.cancel() - else: - cont = False - - # manager.UnregisterAgent(path) - # print "Agent unregistered" diff --git a/test/simple-player b/test/simple-player index 92682844d0f4ef5cefef5f5f36be8b8a71d18d46..8a1cb1e33a4e2b0f0d899ce43115667c92a1b943 100755 --- a/test/simple-player +++ b/test/simple-player @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later -from __future__ import print_function + import os import sys @@ -78,7 +78,7 @@ class Player(dbus.service.Object): """PropertiesChanged(interface, properties, invalidated) Send a PropertiesChanged signal. 'properties' is a dictionary - containing string parameters as specified in doc/media-api.txt. + containing string parameters as specified in doc/media-api.rst. """ pass @@ -119,7 +119,7 @@ class InputHandler: return True try: - exec "self.player.%s" % s + exec("self.player.%s" % s) except Exception as e: print(e) pass diff --git a/test/test-adapter b/test/test-adapter index c56ba95779e679adbe2d13541c5567d5a8125d7b..27aff27b52a4dfe05965fc7d8ec7cbc9efc1ef5a 100755 --- a/test/test-adapter +++ b/test/test-adapter @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/test-device b/test/test-device index c840f0565231db84c44c6cd5ec385e2e52a5509e..8b1eb86d112a269a2d3ce5c7b0dd9d9fa3b2de0f 100755 --- a/test/test-device +++ b/test/test-device @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/test-discovery b/test/test-discovery index 54fc51403a8a3117e0450c1814970060c673318b..6959e7be94a47b8f2c6802a44cc2b46a1dc220d4 100755 --- a/test/test-discovery +++ b/test/test-discovery @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/test-gatt-profile b/test/test-gatt-profile index a973ae14ed31817756e70bd45b9c3baa4b4ea930..64ff3e5f9502dda42d3a503942d75c6edb0116a7 100755 --- a/test/test-gatt-profile +++ b/test/test-gatt-profile @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/test-health b/test/test-health index 3e16c415d48a5cdea4bf7a1ff31837803829e9af..f26def906fc09a5b37703a5bf4951f73fa9d3f8f 100755 --- a/test/test-health +++ b/test/test-health @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/test-health-sink b/test/test-health-sink index 13b9a6b04bb8448b1948c488de49319b97e764ba..fcdc58e3d0095f7345e4d46355626a5d04ebbbe0 100755 --- a/test/test-health-sink +++ b/test/test-health-sink @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/test-hfp b/test/test-hfp index 11e328e54cc86822045551ce3829a7c3c7a42df6..e1edac0aa17463ca506797d61a50c246333b7163 100755 --- a/test/test-hfp +++ b/test/test-hfp @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/test-join b/test/test-join deleted file mode 100644 index 969795094740368b44cdda360da4345b8fd99bde..0000000000000000000000000000000000000000 --- a/test/test-join +++ /dev/null @@ -1,436 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: LGPL-2.1-or-later - -import sys -import struct -import numpy -import dbus -import dbus.service -import dbus.exceptions - -from threading import Timer -import time - -try: - from gi.repository import GObject -except ImportError: - import gobject as GObject -from dbus.mainloop.glib import DBusGMainLoop - -import agent - -MESH_SERVICE_NAME = 'org.bluez.mesh' -DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties' -DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager' - -MESH_NETWORK_IFACE = 'org.bluez.mesh.Network1' -MESH_NODE_IFACE = 'org.bluez.mesh.Node1' -MESH_APPLICATION_IFACE = 'org.bluez.mesh.Application1' -MESH_ELEMENT_IFACE = 'org.bluez.mesh.Element1' - -APP_COMPANY_ID = 0x05f1 -APP_PRODUCT_ID = 0x0001 -APP_VERSION_ID = 0x0001 - -VENDOR_ID_NONE = 0xffff - -mesh_net = None -app = None -bus = None -mainloop = None -node = None - -token = None - -def generic_error_cb(error): - print('D-Bus call failed: ' + str(error)) - -def generic_reply_cb(): - print('D-Bus call done') - -def unwrap(item): - if isinstance(item, dbus.Boolean): - return bool(item) - if isinstance(item, (dbus.UInt16, dbus.Int16, - dbus.UInt32, dbus.Int32, - dbus.UInt64, dbus.Int64)): - return int(item) - if isinstance(item, dbus.Byte): - return bytes([int(item)]) - if isinstance(item, dbus.String): - return item - if isinstance(item, (dbus.Array, list, tuple)): - return [unwrap(x) for x in item] - if isinstance(item, (dbus.Dictionary, dict)): - return dict([(unwrap(x), unwrap(y)) for x, y in item.items()]) - - print('Dictionary item not handled') - print(type(item)) - return item - -def join_cb(): - print('Join procedure started') - -def join_error_cb(reason): - print('Join procedure failed: ', reason) - -def attach_app_cb(node_path, dict_array): - print('Mesh application registered ', node_path) - - obj = bus.get_object(MESH_SERVICE_NAME, node_path) - - global node - node = dbus.Interface(obj, MESH_NODE_IFACE) - - els = unwrap(dict_array) - print("Get Elements") - - for el in els: - idx = struct.unpack('b', el[0])[0] - print('Configuration for Element ', end='') - print(idx) - - models = el[1] - element = app.get_element(idx) - element.set_model_config(models) - -def attach_app_error_cb(error): - print('Failed to register application: ' + str(error)) - mainloop.quit() - -def attach(token): - print('Attach') - mesh_net.Attach(app.get_path(), token, - reply_handler=attach_app_cb, - error_handler=attach_app_error_cb) - -def interfaces_removed_cb(object_path, interfaces): - if not mesh_net: - return - - if object_path == mesh_net[2]: - print('Service was removed') - mainloop.quit() - -def send_response(path, dest, key, data): - print('send response ', end='') - print(data) - node.Send(path, dest, key, data, reply_handler=generic_reply_cb, - error_handler=generic_error_cb) - -def send_publication(path, model_id, data): - print('send publication ', end='') - print(data) - node.Publish(path, model_id, data, reply_handler=generic_reply_cb, - error_handler=generic_error_cb) - -class PubTimer(): - def __init__(self): - self.seconds = None - self.func = None - self.thread = None - self.busy = False - - def _timeout_cb(self): - self.func() - self.busy = True - self._schedule_timer() - self.busy =False - - def _schedule_timer(self): - self.thread = Timer(self.seconds, self._timeout_cb) - self.thread.start() - - def start(self, seconds, func): - self.func = func - self.seconds = seconds - if not self.busy: - self._schedule_timer() - - def cancel(self): - print('Cancel timer') - if self.thread is not None: - print('Cancel thread') - self.thread.cancel() - self.thread = None - -class Application(dbus.service.Object): - - def __init__(self, bus): - self.path = '/example' - self.agent = None - self.elements = [] - dbus.service.Object.__init__(self, bus, self.path) - - def set_agent(self, agent): - self.agent = agent - - def get_path(self): - return dbus.ObjectPath(self.path) - - def add_element(self, element): - self.elements.append(element) - - def get_element(self, idx): - for ele in self.elements: - if ele.get_index() == idx: - return ele - - def get_properties(self): - return { - MESH_APPLICATION_IFACE: { - 'CompanyID': dbus.UInt16(APP_COMPANY_ID), - 'ProductID': dbus.UInt16(APP_PRODUCT_ID), - 'VersionID': dbus.UInt16(APP_VERSION_ID) - } - } - - @dbus.service.method(DBUS_OM_IFACE, out_signature='a{oa{sa{sv}}}') - - def GetManagedObjects(self): - response = {} - print('GetManagedObjects') - response[self.path] = self.get_properties() - response[self.agent.get_path()] = self.agent.get_properties() - for element in self.elements: - response[element.get_path()] = element.get_properties() - return response - - @dbus.service.method(MESH_APPLICATION_IFACE, - in_signature="t", out_signature="") - - def JoinComplete(self, value): - global token - print('JoinComplete ', value) - - token = value - attach(token) - - @dbus.service.method(MESH_APPLICATION_IFACE, - in_signature="s", out_signature="") - - def JoinFailed(self, value): - print('JoinFailed ', value) - token = value - -class Element(dbus.service.Object): - PATH_BASE = '/example/ele' - - def __init__(self, bus, index): - self.path = self.PATH_BASE + format(index, '02x') - print(self.path) - self.models = [] - self.bus = bus - self.index = index - dbus.service.Object.__init__(self, bus, self.path) - - def _get_sig_models(self): - ids = [] - for model in self.models: - id = model.get_id() - vendor = model.get_vendor() - if vendor == VENDOR_ID_NONE: - ids.append(id) - return ids - - def _get_v_models(self): - ids = [] - for model in self.models: - id = model.get_id() - v = model.get_vendor() - if v != VENDOR_ID_NONE: - vendor_id = (v, id) - ids.append(vendor_id) - return ids - - def get_properties(self): - vendor_models = self._get_v_models() - sig_models = self._get_sig_models() - - return { - MESH_ELEMENT_IFACE: { - 'Index': dbus.Byte(self.index), - 'Models': dbus.Array(sig_models, 'q'), - 'VendorModels': dbus.Array(vendor_models, '(qq)'), - } - } - - def add_model(self, model): - model.set_path(self.path) - self.models.append(model) - - def get_index(self): - return self.index - - def set_model_config(self, configs): - print('Set element models config') - for config in configs: - mod_id = config[0] - self.UpdateModelConfiguration(mod_id, config[1]) - - @dbus.service.method(MESH_ELEMENT_IFACE, - in_signature="qqvay", out_signature="") - def MessageReceived(self, source, key, destination, data): - print('Message Received on Element %d, src=%04x, dst=%s' % - self.index, source, destination) - for model in self.models: - model.process_message(source, key, data) - - @dbus.service.method(MESH_ELEMENT_IFACE, - in_signature="qa{sv}", out_signature="") - - def UpdateModelConfiguration(self, model_id, config): - print('UpdateModelConfig ', end='') - print(hex(model_id)) - for model in self.models: - if model_id == model.get_id(): - model.set_config(config) - return - - @dbus.service.method(MESH_ELEMENT_IFACE, - in_signature="", out_signature="") - - def get_path(self): - return dbus.ObjectPath(self.path) - -class Model(): - def __init__(self, model_id): - self.cmd_ops = [] - self.model_id = model_id - self.vendor = VENDOR_ID_NONE - self.bindings = [] - self.pub_period = 0 - self.pub_id = 0 - self.path = None - - def set_path(self, path): - self.path = path - - def get_id(self): - return self.model_id - - def get_vendor(self): - return self.vendor - - def process_message(self, source, key, data): - print('Model process message') - - def set_publication(self, period): - self.pub_period = period - - def set_config(self, config): - if 'Bindings' in config: - self.bindings = config.get('Bindings') - print('Bindings: ', end='') - print(self.bindings) - if 'PublicationPeriod' in config: - self.set_publication(config.get('PublicationPeriod')) - print('Model publication period ', end='') - print(self.pub_period, end='') - print(' ms') - if 'Subscriptions' in config: - self.print_subscriptions(config.get('Subscriptions')) - - def print_subscriptions(self, subscriptions): - print('Model subscriptions ', end='') - for sub in subscriptions: - if isinstance(sub, int): - print('%04x' % sub, end=' ') - - if isinstance(sub, list): - label = uuid.UUID(bytes=b''.join(sub)) - print(label, end=' ') - print() - -class OnOffServer(Model): - def __init__(self, model_id): - Model.__init__(self, model_id) - self.cmd_ops = { 0x8201, # get - 0x8202, # set - 0x8203 } # set unacknowledged - - print("OnOff Server ", end="") - self.state = 0 - print('State ', end='') - self.timer = PubTimer() - - def process_message(self, source, key, data): - datalen = len(data) - print('OnOff Server process message len ', datalen) - - if datalen!=2 and datalen!=3: - return - - if datalen==2: - op_tuple=struct.unpack('<H',bytes(data)) - opcode = op_tuple[0] - if opcode != 0x8201: - print(hex(opcode)) - return - print('Get state') - elif datalen==3: - opcode,self.state=struct.unpack('<HB',bytes(data)) - if opcode != 0x8202 and opcode != 0x8203: - print(hex(opcode)) - return - print('Set state: ', end='') - print(self.state) - - rsp_data = struct.pack('<HB', 0x8204, self.state) - send_response(self.path, source, key, rsp_data) - - def publish(self): - print('Publish') - data = struct.pack('B', self.state) - send_publication(self.path, self.model_id, data) - - def set_publication(self, period): - if period == 0: - self.pub_period = 0 - self.timer.cancel() - return - - # We do not handle ms in this example - if period < 1000: - return - - self.pub_period = period - self.timer.start(period/1000, self.publish) - -def main(): - - DBusGMainLoop(set_as_default=True) - - global bus - bus = dbus.SystemBus() - global mainloop - global app - global mesh_net - - mesh_net = dbus.Interface(bus.get_object(MESH_SERVICE_NAME, - "/org/bluez/mesh"), - MESH_NETWORK_IFACE) - mesh_net.connect_to_signal('InterfacesRemoved', interfaces_removed_cb) - - app = Application(bus) - prov_agent = agent.Agent(bus) - app.set_agent(prov_agent) - first_ele = Element(bus, 0x00) - first_ele.add_model(OnOffServer(0x1000)) - app.add_element(first_ele) - - mainloop = GObject.MainLoop() - - print('Join') - caps = ["out-numeric"] - oob = ["other"] - uuid = bytearray.fromhex("0a0102030405060708090A0B0C0D0E0F") - print(uuid) - mesh_net.Join(app.get_path(), uuid, - reply_handler=join_cb, - error_handler=join_error_cb) - - mainloop.run() - -if __name__ == '__main__': - main() diff --git a/test/test-manager b/test/test-manager index 3fa7205a04b6a1dcd430abd1fdbcab21dd8b4e96..a93819e276ac1ba42b70012e23d98039ed4fdbbd 100755 --- a/test/test-manager +++ b/test/test-manager @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/test-nap b/test/test-nap index d5c757b79de11ec77330cbf81de807afae112e45..76cde74d4fdb21bb68a97aa71ad9bd13aa1304ba 100755 --- a/test/test-nap +++ b/test/test-nap @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/test-network b/test/test-network index acc7dff65e485674f00835d69384884026e7b06b..67be861066a82e706e2899c2f276a8ef494c894b 100755 --- a/test/test-network +++ b/test/test-network @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/test-profile b/test/test-profile index af1e23f765ddef3816e628b406aa910593dec3ed..7d92f390ea67c474dddbe228c53c4e03449e0190 100755 --- a/test/test-profile +++ b/test/test-profile @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/test/test-sap-server b/test/test-sap-server index ddb1efe9bc8cb684c13ea0564f261011c7b32d86..161a4bfec58e20e29e2a5d2df8dbe189e19559d3 100755 --- a/test/test-sap-server +++ b/test/test-sap-server @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals diff --git a/tools/advtest.c b/tools/advtest.c index de036e783325abd53e820efdf82c7402294de5ee..9ef69ed5124acbc6e2f4eabf0f5c982444cbbfc2 100644 --- a/tools/advtest.c +++ b/tools/advtest.c @@ -13,6 +13,13 @@ #include <config.h> #endif +#include <stdlib.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + #include <getopt.h> #include "lib/bluetooth.h" @@ -32,6 +39,9 @@ "\xe1\x23\x99\xc1\xca\x9a\xc3\x31" #define SCAN_IRK "\xfa\x73\x09\x11\x3f\x03\x37\x0f" \ "\xf4\xf9\x93\x1e\xf9\xa3\x63\xa6" +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#endif static struct mgmt *mgmt; static uint16_t index1 = MGMT_INDEX_NONE; @@ -43,13 +53,73 @@ static struct bt_hci *scan_dev; static void print_rpa(const uint8_t addr[6]) { - printf(" Address: %02x:%02x:%02x:%02x:%02x:%02x\n", + printf(" RSI:\t0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]); printf(" Random: %02x%02x%02x\n", addr[3], addr[4], addr[5]); printf(" Hash: %02x%02x%02x\n", addr[0], addr[1], addr[2]); } +static size_t hex2bin(const char *hexstr, uint8_t *buf, size_t buflen) +{ + size_t i, len; + + len = MIN((strlen(hexstr) / 2), buflen); + memset(buf, 0, len); + + for (i = 0; i < len; i++) + if (sscanf(hexstr + (i * 2), "%02hhX", &buf[i]) != 1) + continue; + + + return len; +} + +static bool get_random_bytes(void *buf, size_t num_bytes) +{ + ssize_t len; + int fd; + + fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) + return false; + + len = read(fd, buf, num_bytes); + + close(fd); + + if (len < 0) + return false; + + return true; +} + +static void generate_rsi(char *val) +{ + uint8_t sirk[16], hash[3]; + uint8_t rsi[6] = {0}; + + hex2bin(val, sirk, sizeof(sirk)); + + get_random_bytes(&rsi[3], 3); + + rsi[5] &= 0x3f; /* Clear 2 msb */ + rsi[5] |= 0x40; /* Set 2nd msb */ + + crypto = bt_crypto_new(); + if (!crypto) { + fprintf(stderr, "Failed to open crypto interface\n"); + mainloop_exit_failure(); + return; + } + + bt_crypto_ah(crypto, sirk, rsi + 3, hash); + memcpy(rsi, hash, 3); + + print_rpa(rsi); +} + + static void scan_le_adv_report(const void *data, uint8_t size, void *user_data) { @@ -351,9 +421,11 @@ static void usage(void) printf("\tadvtest [options]\n"); printf("options:\n" "\t-h, --help Show help options\n"); + printf(" \t-i <128bit SIRK>, Generate RSI ADV Data\n"); } static const struct option main_options[] = { + { "hash", no_argument, NULL, 'i' }, { "version", no_argument, NULL, 'v' }, { "help", no_argument, NULL, 'h' }, { } @@ -366,11 +438,15 @@ int main(int argc ,char *argv[]) for (;;) { int opt; - opt = getopt_long(argc, argv, "vh", main_options, NULL); + opt = getopt_long(argc, argv, "i:vh", main_options, NULL); if (opt < 0) break; switch (opt) { + case 'i': + printf("SIRK: %s\n", optarg); + generate_rsi(optarg); + return EXIT_SUCCESS; case 'v': printf("%s\n", VERSION); return EXIT_SUCCESS; diff --git a/tools/avtest.c b/tools/avtest.c index ca37b3b46dfe8a7d30e1adc592c6b41712ec7779..5ac3418aa37d20db5807be21cc1aab5ae2d81695 100644 --- a/tools/avtest.c +++ b/tools/avtest.c @@ -188,7 +188,8 @@ static void dump_buffer(const unsigned char *buf, int len) } static void process_avdtp(int srv_sk, int sk, unsigned char reject, - int fragment) + int fragment, + int reject_code) { unsigned char buf[672]; ssize_t len; @@ -284,7 +285,8 @@ static void process_avdtp(int srv_sk, int sk, unsigned char reject, if (reject == AVDTP_SET_CONFIGURATION) { hdr->message_type = AVDTP_MSG_TYPE_REJECT; buf[2] = buf[4]; - buf[3] = 0x13; /* SEP In Use */ + buf[3] = reject_code ? reject_code : + 0x13; /* SEP In Use */ printf("Rejecting set configuration command\n"); len = write(sk, buf, 4); } else { @@ -443,7 +445,8 @@ static int set_minimum_mtu(int sk) return 0; } -static void do_listen(const bdaddr_t *src, unsigned char reject, int fragment) +static void do_listen(const bdaddr_t *src, unsigned char reject, int fragment, + int reject_code) { struct sockaddr_l2 addr; socklen_t optlen; @@ -483,7 +486,7 @@ static void do_listen(const bdaddr_t *src, unsigned char reject, int fragment) continue; } - process_avdtp(sk, nsk, reject, fragment); + process_avdtp(sk, nsk, reject, fragment, reject_code); if (media_sock >= 0) { close(media_sock); @@ -709,6 +712,7 @@ static void usage(void) printf("Options:\n" "\t--device <hcidev> HCI device\n" "\t--reject <command> Reject command\n" + "\t--reject-code <code> Reject code to use\n" "\t--send <command> Send command\n" "\t--preconf Configure stream before actual command\n" "\t--wait <N> Wait N seconds before exiting\n" @@ -720,6 +724,7 @@ static struct option main_options[] = { { "help", 0, 0, 'h' }, { "device", 1, 0, 'i' }, { "reject", 1, 0, 'r' }, + { "reject-code", 1, 0, 'R' }, { "send", 1, 0, 's' }, { "invalid", 1, 0, 'f' }, { "preconf", 0, 0, 'c' }, @@ -764,12 +769,12 @@ int main(int argc, char *argv[]) unsigned char cmd = 0x00; bdaddr_t src, dst; int opt, mode = MODE_NONE, sk, invalid = 0, preconf = 0, fragment = 0; - int avctp = 0, wait_before_exit = 0; + int avctp = 0, wait_before_exit = 0, reject_code = 0; bacpy(&src, BDADDR_ANY); bacpy(&dst, BDADDR_ANY); - while ((opt = getopt_long(argc, argv, "+i:r:s:f:hcFCw:", + while ((opt = getopt_long(argc, argv, "+i:r:s:f:hcFCw:R:", main_options, NULL)) != EOF) { switch (opt) { case 'i': @@ -809,6 +814,10 @@ int main(int argc, char *argv[]) wait_before_exit = atoi(optarg); break; + case 'R': + reject_code = atoi(optarg); + break; + case 'h': default: usage(); @@ -826,7 +835,7 @@ int main(int argc, char *argv[]) switch (mode) { case MODE_REJECT: - do_listen(&src, cmd, fragment); + do_listen(&src, cmd, fragment, reject_code); break; case MODE_SEND: sk = do_connect(&src, &dst, avctp, fragment); diff --git a/tools/bdaddr.1 b/tools/bdaddr.1 new file mode 100644 index 0000000000000000000000000000000000000000..2e74fa381ceed9bc278e8a6183567095589ae28a --- /dev/null +++ b/tools/bdaddr.1 @@ -0,0 +1,94 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BDADDR" "1" "Sep 27, 2005" "BlueZ" "Linux System Administration" +.SH NAME +bdaddr \- Utility for changing the Bluetooth device address +.SH SYNOPSIS +.sp +\fBbdaddr\fP +.sp +\fBbdaddr\fP \-h +.sp +\fBbdaddr\fP [\-i <\fIdev\fP>] [\-r] [\-t] [\fInew_bdaddr\fP] +.SH DESCRIPTION +.sp +\fBbdaddr(1)\fP is used to query or set the local Bluetooth device address +(BD_ADDR). If run with no arguments, \fBbdaddr\fP prints the chip manufacturer\(aqs +name, and the current BD_ADDR. If the IEEE OUI index file \(dqoui.txt\(dq is +installed on the system, the BD_ADDR owner will be displayed. If the optional +[\fInew_bdaddr\fP] 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 \(aqsoft\(aq reset by specifying the \-r +flag, or a \(aqhard\(aq reset by removing and replugging the device. A \(aqhard\(aq reset +will cause the address to revert to the current non\-volatile value. +.sp +\fBbdaddr\fP 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: \fBEricsson\fP, \fBCambridge Silicon Radio (CSR)\fP, +\fBTexas Instruments (TI)\fP, \fBZeevo\fP and \fBST Microelectronics (ST)\fP\&. +.SH OPTIONS +.INDENT 0.0 +.TP +.B \-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 +.B \-r +Reset device and make new BD_ADDR active. CSR devices only. +.TP +.B \-t +Temporary change. Do not write to non\-volatile memory. +CSR devices only. +.UNINDENT +.SH FILES +.INDENT 0.0 +.TP +.B /usr/share/misc/oui.txt +IEEE Organizationally Unique Identifier consolidated file. +Manually update from: <http://standards.ieee.org/regauth/oui/oui.txt> +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH AUTHOR +Marcel Holtmann <marcel@holtmann.org>, Adam Laurie <adam@algroup.co.uk> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/tools/bdaddr.c b/tools/bdaddr.c index bc0478d461b263e76a477dfc1d8acc93ed20709e..de17416e9c6c51cb84f56fa080dfc2baf997e18c 100644 --- a/tools/bdaddr.c +++ b/tools/bdaddr.c @@ -303,6 +303,7 @@ static struct { { 48, st_write_bd_addr, generic_reset_device }, { 57, ericsson_write_bd_addr, generic_reset_device }, { 72, mrvl_write_bd_addr, generic_reset_device }, + { 305, bcm_write_bd_addr, generic_reset_device }, { 65535, NULL, NULL }, }; diff --git a/tools/bluemoon.c b/tools/bluemoon.c index f50107a2a7e3634026151cd7ca5b99444abf0f2a..9aaf6428da427916f8e6697eea47e568bdab98ea 100644 --- a/tools/bluemoon.c +++ b/tools/bluemoon.c @@ -18,6 +18,7 @@ #include <unistd.h> #include <stdlib.h> #include <string.h> +#include <limits.h> #include <getopt.h> #include <sys/stat.h> #include <sys/param.h> diff --git a/tools/bluetooth-logger.service.in b/tools/bluetooth-logger.service.in index 00900273118fb02da8629147a79ed4f6c05f773a..d6df676b86c4a7bbf3505213cf452f05fb61785f 100644 --- a/tools/bluetooth-logger.service.in +++ b/tools/bluetooth-logger.service.in @@ -4,7 +4,7 @@ ConditionPathIsDirectory=/sys/class/bluetooth [Service] Type=simple -ExecStart=@pkglibexecdir@/btmon-logger -p -b /var/log/bluetooth/hci.log +ExecStart=@PKGLIBEXECDIR@/btmon-logger -p -b /var/log/bluetooth/hci.log NotifyAccess=main CapabilityBoundingSet=CAP_NET_RAW LimitNPROC=1 diff --git a/tools/bluetooth-player.c b/tools/bluetooth-player.c index eba104d09fdb645e09f3b63ab932a2b6c8de863a..83045ca3fe413db18b8f2eed18511b4850d0bed5 100644 --- a/tools/bluetooth-player.c +++ b/tools/bluetooth-player.c @@ -33,21 +33,20 @@ #include "src/shared/shell.h" #include "client/player.h" -#define PROMPT_ON COLOR_BLUE "[bluetooth]" COLOR_OFF "# " -#define PROMPT_OFF "[bluetooth]# " +#define PROMPT "[bluetooth]# " static DBusConnection *dbus_conn; static void connect_handler(DBusConnection *connection, void *user_data) { bt_shell_attach(fileno(stdin)); - bt_shell_set_prompt(PROMPT_ON); + bt_shell_set_prompt(PROMPT, COLOR_BLUE); } static void disconnect_handler(DBusConnection *connection, void *user_data) { bt_shell_detach(); - bt_shell_set_prompt(PROMPT_OFF); + bt_shell_set_prompt(PROMPT, NULL); } int main(int argc, char *argv[]) @@ -56,7 +55,7 @@ int main(int argc, char *argv[]) int status; bt_shell_init(argc, argv, NULL); - bt_shell_set_prompt(PROMPT_OFF); + bt_shell_set_prompt(PROMPT, NULL); dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL); diff --git a/tools/btattach.1 b/tools/btattach.1 new file mode 100644 index 0000000000000000000000000000000000000000..f504dc82179815db67fab785b89ccc4da061c4c8 --- /dev/null +++ b/tools/btattach.1 @@ -0,0 +1,123 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BTATTACH" "1" "November 2015" "BlueZ" "Linux System Administration" +.SH NAME +btattach \- Attach serial devices to BlueZ stack +.SH SYNOPSIS +.sp +\fBbtattach\fP [\fB\-B\fP \fIdevice\fP] [\fB\-A\fP \fIdevice\fP] [\fB\-P\fP \fIprotocol\fP] [\fB\-R\fP] +.SH DESCRIPTION +.sp +\fBbtattach(1)\fP is used to attach a serial UART to the Bluetooth stack as a +transport interface. +.SH OPTIONS +.INDENT 0.0 +.TP +.BI \-B \ device\fR,\fB \ \-\-brder \ device +Attach a BR/EDR controller +.TP +.BI \-A \ device\fR,\fB \ \-\-amp \ device +Attach an AMP controller +.TP +.BI \-P \ protocol\fR,\fB \ \-\-protocol \ protocol +Specify the protocol type for talking to the +device. +.sp +Supported values are: +.UNINDENT +.TS +box center; +l. +T{ +\fIprotocol\fP +T} +_ +T{ +h4 +T} +_ +T{ +bcsp +T} +_ +T{ +3wire +T} +_ +T{ +h4ds +T} +_ +T{ +ll +T} +_ +T{ +ath3k +T} +_ +T{ +intel +T} +_ +T{ +bcm +T} +_ +T{ +qca +T} +.TE +.INDENT 0.0 +.TP +.BI \-S \ baudrate\fR,\fB \ \-\-speed \ baudrate +Specify wich baudrate to use +.TP +.B \-N\fP,\fB \-\-noflowctl +Disable flow control +.TP +.B \-v\fP,\fB \-\-version +Show version +.TP +.B \-h\fP,\fB \-\-help +Show help options +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/tools/btgatt-client.c b/tools/btgatt-client.c index 58a03bd4861ceaf354f0f99b90e4bd5c52b3ea34..b47914da3d44cfb320704ceb67771a953bb79877 100644 --- a/tools/btgatt-client.c +++ b/tools/btgatt-client.c @@ -33,6 +33,7 @@ #include "src/shared/queue.h" #include "src/shared/gatt-db.h" #include "src/shared/gatt-client.h" +#include "src/shared/gatt-helpers.h" #define ATT_CID 4 @@ -57,6 +58,7 @@ struct client { struct bt_gatt_client *gatt; unsigned int reliable_session_id; + bool sec_retry; }; static void print_prompt(void) @@ -172,6 +174,7 @@ static struct client *client_create(int fd, uint16_t mtu) fprintf(stderr, "Failed to allocate memory for client\n"); return NULL; } + cli->sec_retry = true; cli->att = bt_att_new(fd, false); if (!cli->att) { @@ -488,6 +491,7 @@ static void cmd_read_multiple(struct client *cli, char *cmd_str) char *argv[512]; int i; char *endptr = NULL; + unsigned int id; if (!bt_gatt_client_is_ready(cli->gatt)) { printf("GATT client not initialized\n"); @@ -514,9 +518,12 @@ static void cmd_read_multiple(struct client *cli, char *cmd_str) } } - if (!bt_gatt_client_read_multiple(cli->gatt, value, argc, - read_multiple_cb, NULL, NULL)) + id = bt_gatt_client_read_multiple(cli->gatt, value, argc, + read_multiple_cb, NULL, NULL); + if (!id) printf("Failed to initiate read multiple procedure\n"); + else if (!cli->sec_retry) + bt_gatt_client_set_retry(cli->gatt, id, false); free(value); } @@ -558,6 +565,7 @@ static void cmd_read_value(struct client *cli, char *cmd_str) int argc = 0; uint16_t handle; char *endptr = NULL; + unsigned int id; if (!bt_gatt_client_is_ready(cli->gatt)) { printf("GATT client not initialized\n"); @@ -575,9 +583,12 @@ static void cmd_read_value(struct client *cli, char *cmd_str) return; } - if (!bt_gatt_client_read_value(cli->gatt, handle, read_cb, - NULL, NULL)) + id = bt_gatt_client_read_value(cli->gatt, handle, read_cb, + NULL, NULL); + if (!id) printf("Failed to initiate read value procedure\n"); + else if (!cli->sec_retry) + bt_gatt_client_set_retry(cli->gatt, id, false); } static void read_long_value_usage(void) @@ -592,6 +603,7 @@ static void cmd_read_long_value(struct client *cli, char *cmd_str) uint16_t handle; uint16_t offset; char *endptr = NULL; + unsigned int id; if (!bt_gatt_client_is_ready(cli->gatt)) { printf("GATT client not initialized\n"); @@ -616,9 +628,12 @@ static void cmd_read_long_value(struct client *cli, char *cmd_str) return; } - if (!bt_gatt_client_read_long_value(cli->gatt, handle, offset, read_cb, - NULL, NULL)) + id = bt_gatt_client_read_long_value(cli->gatt, handle, offset, read_cb, + NULL, NULL); + if (!id) printf("Failed to initiate read long value procedure\n"); + else if (!cli->sec_retry) + bt_gatt_client_set_retry(cli->gatt, id, false); } static void write_value_usage(void) @@ -659,6 +674,7 @@ static void cmd_write_value(struct client *cli, char *cmd_str) uint8_t *value = NULL; bool without_response = false; bool signed_write = false; + unsigned int id; if (!bt_gatt_client_is_ready(cli->gatt)) { printf("GATT client not initialized\n"); @@ -740,10 +756,13 @@ static void cmd_write_value(struct client *cli, char *cmd_str) goto done; } - if (!bt_gatt_client_write_value(cli->gatt, handle, value, length, + id = bt_gatt_client_write_value(cli->gatt, handle, value, length, write_cb, - NULL, NULL)) + NULL, NULL); + if (!id) printf("Failed to initiate write procedure\n"); + else if (!cli->sec_retry) + bt_gatt_client_set_retry(cli->gatt, id, false); done: free(value); @@ -789,6 +808,7 @@ static void cmd_write_long_value(struct client *cli, char *cmd_str) int length; uint8_t *value = NULL; bool reliable_writes = false; + unsigned int id; if (!bt_gatt_client_is_ready(cli->gatt)) { printf("GATT client not initialized\n"); @@ -863,11 +883,14 @@ static void cmd_write_long_value(struct client *cli, char *cmd_str) } } - if (!bt_gatt_client_write_long_value(cli->gatt, reliable_writes, handle, + id = bt_gatt_client_write_long_value(cli->gatt, reliable_writes, handle, offset, value, length, write_long_cb, - NULL, NULL)) + NULL, NULL); + if (!id) printf("Failed to initiate long write procedure\n"); + else if (!cli->sec_retry) + bt_gatt_client_set_retry(cli->gatt, id, false); free(value); } @@ -999,12 +1022,18 @@ done: value, length, write_long_cb, NULL, NULL); - if (!cli->reliable_session_id) + if (!cli->reliable_session_id) { printf("Failed to proceed prepare write\n"); - else + } else { + if (!cli->sec_retry) + bt_gatt_client_set_retry(cli->gatt, + cli->reliable_session_id, + false); + printf("Prepare write success.\n" "Session id: %d to be used on next write\n", cli->reliable_session_id); + } free(value); } @@ -1236,6 +1265,36 @@ static void cmd_get_security(struct client *cli, char *cmd_str) printf("Security level: %u\n", level); } +static void set_security_retry_usage(void) +{ + printf("Usage: set-security-retry <y/n>\n" + "e.g.:\n" + "\tset-security-retry n\n"); +} + +static void cmd_set_security_retry(struct client *cli, char *cmd_str) +{ + char *argv[2]; + int argc = 0; + + if (!bt_gatt_client_is_ready(cli->gatt)) { + printf("GATT client not initialized\n"); + return; + } + + if (!parse_args(cmd_str, 1, argv, &argc) || argc != 1) { + set_security_retry_usage(); + return; + } + + if (argv[0][0] == 'y') + cli->sec_retry = true; + else if (argv[0][0] == 'n') + cli->sec_retry = false; + else + printf("Invalid argument: %s\n", argv[0]); +} + static bool convert_sign_key(char *optarg, uint8_t key[16]) { int i; @@ -1295,6 +1354,166 @@ static void cmd_set_sign_key(struct client *cli, char *cmd_str) set_sign_key_usage(); } +static void search_service_cb(bool success, uint8_t att_ecode, + struct bt_gatt_result *result, + void *user_data) +{ + struct bt_gatt_iter iter; + uint16_t start_handle, end_handle; + uint128_t u128; + bt_uuid_t uuid; + char uuid_str[MAX_LEN_UUID_STR]; + + if (!success) { + PRLOG("\nService discovery failed: %s (0x%02x)\n", + ecode_to_string(att_ecode), att_ecode); + return; + } + + if (!result || !bt_gatt_iter_init(&iter, result)) + return; + + printf("\n"); + while (bt_gatt_iter_next_service(&iter, &start_handle, &end_handle, + u128.data)) { + bt_uuid128_create(&uuid, u128); + bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str)); + printf("Found start handle: 0x%04x, end handle: 0x%04x, " + "UUID: %s\n", + start_handle, end_handle, uuid_str); + } + PRLOG("\n"); +} + +static void cmd_search_all_primary_services(struct client *cli, char *cmd_str) +{ + if (!bt_gatt_client_is_ready(cli->gatt)) { + printf("GATT client not initialized\n"); + return; + } + + bt_gatt_discover_all_primary_services(bt_gatt_client_get_att(cli->gatt), + NULL, + search_service_cb, + NULL, + NULL); +} + +static void search_service_usage(void) +{ + printf("Usage: search-service <uuid>\n" + "e.g.:\n" + "\tsearch-service 1800\n"); +} + +static void cmd_search_service(struct client *cli, char *cmd_str) +{ + char *argv[2]; + int argc = 0; + bt_uuid_t uuid; + + if (!bt_gatt_client_is_ready(cli->gatt)) { + printf("GATT client not initialized\n"); + return; + } + + if (!parse_args(cmd_str, 1, argv, &argc) || argc != 1) { + search_service_usage(); + return; + } + + if (bt_string_to_uuid(&uuid, argv[0]) < 0) { + printf("Invalid UUID: %s\n", argv[0]); + return; + } + + bt_gatt_discover_primary_services(bt_gatt_client_get_att(cli->gatt), + &uuid, 0x0001, 0xFFFF, + search_service_cb, + NULL, + NULL); +} + +static void search_characteristics_usage(void) +{ + printf("Usage: search-characteristics <start_hanlde> <end_handle> " + "<uuid>\n" + "e.g.:\n" + "\tsearch-characteristics 0x0001 0xFFFF 1800\n"); +} + +static void search_characteristics_cb(bool success, uint8_t att_ecode, + struct bt_gatt_result *result, + void *user_data) +{ + struct bt_gatt_iter iter; + uint16_t handle, length; + const uint8_t *value; + int i; + + if (!success) { + PRLOG("\nCharacteristics discovery failed: %s (0x%02x)\n", + ecode_to_string(att_ecode), att_ecode); + return; + } + + if (!result || !bt_gatt_iter_init(&iter, result)) + return; + + printf("\n"); + while (bt_gatt_iter_next_read_by_type(&iter, &handle, &length, + &value)) { + printf("Found handle: 0x%04x value: ", handle); + for (i = 0; i < length; i++) + printf("%02x ", value[i]); + printf("\n"); + } + PRLOG("\n"); +} + +static void cmd_search_characteristics(struct client *cli, char *cmd_str) +{ + char *argv[4]; + int argc = 0; + uint16_t start_handle, end_handle; + char *endptr = NULL; + bt_uuid_t uuid; + + if (!bt_gatt_client_is_ready(cli->gatt)) { + printf("GATT client not initialized\n"); + return; + } + + if (!parse_args(cmd_str, 3, argv, &argc) || argc != 3) { + search_characteristics_usage(); + return; + } + + start_handle = strtol(argv[0], &endptr, 0); + if (!endptr || *endptr != '\0') { + printf("Invalid start handle: %s\n", argv[0]); + return; + } + + end_handle = strtol(argv[1], &endptr, 0); + if (!endptr || *endptr != '\0') { + printf("Invalid end handle: %s\n", argv[1]); + return; + } + + if (bt_string_to_uuid(&uuid, argv[2]) < 0) { + printf("Invalid UUID: %s\n", argv[2]); + return; + } + + bt_gatt_read_by_type(bt_gatt_client_get_att(cli->gatt), start_handle, + end_handle, + &uuid, + search_characteristics_cb, + NULL, + NULL); +} + static void cmd_help(struct client *cli, char *cmd_str); typedef void (*command_func_t)(struct client *cli, char *cmd_str); @@ -1327,8 +1546,16 @@ static struct { "\tSet security level on le connection"}, { "get-security", cmd_get_security, "\tGet security level on le connection"}, + { "set-security-retry", cmd_set_security_retry, + "\tSet retry on security error by elevating security"}, { "set-sign-key", cmd_set_sign_key, "\tSet signing key for signed write command"}, + { "search-all-primary-services", cmd_search_all_primary_services, + "\tSearch all primary services"}, + { "search-service", cmd_search_service, + "\tSearch service"}, + { "search-characteristics", cmd_search_characteristics, + "\tSearch characteristics"}, { } }; diff --git a/tools/btiotest.c b/tools/btiotest.c index 193e1395b8ab3e6030d059827550f9a6ad7967b7..75af905439505d045367becf613819748b801533 100644 --- a/tools/btiotest.c +++ b/tools/btiotest.c @@ -5,6 +5,7 @@ * * Copyright (C) 2009-2010 Marcel Holtmann <marcel@holtmann.org> * Copyright (C) 2009-2010 Nokia Corporation + * Copyright 2023 NXP * * */ @@ -39,13 +40,15 @@ static int opt_update_sec = 0; } struct bt_iso_qos qos = { - .cig = BT_ISO_QOS_CIG_UNSET, - .cis = BT_ISO_QOS_CIG_UNSET, - .sca = 0x07, - .packing = 0x00, - .framing = 0x00, - .in = DEFAULT_IO_QOS, - .out = DEFAULT_IO_QOS, + .ucast = { + .cig = BT_ISO_QOS_CIG_UNSET, + .cis = BT_ISO_QOS_CIG_UNSET, + .sca = 0x07, + .packing = 0x00, + .framing = 0x00, + .in = DEFAULT_IO_QOS, + .out = DEFAULT_IO_QOS, + }, }; struct io_data { diff --git a/tools/btmgmt.1 b/tools/btmgmt.1 new file mode 100644 index 0000000000000000000000000000000000000000..c80478d1a41bfd671e879369074b3e0ddc71d302 --- /dev/null +++ b/tools/btmgmt.1 @@ -0,0 +1,114 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BTMGMT" "1" "July 2023" "BlueZ" "Linux System Administration" +.SH NAME +btmgmt \- interactive bluetooth management tool +.SH SYNOPSIS +.sp +\fBbtmgmt\fP [\-\-options] [commands] +.SH DESCRIPTION +.sp +\fBbtmgmt(1)\fP interactive bluetooth management tool. The tool issues commands +to the Kernel using the Bluetooth Management socket, some commands may require +net\-admin capability in order to work since the Bluetooth Management interface +is considered a low\-level interface meant for the likes of \fBbluetoothd(8)\fP, +it is not recommended for applications to use it directly as it may result in +unexpected behavior. +.SH OPTIONS +.INDENT 0.0 +.TP +.B \-i/\-\-index +Specify adapter index +.TP +.B \-m\-/\-monitor +Enable monitor output +.TP +.B \-t/\-\-timeout +Timeout in seconds for non\-interactive mode +.TP +.B \-v/\-\-version +Display version +.TP +.B \-i/\-\-init\-script +Init script file +.TP +.B \-h/\-\-help +Display help +.UNINDENT +.SH COMMANDS +.INDENT 0.0 +.TP +.B main +See \fBbluetoothctl\-mgmt(1)\fP +.TP +.B monitor +See \fBbluetoothctl\-monitor(1)\fP +.UNINDENT +.SH AUTOMATION +.sp +Two common ways to automate the tool are to pass the commands directly like in +the follow example: +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +btmgmt <<EOF +list +show +EOF +.EE +.UNINDENT +.UNINDENT +.sp +Or create a script and pass it as init\-script: +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +$ vi test\-script.bt +list +show +quit +:wq +$ btmgmt \-\-init\-script=test\-script +.EE +.UNINDENT +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/tools/btmgmt.c b/tools/btmgmt.c index 29f86091fbfba30bcb833e5dae29982d7b6a2ef8..436c2bb21f1006cdf4204ab367ef885865825f35 100644 --- a/tools/btmgmt.c +++ b/tools/btmgmt.c @@ -11,6026 +11,11 @@ #endif #define _GNU_SOURCE -#include <stdio.h> -#include <stdarg.h> -#include <errno.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <sys/param.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <poll.h> -#include <getopt.h> -#include <stdbool.h> -#include <wordexp.h> -#include <ctype.h> - -#include "lib/bluetooth.h" -#include "lib/hci.h" -#include "lib/hci_lib.h" -#include "lib/sdp.h" -#include "lib/sdp_lib.h" - -#include "src/uuid-helper.h" -#include "lib/mgmt.h" - -#include "src/shared/mainloop.h" -#include "src/shared/io.h" -#include "src/shared/util.h" -#include "src/shared/mgmt.h" -#include "src/shared/shell.h" - -#define SCAN_TYPE_BREDR (1 << BDADDR_BREDR) -#define SCAN_TYPE_LE ((1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM)) -#define SCAN_TYPE_DUAL (SCAN_TYPE_BREDR | SCAN_TYPE_LE) - -static struct mgmt *mgmt = NULL; -static uint16_t mgmt_index = MGMT_INDEX_NONE; - -static bool discovery = false; -static bool resolve_names = true; - -static struct { - uint16_t index; - uint16_t req; - struct mgmt_addr_info addr; -} prompt = { - .index = MGMT_INDEX_NONE, -}; - - -static int pending_index = 0; - -#ifndef MIN -#define MIN(x, y) ((x) < (y) ? (x) : (y)) -#endif - -#define PROMPT_ON COLOR_BLUE "[mgmt]" COLOR_OFF "# " - -static void set_index(const char *arg) -{ - if (!arg || !strcmp(arg, "none") || !strcmp(arg, "any") || - !strcmp(arg, "all")) - mgmt_index = MGMT_INDEX_NONE; - else if(strlen(arg) > 3 && !strncasecmp(arg, "hci", 3)) - mgmt_index = atoi(&arg[3]); - else - mgmt_index = atoi(arg); -} - -static bool parse_setting(int argc, char **argv, uint8_t *val) -{ - if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0) - *val = 1; - else if (strcasecmp(argv[1], "off") == 0) - *val = 0; - else - *val = atoi(argv[1]); - return true; -} - -static void update_prompt(uint16_t index) -{ - char str[32]; - - if (index == MGMT_INDEX_NONE) - snprintf(str, sizeof(str), "%s# ", - COLOR_BLUE "[mgmt]" COLOR_OFF); - else - snprintf(str, sizeof(str), - COLOR_BLUE "[hci%u]" COLOR_OFF "# ", index); - - bt_shell_set_prompt(str); -} - -#define print(fmt, arg...) do { \ - bt_shell_printf(fmt "\n", ## arg); \ -} while (0) - -#define error(fmt, arg...) do { \ - bt_shell_printf(COLOR_RED fmt "\n" COLOR_OFF, ## arg); \ -} while (0) - -static size_t hex2bin(const char *hexstr, uint8_t *buf, size_t buflen) -{ - size_t i, len; - - len = MIN((strlen(hexstr) / 2), buflen); - memset(buf, 0, len); - - for (i = 0; i < len; i++) - sscanf(hexstr + (i * 2), "%02hhX", &buf[i]); - - return len; -} - -static size_t bin2hex(const uint8_t *buf, size_t buflen, char *str, - size_t strlen) -{ - size_t i; - - for (i = 0; i < buflen && i < (strlen / 2); i++) - sprintf(str + (i * 2), "%02x", buf[i]); - - return i; -} - -static void print_eir(const uint8_t *eir, uint16_t eir_len) -{ - uint16_t parsed = 0; - char str[33]; - - while (parsed < eir_len - 1) { - uint8_t field_len = eir[0]; - - if (field_len == 0) - break; - - parsed += field_len + 1; - - if (parsed > eir_len) - break; - - switch (eir[1]) { - case 0x01: - print("Flags: 0x%02x", eir[2]); - break; - case 0x0d: - print("Class of Device: 0x%02x%02x%02x", - eir[4], eir[3], eir[2]); - break; - case 0x0e: - bin2hex(eir + 2, 16, str, sizeof(str)); - print("SSP Hash C-192: %s", str); - break; - case 0x0f: - bin2hex(eir + 2, 16, str, sizeof(str)); - print("SSP Rand R-192: %s", str); - break; - case 0x1b: - ba2str((bdaddr_t *) (eir + 2), str); - print("LE Device Address: %s (%s)", str, - eir[8] ? "random" : "public"); - break; - case 0x1c: - print("LE Role: 0x%02x", eir[2]); - break; - case 0x1d: - bin2hex(eir + 2, 16, str, sizeof(str)); - print("SSP Hash C-256: %s", str); - break; - case 0x1e: - bin2hex(eir + 2, 16, str, sizeof(str)); - print("SSP Rand R-256: %s", str); - break; - case 0x22: - bin2hex(eir + 2, 16, str, sizeof(str)); - print("LE SC Confirmation Value: %s", str); - break; - case 0x23: - bin2hex(eir + 2, 16, str, sizeof(str)); - print("LE SC Random Value: %s", str); - break; - default: - print("Type %u: %u byte%s", eir[1], field_len - 1, - (field_len - 1) == 1 ? "" : "s"); - break; - } - - eir += field_len + 1; - } -} - -static bool load_identity(const char *path, struct mgmt_irk_info *irk) -{ - char *addr, *key; - unsigned int type; - int n; - FILE *fp; - - fp = fopen(path, "r"); - if (!fp) { - error("Failed to open identity file: %s", strerror(errno)); - return false; - } - - n = fscanf(fp, "%m[0-9a-f:] (type %u) %m[0-9a-f]", &addr, &type, &key); - - fclose(fp); - - if (n != 3) - return false; - - str2ba(addr, &irk->addr.bdaddr); - hex2bin(key, irk->val, sizeof(irk->val)); - - free(addr); - free(key); - - switch (type) { - case 0: - irk->addr.type = BDADDR_LE_PUBLIC; - break; - case 1: - irk->addr.type = BDADDR_LE_RANDOM; - break; - default: - error("Invalid address type %u", type); - return false; - } - - return true; -} - -static void controller_error(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_ev_controller_error *ev = param; - - if (len < sizeof(*ev)) { - error("Too short (%u bytes) controller error event", len); - return; - } - - print("hci%u error 0x%02x", index, ev->error_code); -} - -static void index_added(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - print("hci%u added", index); -} - -static void index_removed(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - print("hci%u removed", index); -} - -static void unconf_index_added(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - print("hci%u added (unconfigured)", index); -} - -static void unconf_index_removed(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - print("hci%u removed (unconfigured)", index); -} - -static void ext_index_added(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_ev_ext_index_added *ev = param; - - print("hci%u added (type %u bus %u)", index, ev->type, ev->bus); -} - -static void ext_index_removed(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_ev_ext_index_removed *ev = param; - - print("hci%u removed (type %u bus %u)", index, ev->type, ev->bus); -} - -static const char *options_str[] = { - "external", - "public-address", -}; - -static const char *options2str(uint32_t options) -{ - static char str[256]; - unsigned i; - int off; - - off = 0; - str[0] = '\0'; - - for (i = 0; i < NELEM(options_str); i++) { - if ((options & (1 << i)) != 0) - off += snprintf(str + off, sizeof(str) - off, "%s ", - options_str[i]); - } - - return str; -} - -static void new_config_options(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - const uint32_t *ev = param; - - if (len < sizeof(*ev)) { - error("Too short new_config_options event (%u)", len); - return; - } - - print("hci%u new_config_options: %s", index, options2str(get_le32(ev))); -} - -static const char *settings_str[] = { - "powered", - "connectable", - "fast-connectable", - "discoverable", - "bondable", - "link-security", - "ssp", - "br/edr", - "hs", - "le", - "advertising", - "secure-conn", - "debug-keys", - "privacy", - "configuration", - "static-addr", - "phy-configuration", - "wide-band-speech", -}; - -static const char *settings2str(uint32_t settings) -{ - static char str[256]; - unsigned i; - int off; - - off = 0; - str[0] = '\0'; - - for (i = 0; i < NELEM(settings_str); i++) { - if ((settings & (1 << i)) != 0) - off += snprintf(str + off, sizeof(str) - off, "%s ", - settings_str[i]); - } - - return str; -} - -static void new_settings(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - const uint32_t *ev = param; - - if (len < sizeof(*ev)) { - error("Too short new_settings event (%u)", len); - return; - } - - print("hci%u new_settings: %s", index, settings2str(get_le32(ev))); -} - -static void discovering(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_discovering *ev = param; - - if (len < sizeof(*ev)) { - error("Too short (%u bytes) discovering event", len); - return; - } - - print("hci%u type %u discovering %s", index, ev->type, - ev->discovering ? "on" : "off"); - - if (ev->discovering == 0 && discovery) - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void new_link_key(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_new_link_key *ev = param; - char addr[18]; - - if (len != sizeof(*ev)) { - error("Invalid new_link_key length (%u bytes)", len); - return; - } - - ba2str(&ev->key.addr.bdaddr, addr); - print("hci%u new_link_key %s type 0x%02x pin_len %d store_hint %u", - index, addr, ev->key.type, ev->key.pin_len, ev->store_hint); -} - -static const char *typestr(uint8_t type) -{ - static const char *str[] = { "BR/EDR", "LE Public", "LE Random" }; - - if (type <= BDADDR_LE_RANDOM) - return str[type]; - - return "(unknown)"; -} - -static void connected(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_device_connected *ev = param; - uint16_t eir_len; - char addr[18]; - - if (len < sizeof(*ev)) { - error("Invalid connected event length (%u bytes)", len); - return; - } - - eir_len = get_le16(&ev->eir_len); - if (len != sizeof(*ev) + eir_len) { - error("Invalid connected event length (%u != eir_len %u)", - len, eir_len); - return; - } - - ba2str(&ev->addr.bdaddr, addr); - print("hci%u %s type %s connected eir_len %u", index, addr, - typestr(ev->addr.type), eir_len); -} - -static void disconnected(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_device_disconnected *ev = param; - char addr[18]; - uint8_t reason; - - if (len < sizeof(struct mgmt_addr_info)) { - error("Invalid disconnected event length (%u bytes)", len); - return; - } - - if (len < sizeof(*ev)) - reason = MGMT_DEV_DISCONN_UNKNOWN; - else - reason = ev->reason; - - ba2str(&ev->addr.bdaddr, addr); - print("hci%u %s type %s disconnected with reason %u", - index, addr, typestr(ev->addr.type), reason); -} - -static void conn_failed(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_connect_failed *ev = param; - char addr[18]; - - if (len != sizeof(*ev)) { - error("Invalid connect_failed event length (%u bytes)", len); - return; - } - - ba2str(&ev->addr.bdaddr, addr); - print("hci%u %s type %s connect failed (status 0x%02x, %s)", - index, addr, typestr(ev->addr.type), ev->status, - mgmt_errstr(ev->status)); -} - -static void auth_failed(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_auth_failed *ev = param; - char addr[18]; - - if (len != sizeof(*ev)) { - error("Invalid auth_failed event length (%u bytes)", len); - return; - } - - ba2str(&ev->addr.bdaddr, addr); - print("hci%u %s auth failed with status 0x%02x (%s)", - index, addr, ev->status, mgmt_errstr(ev->status)); -} - -static void class_of_dev_changed(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_ev_class_of_dev_changed *ev = param; - - if (len != sizeof(*ev)) { - error("Invalid class_of_dev_changed length (%u bytes)", len); - return; - } - - print("hci%u class of device changed: 0x%02x%02x%02x", index, - ev->dev_class[2], ev->dev_class[1], ev->dev_class[0]); -} - -static void local_name_changed(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_local_name_changed *ev = param; - - if (len != sizeof(*ev)) { - error("Invalid local_name_changed length (%u bytes)", len); - return; - } - - print("hci%u name changed: %s", index, ev->name); -} - -static void confirm_name_rsp(uint8_t status, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_rp_confirm_name *rp = param; - char addr[18]; - - if (len == 0 && status != 0) { - error("confirm_name failed with status 0x%02x (%s)", status, - mgmt_errstr(status)); - return; - } - - if (len != sizeof(*rp)) { - error("confirm_name rsp length %u instead of %zu", - len, sizeof(*rp)); - return; - } - - ba2str(&rp->addr.bdaddr, addr); - - if (status != 0) - error("confirm_name for %s failed: 0x%02x (%s)", - addr, status, mgmt_errstr(status)); - else - print("confirm_name succeeded for %s", addr); -} - -static char *eir_get_name(const uint8_t *eir, uint16_t eir_len) -{ - uint8_t parsed = 0; - - if (eir_len < 2) - return NULL; - - while (parsed < eir_len - 1) { - uint8_t field_len = eir[0]; - - if (field_len == 0) - break; - - parsed += field_len + 1; - - if (parsed > eir_len) - break; - - /* Check for short of complete name */ - if (eir[1] == 0x09 || eir[1] == 0x08) - return strndup((char *) &eir[2], field_len - 1); - - eir += field_len + 1; - } - - return NULL; -} - -static unsigned int eir_get_flags(const uint8_t *eir, uint16_t eir_len) -{ - uint8_t parsed = 0; - - if (eir_len < 2) - return 0; - - while (parsed < eir_len - 1) { - uint8_t field_len = eir[0]; - - if (field_len == 0) - break; - - parsed += field_len + 1; - - if (parsed > eir_len) - break; - - /* Check for flags */ - if (eir[1] == 0x01) - return eir[2]; - - eir += field_len + 1; - } - - return 0; -} - -static void device_found(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_device_found *ev = param; - struct mgmt *mgmt = user_data; - uint16_t eir_len; - uint32_t flags; - - if (len < sizeof(*ev)) { - error("Too short device_found length (%u bytes)", len); - return; - } - - flags = btohl(ev->flags); - - eir_len = get_le16(&ev->eir_len); - if (len != sizeof(*ev) + eir_len) { - error("dev_found: expected %zu bytes, got %u bytes", - sizeof(*ev) + eir_len, len); - return; - } - - if (discovery) { - char addr[18], *name; - - ba2str(&ev->addr.bdaddr, addr); - print("hci%u dev_found: %s type %s rssi %d " - "flags 0x%04x ", index, addr, - typestr(ev->addr.type), ev->rssi, flags); - - if (ev->addr.type != BDADDR_BREDR) - print("AD flags 0x%02x ", - eir_get_flags(ev->eir, eir_len)); - - name = eir_get_name(ev->eir, eir_len); - if (name) - print("name %s", name); - else - print("eir_len %u", eir_len); - - free(name); - } - - if (discovery && (flags & MGMT_DEV_FOUND_CONFIRM_NAME)) { - struct mgmt_cp_confirm_name cp; - - memset(&cp, 0, sizeof(cp)); - memcpy(&cp.addr, &ev->addr, sizeof(cp.addr)); - if (resolve_names) - cp.name_known = 0; - else - cp.name_known = 1; - - mgmt_reply(mgmt, MGMT_OP_CONFIRM_NAME, index, sizeof(cp), &cp, - confirm_name_rsp, NULL, NULL); - } -} - -static void pin_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("PIN Code reply failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("PIN Reply successful"); -} - -static int mgmt_pin_reply(uint16_t index, const struct mgmt_addr_info *addr, - const char *pin, size_t len) -{ - struct mgmt_cp_pin_code_reply cp; - - memset(&cp, 0, sizeof(cp)); - memcpy(&cp.addr, addr, sizeof(cp.addr)); - cp.pin_len = len; - memcpy(cp.pin_code, pin, len); - - return mgmt_reply(mgmt, MGMT_OP_PIN_CODE_REPLY, index, - sizeof(cp), &cp, pin_rsp, NULL, NULL); -} - -static void pin_neg_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("PIN Neg reply failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("PIN Negative Reply successful"); -} - -static int mgmt_pin_neg_reply(uint16_t index, const struct mgmt_addr_info *addr) -{ - struct mgmt_cp_pin_code_neg_reply cp; - - memset(&cp, 0, sizeof(cp)); - memcpy(&cp.addr, addr, sizeof(cp.addr)); - - return mgmt_reply(mgmt, MGMT_OP_PIN_CODE_NEG_REPLY, index, - sizeof(cp), &cp, pin_neg_rsp, NULL, NULL); -} - -static void confirm_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("User Confirm reply failed. status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("User Confirm Reply successful"); -} - -static int mgmt_confirm_reply(uint16_t index, const struct mgmt_addr_info *addr) -{ - struct mgmt_cp_user_confirm_reply cp; - - memset(&cp, 0, sizeof(cp)); - memcpy(&cp.addr, addr, sizeof(*addr)); - - return mgmt_reply(mgmt, MGMT_OP_USER_CONFIRM_REPLY, index, - sizeof(cp), &cp, confirm_rsp, NULL, NULL); -} - -static void confirm_neg_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("Confirm Neg reply failed. status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("User Confirm Negative Reply successful"); -} - -static int mgmt_confirm_neg_reply(uint16_t index, - const struct mgmt_addr_info *addr) -{ - struct mgmt_cp_user_confirm_reply cp; - - memset(&cp, 0, sizeof(cp)); - memcpy(&cp.addr, addr, sizeof(*addr)); - - return mgmt_reply(mgmt, MGMT_OP_USER_CONFIRM_NEG_REPLY, index, - sizeof(cp), &cp, confirm_neg_rsp, NULL, NULL); -} - -static void passkey_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("User Passkey reply failed. status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("User Passkey Reply successful"); -} - -static int mgmt_passkey_reply(uint16_t index, const struct mgmt_addr_info *addr, - uint32_t passkey) -{ - struct mgmt_cp_user_passkey_reply cp; - - memset(&cp, 0, sizeof(cp)); - memcpy(&cp.addr, addr, sizeof(*addr)); - put_le32(passkey, &cp.passkey); - - return mgmt_reply(mgmt, MGMT_OP_USER_PASSKEY_REPLY, index, - sizeof(cp), &cp, passkey_rsp, NULL, NULL); -} - -static void passkey_neg_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("Passkey Neg reply failed. status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("User Passkey Negative Reply successful"); -} - -static int mgmt_passkey_neg_reply(uint16_t index, - const struct mgmt_addr_info *addr) -{ - struct mgmt_cp_user_passkey_reply cp; - - memset(&cp, 0, sizeof(cp)); - memcpy(&cp.addr, addr, sizeof(*addr)); - - return mgmt_reply(mgmt, MGMT_OP_USER_PASSKEY_NEG_REPLY, index, - sizeof(cp), &cp, passkey_neg_rsp, NULL, NULL); -} - -static void prompt_input(const char *input, void *user_data) -{ - size_t len; - - len = strlen(input); - - switch (prompt.req) { - case MGMT_EV_PIN_CODE_REQUEST: - if (len) - mgmt_pin_reply(prompt.index, &prompt.addr, input, len); - else - mgmt_pin_neg_reply(prompt.index, &prompt.addr); - break; - case MGMT_EV_USER_PASSKEY_REQUEST: - if (strlen(input) > 0) - mgmt_passkey_reply(prompt.index, &prompt.addr, - atoi(input)); - else - mgmt_passkey_neg_reply(prompt.index, - &prompt.addr); - break; - case MGMT_EV_USER_CONFIRM_REQUEST: - if (input[0] == 'y' || input[0] == 'Y') - mgmt_confirm_reply(prompt.index, &prompt.addr); - else - mgmt_confirm_neg_reply(prompt.index, &prompt.addr); - break; - } -} - -static void ask(uint16_t index, uint16_t req, const struct mgmt_addr_info *addr, - const char *fmt, ...) -{ - char msg[256]; - va_list ap; - int off; - - prompt.index = index; - prompt.req = req; - memcpy(&prompt.addr, addr, sizeof(*addr)); - - va_start(ap, fmt); - off = vsnprintf(msg, sizeof(msg), fmt, ap); - va_end(ap); - - snprintf(msg + off, sizeof(msg) - off, " %s ", - COLOR_BOLDGRAY ">>" COLOR_OFF); - - bt_shell_prompt_input("", msg, prompt_input, NULL); -} - -static void request_pin(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_pin_code_request *ev = param; - char addr[18]; - - if (len != sizeof(*ev)) { - error("Invalid pin_code request length (%u bytes)", len); - return; - } - - ba2str(&ev->addr.bdaddr, addr); - print("hci%u %s request PIN", index, addr); - - ask(index, MGMT_EV_PIN_CODE_REQUEST, &ev->addr, - "PIN Request (press enter to reject)"); -} - -static void user_confirm(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_user_confirm_request *ev = param; - uint32_t val; - char addr[18]; - - if (len != sizeof(*ev)) { - error("Invalid user_confirm request length (%u)", len); - return; - } - - ba2str(&ev->addr.bdaddr, addr); - val = get_le32(&ev->value); - - print("hci%u %s User Confirm %06u hint %u", index, addr, - val, ev->confirm_hint); - - if (ev->confirm_hint) - ask(index, MGMT_EV_USER_CONFIRM_REQUEST, &ev->addr, - "Accept pairing with %s (yes/no)", addr); - else - ask(index, MGMT_EV_USER_CONFIRM_REQUEST, &ev->addr, - "Confirm value %06u for %s (yes/no)", val, addr); -} - -static void request_passkey(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_user_passkey_request *ev = param; - char addr[18]; - - if (len != sizeof(*ev)) { - error("Invalid passkey request length (%u bytes)", len); - return; - } - - ba2str(&ev->addr.bdaddr, addr); - print("hci%u %s request passkey", index, addr); - - ask(index, MGMT_EV_USER_PASSKEY_REQUEST, &ev->addr, - "Passkey Request (press enter to reject)"); -} - -static void passkey_notify(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_passkey_notify *ev = param; - char addr[18]; - - if (len != sizeof(*ev)) { - error("Invalid passkey request length (%u bytes)", len); - return; - } - - ba2str(&ev->addr.bdaddr, addr); - print("hci%u %s request passkey", index, addr); - - print("Passkey Notify: %06u (entered %u)", get_le32(&ev->passkey), - ev->entered); -} - -static void local_oob_data_updated(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_ev_local_oob_data_updated *ev = param; - uint16_t eir_len; - - if (len < sizeof(*ev)) { - error("Too small (%u bytes) local_oob_updated event", len); - return; - } - - eir_len = le16_to_cpu(ev->eir_len); - if (len != sizeof(*ev) + eir_len) { - error("local_oob_updated: expected %zu bytes, got %u bytes", - sizeof(*ev) + eir_len, len); - return; - } - - print("hci%u oob data updated: type %u len %u", index, - ev->type, eir_len); -} - -static void advertising_added(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_ev_advertising_added *ev = param; - - if (len < sizeof(*ev)) { - error("Too small (%u bytes) advertising_added event", len); - return; - } - - print("hci%u advertising_added: instance %u", index, ev->instance); -} - -static void advertising_removed(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_ev_advertising_removed *ev = param; - - if (len < sizeof(*ev)) { - error("Too small (%u bytes) advertising_removed event", len); - return; - } - - print("hci%u advertising_removed: instance %u", index, ev->instance); -} - -static void flags_changed(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_device_flags_changed *ev = param; - char addr[18]; - - if (len < sizeof(*ev)) { - error("Too small (%u bytes) %s event", len, __func__); - return; - } - - ba2str(&ev->addr.bdaddr, addr); - print("hci%u device_flags_changed: %s (%s)", index, addr, - typestr(ev->addr.type)); - print(" supp: 0x%08x curr: 0x%08x", - ev->supported_flags, ev->current_flags); -} - -static void advmon_added(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_adv_monitor_added *ev = param; - - if (len < sizeof(*ev)) { - error("Too small (%u bytes) %s event", len, __func__); - return; - } - - print("hci%u %s: handle %u", index, __func__, - le16_to_cpu(ev->monitor_handle)); -} - -static void advmon_removed(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_adv_monitor_removed *ev = param; - - if (len < sizeof(*ev)) { - error("Too small (%u bytes) %s event", len, __func__); - return; - } - - print("hci%u %s: handle %u", index, __func__, - le16_to_cpu(ev->monitor_handle)); -} - -static void version_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_version *rp = param; - - if (status != 0) { - error("Reading mgmt version failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - goto done; - } - - if (len < sizeof(*rp)) { - error("Too small version reply (%u bytes)", len); - goto done; - } - - print("MGMT Version %u, revision %u", rp->version, - get_le16(&rp->revision)); - -done: - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_revision(int argc, char **argv) -{ - if (mgmt_send(mgmt, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE, - 0, NULL, version_rsp, NULL, NULL) == 0) { - error("Unable to send read_version cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void commands_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_commands *rp = param; - uint16_t num_commands, num_events; - size_t expected_len; - int i; - - if (status != 0) { - error("Read Supported Commands failed: status 0x%02x (%s)", - status, mgmt_errstr(status)); - goto done; - } - - if (len < sizeof(*rp)) { - error("Too small commands reply (%u bytes)", len); - goto done; - } - - num_commands = get_le16(&rp->num_commands); - num_events = get_le16(&rp->num_events); - - expected_len = sizeof(*rp) + num_commands * sizeof(uint16_t) + - num_events * sizeof(uint16_t); - - if (len < expected_len) { - error("Too small commands reply (%u != %zu)", - len, expected_len); - goto done; - } - - print("%u commands:", num_commands); - for (i = 0; i < num_commands; i++) { - uint16_t op = get_le16(rp->opcodes + i); - print("\t%s (0x%04x)", mgmt_opstr(op), op); - } - - print("%u events:", num_events); - for (i = 0; i < num_events; i++) { - uint16_t ev = get_le16(rp->opcodes + num_commands + i); - print("\t%s (0x%04x)", mgmt_evstr(ev), ev); - } - -done: - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_commands(int argc, - char **argv) -{ - if (mgmt_send(mgmt, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE, - 0, NULL, commands_rsp, NULL, NULL) == 0) { - error("Unable to send read_commands cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void config_info_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_config_info *rp = param; - uint16_t index = PTR_TO_UINT(user_data); - uint32_t supported_options, missing_options; - - if (status != 0) { - error("Reading hci%u config failed with status 0x%02x (%s)", - index, status, mgmt_errstr(status)); - goto done; - } - - if (len < sizeof(*rp)) { - error("Too small info reply (%u bytes)", len); - goto done; - } - - print("hci%u:\tUnconfigured controller", index); - - print("\tmanufacturer %u", le16_to_cpu(rp->manufacturer)); - - supported_options = le32_to_cpu(rp->supported_options); - print("\tsupported options: %s", options2str(supported_options)); - - missing_options = le32_to_cpu(rp->missing_options); - print("\tmissing options: %s", options2str(missing_options)); - -done: - pending_index--; - - if (pending_index > 0) - return; - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void unconf_index_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_unconf_index_list *rp = param; - uint16_t count; - unsigned int i; - - if (status != 0) { - error("Reading index list failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small index list reply (%u bytes)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - count = le16_to_cpu(rp->num_controllers); - - if (len < sizeof(*rp) + count * sizeof(uint16_t)) { - error("Index count (%u) doesn't match reply length (%u)", - count, len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Unconfigured index list with %u item%s", - count, count != 1 ? "s" : ""); - - for (i = 0; i < count; i++) { - uint16_t index = le16_to_cpu(rp->index[i]); - - if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, index, 0, NULL, - config_info_rsp, UINT_TO_PTR(index), NULL)) { - error("Unable to send read_config_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - pending_index++; - } - - if (!count) - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_config(int argc, char **argv) -{ - if (mgmt_index == MGMT_INDEX_NONE) { - if (!mgmt_send(mgmt, MGMT_OP_READ_UNCONF_INDEX_LIST, - MGMT_INDEX_NONE, 0, NULL, - unconf_index_rsp, mgmt, NULL)) { - error("Unable to send unconf_index_list cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - return; - } - - if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, mgmt_index, 0, NULL, - config_info_rsp, UINT_TO_PTR(index), NULL)) { - error("Unable to send read_config_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void config_options_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_config_info *rp = param; - uint16_t index = PTR_TO_UINT(user_data); - uint32_t supported_options, missing_options; - - if (status != 0) { - error("Reading hci%u config failed with status 0x%02x (%s)", - index, status, mgmt_errstr(status)); - goto done; - } - - if (len < sizeof(*rp)) { - error("Too small info reply (%u bytes)", len); - goto done; - } - - print("hci%u:\tConfiguration options", index); - - supported_options = le32_to_cpu(rp->supported_options); - print("\tsupported options: %s", options2str(supported_options)); - - missing_options = le32_to_cpu(rp->missing_options); - print("\tmissing options: %s", options2str(missing_options)); - -done: - pending_index--; - - if (pending_index > 0) - return; - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void info_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_info *rp = param; - uint16_t index = PTR_TO_UINT(user_data); - uint32_t supported_settings, current_settings; - char addr[18]; - - if (status != 0) { - error("Reading hci%u info failed with status 0x%02x (%s)", - index, status, mgmt_errstr(status)); - goto done; - } - - if (len < sizeof(*rp)) { - error("Too small info reply (%u bytes)", len); - goto done; - } - - print("hci%u:\tPrimary controller", index); - - ba2str(&rp->bdaddr, addr); - print("\taddr %s version %u manufacturer %u class 0x%02x%02x%02x", - addr, rp->version, le16_to_cpu(rp->manufacturer), - rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]); - - supported_settings = le32_to_cpu(rp->supported_settings); - print("\tsupported settings: %s", settings2str(supported_settings)); - - current_settings = le32_to_cpu(rp->current_settings); - print("\tcurrent settings: %s", settings2str(current_settings)); - - print("\tname %s", rp->name); - print("\tshort name %s", rp->short_name); - - if (supported_settings & MGMT_SETTING_CONFIGURATION) { - if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, - index, 0, NULL, config_options_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send read_config cmd"); - goto done; - } - return; - } - -done: - pending_index--; - - if (pending_index > 0) - return; - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void ext_info_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_ext_info *rp = param; - uint16_t index = PTR_TO_UINT(user_data); - uint32_t supported_settings, current_settings; - char addr[18]; - - if (status != 0) { - error("Reading hci%u info failed with status 0x%02x (%s)", - index, status, mgmt_errstr(status)); - goto done; - } - - if (len < sizeof(*rp)) { - error("Too small info reply (%u bytes)", len); - goto done; - } - - print("hci%u:\tPrimary controller", index); - - ba2str(&rp->bdaddr, addr); - print("\taddr %s version %u manufacturer %u", - addr, rp->version, le16_to_cpu(rp->manufacturer)); - - supported_settings = le32_to_cpu(rp->supported_settings); - print("\tsupported settings: %s", settings2str(supported_settings)); - - current_settings = le32_to_cpu(rp->current_settings); - print("\tcurrent settings: %s", settings2str(current_settings)); - - if (supported_settings & MGMT_SETTING_CONFIGURATION) { - if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, - index, 0, NULL, config_options_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send read_config cmd"); - goto done; - } - return; - } - -done: - pending_index--; - - if (pending_index > 0) - return; - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void index_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_index_list *rp = param; - struct mgmt *mgmt = user_data; - uint16_t count; - unsigned int i; - - if (status != 0) { - error("Reading index list failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small index list reply (%u bytes)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - count = le16_to_cpu(rp->num_controllers); - - if (len < sizeof(*rp) + count * sizeof(uint16_t)) { - error("Index count (%u) doesn't match reply length (%u)", - count, len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Index list with %u item%s", count, count != 1 ? "s" : ""); - - for (i = 0; i < count; i++) { - uint16_t index = le16_to_cpu(rp->index[i]); - - if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL, - info_rsp, UINT_TO_PTR(index), NULL)) { - error("Unable to send read_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - pending_index++; - } - - if (!count) - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_info(int argc, char **argv) -{ - if (mgmt_index == MGMT_INDEX_NONE) { - if (!mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST, - MGMT_INDEX_NONE, 0, NULL, - index_rsp, mgmt, NULL)) { - error("Unable to send index_list cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - return; - } - - if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, mgmt_index, 0, NULL, info_rsp, - UINT_TO_PTR(mgmt_index), NULL)) { - error("Unable to send read_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void ext_index_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_ext_index_list *rp = param; - uint16_t count; - unsigned int i; - - if (status != 0) { - error("Reading ext index list failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small ext index list reply (%u bytes)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - count = get_le16(&rp->num_controllers); - - if (len < sizeof(*rp) + count * (sizeof(uint16_t) + sizeof(uint8_t))) { - error("Index count (%u) doesn't match reply length (%u)", - count, len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Extended index list with %u item%s", - count, count != 1 ? "s" : ""); - - for (i = 0; i < count; i++) { - uint16_t index = le16_to_cpu(rp->entry[i].index); - char *busstr = hci_bustostr(rp->entry[i].bus); - - switch (rp->entry[i].type) { - case 0x00: - print("Primary controller (hci%u,%s)", index, busstr); - if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INFO, - index, 0, NULL, ext_info_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send read_ext_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - pending_index++; - break; - case 0x01: - print("Unconfigured controller (hci%u,%s)", - index, busstr); - if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, - index, 0, NULL, config_info_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send read_config cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - pending_index++; - break; - case 0x02: - print("AMP controller (hci%u,%s)", index, busstr); - break; - default: - print("Type %u controller (hci%u,%s)", - rp->entry[i].type, index, busstr); - break; - } - } - - print(""); - - if (!count) - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_extinfo(int argc, char **argv) -{ - if (mgmt_index == MGMT_INDEX_NONE) { - if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INDEX_LIST, - MGMT_INDEX_NONE, 0, NULL, - ext_index_rsp, mgmt, NULL)) { - error("Unable to send ext_index_list cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - return; - } - - if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INFO, mgmt_index, 0, NULL, - ext_info_rsp, - UINT_TO_PTR(mgmt_index), NULL)) { - error("Unable to send ext_read_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void print_cap(const uint8_t *cap, uint16_t cap_len) -{ - uint16_t parsed = 0; - - while (parsed < cap_len - 1) { - uint8_t field_len = cap[0]; - - if (field_len == 0) - break; - - parsed += field_len + 1; - - if (parsed > cap_len) - break; - - switch (cap[1]) { - case 0x01: - print("\tFlags: 0x%02x", cap[2]); - break; - case 0x02: - print("\tMax Key Size (BR/EDR): %u", cap[2]); - break; - case 0x03: - print("\tMax Key Size (LE): %u", cap[2]); - break; - default: - print("\tType %u: %u byte%s", cap[1], field_len - 1, - (field_len - 1) == 1 ? "" : "s"); - break; - } - - cap += field_len + 1; - } -} - -static void sec_info_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_controller_cap *rp = param; - uint16_t index = PTR_TO_UINT(user_data); - - if (status != 0) { - error("Reading hci%u security failed with status 0x%02x (%s)", - index, status, mgmt_errstr(status)); - goto done; - } - - if (len < sizeof(*rp)) { - error("Too small info reply (%u bytes)", len); - goto done; - } - - print("Primary controller (hci%u)", index); - print("\tInfo length: %u", le16_to_cpu(rp->cap_len)); - print_cap(rp->cap, le16_to_cpu(rp->cap_len)); - -done: - pending_index--; - - if (pending_index > 0) - return; - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void sec_index_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_ext_index_list *rp = param; - uint16_t count; - unsigned int i; - - if (status != 0) { - error("Reading ext index list failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small ext index list reply (%u bytes)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - count = get_le16(&rp->num_controllers); - - if (len < sizeof(*rp) + count * (sizeof(uint16_t) + sizeof(uint8_t))) { - error("Index count (%u) doesn't match reply length (%u)", - count, len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - for (i = 0; i < count; i++) { - uint16_t index = le16_to_cpu(rp->entry[i].index); - - if (rp->entry[i].type != 0x00) - continue; - - if (!mgmt_send(mgmt, MGMT_OP_READ_CONTROLLER_CAP, - index, 0, NULL, sec_info_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send read_security_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - pending_index++; - } - - if (!count) - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_secinfo(int argc, char **argv) -{ - if (mgmt_index == MGMT_INDEX_NONE) { - if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INDEX_LIST, - MGMT_INDEX_NONE, 0, NULL, - sec_index_rsp, mgmt, NULL)) { - error("Unable to send ext_index_list cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - return; - } - - if (!mgmt_send(mgmt, MGMT_OP_READ_CONTROLLER_CAP, mgmt_index, 0, NULL, - sec_info_rsp, - UINT_TO_PTR(mgmt_index), NULL)) { - error("Unable to send read_security_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void exp_info_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_exp_features_info *rp = param; - uint16_t index = PTR_TO_UINT(user_data); - - if (status != 0) { - error("Reading hci%u exp features failed with status 0x%02x (%s)", - index, status, mgmt_errstr(status)); - goto done; - } - - if (len < sizeof(*rp)) { - error("Too small info reply (%u bytes)", len); - goto done; - } - - if (index == MGMT_INDEX_NONE) - print("Global"); - else - print("Primary controller (hci%u)", index); - - print("\tNumber of experimental features: %u", - le16_to_cpu(rp->feature_count)); - -done: - pending_index--; - - if (pending_index > 0) - return; - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void exp_index_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_ext_index_list *rp = param; - uint16_t count; - unsigned int i; - - if (status != 0) { - error("Reading ext index list failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small ext index list reply (%u bytes)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - count = get_le16(&rp->num_controllers); - - if (len < sizeof(*rp) + count * (sizeof(uint16_t) + sizeof(uint8_t))) { - error("Index count (%u) doesn't match reply length (%u)", - count, len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - for (i = 0; i < count; i++) { - uint16_t index = le16_to_cpu(rp->entry[i].index); - - if (rp->entry[i].type != 0x00) - continue; - - if (!mgmt_send(mgmt, MGMT_OP_READ_EXP_FEATURES_INFO, - index, 0, NULL, exp_info_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send read_exp_features_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - pending_index++; - } -} - -static void cmd_expinfo(int argc, char **argv) -{ - if (mgmt_index == MGMT_INDEX_NONE) { - if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INDEX_LIST, - MGMT_INDEX_NONE, 0, NULL, - exp_index_rsp, mgmt, NULL)) { - error("Unable to send ext_index_list cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (!mgmt_send(mgmt, MGMT_OP_READ_EXP_FEATURES_INFO, - MGMT_INDEX_NONE, 0, NULL, - exp_info_rsp, - UINT_TO_PTR(MGMT_INDEX_NONE), NULL)) { - error("Unable to send read_exp_features_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - pending_index++; - return; - } - - if (!mgmt_send(mgmt, MGMT_OP_READ_EXP_FEATURES_INFO, mgmt_index, - 0, NULL, exp_info_rsp, - UINT_TO_PTR(mgmt_index), NULL)) { - error("Unable to send read_exp_features_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void exp_debug_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Set debug feature failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Debug feature successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_exp_debug(int argc, char **argv) -{ - /* d4992530-b9ec-469f-ab01-6c481c47da1c */ - static const uint8_t uuid[16] = { - 0x1c, 0xda, 0x47, 0x1c, 0x48, 0x6c, 0x01, 0xab, - 0x9f, 0x46, 0xec, 0xb9, 0x30, 0x25, 0x99, 0xd4, - }; - struct mgmt_cp_set_exp_feature cp; - uint8_t val; - - if (parse_setting(argc, argv, &val) == false) - return bt_shell_noninteractive_quit(EXIT_FAILURE); - - memset(&cp, 0, sizeof(cp)); - memcpy(cp.uuid, uuid, 16); - cp.action = val; - - if (mgmt_send(mgmt, MGMT_OP_SET_EXP_FEATURE, mgmt_index, - sizeof(cp), &cp, exp_debug_rsp, NULL, NULL) == 0) { - error("Unable to send debug feature cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void exp_privacy_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Set LL privacy feature failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("LL privacy feature successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_exp_privacy(int argc, char **argv) -{ - /* 15c0a148-c273-11ea-b3de-0242ac130004 */ - static const uint8_t uuid[16] = { - 0x04, 0x00, 0x13, 0xac, 0x42, 0x02, 0xde, 0xb3, - 0xea, 0x11, 0x73, 0xc2, 0x48, 0xa1, 0xc0, 0x15, - }; - struct mgmt_cp_set_exp_feature cp; - uint8_t val; - - if (parse_setting(argc, argv, &val) == false) - return bt_shell_noninteractive_quit(EXIT_FAILURE); - - memset(&cp, 0, sizeof(cp)); - memcpy(cp.uuid, uuid, 16); - cp.action = val; - - if (mgmt_send(mgmt, MGMT_OP_SET_EXP_FEATURE, mgmt_index, - sizeof(cp), &cp, exp_privacy_rsp, NULL, NULL) == 0) { - error("Unable to send LL privacy feature cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void exp_quality_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Set Quality Report feature failed: 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Quality Report feature successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_exp_quality(int argc, char **argv) -{ - /* 330859bc-7506-492d-9370-9a6f0614037f */ - static const uint8_t uuid[16] = { - 0x7f, 0x03, 0x14, 0x06, 0x6f, 0x9a, 0x70, 0x93, - 0x2d, 0x49, 0x06, 0x75, 0xbc, 0x59, 0x08, 0x33, - }; - struct mgmt_cp_set_exp_feature cp; - uint8_t val; - - if (mgmt_index == MGMT_INDEX_NONE) { - error("BQR feature requires a valid controller index"); - return; - } - - if (parse_setting(argc, argv, &val) == false) - return bt_shell_noninteractive_quit(EXIT_FAILURE); - - if (val != 0 && val != 1) { - error("Invalid value %u", val); - return; - } - - memset(&cp, 0, sizeof(cp)); - memcpy(cp.uuid, uuid, 16); - cp.action = val; - - if (mgmt_send(mgmt, MGMT_OP_SET_EXP_FEATURE, mgmt_index, - sizeof(cp), &cp, exp_quality_rsp, NULL, NULL) == 0) { - error("Unable to send quality report feature cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void print_mgmt_tlv(void *data, void *user_data) -{ - const struct mgmt_tlv *entry = data; - char buf[256]; - - bin2hex(entry->value, entry->length, buf, sizeof(buf)); - print("Type: 0x%04x\tLength: %02hhu\tValue: %s", entry->type, - entry->length, buf); -} - -static void read_sysconfig_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - struct mgmt_tlv_list *tlv_list; - - if (status != 0) { - error("Read system configuration failed with status " - "0x%02x (%s)", status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - tlv_list = mgmt_tlv_list_load_from_buf(param, len); - if (!tlv_list) { - error("Unable to parse response of read system configuration"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - mgmt_tlv_list_foreach(tlv_list, print_mgmt_tlv, NULL); - mgmt_tlv_list_free(tlv_list); - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_read_sysconfig(int argc, char **argv) -{ - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (!mgmt_send(mgmt, MGMT_OP_READ_DEF_SYSTEM_CONFIG, index, - 0, NULL, read_sysconfig_rsp, NULL, NULL)) { - error("Unable to send read system configuration cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static bool parse_mgmt_tlv(const char *input, uint16_t *type, uint8_t *length, - uint8_t *value) -{ - int i, value_starting_pos; - - if (sscanf(input, "%4hx:%1hhu:%n", type, length, - &value_starting_pos) < 2) { - return false; - } - - input += value_starting_pos; - - if (*length * 2 != strlen(input)) - return false; - - for (i = 0; i < *length; i++) { - if (sscanf(input + i * 2, "%2hhx", &value[i]) < 1) - return false; - } - - return true; -} - -static void set_sysconfig_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != MGMT_STATUS_SUCCESS) { - error("Could not set default system configuration with status " - "0x%02x (%s)", status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Set default system configuration success"); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static bool set_sysconfig(int argc, char **argv) -{ - struct mgmt_tlv_list *tlv_list = NULL; - int i; - uint16_t index, type; - uint8_t length; - uint8_t value[256] = {}; - bool success = false; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - tlv_list = mgmt_tlv_list_new(); - if (!tlv_list) { - error("tlv_list failed to init"); - goto failed; - } - - for (i = 0; i < argc; i++) { - if (!parse_mgmt_tlv(argv[i], &type, &length, value)) { - error("failed to parse"); - goto failed; - } - - if (!mgmt_tlv_add(tlv_list, type, length, value)) { - error("failed to add"); - goto failed; - } - } - - if (!mgmt_send_tlv(mgmt, MGMT_OP_SET_DEF_SYSTEM_CONFIG, index, - tlv_list, set_sysconfig_rsp, NULL, NULL)) { - error("Failed to send \"Set Default System Configuration\"" - " command"); - goto failed; - } - - success = true; - -failed: - if (tlv_list) - mgmt_tlv_list_free(tlv_list); - - return success; -} - -static void set_sysconfig_usage(void) -{ - bt_shell_usage(); - print("Parameters:\n\t-v <type:length:value>...\n" - "e.g.:\n\tset-sysconfig -v 001a:2:1234 001f:1:00"); -} - -static void cmd_set_sysconfig(int argc, char **argv) -{ - bool success = false; - - if (strcasecmp(argv[1], "-v") == 0 && argc > 2) { - argc -= 2; - argv += 2; - success = set_sysconfig(argc, argv); - } - - if (!success) { - set_sysconfig_usage(); - bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void auto_power_enable_rsp(uint8_t status, uint16_t len, - const void *param, void *user_data) -{ - uint16_t index = PTR_TO_UINT(user_data); - - print("Successfully enabled controller with index %u", index); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void auto_power_info_rsp(uint8_t status, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_rp_read_info *rp = param; - uint16_t index = PTR_TO_UINT(user_data); - uint32_t supported_settings, current_settings, missing_settings; - uint8_t val = 0x01; - - if (status) { - error("Reading info failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - supported_settings = le32_to_cpu(rp->supported_settings); - current_settings = le32_to_cpu(rp->current_settings); - missing_settings = current_settings ^ supported_settings; - - if (missing_settings & MGMT_SETTING_BREDR) - mgmt_send(mgmt, MGMT_OP_SET_BREDR, index, sizeof(val), &val, - NULL, NULL, NULL); - - if (missing_settings & MGMT_SETTING_SSP) - mgmt_send(mgmt, MGMT_OP_SET_SSP, index, sizeof(val), &val, - NULL, NULL, NULL); - - if (missing_settings & MGMT_SETTING_LE) - mgmt_send(mgmt, MGMT_OP_SET_LE, index, sizeof(val), &val, - NULL, NULL, NULL); - - if (missing_settings & MGMT_SETTING_SECURE_CONN) - mgmt_send(mgmt, MGMT_OP_SET_SECURE_CONN, index, - sizeof(val), &val, - NULL, NULL, NULL); - - if (missing_settings & MGMT_SETTING_BONDABLE) - mgmt_send(mgmt, MGMT_OP_SET_BONDABLE, index, sizeof(val), &val, - NULL, NULL, NULL); - - if (current_settings & MGMT_SETTING_POWERED) - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - - if (!mgmt_send(mgmt, MGMT_OP_SET_POWERED, index, sizeof(val), &val, - auto_power_enable_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send set powerd cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void auto_power_index_evt(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - uint16_t index_filter = PTR_TO_UINT(user_data); - - if (index != index_filter) - return; - - print("New controller with index %u", index); - - if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL, - auto_power_info_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send read info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void auto_power_index_rsp(uint8_t status, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_rp_read_index_list *rp = param; - uint16_t index = PTR_TO_UINT(user_data); - uint16_t i, count; - bool found = false; - - if (status) { - error("Reading index list failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - count = le16_to_cpu(rp->num_controllers); - for (i = 0; i < count; i++) { - if (le16_to_cpu(rp->index[i]) == index) - found = true; - } - - if (!found) { - print("Waiting for index %u to appear", index); - - mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, index, - auto_power_index_evt, - UINT_TO_PTR(index), NULL); - return; - } - - print("Found controller with index %u", index); - - if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL, - auto_power_info_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send read info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_auto_power(int argc, char **argv) -{ - int index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (!mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL, - auto_power_index_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send read index list cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void get_flags_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_get_device_flags *rp = param; - - if (status != 0) { - error("Get device flags failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Supported Flags: 0x%08x", rp->supported_flags); - print("Current Flags: 0x%08x", rp->current_flags); - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option get_flags_options[] = { - { "help", 0, 0, 'h' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_get_flags(int argc, char **argv) -{ - struct mgmt_cp_get_device_flags cp; - uint8_t type = BDADDR_BREDR; - char addr[18]; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+t:h", get_flags_options, - NULL)) != -1) { - switch (opt) { - case 't': - type = strtol(optarg, NULL, 0); - break; - case 'h': - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - default: - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - - ba2str(&cp.addr.bdaddr, addr); - print("Get device flag of %s (%s)", addr, typestr(cp.addr.type)); - - if (mgmt_send(mgmt, MGMT_OP_GET_DEVICE_FLAGS, index, sizeof(cp), &cp, - get_flags_rsp, NULL, NULL) == 0) { - error("Unable to send Get Device Flags command"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void set_flags_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("Set device flags failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - bt_shell_noninteractive_quit(EXIT_FAILURE); - } - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option set_flags_options[] = { - { "help", 0, 0, 'h' }, - { "type", 1, 0, 't' }, - { "flags", 1, 0, 'f' }, - { 0, 0, 0, 0 } -}; - -static void cmd_set_flags(int argc, char **argv) -{ - struct mgmt_cp_set_device_flags cp; - uint8_t type = BDADDR_BREDR; - uint32_t flags = 0; - char addr[18]; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+f:t:h", set_flags_options, - NULL)) != -1) { - switch (opt) { - case 'f': - flags = strtol(optarg, NULL, 0); - break; - case 't': - type = strtol(optarg, NULL, 0); - break; - case 'h': - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - default: - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - cp.current_flags = flags; - - ba2str(&cp.addr.bdaddr, addr); - print("Set device flag of %s (%s)", addr, typestr(cp.addr.type)); - - if (mgmt_send(mgmt, MGMT_OP_SET_DEVICE_FLAGS, index, sizeof(cp), &cp, - set_flags_rsp, NULL, NULL) == 0) { - error("Unable to send Set Device Flags command"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - -} - -/* Wrapper to get the index and opcode to the response callback */ -struct command_data { - uint16_t id; - uint16_t op; - void (*callback) (uint16_t id, uint16_t op, uint8_t status, - uint16_t len, const void *param); -}; - -static void cmd_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - struct command_data *data = user_data; - - data->callback(data->op, data->id, status, len, param); -} - -static unsigned int send_cmd(struct mgmt *mgmt, uint16_t op, uint16_t id, - uint16_t len, const void *param, - void (*cb)(uint16_t id, uint16_t op, - uint8_t status, uint16_t len, - const void *param)) -{ - struct command_data *data; - unsigned int send_id; - - data = new0(struct command_data, 1); - if (!data) - return 0; - - data->id = id; - data->op = op; - data->callback = cb; - - send_id = mgmt_send(mgmt, op, id, len, param, cmd_rsp, data, free); - if (send_id == 0) - free(data); - - return send_id; -} - -static void setting_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len, - const void *param) -{ - const uint32_t *rp = param; - - if (status != 0) { - error("%s for hci%u failed with status 0x%02x (%s)", - mgmt_opstr(op), id, status, mgmt_errstr(status)); - goto done; - } - - if (len < sizeof(*rp)) { - error("Too small %s response (%u bytes)", - mgmt_opstr(op), len); - goto done; - } - - print("hci%u %s complete, settings: %s", id, mgmt_opstr(op), - settings2str(get_le32(rp))); - -done: - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_setting(uint16_t op, int argc, char **argv) -{ - int index; - uint8_t val; - - if (parse_setting(argc, argv, &val) == false) - return bt_shell_noninteractive_quit(EXIT_FAILURE); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (send_cmd(mgmt, op, index, sizeof(val), &val, setting_rsp) == 0) { - error("Unable to send %s cmd", mgmt_opstr(op)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_power(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_POWERED, argc, argv); -} - -static void cmd_discov(int argc, char **argv) -{ - struct mgmt_cp_set_discoverable cp; - uint16_t index; - - memset(&cp, 0, sizeof(cp)); - - if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0) - cp.val = 1; - else if (strcasecmp(argv[1], "off") == 0) - cp.val = 0; - else if (strcasecmp(argv[1], "limited") == 0) - cp.val = 2; - else - cp.val = atoi(argv[1]); - - if (argc > 2) - cp.timeout = htobs(atoi(argv[2])); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (send_cmd(mgmt, MGMT_OP_SET_DISCOVERABLE, index, sizeof(cp), &cp, - setting_rsp) == 0) { - error("Unable to send set_discoverable cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_connectable(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_CONNECTABLE, argc, argv); -} - -static void cmd_fast_conn(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_FAST_CONNECTABLE, argc, argv); -} - -static void cmd_bondable(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_BONDABLE, argc, argv); -} - -static void cmd_linksec(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_LINK_SECURITY, argc, argv); -} - -static void cmd_ssp(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_SSP, argc, argv); -} - -static void cmd_sc(int argc, char **argv) -{ - uint8_t val; - uint16_t index; - - if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0) - val = 1; - else if (strcasecmp(argv[1], "off") == 0) - val = 0; - else if (strcasecmp(argv[1], "only") == 0) - val = 2; - else - val = atoi(argv[1]); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (send_cmd(mgmt, MGMT_OP_SET_SECURE_CONN, index, - sizeof(val), &val, setting_rsp) == 0) { - error("Unable to send set_secure_conn cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_hs(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_HS, argc, argv); -} - -static void cmd_le(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_LE, argc, argv); -} - -static void cmd_advertising(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_ADVERTISING, argc, argv); -} - -static void cmd_bredr(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_BREDR, argc, argv); -} - -static void cmd_privacy(int argc, char **argv) -{ - struct mgmt_cp_set_privacy cp; - uint16_t index; - - if (parse_setting(argc, argv, &cp.privacy) == false) - return bt_shell_noninteractive_quit(EXIT_FAILURE); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (argc > 2) { - if (hex2bin(argv[2], cp.irk, - sizeof(cp.irk)) != sizeof(cp.irk)) { - error("Invalid key format"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } else { - int fd; - - fd = open("/dev/urandom", O_RDONLY); - if (fd < 0) { - error("open(/dev/urandom): %s", strerror(errno)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (read(fd, cp.irk, sizeof(cp.irk)) != sizeof(cp.irk)) { - error("Reading from urandom failed"); - close(fd); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - close(fd); - } - - if (send_cmd(mgmt, MGMT_OP_SET_PRIVACY, index, sizeof(cp), &cp, - setting_rsp) == 0) { - error("Unable to send Set Privacy command"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void exp_offload_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Set offload codec failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Offload codec feature successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_exp_offload_codecs(int argc, char **argv) -{ - /* a6695ace-ee7f-4fb9-881a-5fac66c629af */ - static const uint8_t uuid[16] = { - 0xaf, 0x29, 0xc6, 0x66, 0xac, 0x5f, 0x1a, 0x88, - 0xb9, 0x4f, 0x7f, 0xee, 0xce, 0x5a, 0x69, 0xa6, - }; - - struct mgmt_cp_set_exp_feature cp; - uint8_t val; - uint16_t index; - - if (parse_setting(argc, argv, &val) == false) - return bt_shell_noninteractive_quit(EXIT_FAILURE); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - memcpy(cp.uuid, uuid, 16); - cp.action = val; - - if (mgmt_send(mgmt, MGMT_OP_SET_EXP_FEATURE, index, - sizeof(cp), &cp, exp_offload_rsp, NULL, NULL) == 0) { - error("Unable to send offload codecs feature cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void class_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len, - const void *param) -{ - const struct mgmt_ev_class_of_dev_changed *rp = param; - - if (len == 0 && status != 0) { - error("%s failed, status 0x%02x (%s)", - mgmt_opstr(op), status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Unexpected %s len %u", mgmt_opstr(op), len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("%s succeeded. Class 0x%02x%02x%02x", mgmt_opstr(op), - rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_class(int argc, char **argv) -{ - uint8_t class[2]; - uint16_t index; - - class[0] = atoi(argv[1]); - class[1] = atoi(argv[2]); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (send_cmd(mgmt, MGMT_OP_SET_DEV_CLASS, index, sizeof(class), class, - class_rsp) == 0) { - error("Unable to send set_dev_class cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void disconnect_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_disconnect *rp = param; - char addr[18]; - - if (len == 0 && status != 0) { - error("Disconnect failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Invalid disconnect response length (%u)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - ba2str(&rp->addr.bdaddr, addr); - - if (status == 0) - print("%s disconnected", addr); - else - error("Disconnecting %s failed with status 0x%02x (%s)", - addr, status, mgmt_errstr(status)); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option disconnect_options[] = { - { "help", 0, 0, 'h' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_disconnect(int argc, char **argv) -{ - struct mgmt_cp_disconnect cp; - uint8_t type = BDADDR_BREDR; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+t:h", disconnect_options, - NULL)) != -1) { - switch (opt) { - case 't': - type = strtol(optarg, NULL, 0); - break; - case 'h': - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - default: - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } - - argv += optind; - optind = 0; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - - if (mgmt_send(mgmt, MGMT_OP_DISCONNECT, index, sizeof(cp), &cp, - disconnect_rsp, NULL, NULL) == 0) { - error("Unable to send disconnect cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void con_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_get_connections *rp = param; - uint16_t count, i; - - if (len < sizeof(*rp)) { - error("Too small (%u bytes) get_connections rsp", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - count = get_le16(&rp->conn_count); - if (len != sizeof(*rp) + count * sizeof(struct mgmt_addr_info)) { - error("Invalid get_connections length (count=%u, len=%u)", - count, len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - for (i = 0; i < count; i++) { - char addr[18]; - - ba2str(&rp->addr[i].bdaddr, addr); - - print("%s type %s", addr, typestr(rp->addr[i].type)); - } - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_con(int argc, char **argv) -{ - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (mgmt_send(mgmt, MGMT_OP_GET_CONNECTIONS, index, 0, NULL, - con_rsp, NULL, NULL) == 0) { - error("Unable to send get_connections cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void find_service_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("Start Service Discovery failed: status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Service discovery started"); - discovery = true; -} - -static struct option find_service_options[] = { - { "help", no_argument, 0, 'h' }, - { "le-only", no_argument, 0, 'l' }, - { "bredr-only", no_argument, 0, 'b' }, - { "uuid", required_argument, 0, 'u' }, - { "rssi", required_argument, 0, 'r' }, - { 0, 0, 0, 0 } -}; - -static void uuid_to_uuid128(uuid_t *uuid128, const uuid_t *uuid) -{ - if (uuid->type == SDP_UUID16) - sdp_uuid16_to_uuid128(uuid128, uuid); - else if (uuid->type == SDP_UUID32) - sdp_uuid32_to_uuid128(uuid128, uuid); - else - memcpy(uuid128, uuid, sizeof(*uuid)); -} - -#define MAX_UUIDS 4 - -static void cmd_find_service(int argc, char **argv) -{ - struct mgmt_cp_start_service_discovery *cp; - uint8_t buf[sizeof(*cp) + 16 * MAX_UUIDS]; - uuid_t uuid; - uint128_t uint128; - uuid_t uuid128; - uint8_t type = SCAN_TYPE_DUAL; - int8_t rssi; - uint16_t count; - int opt; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - rssi = 127; - count = 0; - - while ((opt = getopt_long(argc, argv, "+lbu:r:h", - find_service_options, NULL)) != -1) { - switch (opt) { - case 'l': - type &= ~SCAN_TYPE_BREDR; - type |= SCAN_TYPE_LE; - break; - case 'b': - type |= SCAN_TYPE_BREDR; - type &= ~SCAN_TYPE_LE; - break; - case 'u': - if (count == MAX_UUIDS) { - print("Max %u UUIDs supported", MAX_UUIDS); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (bt_string2uuid(&uuid, optarg) < 0) { - print("Invalid UUID: %s", optarg); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - cp = (void *) buf; - uuid_to_uuid128(&uuid128, &uuid); - ntoh128((uint128_t *) uuid128.value.uuid128.data, - &uint128); - htob128(&uint128, (uint128_t *) cp->uuids[count++]); - break; - case 'r': - rssi = atoi(optarg); - break; - case 'h': - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - default: - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } - - optind = 0; - - cp = (void *) buf; - cp->type = type; - cp->rssi = rssi; - cp->uuid_count = cpu_to_le16(count); - - if (mgmt_send(mgmt, MGMT_OP_START_SERVICE_DISCOVERY, index, - sizeof(*cp) + count * 16, cp, - find_service_rsp, NULL, NULL) == 0) { - error("Unable to send start_service_discovery cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void find_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("Unable to start discovery. status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Discovery started"); - discovery = true; -} - -static struct option find_options[] = { - { "help", 0, 0, 'h' }, - { "le-only", 1, 0, 'l' }, - { "bredr-only", 1, 0, 'b' }, - { "limited", 1, 0, 'L' }, - { 0, 0, 0, 0 } -}; - -static void cmd_find(int argc, char **argv) -{ - struct mgmt_cp_start_discovery cp; - uint8_t op = MGMT_OP_START_DISCOVERY; - uint8_t type = SCAN_TYPE_DUAL; - int opt; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - while ((opt = getopt_long(argc, argv, "+lbLh", find_options, - NULL)) != -1) { - switch (opt) { - case 'l': - type &= ~SCAN_TYPE_BREDR; - type |= SCAN_TYPE_LE; - break; - case 'b': - type |= SCAN_TYPE_BREDR; - type &= ~SCAN_TYPE_LE; - break; - case 'L': - op = MGMT_OP_START_LIMITED_DISCOVERY; - break; - case 'h': - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - default: - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } - - optind = 0; - - memset(&cp, 0, sizeof(cp)); - cp.type = type; - - if (mgmt_send(mgmt, op, index, sizeof(cp), &cp, find_rsp, - NULL, NULL) == 0) { - error("Unable to send start_discovery cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void stop_find_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("Stop Discovery failed: status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - } - - print("Discovery stopped"); - discovery = false; - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option stop_find_options[] = { - { "help", 0, 0, 'h' }, - { "le-only", 1, 0, 'l' }, - { "bredr-only", 1, 0, 'b' }, - { 0, 0, 0, 0 } -}; - -static void cmd_stop_find(int argc, char **argv) -{ - struct mgmt_cp_stop_discovery cp; - uint8_t type = SCAN_TYPE_DUAL; - int opt; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - while ((opt = getopt_long(argc, argv, "+lbh", stop_find_options, - NULL)) != -1) { - switch (opt) { - case 'l': - type &= ~SCAN_TYPE_BREDR; - type |= SCAN_TYPE_LE; - break; - case 'b': - type |= SCAN_TYPE_BREDR; - type &= ~SCAN_TYPE_LE; - break; - case 'h': - default: - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - } - } - - optind = 0; - - memset(&cp, 0, sizeof(cp)); - cp.type = type; - - if (mgmt_send(mgmt, MGMT_OP_STOP_DISCOVERY, index, sizeof(cp), &cp, - stop_find_rsp, NULL, NULL) == 0) { - error("Unable to send stop_discovery cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void name_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Unable to set local name with status 0x%02x (%s)", - status, mgmt_errstr(status)); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_name(int argc, char **argv) -{ - struct mgmt_cp_set_local_name cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - strncpy((char *) cp.name, argv[1], HCI_MAX_NAME_LENGTH); - if (argc > 2) - strncpy((char *) cp.short_name, argv[2], - MGMT_MAX_SHORT_NAME_LENGTH - 1); - - if (mgmt_send(mgmt, MGMT_OP_SET_LOCAL_NAME, index, sizeof(cp), &cp, - name_rsp, NULL, NULL) == 0) { - error("Unable to send set_name cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void pair_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_pair_device *rp = param; - char addr[18]; - - if (len == 0 && status != 0) { - error("Pairing failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Unexpected pair_rsp len %u", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - ba2str(&rp->addr.bdaddr, addr); - - if (status) - error("Pairing with %s (%s) failed. status 0x%02x (%s)", - addr, typestr(rp->addr.type), status, - mgmt_errstr(status)); - else - print("Paired with %s (%s)", addr, typestr(rp->addr.type)); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option pair_options[] = { - { "help", 0, 0, 'h' }, - { "capability", 1, 0, 'c' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_pair(int argc, char **argv) -{ - struct mgmt_cp_pair_device cp; - uint8_t cap = 0x01; - uint8_t type = BDADDR_BREDR; - char addr[18]; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+c:t:h", pair_options, - NULL)) != -1) { - switch (opt) { - case 'c': - cap = strtol(optarg, NULL, 0); - break; - case 't': - type = strtol(optarg, NULL, 0); - break; - case 'h': - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - default: - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - cp.io_cap = cap; - - ba2str(&cp.addr.bdaddr, addr); - print("Pairing with %s (%s)", addr, typestr(cp.addr.type)); - - if (mgmt_send(mgmt, MGMT_OP_PAIR_DEVICE, index, sizeof(cp), &cp, - pair_rsp, NULL, NULL) == 0) { - error("Unable to send pair_device cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cancel_pair_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_addr_info *rp = param; - char addr[18]; - - if (len == 0 && status != 0) { - error("Cancel Pairing failed with 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Unexpected cancel_pair_rsp len %u", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - ba2str(&rp->bdaddr, addr); - - if (status) - error("Cancel Pairing with %s (%s) failed. 0x%02x (%s)", - addr, typestr(rp->type), status, - mgmt_errstr(status)); - else - print("Pairing Cancelled with %s", addr); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option cancel_pair_options[] = { - { "help", 0, 0, 'h' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_cancel_pair(int argc, char **argv) -{ - struct mgmt_addr_info cp; - uint8_t type = BDADDR_BREDR; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+t:h", cancel_pair_options, - NULL)) != -1) { - switch (opt) { - case 't': - type = strtol(optarg, NULL, 0); - break; - case 'h': - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - default: - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.bdaddr); - cp.type = type; - - if (mgmt_reply(mgmt, MGMT_OP_CANCEL_PAIR_DEVICE, index, sizeof(cp), &cp, - cancel_pair_rsp, NULL, NULL) == 0) { - error("Unable to send cancel_pair_device cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void unpair_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_unpair_device *rp = param; - char addr[18]; - - if (len == 0 && status != 0) { - error("Unpair device failed. status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Unexpected unpair_device_rsp len %u", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - ba2str(&rp->addr.bdaddr, addr); - - if (status) - error("Unpairing %s failed. status 0x%02x (%s)", - addr, status, mgmt_errstr(status)); - else - print("%s unpaired", addr); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option unpair_options[] = { - { "help", 0, 0, 'h' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_unpair(int argc, char **argv) -{ - struct mgmt_cp_unpair_device cp; - uint8_t type = BDADDR_BREDR; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+t:h", unpair_options, - NULL)) != -1) { - switch (opt) { - case 't': - type = strtol(optarg, NULL, 0); - break; - case 'h': - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - default: - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - cp.disconnect = 1; - - if (mgmt_send(mgmt, MGMT_OP_UNPAIR_DEVICE, index, sizeof(cp), &cp, - unpair_rsp, NULL, NULL) == 0) { - error("Unable to send unpair_device cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void keys_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Load keys failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Keys successfully loaded"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_keys(int argc, char **argv) -{ - struct mgmt_cp_load_link_keys cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - - if (mgmt_send(mgmt, MGMT_OP_LOAD_LINK_KEYS, index, sizeof(cp), &cp, - keys_rsp, NULL, NULL) == 0) { - error("Unable to send load_keys cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void ltks_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Load keys failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Long term keys successfully loaded"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_ltks(int argc, char **argv) -{ - struct mgmt_cp_load_long_term_keys cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - - if (mgmt_send(mgmt, MGMT_OP_LOAD_LONG_TERM_KEYS, index, sizeof(cp), &cp, - ltks_rsp, NULL, NULL) == 0) { - error("Unable to send load_ltks cmd"); - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - } -} - -static void irks_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Load IRKs failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Identity Resolving Keys successfully loaded"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option irks_options[] = { - { "help", 0, 0, 'h' }, - { "local", 1, 0, 'l' }, - { "file", 1, 0, 'f' }, - { 0, 0, 0, 0 } -}; - -#define MAX_IRKS 4 - -static void cmd_irks(int argc, char **argv) -{ - struct mgmt_cp_load_irks *cp; - uint8_t buf[sizeof(*cp) + 23 * MAX_IRKS]; - uint16_t count, local_index; - char path[PATH_MAX]; - int opt; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cp = (void *) buf; - count = 0; - - while ((opt = getopt_long(argc, argv, "+l:f:h", - irks_options, NULL)) != -1) { - switch (opt) { - case 'l': - if (count >= MAX_IRKS) { - error("Number of IRKs exceeded"); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - if (strlen(optarg) > 3 && - strncasecmp(optarg, "hci", 3) == 0) - local_index = atoi(optarg + 3); - else - local_index = atoi(optarg); - snprintf(path, sizeof(path), - "/sys/kernel/debug/bluetooth/hci%u/identity", - local_index); - if (!load_identity(path, &cp->irks[count])) { - error("Unable to load identity"); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - count++; - break; - case 'f': - if (count >= MAX_IRKS) { - error("Number of IRKs exceeded"); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - if (!load_identity(optarg, &cp->irks[count])) { - error("Unable to load identities"); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - count++; - break; - case 'h': - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - default: - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } - - optind = 0; - - cp->irk_count = cpu_to_le16(count); - - if (mgmt_send(mgmt, MGMT_OP_LOAD_IRKS, index, - sizeof(*cp) + count * 23, cp, - irks_rsp, NULL, NULL) == 0) { - error("Unable to send load_irks cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void block_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len, - const void *param) -{ - const struct mgmt_addr_info *rp = param; - char addr[18]; - - if (len == 0 && status != 0) { - error("%s failed, status 0x%02x (%s)", - mgmt_opstr(op), status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Unexpected %s len %u", mgmt_opstr(op), len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - ba2str(&rp->bdaddr, addr); - - if (status) - error("%s %s (%s) failed. status 0x%02x (%s)", - mgmt_opstr(op), addr, typestr(rp->type), - status, mgmt_errstr(status)); - else - print("%s %s succeeded", mgmt_opstr(op), addr); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option block_options[] = { - { "help", 0, 0, 'h' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_block(int argc, char **argv) -{ - struct mgmt_cp_block_device cp; - uint8_t type = BDADDR_BREDR; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+t:h", block_options, - NULL)) != -1) { - switch (opt) { - case 't': - type = strtol(optarg, NULL, 0); - break; - case 'h': - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - default: - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - - if (send_cmd(mgmt, MGMT_OP_BLOCK_DEVICE, index, sizeof(cp), &cp, - block_rsp) == 0) { - error("Unable to send block_device cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_unblock(int argc, char **argv) -{ - struct mgmt_cp_unblock_device cp; - uint8_t type = BDADDR_BREDR; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+t:h", block_options, - NULL)) != -1) { - switch (opt) { - case 't': - type = strtol(optarg, NULL, 0); - break; - case 'h': - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - default: - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - - if (send_cmd(mgmt, MGMT_OP_UNBLOCK_DEVICE, index, sizeof(cp), &cp, - block_rsp) == 0) { - error("Unable to send unblock_device cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_add_uuid(int argc, char **argv) -{ - struct mgmt_cp_add_uuid cp; - uint128_t uint128; - uuid_t uuid, uuid128; - uint16_t index; - - if (argc < 3) { - print("UUID and service hint needed"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (bt_string2uuid(&uuid, argv[1]) < 0) { - print("Invalid UUID: %s", argv[1]); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - memset(&cp, 0, sizeof(cp)); - - uuid_to_uuid128(&uuid128, &uuid); - ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128); - htob128(&uint128, (uint128_t *) cp.uuid); - - cp.svc_hint = atoi(argv[2]); - - if (send_cmd(mgmt, MGMT_OP_ADD_UUID, index, sizeof(cp), &cp, - class_rsp) == 0) { - error("Unable to send add_uuid cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_remove_uuid(int argc, char **argv) -{ - struct mgmt_cp_remove_uuid cp; - uint128_t uint128; - uuid_t uuid, uuid128; - uint16_t index; - - if (argc < 2) { - print("UUID needed"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (bt_string2uuid(&uuid, argv[1]) < 0) { - print("Invalid UUID: %s", argv[1]); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - memset(&cp, 0, sizeof(cp)); - - uuid_to_uuid128(&uuid128, &uuid); - ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128); - htob128(&uint128, (uint128_t *) cp.uuid); - - if (send_cmd(mgmt, MGMT_OP_REMOVE_UUID, index, sizeof(cp), &cp, - class_rsp) == 0) { - error("Unable to send remove_uuid cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_clr_uuids(int argc, char **argv) -{ - char *uuid_any = "00000000-0000-0000-0000-000000000000"; - char *rm_argv[] = { "rm-uuid", uuid_any, NULL }; - - cmd_remove_uuid(2, rm_argv); -} - -static void local_oob_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_local_oob_data *rp = param; - char str[33]; - - if (status != 0) { - error("Read Local OOB Data failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small (%u bytes) read_local_oob rsp", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - bin2hex(rp->hash192, 16, str, sizeof(str)); - print("Hash C from P-192: %s", str); - - bin2hex(rp->rand192, 16, str, sizeof(str)); - print("Randomizer R with P-192: %s", str); - - if (len < sizeof(*rp)) - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - - bin2hex(rp->hash256, 16, str, sizeof(str)); - print("Hash C from P-256: %s", str); - - bin2hex(rp->rand256, 16, str, sizeof(str)); - print("Randomizer R with P-256: %s", str); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_local_oob(int argc, char **argv) -{ - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_DATA, index, 0, NULL, - local_oob_rsp, NULL, NULL) == 0) { - error("Unable to send read_local_oob cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void remote_oob_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_addr_info *rp = param; - char addr[18]; - - if (status != 0) { - error("Add Remote OOB Data failed: 0x%02x (%s)", - status, mgmt_errstr(status)); - return; - } - - if (len < sizeof(*rp)) { - error("Too small (%u bytes) add_remote_oob rsp", len); - return; - } - - ba2str(&rp->bdaddr, addr); - print("Remote OOB data added for %s (%u)", addr, rp->type); -} - -static struct option remote_oob_opt[] = { - { "help", 0, 0, '?' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_remote_oob(int argc, char **argv) -{ - struct mgmt_cp_add_remote_oob_data cp; - int opt; - uint16_t index; - - memset(&cp, 0, sizeof(cp)); - cp.addr.type = BDADDR_BREDR; - - while ((opt = getopt_long(argc, argv, "+t:r:R:h:H:", - remote_oob_opt, NULL)) != -1) { - switch (opt) { - case 't': - cp.addr.type = strtol(optarg, NULL, 0); - break; - case 'r': - hex2bin(optarg, cp.rand192, 16); - break; - case 'h': - hex2bin(optarg, cp.hash192, 16); - break; - case 'R': - hex2bin(optarg, cp.rand256, 16); - break; - case 'H': - hex2bin(optarg, cp.hash256, 16); - break; - default: - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - str2ba(argv[0], &cp.addr.bdaddr); - - print("Adding OOB data for %s (%s)", argv[0], typestr(cp.addr.type)); - - if (mgmt_send(mgmt, MGMT_OP_ADD_REMOTE_OOB_DATA, index, - sizeof(cp), &cp, remote_oob_rsp, - NULL, NULL) == 0) { - error("Unable to send add_remote_oob cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void did_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Set Device ID failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Device ID successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_did(int argc, char **argv) -{ - struct mgmt_cp_set_device_id cp; - uint16_t vendor, product, version , source; - int result; - uint16_t index; - - result = sscanf(argv[1], "bluetooth:%4hx:%4hx:%4hx", &vendor, &product, - &version); - if (result == 3) { - source = 0x0001; - goto done; - } - - result = sscanf(argv[1], "usb:%4hx:%4hx:%4hx", &vendor, &product, - &version); - if (result == 3) { - source = 0x0002; - goto done; - } - - return; -done: - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cp.source = htobs(source); - cp.vendor = htobs(vendor); - cp.product = htobs(product); - cp.version = htobs(version); - - if (mgmt_send(mgmt, MGMT_OP_SET_DEVICE_ID, index, sizeof(cp), &cp, - did_rsp, NULL, NULL) == 0) { - error("Unable to send set_device_id cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void static_addr_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Set static address failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Static address successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_static_addr(int argc, char **argv) -{ - struct mgmt_cp_set_static_address cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - str2ba(argv[1], &cp.bdaddr); - - if (mgmt_send(mgmt, MGMT_OP_SET_STATIC_ADDRESS, index, sizeof(cp), &cp, - static_addr_rsp, NULL, NULL) == 0) { - error("Unable to send set_static_address cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void options_rsp(uint16_t op, uint16_t id, uint8_t status, - uint16_t len, const void *param) -{ - const uint32_t *rp = param; - - if (status != 0) { - error("%s for hci%u failed with status 0x%02x (%s)", - mgmt_opstr(op), id, status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small %s response (%u bytes)", - mgmt_opstr(op), len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("hci%u %s complete, options: %s", id, mgmt_opstr(op), - options2str(get_le32(rp))); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_public_addr(int argc, char **argv) -{ - struct mgmt_cp_set_public_address cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - str2ba(argv[1], &cp.bdaddr); - - if (send_cmd(mgmt, MGMT_OP_SET_PUBLIC_ADDRESS, index, sizeof(cp), &cp, - options_rsp) == 0) { - error("Unable to send Set Public Address cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_ext_config(int argc, char **argv) -{ - struct mgmt_cp_set_external_config cp; - uint16_t index; - - if (parse_setting(argc, argv, &cp.config) == false) - return bt_shell_noninteractive_quit(EXIT_FAILURE); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (send_cmd(mgmt, MGMT_OP_SET_EXTERNAL_CONFIG, index, sizeof(cp), &cp, - options_rsp) == 0) { - error("Unable to send Set External Config cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_debug_keys(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_DEBUG_KEYS, argc, argv); -} - -static void conn_info_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_get_conn_info *rp = param; char addr[18]; - - if (len == 0 && status != 0) { - error("Get Conn Info failed, status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Unexpected Get Conn Info len %u", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - ba2str(&rp->addr.bdaddr, addr); - - if (status) { - error("Get Conn Info for %s (%s) failed. status 0x%02x (%s)", - addr, typestr(rp->addr.type), - status, mgmt_errstr(status)); - } else { - print("Connection Information for %s (%s)", - addr, typestr(rp->addr.type)); - print("\tRSSI %d\tTX power %d\tmaximum TX power %d", - rp->rssi, rp->tx_power, rp->max_tx_power); - } - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option conn_info_options[] = { - { "help", 0, 0, 'h' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_conn_info(int argc, char **argv) -{ - struct mgmt_cp_get_conn_info cp; - uint8_t type = BDADDR_BREDR; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+t:h", conn_info_options, - NULL)) != -1) { - switch (opt) { - case 't': - type = strtol(optarg, NULL, 0); - break; - case 'h': - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - default: - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - - if (mgmt_send(mgmt, MGMT_OP_GET_CONN_INFO, index, sizeof(cp), &cp, - conn_info_rsp, NULL, NULL) == 0) { - error("Unable to send get_conn_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void io_cap_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Could not set IO Capability with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("IO Capabilities successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_io_cap(int argc, char **argv) -{ - struct mgmt_cp_set_io_capability cp; - uint8_t cap; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cap = strtol(argv[1], NULL, 0); - memset(&cp, 0, sizeof(cp)); - cp.io_capability = cap; - - if (mgmt_send(mgmt, MGMT_OP_SET_IO_CAPABILITY, index, sizeof(cp), &cp, - io_cap_rsp, NULL, NULL) == 0) { - error("Unable to send set-io-cap cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void scan_params_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Set scan parameters failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Scan parameters successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_scan_params(int argc, char **argv) -{ - struct mgmt_cp_set_scan_params cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cp.interval = strtol(argv[1], NULL, 0); - cp.window = strtol(argv[2], NULL, 0); - - if (mgmt_send(mgmt, MGMT_OP_SET_SCAN_PARAMS, index, sizeof(cp), &cp, - scan_params_rsp, NULL, NULL) == 0) { - error("Unable to send set_scan_params cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void clock_info_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_get_clock_info *rp = param; - - if (len < sizeof(*rp)) { - error("Unexpected Get Clock Info len %u", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (status) { - error("Get Clock Info failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Local Clock: %u", le32_to_cpu(rp->local_clock)); - print("Piconet Clock: %u", le32_to_cpu(rp->piconet_clock)); - print("Accurary: %u", le16_to_cpu(rp->accuracy)); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_clock_info(int argc, char **argv) -{ - struct mgmt_cp_get_clock_info cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - - if (argc > 1) - str2ba(argv[1], &cp.addr.bdaddr); - - if (mgmt_send(mgmt, MGMT_OP_GET_CLOCK_INFO, index, sizeof(cp), &cp, - clock_info_rsp, NULL, NULL) == 0) { - error("Unable to send get_clock_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void add_device_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Add device failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option add_device_options[] = { - { "help", 0, 0, 'h' }, - { "action", 1, 0, 'a' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_add_device(int argc, char **argv) -{ - struct mgmt_cp_add_device cp; - uint8_t action = 0x00; - uint8_t type = BDADDR_BREDR; - char addr[18]; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+a:t:h", add_device_options, - NULL)) != -1) { - switch (opt) { - case 'a': - action = strtol(optarg, NULL, 0); - break; - case 't': - type = strtol(optarg, NULL, 0); - break; - case 'h': - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - default: - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - cp.action = action; - - ba2str(&cp.addr.bdaddr, addr); - print("Adding device with %s (%s)", addr, typestr(cp.addr.type)); - - if (mgmt_send(mgmt, MGMT_OP_ADD_DEVICE, index, sizeof(cp), &cp, - add_device_rsp, NULL, NULL) == 0) { - error("Unable to send add device command"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void remove_device_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Remove device failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option del_device_options[] = { - { "help", 0, 0, 'h' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_del_device(int argc, char **argv) -{ - struct mgmt_cp_remove_device cp; - uint8_t type = BDADDR_BREDR; - char addr[18]; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+t:h", del_device_options, - NULL)) != -1) { - switch (opt) { - case 't': - type = strtol(optarg, NULL, 0); - break; - case 'h': - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - default: - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - - ba2str(&cp.addr.bdaddr, addr); - print("Removing device with %s (%s)", addr, typestr(cp.addr.type)); - - if (mgmt_send(mgmt, MGMT_OP_REMOVE_DEVICE, index, sizeof(cp), &cp, - remove_device_rsp, NULL, NULL) == 0) { - error("Unable to send remove device command"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_clr_devices(int argc, char **argv) -{ - char *bdaddr_any = "00:00:00:00:00:00"; - char *rm_argv[] = { "del-device", bdaddr_any, NULL }; - - cmd_del_device(2, rm_argv); -} - -static void local_oob_ext_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_local_oob_ext_data *rp = param; - uint16_t eir_len; - - if (status != 0) { - error("Read Local OOB Ext Data failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small (%u bytes) read_local_oob_ext rsp", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - eir_len = le16_to_cpu(rp->eir_len); - if (len != sizeof(*rp) + eir_len) { - error("local_oob_ext: expected %zu bytes, got %u bytes", - sizeof(*rp) + eir_len, len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print_eir(rp->eir, eir_len); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_bredr_oob(int argc, char **argv) -{ - struct mgmt_cp_read_local_oob_ext_data cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cp.type = SCAN_TYPE_BREDR; - - if (!mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, - index, sizeof(cp), &cp, - local_oob_ext_rsp, NULL, NULL)) { - error("Unable to send read_local_oob_ext cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_le_oob(int argc, char **argv) -{ - struct mgmt_cp_read_local_oob_ext_data cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cp.type = SCAN_TYPE_LE; - - if (!mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, - index, sizeof(cp), &cp, - local_oob_ext_rsp, NULL, NULL)) { - error("Unable to send read_local_oob_ext cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static const char *adv_flags_str[] = { - "connectable", - "general-discoverable", - "limited-discoverable", - "managed-flags", - "tx-power", - "scan-rsp-appearance", - "scan-rsp-local-name", - "Secondary-channel-1M", - "Secondary-channel-2M", - "Secondary-channel-CODED", -}; - -static const char *adv_flags2str(uint32_t flags) -{ - static char str[256]; - unsigned i; - int off; - - off = 0; - str[0] = '\0'; - - for (i = 0; i < NELEM(adv_flags_str); i++) { - if ((flags & (1 << i)) != 0) - off += snprintf(str + off, sizeof(str) - off, "%s ", - adv_flags_str[i]); - } - - return str; -} - -static void adv_features_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_adv_features *rp = param; - uint32_t supported_flags; - - if (status != 0) { - error("Reading adv features failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small adv features reply (%u bytes)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp) + rp->num_instances * sizeof(uint8_t)) { - error("Instances count (%u) doesn't match reply length (%u)", - rp->num_instances, len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - supported_flags = le32_to_cpu(rp->supported_flags); - print("Supported flags: %s", adv_flags2str(supported_flags)); - print("Max advertising data len: %u", rp->max_adv_data_len); - print("Max scan response data len: %u", rp->max_scan_rsp_len); - print("Max instances: %u", rp->max_instances); - - print("Instances list with %u item%s", rp->num_instances, - rp->num_instances != 1 ? "s" : ""); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_advinfo(int argc, char **argv) -{ - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (!mgmt_send(mgmt, MGMT_OP_READ_ADV_FEATURES, index, 0, NULL, - adv_features_rsp, NULL, NULL)) { - error("Unable to send advertising features command"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void adv_size_info_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_get_adv_size_info *rp = param; - uint32_t flags; - - if (status != 0) { - error("Reading adv size info failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small adv size info reply (%u bytes)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - flags = le32_to_cpu(rp->flags); - print("Instance: %u", rp->instance); - print("Flags: %s", adv_flags2str(flags)); - print("Max advertising data len: %u", rp->max_adv_data_len); - print("Max scan response data len: %u", rp->max_scan_rsp_len); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void advsize_usage(void) -{ - bt_shell_usage(); - print("Options:\n" - "\t -c, --connectable \"connectable\" flag\n" - "\t -g, --general-discov \"general-discoverable\" flag\n" - "\t -l, --limited-discov \"limited-discoverable\" flag\n" - "\t -m, --managed-flags \"managed-flags\" flag\n" - "\t -p, --tx-power \"tx-power\" flag\n" - "\t -a, --appearance \"appearance\" flag\n" - "\t -n, --local-name \"local-name\" flag"); -} - -static struct option advsize_options[] = { - { "help", 0, 0, 'h' }, - { "connectable", 0, 0, 'c' }, - { "general-discov", 0, 0, 'g' }, - { "limited-discov", 0, 0, 'l' }, - { "managed-flags", 0, 0, 'm' }, - { "tx-power", 0, 0, 'p' }, - { "appearance", 0, 0, 'a' }, - { "local-name", 0, 0, 'n' }, - { 0, 0, 0, 0} -}; - -static void cmd_advsize(int argc, char **argv) -{ - struct mgmt_cp_get_adv_size_info cp; - uint8_t instance; - uint32_t flags = 0; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+cglmphna", - advsize_options, NULL)) != -1) { - switch (opt) { - case 'c': - flags |= MGMT_ADV_FLAG_CONNECTABLE; - break; - case 'g': - flags |= MGMT_ADV_FLAG_DISCOV; - break; - case 'l': - flags |= MGMT_ADV_FLAG_LIMITED_DISCOV; - break; - case 'm': - flags |= MGMT_ADV_FLAG_MANAGED_FLAGS; - break; - case 'p': - flags |= MGMT_ADV_FLAG_TX_POWER; - break; - case 'a': - flags |= MGMT_ADV_FLAG_APPEARANCE; - break; - case 'n': - flags |= MGMT_ADV_FLAG_LOCAL_NAME; - break; - default: - advsize_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc != 1) { - advsize_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - instance = strtol(argv[0], NULL, 0); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - - cp.instance = instance; - cp.flags = cpu_to_le32(flags); - - if (!mgmt_send(mgmt, MGMT_OP_GET_ADV_SIZE_INFO, index, sizeof(cp), &cp, - adv_size_info_rsp, NULL, NULL)) { - error("Unable to send advertising size info command"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void add_adv_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_add_advertising *rp = param; - - if (status != 0) { - error("Add Advertising failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Invalid Add Advertising response length (%u)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Instance added: %u", rp->instance); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void add_adv_usage(void) -{ - bt_shell_usage(); - print("Options:\n" - "\t -u, --uuid <uuid> Service UUID\n" - "\t -d, --adv-data <data> Advertising Data bytes\n" - "\t -s, --scan-rsp <data> Scan Response Data bytes\n" - "\t -t, --timeout <timeout> Timeout in seconds\n" - "\t -D, --duration <duration> Duration in seconds\n" - "\t -P, --phy <phy> Phy type, Specify 1M/2M/CODED\n" - "\t -c, --connectable \"connectable\" flag\n" - "\t -g, --general-discov \"general-discoverable\" flag\n" - "\t -l, --limited-discov \"limited-discoverable\" flag\n" - "\t -n, --scan-rsp-local-name \"local-name\" flag\n" - "\t -a, --scan-rsp-appearance \"appearance\" flag\n" - "\t -m, --managed-flags \"managed-flags\" flag\n" - "\t -p, --tx-power \"tx-power\" flag\n" - "e.g.:\n" - "\tadd-adv -u 180d -u 180f -d 080954657374204C45 1"); -} - -static struct option add_adv_options[] = { - { "help", 0, 0, 'h' }, - { "uuid", 1, 0, 'u' }, - { "adv-data", 1, 0, 'd' }, - { "scan-rsp", 1, 0, 's' }, - { "timeout", 1, 0, 't' }, - { "duration", 1, 0, 'D' }, - { "phy", 1, 0, 'P' }, - { "connectable", 0, 0, 'c' }, - { "general-discov", 0, 0, 'g' }, - { "limited-discov", 0, 0, 'l' }, - { "managed-flags", 0, 0, 'm' }, - { "tx-power", 0, 0, 'p' }, - { 0, 0, 0, 0} -}; - -static bool parse_bytes(char *optarg, uint8_t **bytes, size_t *len) -{ - unsigned i; - - if (!optarg) { - add_adv_usage(); - return false; - } - - *len = strlen(optarg); - - if (*len % 2) { - error("Malformed data"); - return false; - } - - *len /= 2; - if (*len > UINT8_MAX) { - error("Data too long"); - return false; - } - - *bytes = malloc(*len); - if (!*bytes) { - error("Failed to allocate memory"); - return false; - } - - for (i = 0; i < *len; i++) { - if (sscanf(optarg + (i * 2), "%2hhx", *bytes + i) != 1) { - error("Invalid data"); - free(*bytes); - *bytes = NULL; - return false; - } - } - - return true; -} - -#define MAX_AD_UUID_BYTES 32 - -static void cmd_add_adv(int argc, char **argv) -{ - struct mgmt_cp_add_advertising *cp = NULL; - int opt; - uint8_t *adv_data = NULL, *scan_rsp = NULL; - size_t adv_len = 0, scan_rsp_len = 0; - size_t cp_len; - uint8_t uuids[MAX_AD_UUID_BYTES]; - size_t uuid_bytes = 0; - uint8_t uuid_type = 0; - uint16_t timeout = 0, duration = 0; - uint8_t instance; - uuid_t uuid; - bool success = false; - bool quit = true; - uint32_t flags = 0; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+u:d:s:t:D:P:cglmphna", - add_adv_options, NULL)) != -1) { - switch (opt) { - case 'u': - if (bt_string2uuid(&uuid, optarg) < 0) { - print("Invalid UUID: %s", optarg); - goto done; - } - - if (uuid_type && uuid_type != uuid.type) { - print("UUID types must be consistent"); - goto done; - } - - if (uuid.type == SDP_UUID16) { - if (uuid_bytes + 2 >= MAX_AD_UUID_BYTES) { - print("Too many UUIDs"); - goto done; - } - - put_le16(uuid.value.uuid16, uuids + uuid_bytes); - uuid_bytes += 2; - } else if (uuid.type == SDP_UUID128) { - if (uuid_bytes + 16 >= MAX_AD_UUID_BYTES) { - print("Too many UUIDs"); - goto done; - } - - bswap_128(uuid.value.uuid128.data, - uuids + uuid_bytes); - uuid_bytes += 16; - } else { - printf("Unsupported UUID type"); - goto done; - } - - if (!uuid_type) - uuid_type = uuid.type; - - break; - case 'd': - if (adv_len) { - print("Only one adv-data option allowed"); - goto done; - } - - if (!parse_bytes(optarg, &adv_data, &adv_len)) - goto done; - break; - case 's': - if (scan_rsp_len) { - print("Only one scan-rsp option allowed"); - goto done; - } - - if (!parse_bytes(optarg, &scan_rsp, &scan_rsp_len)) - goto done; - break; - case 't': - timeout = strtol(optarg, NULL, 0); - break; - case 'D': - duration = strtol(optarg, NULL, 0); - break; - case 'c': - flags |= MGMT_ADV_FLAG_CONNECTABLE; - break; - case 'g': - flags |= MGMT_ADV_FLAG_DISCOV; - break; - case 'l': - flags |= MGMT_ADV_FLAG_LIMITED_DISCOV; - break; - case 'm': - flags |= MGMT_ADV_FLAG_MANAGED_FLAGS; - break; - case 'p': - flags |= MGMT_ADV_FLAG_TX_POWER; - break; - case 'n': - flags |= MGMT_ADV_FLAG_LOCAL_NAME; - break; - case 'a': - flags |= MGMT_ADV_FLAG_APPEARANCE; - break; - case 'P': - if (strcasecmp(optarg, "1M") == 0) - flags |= MGMT_ADV_FLAG_SEC_1M; - else if (strcasecmp(optarg, "2M") == 0) - flags |= MGMT_ADV_FLAG_SEC_2M; - else if (strcasecmp(optarg, "CODED") == 0) - flags |= MGMT_ADV_FLAG_SEC_CODED; - else - goto done; - break; - case 'h': - success = true; - /* fall through */ - default: - add_adv_usage(); - optind = 0; - goto done; - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc != 1) { - add_adv_usage(); - goto done; - } - - if (uuid_bytes) - uuid_bytes += 2; - - instance = strtol(argv[0], NULL, 0); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cp_len = sizeof(*cp) + uuid_bytes + adv_len + scan_rsp_len; - cp = malloc0(cp_len); - if (!cp) - goto done; - - cp->instance = instance; - put_le32(flags, &cp->flags); - put_le16(timeout, &cp->timeout); - put_le16(duration, &cp->duration); - cp->adv_data_len = adv_len + uuid_bytes; - cp->scan_rsp_len = scan_rsp_len; - - if (uuid_bytes) { - cp->data[0] = uuid_bytes - 1; - cp->data[1] = uuid_type == SDP_UUID16 ? 0x03 : 0x07; - memcpy(cp->data + 2, uuids, uuid_bytes - 2); - } - - if (adv_len) - memcpy(cp->data + uuid_bytes, adv_data, adv_len); - - if (scan_rsp_len) - memcpy(cp->data + uuid_bytes + adv_len, scan_rsp, scan_rsp_len); - - if (!mgmt_send(mgmt, MGMT_OP_ADD_ADVERTISING, index, cp_len, cp, - add_adv_rsp, NULL, NULL)) { - error("Unable to send \"Add Advertising\" command"); - goto done; - } - - quit = false; - -done: - free(adv_data); - free(scan_rsp); - free(cp); - - if (quit) - bt_shell_noninteractive_quit(success ? EXIT_SUCCESS : EXIT_FAILURE); -} - -static void rm_adv_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_remove_advertising *rp = param; - - if (status != 0) { - error("Remove Advertising failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Invalid Remove Advertising response length (%u)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Instance removed: %u", rp->instance); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_rm_adv(int argc, char **argv) -{ - struct mgmt_cp_remove_advertising cp; - uint8_t instance; - uint16_t index; - - instance = strtol(argv[1], NULL, 0); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - - cp.instance = instance; - - if (!mgmt_send(mgmt, MGMT_OP_REMOVE_ADVERTISING, index, sizeof(cp), &cp, - rm_adv_rsp, NULL, NULL)) { - error("Unable to send \"Remove Advertising\" command"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_clr_adv(int argc, char **argv) -{ - char *all_instances = "0"; - char *rm_argv[] = { "rm-adv", all_instances, NULL }; - - cmd_rm_adv(2, rm_argv); -} - -static void add_ext_adv_params_rsp(uint8_t status, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_rp_add_ext_adv_params *rp = param; - - if (status != 0) { - error("Add Ext Adv Params failed status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Invalid Add Ext Adv Params response length (%u)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Instance added: %u", rp->instance); - print("Tx Power: %u", rp->tx_power); - print("Max adv data len: %u", rp->max_adv_data_len); - print("Max scan resp len: %u", rp->max_scan_rsp_len); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void add_ext_adv_params_usage(void) -{ - bt_shell_usage(); - print("Options:\n" - "\t -d, --duration <duration> Duration in seconds\n" - "\t -t, --timeout <timeout> Timeout in seconds\n" - "\t -r, --min-interval <valr> Minimum interval\n" - "\t -x, --max-interval <valr> Maximum interval\n" - "\t -w, --tx-power <power> Tx power\n" - "\t -P, --phy <phy> Phy type, Specify 1M/2M/CODED\n" - "\t -c, --connectable \"connectable\" flag\n" - "\t -g, --general-discov \"general-discoverable\" flag\n" - "\t -l, --limited-discov \"limited-discoverable\" flag\n" - "\t -m, --managed-flags \"managed-flags\" flag\n" - "\t -p, --add-tx-power \"tx-power\" flag\n" - "\t -a, --scan-rsp-appearance \"appearance\" flag\n" - "\t -n, --scan-rsp-local-name \"local-name\" flag\n" - "\t -s, --adv-scan-rsp \"scan resp in adv\" flag\n" - "\t -h, --help Show help\n" - "e.g.:\n" - "\tadd-ext-adv-params -r 0x801 -x 0x802 -P 2M -g 1"); -} - -static struct option add_ext_adv_params_options[] = { - { "help", 0, 0, 'h' }, - { "duration", 1, 0, 'd' }, - { "timeout", 1, 0, 't' }, - { "min-internal", 1, 0, 'r' }, - { "max-interval", 1, 0, 'x' }, - { "tx-power", 1, 0, 'w' }, - { "phy", 1, 0, 'P' }, - { "connectable", 0, 0, 'c' }, - { "general-discov", 0, 0, 'g' }, - { "limited-discov", 0, 0, 'l' }, - { "scan-rsp-local-name", 0, 0, 'n' }, - { "scan-rsp-appearance", 0, 0, 'a' }, - { "managed-flags", 0, 0, 'm' }, - { "add-tx-power", 0, 0, 'p' }, - { "adv-scan-rsp", 0, 0, 's' }, - { 0, 0, 0, 0} -}; - -static void cmd_add_ext_adv_params(int argc, char **argv) -{ - struct mgmt_cp_add_ext_adv_params *cp = NULL; - int opt; - uint16_t timeout = 0, duration = 0; - uint8_t instance; - bool success = false; - bool quit = true; - uint32_t flags = 0; - uint32_t min_interval = 0; - uint32_t max_interval = 0; - uint8_t tx_power = 0; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "d:t:r:x:w:P:cglmpansh", - add_ext_adv_params_options, NULL)) != -1) { - switch (opt) { - case 'd': - duration = strtol(optarg, NULL, 0); - flags |= MGMT_ADV_PARAM_DURATION; - break; - case 't': - timeout = strtol(optarg, NULL, 0); - flags |= MGMT_ADV_PARAM_TIMEOUT; - break; - case 'r': - min_interval = strtol(optarg, NULL, 0); - break; - case 'x': - max_interval = strtol(optarg, NULL, 0); - break; - case 'w': - tx_power = strtol(optarg, NULL, 0); - flags |= MGMT_ADV_PARAM_TX_POWER; - break; - case 'P': - if (strcasecmp(optarg, "1M") == 0) - flags |= MGMT_ADV_FLAG_SEC_1M; - else if (strcasecmp(optarg, "2M") == 0) - flags |= MGMT_ADV_FLAG_SEC_2M; - else if (strcasecmp(optarg, "CODED") == 0) - flags |= MGMT_ADV_FLAG_SEC_CODED; - else - goto done; - break; - case 'c': - flags |= MGMT_ADV_FLAG_CONNECTABLE; - break; - case 'g': - flags |= MGMT_ADV_FLAG_DISCOV; - break; - case 'l': - flags |= MGMT_ADV_FLAG_LIMITED_DISCOV; - break; - case 'n': - flags |= MGMT_ADV_FLAG_LOCAL_NAME; - break; - case 'a': - flags |= MGMT_ADV_FLAG_APPEARANCE; - break; - case 'm': - flags |= MGMT_ADV_FLAG_MANAGED_FLAGS; - break; - case 'p': - flags |= MGMT_ADV_FLAG_TX_POWER; - break; - case 's': - flags |= MGMT_ADV_PARAM_SCAN_RSP; - break; - case 'h': - success = true; - /* fall through */ - default: - add_ext_adv_params_usage(); - optind = 0; - goto done; - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc != 1) { - add_ext_adv_params_usage(); - goto done; - } - - /* Only if both min_interval and max_interval are defined */ - if (min_interval && max_interval) - flags |= MGMT_ADV_PARAM_INTERVALS; - - instance = strtol(argv[0], NULL, 0); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cp = malloc0(sizeof(*cp)); - if (!cp) - goto done; - - cp->instance = instance; - put_le32(flags, &cp->flags); - put_le16(timeout, &cp->timeout); - put_le16(duration, &cp->duration); - put_le32(min_interval, &cp->min_interval); - put_le32(max_interval, &cp->max_interval); - cp->tx_power = tx_power; - - if (!mgmt_send(mgmt, MGMT_OP_ADD_EXT_ADV_PARAMS, index, sizeof(*cp), cp, - add_ext_adv_params_rsp, NULL, NULL)) { - error("Unable to send \"Add Ext Advertising Params\" command"); - goto done; - } - - quit = false; - -done: - free(cp); - - if (quit) - bt_shell_noninteractive_quit(success ? - EXIT_SUCCESS : EXIT_FAILURE); -} - -static void add_ext_adv_data_rsp(uint8_t status, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_rp_add_ext_adv_data *rp = param; - - if (status != 0) { - error("Add Ext Advertising Data failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Invalid Add Ext Advertising Data response length (%u)", - len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Instance added: %u", rp->instance); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void add_ext_adv_data_usage(void) -{ - bt_shell_usage(); - print("Options:\n" - "\t -u, --uuid <uuid> Service UUID\n" - "\t -d, --adv-data <data> Advertising Data bytes\n" - "\t -s, --scan-rsp <data> Scan Response Data bytes\n" - "e.g.:\n" - "\tadd-ext-adv-data -u 180d -u 180f -d 080954657374204C45 1"); -} - -static struct option add_ext_adv_data_options[] = { - { "help", 0, 0, 'h' }, - { "uuid", 1, 0, 'u' }, - { "adv-data", 1, 0, 'd' }, - { "scan-rsp", 1, 0, 's' }, - { 0, 0, 0, 0} -}; - -static void cmd_add_ext_adv_data(int argc, char **argv) -{ - struct mgmt_cp_add_ext_adv_data *cp = NULL; - int opt; - uint8_t *adv_data = NULL, *scan_rsp = NULL; - size_t adv_len = 0, scan_rsp_len = 0; - size_t cp_len; - uint8_t uuids[MAX_AD_UUID_BYTES]; - size_t uuid_bytes = 0; - uint8_t uuid_type = 0; - uint8_t instance; - uuid_t uuid; - bool success = false; - bool quit = true; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+u:d:s:h", - add_ext_adv_data_options, NULL)) != -1) { - switch (opt) { - case 'u': - if (bt_string2uuid(&uuid, optarg) < 0) { - print("Invalid UUID: %s", optarg); - goto done; - } - - if (uuid_type && uuid_type != uuid.type) { - print("UUID types must be consistent"); - goto done; - } - - if (uuid.type == SDP_UUID16) { - if (uuid_bytes + 2 >= MAX_AD_UUID_BYTES) { - print("Too many UUIDs"); - goto done; - } - - put_le16(uuid.value.uuid16, uuids + uuid_bytes); - uuid_bytes += 2; - } else if (uuid.type == SDP_UUID128) { - if (uuid_bytes + 16 >= MAX_AD_UUID_BYTES) { - print("Too many UUIDs"); - goto done; - } - - bswap_128(uuid.value.uuid128.data, - uuids + uuid_bytes); - uuid_bytes += 16; - } else { - printf("Unsupported UUID type"); - goto done; - } - - if (!uuid_type) - uuid_type = uuid.type; - - break; - case 'd': - if (adv_len) { - print("Only one adv-data option allowed"); - goto done; - } - - if (!parse_bytes(optarg, &adv_data, &adv_len)) - goto done; - break; - case 's': - if (scan_rsp_len) { - print("Only one scan-rsp option allowed"); - goto done; - } - - if (!parse_bytes(optarg, &scan_rsp, &scan_rsp_len)) - goto done; - break; - case 'h': - success = true; - /* fall through */ - default: - add_ext_adv_data_usage(); - optind = 0; - goto done; - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc != 1) { - add_ext_adv_data_usage(); - goto done; - } - - if (uuid_bytes) - uuid_bytes += 2; - - instance = strtol(argv[0], NULL, 0); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cp_len = sizeof(*cp) + uuid_bytes + adv_len + scan_rsp_len; - cp = malloc0(cp_len); - if (!cp) - goto done; - - cp->instance = instance; - cp->adv_data_len = adv_len + uuid_bytes; - cp->scan_rsp_len = scan_rsp_len; - - if (uuid_bytes) { - cp->data[0] = uuid_bytes - 1; - cp->data[1] = uuid_type == SDP_UUID16 ? 0x03 : 0x07; - memcpy(cp->data + 2, uuids, uuid_bytes - 2); - } - - if (adv_len) - memcpy(cp->data + uuid_bytes, adv_data, adv_len); - - if (scan_rsp_len) - memcpy(cp->data + uuid_bytes + adv_len, scan_rsp, scan_rsp_len); - - if (!mgmt_send(mgmt, MGMT_OP_ADD_EXT_ADV_DATA, index, cp_len, cp, - add_ext_adv_data_rsp, NULL, NULL)) { - error("Unable to send \"Add Ext Advertising Data\" command"); - goto done; - } - - quit = false; - -done: - free(adv_data); - free(scan_rsp); - free(cp); - - if (quit) - bt_shell_noninteractive_quit(success ? - EXIT_SUCCESS : EXIT_FAILURE); -} - -static void appearance_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Could not set Appearance with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Appearance successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_appearance(int argc, char **argv) -{ - struct mgmt_cp_set_appearance cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cp.appearance = cpu_to_le16(strtol(argv[1], NULL, 0)); - - if (mgmt_send(mgmt, MGMT_OP_SET_APPEARANCE, index, sizeof(cp), &cp, - appearance_rsp, NULL, NULL) == 0) { - error("Unable to send appearance cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static const char *phys_str[] = { - "BR1M1SLOT", - "BR1M3SLOT", - "BR1M5SLOT", - "EDR2M1SLOT", - "EDR2M3SLOT", - "EDR2M5SLOT", - "EDR3M1SLOT", - "EDR3M3SLOT", - "EDR3M5SLOT", - "LE1MTX", - "LE1MRX", - "LE2MTX", - "LE2MRX", - "LECODEDTX", - "LECODEDRX", -}; - -static const char *phys2str(uint32_t phys) -{ - static char str[256]; - unsigned int i; - int off; - - off = 0; - str[0] = '\0'; - - for (i = 0; i < NELEM(phys_str); i++) { - if ((phys & (1 << i)) != 0) - off += snprintf(str + off, sizeof(str) - off, "%s ", - phys_str[i]); - } - - return str; -} - -static bool str2phy(const char *phy_str, uint32_t *phy_val) -{ - unsigned int i; - - for (i = 0; i < NELEM(phys_str); i++) { - if (strcasecmp(phys_str[i], phy_str) == 0) { - *phy_val = (1 << i); - return true; - } - } - - return false; -} - -static void get_phy_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_get_phy_confguration *rp = param; - uint32_t supported_phys, selected_phys, configurable_phys; - - if (status != 0) { - error("Get PHY Configuration failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small get-phy reply (%u bytes)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - supported_phys = get_le32(&rp->supported_phys); - configurable_phys = get_le32(&rp->configurable_phys); - selected_phys = get_le32(&rp->selected_phys); - - print("Supported phys: %s", phys2str(supported_phys)); - print("Configurable phys: %s", phys2str(configurable_phys)); - print("Selected phys: %s", phys2str(selected_phys)); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void get_phy(void) -{ - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (mgmt_send(mgmt, MGMT_OP_GET_PHY_CONFIGURATION, index, 0, NULL, - get_phy_rsp, NULL, NULL) == 0) { - error("Unable to send Get PHY cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void set_phy_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("Could not set PHY Configuration with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("PHY Configuration successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_phy(int argc, char **argv) -{ - struct mgmt_cp_set_phy_confguration cp; - int i; - uint32_t phys = 0; - uint16_t index; - - if (argc < 2) - return get_phy(); - - for (i = 1; i < argc; i++) { - uint32_t phy_val; - - if (str2phy(argv[i], &phy_val)) - phys |= phy_val; - } - - cp.selected_phys = cpu_to_le32(phys); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (mgmt_send(mgmt, MGMT_OP_SET_PHY_CONFIGURATION, index, sizeof(cp), - &cp, set_phy_rsp, NULL, NULL) == 0) { - error("Unable to send %s cmd", - mgmt_opstr(MGMT_OP_SET_PHY_CONFIGURATION)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_wbs(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_WIDEBAND_SPEECH, argc, argv); -} - -static const char * const advmon_features_str[] = { - "Pattern monitor with logic OR.", -}; - -static const char *advmon_features2str(uint32_t features) -{ - static char str[512]; - unsigned int off, i; - - off = 0; - snprintf(str, sizeof(str), "\n\tNone"); - - for (i = 0; i < NELEM(advmon_features_str); i++) { - if ((features & (1 << i)) != 0 && off < sizeof(str)) - off += snprintf(str + off, sizeof(str) - off, "\n\t%s", - advmon_features_str[i]); - } - - return str; -} - -static void advmon_features_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_adv_monitor_features *rp = param; - uint32_t supported_features, enabled_features; - uint16_t num_handles; - int i; - - if (status != MGMT_STATUS_SUCCESS) { - error("Reading adv monitor features failed with status 0x%02x " - "(%s)", status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small adv monitor features reply (%u bytes)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - supported_features = le32_to_cpu(rp->supported_features); - enabled_features = le32_to_cpu(rp->enabled_features); - num_handles = le16_to_cpu(rp->num_handles); - - if (len < sizeof(*rp) + num_handles * sizeof(uint16_t)) { - error("Handles count (%u) doesn't match reply length (%u)", - num_handles, len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Supported features:%s", advmon_features2str(supported_features)); - print("Enabled features:%s", advmon_features2str(enabled_features)); - print("Max number of handles: %u", le16_to_cpu(rp->max_num_handles)); - print("Max number of patterns: %u", rp->max_num_patterns); - print("Handles list with %u item%s", num_handles, - num_handles == 0 ? "" : num_handles == 1 ? ":" : "s:"); - for (i = 0; i < num_handles; i++) - print("\t0x%04x ", le16_to_cpu(rp->handles[i])); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_advmon_features(int argc, char **argv) -{ - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (!mgmt_send(mgmt, MGMT_OP_READ_ADV_MONITOR_FEATURES, index, 0, NULL, - advmon_features_rsp, NULL, NULL)) { - error("Unable to send advertising monitor features command"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void advmon_add_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_add_adv_patterns_monitor *rp = param; - - if (status != MGMT_STATUS_SUCCESS) { - error("Could not add advertisement monitor with status " - "0x%02x (%s)", status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Advertisement monitor with handle:0x%04x added", - le16_to_cpu(rp->monitor_handle)); - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static bool str2pattern(struct mgmt_adv_pattern *pattern, const char *str) -{ - int type_len, offset_len, offset_end_pos, str_len; - int i, j; - char pattern_str[62] = { 0 }; - char tmp; - - if (sscanf(str, "%2hhx%n:%2hhx%n:%61s", &pattern->ad_type, &type_len, - &pattern->offset, &offset_end_pos, pattern_str) != 3) - return false; - - offset_len = offset_end_pos - type_len - 1; - str_len = strlen(pattern_str); - pattern->length = str_len / 2 + str_len % 2; - - if (type_len > 2 || offset_len > 2 || - pattern->offset + pattern->length > 31) - return false; - - for (i = 0, j = 0; i < str_len; i++, j++) { - if (sscanf(&pattern_str[i++], "%2hhx", &pattern->value[j]) - != 1) - return false; - if (i < str_len && sscanf(&pattern_str[i], "%1hhx", &tmp) != 1) - return false; - } - - return true; -} - -static struct option add_monitor_rssi_options[] = { - { "help", 0, 0, 'h' }, - { "high-threshold", 1, 0, 'R' }, - { "low-threshold", 1, 0, 'r' }, - { "high-timeout", 1, 0, 'T' }, - { "low-timeout", 1, 0, 't' }, - { "sampling", 1, 0, 's' }, - { 0, 0, 0, 0 } -}; - -static void advmon_add_pattern_usage(void) -{ - bt_shell_usage(); - print("patterns format:\n" - "\t<ad_type:offset:pattern> [patterns]\n" - "e.g.:\n" - "\tadd-pattern 0:1:c504 ff:a:9a55beef"); -} - -static void advmon_add_pattern_rssi_usage(void) -{ - bt_shell_usage(); - print("RSSI options:\n" - "\t -R, --high-threshold <dBm> " - "RSSI high threshold. Default: -70\n" - "\t -r, --low-threshold <dBm> " - "RSSI low threshold. Default: -50\n" - "\t -T, --high-timeout <s> " - "RSSI high threshold duration. Default: 0\n" - "\t -t, --low-timeout <s> " - "RSSI low threshold duration. Default: 5\n" - "\t -s, --sampling <N * 100ms> " - "RSSI sampling period. Default: 0\n" - "patterns format:\n" - "\t<ad_type:offset:pattern> [patterns]\n" - "e.g.:\n" - "\tadd-pattern-rssi -R 0xb2 -r -102 0:1:c504 ff:a:9a55beef"); -} - -static void cmd_advmon_add_pattern(int argc, char **argv) -{ - bool success = true; - uint16_t index; - int i, cp_len; - struct mgmt_cp_add_adv_monitor *cp = NULL; - - if (!strcmp(argv[1], "-h")) - goto done; - - argc -= 1; - argv += 1; - - cp_len = sizeof(*cp) + argc * sizeof(struct mgmt_adv_pattern); - cp = malloc0(cp_len); - if (!cp) { - error("Failed to alloc patterns."); - success = false; - goto done; - } - - cp->pattern_count = argc; - - for (i = 0; i < argc; i++) { - if (!str2pattern(&cp->patterns[i], argv[i])) { - error("Failed to parse monitor patterns."); - success = false; - goto done; - } - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (!mgmt_send(mgmt, MGMT_OP_ADD_ADV_PATTERNS_MONITOR, index, - cp_len, cp, advmon_add_rsp, NULL, NULL)) { - error("Unable to send Add Advertising Monitor command"); - success = false; - goto done; - } - - free(cp); - return; - -done: - free(cp); - advmon_add_pattern_usage(); - bt_shell_noninteractive_quit(success ? EXIT_SUCCESS : EXIT_FAILURE); -} - -static void cmd_advmon_add_pattern_rssi(int argc, char **argv) -{ - bool success = true; - int opt; - int8_t rssi_low = -70; - int8_t rssi_high = -50; - uint16_t rssi_low_timeout = 5; - uint16_t rssi_high_timeout = 0; - uint8_t rssi_sampling_period = 0; - uint16_t index; - int i, cp_len; - struct mgmt_cp_add_adv_patterns_monitor_rssi *cp = NULL; - - while ((opt = getopt_long(argc, argv, "+hr:R:t:T:s:", - add_monitor_rssi_options, NULL)) != -1) { - switch (opt) { - case 'h': - goto done; - case 'r': - rssi_low = strtol(optarg, NULL, 0); - break; - case 'R': - rssi_high = strtol(optarg, NULL, 0); - break; - case 't': - rssi_low_timeout = strtol(optarg, NULL, 0); - break; - case 'T': - rssi_high_timeout = strtol(optarg, NULL, 0); - break; - case 's': - rssi_sampling_period = strtol(optarg, NULL, 0); - break; - default: - success = false; - goto done; - } - } - - argc -= optind; - argv += optind; - optind = 0; - - cp_len = sizeof(*cp) + argc * sizeof(struct mgmt_adv_pattern); - cp = malloc0(cp_len); - if (!cp) { - error("Failed to alloc patterns."); - success = false; - goto done; - } - - cp->pattern_count = argc; - cp->rssi.high_threshold = rssi_high; - cp->rssi.low_threshold = rssi_low; - cp->rssi.high_threshold_timeout = htobs(rssi_high_timeout); - cp->rssi.low_threshold_timeout = htobs(rssi_low_timeout); - cp->rssi.sampling_period = rssi_sampling_period; - - for (i = 0; i < argc; i++) { - if (!str2pattern(&cp->patterns[i], argv[i])) { - error("Failed to parse monitor patterns."); - success = false; - goto done; - } - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (!mgmt_send(mgmt, MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, index, - cp_len, cp, advmon_add_rsp, NULL, NULL)) { - error("Unable to send Add Advertising Monitor RSSI command"); - success = false; - goto done; - } - - free(cp); - return; - -done: - free(cp); - optind = 0; - advmon_add_pattern_rssi_usage(); - bt_shell_noninteractive_quit(success ? EXIT_SUCCESS : EXIT_FAILURE); -} - -static void advmon_remove_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_remove_adv_monitor *rp = param; - - if (status != MGMT_STATUS_SUCCESS) { - error("Could not remove advertisement monitor with status " - "0x%02x (%s)", status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Advertisement monitor with handle: 0x%04x removed", - le16_to_cpu(rp->monitor_handle)); - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_advmon_remove(int argc, char **argv) -{ - struct mgmt_cp_remove_adv_monitor cp; - uint16_t index, monitor_handle; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (sscanf(argv[1], "%hx", &monitor_handle) != 1) { - error("Wrong formatted handle argument"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - cp.monitor_handle = cpu_to_le16(monitor_handle); - if (mgmt_send(mgmt, MGMT_OP_REMOVE_ADV_MONITOR, index, sizeof(cp), &cp, - advmon_remove_rsp, NULL, NULL) == 0) { - error("Unable to send appearance cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void register_mgmt_callbacks(struct mgmt *mgmt, uint16_t index) -{ - mgmt_register(mgmt, MGMT_EV_CONTROLLER_ERROR, index, controller_error, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, index, index_added, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_INDEX_REMOVED, index, index_removed, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_NEW_SETTINGS, index, new_settings, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_DISCOVERING, index, discovering, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_NEW_LINK_KEY, index, new_link_key, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_DEVICE_CONNECTED, index, connected, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_DEVICE_DISCONNECTED, index, disconnected, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_CONNECT_FAILED, index, conn_failed, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_AUTH_FAILED, index, auth_failed, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_CLASS_OF_DEV_CHANGED, index, - class_of_dev_changed, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_LOCAL_NAME_CHANGED, index, - local_name_changed, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_DEVICE_FOUND, index, device_found, - mgmt, NULL); - mgmt_register(mgmt, MGMT_EV_PIN_CODE_REQUEST, index, request_pin, - mgmt, NULL); - mgmt_register(mgmt, MGMT_EV_USER_CONFIRM_REQUEST, index, user_confirm, - mgmt, NULL); - mgmt_register(mgmt, MGMT_EV_USER_PASSKEY_REQUEST, index, - request_passkey, mgmt, NULL); - mgmt_register(mgmt, MGMT_EV_PASSKEY_NOTIFY, index, - passkey_notify, mgmt, NULL); - mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_ADDED, index, - unconf_index_added, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_REMOVED, index, - unconf_index_removed, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_NEW_CONFIG_OPTIONS, index, - new_config_options, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_EXT_INDEX_ADDED, index, - ext_index_added, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_EXT_INDEX_REMOVED, index, - ext_index_removed, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_LOCAL_OOB_DATA_UPDATED, index, - local_oob_data_updated, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_ADVERTISING_ADDED, index, - advertising_added, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_ADVERTISING_REMOVED, index, - advertising_removed, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_DEVICE_FLAGS_CHANGED, index, - flags_changed, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_ADV_MONITOR_ADDED, index, advmon_added, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_ADV_MONITOR_REMOVED, index, advmon_removed, - NULL, NULL); -} - -static void cmd_select(int argc, char **argv) -{ - mgmt_cancel_all(mgmt); - mgmt_unregister_all(mgmt); - - set_index(argv[1]); - - register_mgmt_callbacks(mgmt, mgmt_index); - - print("Selected index %u", mgmt_index); - - update_prompt(mgmt_index); -} - -static const struct bt_shell_menu monitor_menu = { - .name = "monitor", - .desc = "Advertisement Monitor Submenu", - .entries = { - { "features", NULL, - cmd_advmon_features, "Show advertisement monitor " - "features" }, - { "remove", "<handle>", - cmd_advmon_remove, "Remove advertisement monitor " }, - { "add-pattern", "[-h] <patterns>", - cmd_advmon_add_pattern, "Add advertisement monitor pattern" }, - { "add-pattern-rssi", "[options] <patterns>", - cmd_advmon_add_pattern_rssi, - "Add advertisement monitor pattern with RSSI options" }, - { } }, -}; - -static const struct bt_shell_menu main_menu = { - .name = "main", - .entries = { - { "select", "<index>", - cmd_select, "Select a different index" }, - { "revision", NULL, - cmd_revision, "Get the MGMT Revision" }, - { "commands", NULL, - cmd_commands, "List supported commands" }, - { "config", NULL, - cmd_config, "Show configuration info" }, - { "info", NULL, - cmd_info, "Show controller info" }, - { "extinfo", NULL, - cmd_extinfo, "Show extended controller info" }, - { "auto-power", NULL, - cmd_auto_power, "Power all available features" }, - { "power", "<on/off>", - cmd_power, "Toggle powered state" }, - { "discov", "<yes/no/limited> [timeout]", - cmd_discov, "Toggle discoverable state" }, - { "connectable", "<on/off>", - cmd_connectable, "Toggle connectable state" }, - { "fast-conn", "<on/off>", - cmd_fast_conn, "Toggle fast connectable state" }, - { "bondable", "<on/off>", - cmd_bondable, "Toggle bondable state" }, - { "pairable", "<on/off>", - cmd_bondable, "Toggle bondable state" }, - { "linksec", "<on/off>", - cmd_linksec, "Toggle link level security" }, - { "ssp", "<on/off>", - cmd_ssp, "Toggle SSP mode" }, - { "sc", "<on/off/only>", - cmd_sc, "Toogle SC support" }, - { "hs", "<on/off>", - cmd_hs, "Toggle HS support" }, - { "le", "<on/off>", - cmd_le, "Toggle LE support" }, - { "advertising", "<on/off>", - cmd_advertising, "Toggle LE advertising", }, - { "bredr", "<on/off>", - cmd_bredr, "Toggle BR/EDR support", }, - { "privacy", "<on/off> [irk]", - cmd_privacy, "Toggle privacy support" }, - { "class", "<major> <minor>", - cmd_class, "Set device major/minor class" }, - { "disconnect", "[-t type] <remote address>", - cmd_disconnect, "Disconnect device" }, - { "con", NULL, - cmd_con, "List connections" }, - { "find", "[-l|-b] [-L]", - cmd_find, "Discover nearby devices" }, - { "find-service", "[-u UUID] [-r RSSI_Threshold] [-l|-b]", - cmd_find_service, "Discover nearby service" }, - { "stop-find", "[-l|-b]", - cmd_stop_find, "Stop discovery" }, - { "name", "<name> [shortname]", - cmd_name, "Set local name" }, - { "pair", "[-c cap] [-t type] <remote address>", - cmd_pair, "Pair with a remote device" }, - { "cancelpair", "[-t type] <remote address>", - cmd_cancel_pair, "Cancel pairing" }, - { "unpair", "[-t type] <remote address>", - cmd_unpair, "Unpair device" }, - { "keys", NULL, - cmd_keys, "Load Link Keys" }, - { "ltks", NULL, - cmd_ltks, "Load Long Term Keys" }, - { "irks", "[--local index] [--file file path]", - cmd_irks, "Load Identity Resolving Keys" }, - { "block", "[-t type] <remote address>", - cmd_block, "Block Device" }, - { "unblock", "[-t type] <remote address>", - cmd_unblock, "Unblock Device" }, - { "add-uuid", "<UUID> <service class hint>", - cmd_add_uuid, "Add UUID" }, - { "rm-uuid", "<UUID>", - cmd_remove_uuid, "Remove UUID" }, - { "clr-uuids", NULL, - cmd_clr_uuids, "Clear UUIDs" }, - { "local-oob", NULL, - cmd_local_oob, "Local OOB data" }, - { "remote-oob", "[-t <addr_type>] [-r <rand192>] " - "[-h <hash192>] [-R <rand256>] " - "[-H <hash256>] <addr>", - cmd_remote_oob, "Remote OOB data" }, - { "did", "<source>:<vendor>:<product>:<version>", - cmd_did, "Set Device ID" }, - { "static-addr", "<address>", - cmd_static_addr, "Set static address" }, - { "public-addr", "<address>", - cmd_public_addr, "Set public address" }, - { "ext-config", "<on/off>", - cmd_ext_config, "External configuration" }, - { "debug-keys", "<on/off>", - cmd_debug_keys, "Toogle debug keys" }, - { "conn-info", "[-t type] <remote address>", - cmd_conn_info, "Get connection information" }, - { "io-cap", "<cap>", - cmd_io_cap, "Set IO Capability" }, - { "scan-params", "<interval> <window>", - cmd_scan_params, "Set Scan Parameters" }, - { "get-clock", "[address]", - cmd_clock_info, "Get Clock Information" }, - { "add-device", "[-a action] [-t type] <address>", - cmd_add_device, "Add Device" }, - { "del-device", "[-t type] <address>", - cmd_del_device, "Remove Device" }, - { "clr-devices", NULL, - cmd_clr_devices, "Clear Devices" }, - { "bredr-oob", NULL, - cmd_bredr_oob, "Local OOB data (BR/EDR)" }, - { "le-oob", NULL, - cmd_le_oob, "Local OOB data (LE)" }, - { "advinfo", NULL, - cmd_advinfo, "Show advertising features" }, - { "advsize", "[options] <instance_id>", - cmd_advsize, "Show advertising size info" }, - { "add-adv", "[options] <instance_id>", - cmd_add_adv, "Add advertising instance" }, - { "rm-adv", "<instance_id>", - cmd_rm_adv, "Remove advertising instance" }, - { "clr-adv", NULL, - cmd_clr_adv, "Clear advertising instances" }, - { "add-ext-adv-params", "[options] <instance_id>", - cmd_add_ext_adv_params, - "Add extended advertising params" }, - { "add-ext-adv-data", "[options] <instance_id>", - cmd_add_ext_adv_data, - "Add extended advertising data" }, - { "appearance", "<appearance>", - cmd_appearance, "Set appearance" }, - { "phy", "[LE1MTX] [LE1MRX] [LE2MTX] [LE2MRX] " - "[LECODEDTX] [LECODEDRX] " - "[BR1M1SLOT] [BR1M3SLOT] [BR1M5SLOT]" - "[EDR2M1SLOT] [EDR2M3SLOT] [EDR2M5SLOT]" - "[EDR3M1SLOT] [EDR3M3SLOT] [EDR3M5SLOT]", - cmd_phy, "Get/Set PHY Configuration" }, - { "wbs", "<on/off>", - cmd_wbs, "Toggle Wideband-Speech support"}, - { "secinfo", NULL, - cmd_secinfo, "Show security information" }, - { "expinfo", NULL, - cmd_expinfo, "Show experimental features" }, - { "exp-debug", "<on/off>", - cmd_exp_debug, "Set debug feature" }, - { "exp-privacy", "<on/off>", - cmd_exp_privacy, "Set LL privacy feature" }, - { "exp-quality", "<on/off>", cmd_exp_quality, - "Set bluetooth quality report feature" }, - { "exp-offload", "<on/off>", - cmd_exp_offload_codecs, "Toggle codec support" }, - { "read-sysconfig", NULL, - cmd_read_sysconfig, "Read System Configuration" }, - { "set-sysconfig", "<-v|-h> [options...]", - cmd_set_sysconfig, "Set System Configuration" }, - { "get-flags", "[-t type] <address>", - cmd_get_flags, "Get device flags" }, - { "set-flags", "[-f flags] [-t type] <address>", - cmd_set_flags, "Set device flags" }, - {} }, -}; - -static void mgmt_debug(const char *str, void *user_data) -{ - const char *prefix = user_data; +#include <stdlib.h> +#include <stdio.h> - print("%s%s", prefix, str); -} +#include "src/shared/shell.h" +#include "client/mgmt.h" static const char *index_option; @@ -6060,30 +45,17 @@ int main(int argc, char *argv[]) int status; bt_shell_init(argc, argv, &opt); - bt_shell_set_menu(&main_menu); - bt_shell_add_submenu(&monitor_menu); - mgmt = mgmt_new_default(); - if (!mgmt) { + if (!mgmt_add_submenu()) { fprintf(stderr, "Unable to open mgmt_socket\n"); return EXIT_FAILURE; } - if (getenv("MGMT_DEBUG")) - mgmt_set_debug(mgmt, mgmt_debug, "mgmt: ", NULL); - - if (index_option) - set_index(index_option); - - register_mgmt_callbacks(mgmt, mgmt_index); - + mgmt_set_index(index_option); bt_shell_attach(fileno(stdin)); - update_prompt(mgmt_index); status = bt_shell_run(); - mgmt_cancel_all(mgmt); - mgmt_unregister_all(mgmt); - mgmt_unref(mgmt); + mgmt_remove_submenu(); return status; } diff --git a/tools/btmgmt.rst b/tools/btmgmt.rst new file mode 100644 index 0000000000000000000000000000000000000000..0159ee128f62b7e9b382ed940ca39f13926cab79 --- /dev/null +++ b/tools/btmgmt.rst @@ -0,0 +1,79 @@ +====== +btmgmt +====== + +------------------------------------- +interactive bluetooth management tool +------------------------------------- + +:Version: BlueZ +:Copyright: Free use of this software is granted under ther terms of the GNU + Lesser General Public Licenses (LGPL). +:Date: July 2023 +:Manual section: 1 +:Manual group: Linux System Administration + +SYNOPSIS +======== + +**btmgmt** [--options] [commands] + +DESCRIPTION +=========== + +**btmgmt(1)** interactive bluetooth management tool. The tool issues commands +to the Kernel using the Bluetooth Management socket, some commands may require +net-admin capability in order to work since the Bluetooth Management interface +is considered a low-level interface meant for the likes of **bluetoothd(8)**, +it is not recommended for applications to use it directly as it may result in +unexpected behavior. + +OPTIONS +======= + +:-i/--index: Specify adapter index +:-m-/-monitor: Enable monitor output +:-t/--timeout: Timeout in seconds for non-interactive mode +:-v/--version: Display version +:-i/--init-script: Init script file +:-h/--help: Display help + +COMMANDS +======== + +:main: See **bluetoothctl-mgmt(1)** +:monitor: See **bluetoothctl-monitor(1)** + +AUTOMATION +========== + +Two common ways to automate the tool are to pass the commands directly like in +the follow example: + +.. code-block:: + + btmgmt <<EOF + list + show + EOF + +Or create a script and pass it as init-script: + +.. code-block:: + + $ vi test-script.bt + list + show + quit + :wq + $ btmgmt --init-script=test-script + +RESOURCES +========= + +http://www.bluez.org + +REPORTING BUGS +============== + +linux-bluetooth@vger.kernel.org diff --git a/tools/btpclientctl.c b/tools/btpclientctl.c index c30d5bd4e739aa10613d615c0f0376e6b1c5a2ac..eb97463148d24edeeb07b2654e10954d118ece3b 100644 --- a/tools/btpclientctl.c +++ b/tools/btpclientctl.c @@ -2340,7 +2340,7 @@ int main(int argc, char *argv[]) mainloop_add_fd(btpclientctl->server_fd, EPOLLIN, server_callback, btpclientctl, NULL); - bt_shell_set_prompt(PROMPT_ON); + bt_shell_set_prompt(PROMPT_ON, COLOR_BLUE); status = bt_shell_run(); diff --git a/tools/btsnoop.c b/tools/btsnoop.c index a0d6cf3562e9de01065c104391cb9d8c56714e9b..0bd28b65b6e10c4cec7f0c920bfc926b209bb455 100644 --- a/tools/btsnoop.c +++ b/tools/btsnoop.c @@ -283,7 +283,7 @@ next_packet: if (len < 0 || len != BTSNOOP_PKT_SIZE) goto close_input; - toread = be32toh(pkt.size); + toread = be32toh(pkt.len); flags = be32toh(pkt.flags); opcode = flags & 0x00ff; @@ -356,7 +356,7 @@ next_packet: if (len < 0 || len != BTSNOOP_PKT_SIZE) goto close_input; - toread = be32toh(pkt.size); + toread = be32toh(pkt.len); flags = be32toh(pkt.flags); opcode = flags & 0x00ff; @@ -433,7 +433,7 @@ next_packet: if (len < 0 || len != BTSNOOP_PKT_SIZE) goto close_input; - toread = be32toh(pkt.size); + toread = be32toh(pkt.len); len = read(fd, buf, toread); if (len < 0 || len != (ssize_t) toread) { @@ -448,7 +448,7 @@ next_packet: acl_flags = buf[2] >> 4; /* use only packet with ACL start flag */ - if (acl_flags & 0x02) { + if ((acl_flags & 0x02) && len > 9) { if (current_cid == 0x0040 && pdu_len > 0) { int i; if (!pdu_first) @@ -472,7 +472,7 @@ next_packet: current_cid = buf[8] << 8 | buf[7]; memcpy(pdu_buf, buf + 9, len - 9); pdu_len = len - 9; - } else if (acl_flags & 0x01) { + } else if ((acl_flags & 0x01) && len > 5) { memcpy(pdu_buf + pdu_len, buf + 5, len - 5); pdu_len += len - 5; } diff --git a/tools/ciptool.1 b/tools/ciptool.1 new file mode 100644 index 0000000000000000000000000000000000000000..7dfb68a104bb9afed7d4c84ffd67638817450049 --- /dev/null +++ b/tools/ciptool.1 @@ -0,0 +1,89 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "CIPTOOL" "1" "June 3, 2003" "BlueZ" "Linux System Administration" +.SH NAME +ciptool \- Bluetooth Common ISDN Access Profile (CIP) +.SH SYNOPSIS +.sp +\fBciptool\fP [\fIOPTIONS\fP] \fICOMMANDS\fP +.SH DESCRIPTION +.sp +\fBciptool(1)\fP is used to set up, maintain, and inspect the CIP configuration +of the Bluetooth subsystem in the Linux kernel. +.SH OPTIONS +.INDENT 0.0 +.TP +.BI \-i \ <hciX|BDADDR> +The command is applied to device \fIhciX\fP , which must be the +name or the address of an installed Bluetooth device. +.sp +If not specified, the command will be use the first +available Bluetooth device. +.TP +.B \-h\fP,\fB \-\-help +Show help options +.UNINDENT +.SH COMMANDS +.INDENT 0.0 +.TP +.B show +Display information about the connected devices. +.TP +.B search +Search for Bluetooth devices and connect to first one that offers CIP +support. +.TP +.B connect <\fIBDADDR\fP> [\fIPSM\fP] +Connect the local device to the remote Bluetooth device on the specified +\fIPSM\fP number. If no \fIPSM\fP is specified, it will use the SDP to retrieve +it from the remote device. +.TP +.B release [\fIBDADDR\fP] +Release a connection to the specific device. If no \fIBDADDR\fP is given and +only one device is connected this will be released. +.TP +.B loopback <\fIBDADDR\fP> [\fIPSM\fP] +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. +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH AUTHOR +Marcel Holtmann <marcel@holtmann.org> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/tools/example.psr b/tools/example.psr deleted file mode 100644 index bbbec73ab6f166d1998db73c7bbf13c4ba098ff1..0000000000000000000000000000000000000000 --- a/tools/example.psr +++ /dev/null @@ -1,12 +0,0 @@ -// 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/tools/hciattach.1 b/tools/hciattach.1 new file mode 100644 index 0000000000000000000000000000000000000000..f1c0d4a24e62b2270e01d03334830200ccd9c28d --- /dev/null +++ b/tools/hciattach.1 @@ -0,0 +1,258 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "HCIATTACH" "1" "Jan 22, 2002" "BlueZ" "Linux System Administration" +.SH NAME +hciattach \- attach serial devices via UART HCI to BlueZ stack +.SH SYNOPSIS +.sp +\fBhciattach\fP [\fIOPTIONS\fP] <\fItty\fP> <\fItype|id\fP> [\fIspeed\fP] [\fIflow\fP] [\fIsleep\fP] [\fIbdaddr\fP] +.sp +\fBhciattach\fP \-1 +.SH DESCRIPTION +.sp +\fBhciattach(1)\fP is used to attach a serial UART to the Bluetooth stack as HCI +transport interface. +.SH OPTIONS +.INDENT 0.0 +.TP +.B \-i +Send break +.TP +.B \-n +Don\(aqt 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 +.BI \-s \ speed +Specify an initial speed instead of the hardware default. +.TP +.B \-l +List all available configurations. +.TP +.B \-r +Set the HCI device into raw mode. The kernel and bluetooth daemon +will ignore it. +.TP +.B \-h\fP,\fB \-\-help +Show help options +.UNINDENT +.SH ARGUMENTS +.INDENT 0.0 +.TP +.B \fIshow\fP +This specifies the serial device to attach. A leading /dev can be omitted. +.sp +Examples: \fB/dev/ttyS1 ttyS2\fP +.TP +.B \fItype|id\fP +The \fItype\fP or \fIid\fP of the Bluetooth device that is to be attached, +i.e. vendor or other device specific identifier. +Currently supported types are +.UNINDENT +.TS +box center; +l|l. +T{ +\fItype\fP +T} T{ +Description +T} +_ +T{ +any +T} T{ +Unspecified HCI_UART interface, no vendor specific options +T} +_ +T{ +ericsson +T} T{ +Ericsson based modules +T} +_ +T{ +digi +T} T{ +Digianswer based cards +T} +_ +T{ +xircom +T} T{ +Xircom PCMCIA cards: Credit Card Adapter and Real Port Adapter +T} +_ +T{ +csr +T} T{ +CSR Casira serial adapter or BrainBoxes serial dongle (BL642) +T} +_ +T{ +bboxes +T} T{ +BrainBoxes PCMCIA card (BL620) +T} +_ +T{ +swave +T} T{ +Silicon Wave kits +T} +_ +T{ +bcsp +T} T{ +Serial adapters using CSR chips with BCSP serial protocol +T} +_ +T{ +ath3k +T} T{ +Atheros AR300x based serial Bluetooth device +T} +_ +T{ +intel +T} T{ +Intel Bluetooth device +T} +.TE +.TS +box center; +l|l. +T{ +.nf +Supported ID +(manufacturer id, product id) +.fi +T} T{ +Description +T} +_ +T{ +0x0105, 0x080a +T} T{ +Xircom PCMCIA cards: Credit Card Adapter and Real Port Adapter +T} +_ +T{ +0x0160, 0x0002 +T} T{ +BrainBoxes PCMCIA card (BL620) +T} +.TE +.INDENT 0.0 +.TP +.B \fIspeed\fP +The \fIspeed\fP specifies the UART speed to use. Baudrates higher than 115200bps +require vendor specific initializations that are not implemented for all +types of devices. In general the following speeds are supported: +.sp +Supported vendor devices are automatically initialised to their respective +best settings. +.UNINDENT +.TS +box center; +l. +T{ +9600 +T} +_ +T{ +19200 +T} +_ +T{ +38400 +T} +_ +T{ +57600 +T} +_ +T{ +115200 +T} +_ +T{ +230400 +T} +_ +T{ +460800 +T} +_ +T{ +921600 +T} +.TE +.INDENT 0.0 +.TP +.B \fIflow\fP +If the \fIflow\fP is appended to the list of options then hardware flow control +is forced on the serial link (\fBCRTSCTS\fP). All above mentioned device +types have flow set by default. To force no flow control use \fInoflow\fP +instead. +.TP +.B \fIsleep|nosleep\fP +Enables hardware specific power management feature. If \fIsleep\fP is appended +to the list of options then this feature is enabled. To disable this +feature use \fInosleep\fP instead. All above mentioned device types have +\fInosleep\fP set by default. +.sp +Note: This option will only be valid for hardware which support hardware +specific power management enable option from host. +.TP +.B \fIbdaddr\fP +The 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. +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH AUTHOR +Maxim Krasnyansky <maxk@qualcomm.com>, Nils Faerber <nils@kernelconcepts.de> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/tools/hciattach.c b/tools/hciattach.c index 276a4e56ef9d6c38f1652b04694d4d311f6b3740..adf79baf6ebdbf9737364138ddb8c09b569e23e8 100644 --- a/tools/hciattach.c +++ b/tools/hciattach.c @@ -26,6 +26,7 @@ #include <termios.h> #include <time.h> #include <poll.h> +#include <limits.h> #include <sys/time.h> #include <sys/param.h> #include <sys/ioctl.h> diff --git a/tools/hciattach_ath3k.c b/tools/hciattach_ath3k.c index d119155bb53b746baf3dd1bcc7d24444c82d7f04..8922b480f629835ae0001fc4a609445dd69a2ac7 100644 --- a/tools/hciattach_ath3k.c +++ b/tools/hciattach_ath3k.c @@ -16,6 +16,7 @@ #include <string.h> #include <ctype.h> #include <time.h> +#include <limits.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/types.h> diff --git a/tools/hciattach_intel.c b/tools/hciattach_intel.c index e243b3d07c5e1f202edb606b350ad8c2d9ad9f07..b68678991bf90b0f0d04a97aa47c0f7fc45fcba8 100644 --- a/tools/hciattach_intel.c +++ b/tools/hciattach_intel.c @@ -19,6 +19,7 @@ #include <string.h> #include <errno.h> #include <fcntl.h> +#include <limits.h> #include <sys/param.h> #include <sys/ioctl.h> #include <time.h> diff --git a/tools/hciattach_st.c b/tools/hciattach_st.c index 4a7186aa66336d5ff7d862886f48561ee47cfc90..def761305944e8d5162053a213e6c13ab979a5d2 100644 --- a/tools/hciattach_st.c +++ b/tools/hciattach_st.c @@ -12,6 +12,7 @@ #include <config.h> #endif +#include <limits.h> #include <stdio.h> #include <errno.h> #include <fcntl.h> diff --git a/tools/hciattach_ti.c b/tools/hciattach_ti.c index 24efceaa1ae55368dcfd1ffa5a7e4bdd840366bb..c0a0025ff8884fc606cc36eddef31ea837ce7f69 100644 --- a/tools/hciattach_ti.c +++ b/tools/hciattach_ti.c @@ -14,6 +14,7 @@ #endif #define _GNU_SOURCE +#include <limits.h> #include <stdio.h> #include <errno.h> #include <unistd.h> diff --git a/tools/hciconfig.1 b/tools/hciconfig.1 new file mode 100644 index 0000000000000000000000000000000000000000..5bd2f97f5998c56f94901124214f03c7a6d9be42 --- /dev/null +++ b/tools/hciconfig.1 @@ -0,0 +1,334 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "HCICONFIG" "1" "Nov 11, 2002" "BlueZ" "Linux System Administration" +.SH NAME +hciconfig \- Configure Bluetooth devices +.SH SYNOPSIS +.sp +\fBhciconfig\fP \-h +.sp +\fBhciconfig\fP [\-a] +.sp +\fBhciconfig\fP [\-a] \fIhciX\fP [\fICOMMAND\fP [\fIPARAMETERS\fP]] +.SH DESCRIPTION +.sp +\fBhciconfig(1)\fP is used to configure Bluetooth devices. \fIhciX\fP is the name of a +Bluetooth device installed in the system. If hciX is not given, hciconfig +prints name and basic information about all the Bluetooth devices installed +in the system. +.sp +If \fIhciX\fP is given but no command is given, it prints basic information on +device \fIhciX\fP 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 +.INDENT 0.0 +.TP +.B \-a\fP,\fB \-\-all +Print features, packet type, link policy, link mode, class, Version +other than the basic info. +.TP +.B \-h\fP,\fB \-\-help +Show help options +.UNINDENT +.SH COMMANDS +.INDENT 0.0 +.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 +.B ptype [\fItype\fP] +With no \fItype\fP , displays the current packet types. Otherwise, all the +packet types specified by \fItype\fP are set. \fItype\fP is a comma\-separated list +of packet types, where the possible packet types are \fBDM1\fP, \fBDM3\fP, +\fBDM5\fP, \fBDH1\fP, \fBDH3\fP, \fBDH5\fP, \fBHV1\fP, \fBHV2\fP, \fBHV3\fP\&. +.TP +.B name [\fIname\fP] +With no \fIname\fP, prints local name. Otherwise, sets local name to \fIname\fP\&. +.TP +.B class [\fIclass\fP] +With no \fIclass\fP, prints class of device. Otherwise, sets class of device +to \fIclass\fP\&. \fIclass\fP is a 24\-bit hex number describing the class of device, +as specified in section 1.2 of the Bluetooth Assigned Numers document. +.TP +.B voice [\fIvoice\fP] +With no \fIvoice\fP, prints voice setting. Otherwise, sets voice setting to +\fIvoice\fP\&. \fIvoice\fP is a 16\-bit hex number describing the voice setting. +.TP +.B iac [\fIiac\fP] +With no \fIiac\fP, prints the current IAC setting. Otherwise, sets the IAC to +\fIiac\fP\&. +.TP +.B inqtpl [\fIlevel\fP] +With no \fIlevel\fP, prints out the current inquiry transmit power level. +Otherwise, sets inquiry transmit power level to \fIlevel\fP\&. +.TP +.B inqmode [\fImode\fP] +.INDENT 7.0 +.INDENT 3.5 +With no \fImode\fP, prints out the current inquiry mode. Otherwise, sets +inquiry mode to \fImode\fP\&. +.UNINDENT +.UNINDENT +.TS +box center; +l|l. +T{ +\fImode\fP +T} T{ +Description +T} +_ +T{ +0 +T} T{ +Standard Inquiry +T} +_ +T{ +1 +T} T{ +Inquiry with RSSI +T} +_ +T{ +2 +T} T{ +Inquiry with RSSI or Extended Inquiry +T} +.TE +.TP +.B inqdata [\fIdata\fP] +With no \fIdata\fP, prints out the current inquiry data. Otherwise, sets +inquiry data to \fIdata\fP\&. +.TP +.B inqtype [\fItype\fP] +With no \fItype\fP, prints out the current inquiry scan type. Otherwise, sets +inquiry scan type to \fItype\fP\&. +.TP +.B inqparams [\fIwin:int\fP] +With no \fIwin:int\fP, prints inquiry scan window and interval. Otherwise, +sets inquiry scan window to \fIwin\fP slots and inquiry scan interval to +\fIint\fP slots. +.TP +.B pageparms [\fIwin:int\fP] +With no \fIwin:int\fP, prints page scan window and interval. Otherwise, +sets page scan window to \fIwin\fP slots and page scan interval to \fIint\fP slots. +.TP +.B pageto [\fIto\fP] +With no \fIto\fP, prints page timeout. Otherwise, sets page timeout \fIto\fP to +slots. +.TP +.B afhmode [\fImode\fP] +With no \fImode\fP, prints out the current AFH mode. Otherwise, sets AFH mode +to \fImode\fP\&. +.UNINDENT +.TS +box center; +l|l. +T{ +\fImode\fP +T} T{ +Description +T} +_ +T{ +0 +T} T{ +Enable +T} +_ +T{ +1 +T} T{ +Disable +T} +.TE +.INDENT 0.0 +.TP +.B sspmode [\fImode\fP] +With no \fImode\fP, prints out the current Simple Pairing mode. Otherwise, +sets Simple Pairing mode to \fImode\fP\&. +.UNINDENT +.TS +box center; +l|l. +T{ +\fImode\fP +T} T{ +Description +T} +_ +T{ +0 +T} T{ +Enable +T} +_ +T{ +1 +T} T{ +Disable +T} +.TE +.INDENT 0.0 +.TP +.B aclmtu \fImtu:pkt\fP +Sets ACL MTU to \fImtu\fP bytes and ACL buffer size to \fIpkt\fP packets. +.TP +.B scomtu \fImtu:pkt\fP +Sets SCO MTU to \fImtu\fP bytes and SCO buffer size to \fIpkt\fP packets. +.TP +.B delkey <\fIbdaddr\fP> +This command deletes the stored link key for \fIbdaddr\fP from the device. +.TP +.B oobdata +Get local OOB data (invalidates previously read data). +.TP +.B commands +Display supported commands. +.TP +.B features +Display device features. +.TP +.B version +Display version information. +.TP +.B revision +Display revision information. +.TP +.B lm [\fImode\fP] +With no \fImode\fP, prints link mode. \fBCENTRAL\fP or \fBPERIPHERAL\fP mean, +respectively, to ask to become central or to remain peripheral when a +connection request comes in. The additional keyword \fBACCEPT\fP means that +baseband connections will be accepted even if there are no listening +\fIAF_BLUETOOTH\fP sockets. \fImode\fP is \fBNONE\fP or a comma\-separated list of +keywords, where possible keywords are \fBCENTRAL\fP and \fBACCEPT\fP\&. \fBNONE\fP +sets link policy to the default behaviour of remaining peripheral and not +accepting baseband connections when there are no listening \fIAF_BLUETOOTH\fP +sockets. If \fBCENTRAL\fP is present, the device will ask to become central +if a connection request comes in. If \fBACCEPT\fP is present, the device will +accept baseband connections even when there are no listening \fIAF_BLUETOOTH\fP +sockets. +.TP +.B block <\fIbdaddr\fP> +Add a device to the reject list +.TP +.B unblock <\fIbdaddr\fP> +Remove a device from the reject list +.TP +.B lerandaddr <\fIbdaddr\fP> +Set LE Random Address +.TP +.B leadv [\fItype\fP] +Enable LE Advertising. +.UNINDENT +.TS +box center; +l|l. +T{ +\fItype\fP +T} T{ +Description +T} +_ +T{ +0 +T} T{ +Connectable undirected advertising (default) +T} +_ +T{ +3 +T} T{ +Non connectable undirected advertising +T} +.TE +.INDENT 0.0 +.TP +.B noleadv +Disable LE Advertising +.TP +.B lestates +Display the supported LE states +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH AUTHOR +Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>, Fabrizio Gennari <fabrizio.gennari@philips.com> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/tools/hcidump.1 b/tools/hcidump.1 new file mode 100644 index 0000000000000000000000000000000000000000..57b0c00f461d03bbce416545bcb7bbf828d97dd6 --- /dev/null +++ b/tools/hcidump.1 @@ -0,0 +1,131 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "HCIDUMP" "1" "Nov 12, 2002" "BlueZ" "Linux System Administration" +.SH NAME +hcidump \- Parse HCI data +.SH SYNOPSIS +.sp +\fBhcidump\fP \-h +.sp +\fBhcidump\fP [OPTIONS ...] [FILTERS] +.SH DESCRIPTION +.sp +\fBhcidump(1)\fP reads raw HCI data coming from and going to a Bluetooth device +(which can be specified with the option \fB\-i\fP, default is the first available +one) and prints to screen commands, events and data in a human\-readable form. +Optionally, the dump can be written to a file rather than parsed, and the dump +file can be parsed in a subsequent moment. +.SH OPTIONS +.INDENT 0.0 +.TP +.BI \-i \ <hciX> +Data is read from \fIhciX\fP, which must be the name of an installed Bluetooth +device. If not specified, and if \fB\-r\fP option is not set, data is read from +the first available Bluetooth device. +.TP +.BI \-l \ <len>\fR,\fB \ \-\-snap\-len\fB= <len> +Sets max length of processed packets to \fIlen\fP\&. +.TP +.BI \-p \ <psm>\fR,\fB \ \-\-psm\fB= <psm> +Sets default Protocol Service Multiplexer to \fIpsm\fP\&. +.TP +.BI \-m \ <compid>\fR,\fB \ \-\-manufacturer\fB= <compid> +Sets default company id for manufacturer to \fIcompid\fP\&. +.TP +.BI \-w \ <file>\fR,\fB \ \-\-save\-dump\fB= <file> +Parse output is not printed to screen, instead data read from device is +saved in \fIfile\fP\&. The saved dump file can be subsequently parsed with +option \fB\-r\fP\&. +.TP +.BI \-r \ <file>\fR,\fB \ \-\-read\-dump\fB= <file> +Data is not read from a Bluetooth device, but from \fIfile\fP\&. \fIfile\fP is +created with option \fB\-t\fP, \fB\-\-timestamp\fP prepend a time stamp to every +packet. +.TP +.B \-a\fP,\fB \-\-ascii +For every packet, not only is the packet type displayed, but also all data +in ASCII. +.TP +.B \-x\fP,\fB \-\-hex +For every packet, not only is the packet type displayed, but also all data +in hex. +.TP +.B \-X\fP,\fB \-\-ext +For every packet, not only is the packet type displayed, but also all data +in hex and ASCII. +.TP +.B \-R\fP,\fB \-\-raw +For every packet, only the raw data is displayed. +.TP +.BI \-C \ <psm>\fR,\fB \ \-\-cmtp\fB= <psm> +Sets the PSM value for the CAPI Message Transport Protocol. +.TP +.BI \-H \ <psm>\fR,\fB \ \-\-hcrp\fB= <psm> +Sets the PSM value for the Hardcopy Control Channel. +.TP +.BI \-O \ <channel>\fR,\fB \ \-\-obex\fB= <channel> +Sets the RFCOMM channel value for the Object Exchange Protocol. +.TP +.BI \-P \ <channel>\fR,\fB \ \-\-ppp\fB= <channel> +Sets the RFCOMM channel value for the Point\-to\-Point Protocol. +.TP +.BI \-D \ <file>\fR,\fB \ \-\-pppdump\fB= <file> +Extract PPP traffic with pppdump format. +.TP +.BI \-A \ <file>\fR,\fB \ \-\-audio\fB= <file> +Extract SCO audio data. +.TP +.B \-Y\fP,\fB \-\-novendor +Don\(aqt display any vendor commands or events and don\(aqt show any pin code or +link key in plain text. +.TP +.B \-h +Prints usage info and exits +.UNINDENT +.SH FILTERS +.sp +filter is a space\-separated list of packet categories: available categories are +\fIlmp\fP, \fIhci\fP, \fIsco\fP, \fIl2cap\fP, \fIrfcomm\fP, \fIsdp\fP, \fIbnep\fP, \fIcmtp\fP, \fIhidp\fP, \fIhcrp\fP, +\fIavdtp\fP, \fIavctp\fP, \fIobex\fP, \fIcapi\fP and \fIppp\fP\&. If filters are used, only packets +belonging to the specified categories are dumped. By default, all packets are +dumped. +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH AUTHOR +Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>, Fabrizio Gennari <fabrizio.gennari@philips.com> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/tools/hcidump.c b/tools/hcidump.c index 011864bc0c4ce027b0b70ee520138ca40ebea4c5..d517031dc6b7ddeb7f05f805830f0308980befca 100644 --- a/tools/hcidump.c +++ b/tools/hcidump.c @@ -610,7 +610,7 @@ static void usage(void) " -m, --manufacturer=compid Default manufacturer\n" " -w, --save-dump=file Save dump to a file\n" " -r, --read-dump=file Read dump from a file\n" - " -t, --ts Display time stamps\n" + " -t, --timestamp Display time stamps\n" " -a, --ascii Dump data in ascii\n" " -x, --hex Dump data in hex\n" " -X, --ext Dump data in hex and ascii\n" diff --git a/tools/hcitool.1 b/tools/hcitool.1 new file mode 100644 index 0000000000000000000000000000000000000000..9b0d4ee60fe5ec2035261529040692003aa01558 --- /dev/null +++ b/tools/hcitool.1 @@ -0,0 +1,229 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "HCITOOL" "1" "Nov 12, 2002" "BlueZ" "Linux System Administration" +.SH NAME +hcitool \- Configure Bluetooth connections +.SH SYNOPSIS +.sp +\fBhcitool\fP \-h +.sp +\fBhcitool\fP \fICOMMAND\fP \-\-help +.sp +\fBhcitool\fP [\-i \fIhciX\fP] [\fICOMMAND\fP [\fIPARAMETERS\fP]] +.SH DESCRIPTION +.sp +\fBhcitool(1)\fP is used to configure Bluetooth connections and send some special +command to Bluetooth devices. If no \fBcommand\fP is given, or if the option +\fB\-h\fP is used, \fIhcitool\fP prints some usage information and exits. +.SH OPTIONS +.INDENT 0.0 +.TP +.BI \-i \ <hciX> +The command is applied to device \fIhciX\fP, which must be the name of +an installed Bluetooth device. If not specified, the command will +be sent to the first available Bluetooth device. +.TP +.B \-h +Gives a list of possible commands +.UNINDENT +.SH COMMANDS +.INDENT 0.0 +.TP +.B dev +Display local devices +.TP +.B inq +Inquire remote devices. For each discovered device, Bluetooth device +address, clock offset and class are printed. +.TP +.B scan +Inquire remote devices. For each discovered device, device name are printed. +.TP +.B name <\fIbdaddr\fP> +Print device name of remote device with Bluetooth address \fIbdaddr\fP\&. +.TP +.B info <\fIbdaddr\fP> +Print device name, version and supported features of remote device with +Bluetooth address \fIbdaddr\fP\&. +.TP +.B spinq +Start periodic inquiry process. No inquiry results are printed. +.TP +.B epinq +Exit periodic inquiry process. +.TP +.B cmd <\fIogf\fP> <\fIocf\fP> [\fIparameters\fP] +Submit an arbitrary HCI command to local device. \fIogf\fP, \fIocf\fP and +parameters are hexadecimal bytes. +.TP +.B con +Display active baseband connections +.TP +.B cc [\-\-\fIrole\fP=c|p] [\-\-\fIpkt\-type\fP=<\fIptype\fP>] <\fIbdaddr\fP> +Create baseband connection to remote device with Bluetooth address \fIbdaddr\fP\&. +.sp +Option \fB\-\-pkt\-type\fP specifies a list of allowed packet types. +<\fIptype\fP> is a comma\-separated list of packet types, where the possible +packet types are \fBDM1\fP, \fBDM3\fP, \fBDM5\fP, \fBDH1\fP, \fBDH3\fP, \fBDH5\fP, +\fBHV1\fP, \fBHV2\fP, \fBHV3\fP\&. Default is to allow all packet types. +.sp +Option \fB\-\-role\fP can have value \fBc\fP (do not allow role switch, stay +central) or \fBp\fP (allow role switch, become peripheral if the peer asks to +become central). Default is \fBc\fP\&. +.TP +.B dc <\fIbdaddr\fP> [\fIreason\fP] +Delete baseband connection from remote device with Bluetooth address +\fIbdaddr\fP\&. +.sp +The reason can be one of the Bluetooth HCI error codes. +Default is \fB19\fP for user ended connections. The value must be given in +decimal. +.TP +.B sr <\fIbdaddr\fP> <\fIrole\fP> +Switch role for the baseband connection from the remote device to +\fBcentral\fP or \fBperipheral\fP\&. +.TP +.B cpt <\fIbdaddr\fP> <\fIptypes\fP> +Change packet types for baseband connection to device with Bluetooth +address \fIbdaddr\fP\&. \fIptypes\fP is a comma\-separated list of packet types, +where the possible packet types are \fBDM1\fP, \fBDM3\fP, \fBDM5\fP, \fBDH1\fP, +\fBDH3\fP, \fBDH5\fP, \fBHV1\fP, \fBHV2\fP, \fBHV3\fP\&. +.TP +.B rssi <\fIbdaddr\fP> +Display received signal strength information for the connection to the +device with Bluetooth address \fIbdaddr\fP\&. +.TP +.B lq <\fIbdaddr\fP> +Display link quality for the connection to the device with Bluetooth +address \fIbdaddr\fP\&. +.TP +.B tpl <\fIbdaddr\fP> [\fItype\fP] +Display transmit power level for the connection to the device with +Bluetooth address \fIbdaddr\fP\&. +.sp +The \fItype\fP can be \fB0\fP for the current transmit power level (which is +default) or \fB1\fP for the maximum transmit power level. +.TP +.B afh <\fIbdaddr\fP> +Display AFH channel map for the connection to the device with Bluetooth +address \fIbdaddr\fP\&. +.TP +.B lp <\fIbdaddr\fP> [\fIvalue\fP] +With no value, displays link policy settings for the connection to the +device with Bluetooth address \fIbdaddr\fP\&. +.sp +If \fIvalue\fP is given, sets the link policy settings for that connection to +\fIvalue\fP\&. Possible values are \fBRSWITCH\fP, \fBHOLD\fP, \fBSNIFF\fP and \fBPARK\fP\&. +.TP +.B lst <\fIbdaddr\fP> [\fIvalue\fP] +With no value, displays link supervision timeout for the connection to +the device with Bluetooth address \fIbdaddr\fP\&. +.sp +If \fIvalue\fP is given, sets the link supervision timeout for that connection +to \fIvalue\fP slots, or to infinite if value is 0. +.TP +.B auth <\fIbdaddr\fP> +Request authentication for the device with Bluetooth address \fIbdaddr\fP\&. +.TP +.B enc <\fIbdaddr\fP> [\fIencrypt\fP] +\fBenable\fP or \fBdisable\fP the encryption for the device with Bluetooth +address \fIbdaddr\fP\&. +.TP +.B key <\fIbdaddr\fP> +Change the connection link key for the device with Bluetooth address +\fIbdaddr\fP\&. +.TP +.B clkoff <\fIbdaddr\fP> +Read the clock offset for the device with Bluetooth address \fIbdaddr\fP\&. +.TP +.B clock [\fIbdaddr\fP] [\fIclock\fP] +Read the clock for the device with Bluetooth address \fIbdaddr\fP\&. +.sp +The \fIclock\fP can be \fB0\fP for the local clock or \fB1\fP for the piconet +clock (which is default). +.TP +.B lescan [\-\-\fIprivacy\fP] [\-\-\fIpassive\fP] [\-\-\fIacceptlist\fP] [\-\-\fIdiscovery\fP=g|l] [\-\-\fIduplicates\fP] +Start LE scan +.TP +.B leinfo [\-\-\fIstatic\fP] [\-\-\fIrandom\fP] <\fIbdaddr\fP> +Get LE remote information +.TP +.B lealadd [\-\-\fIrandom\fP] <\fIbdaddr\fP> +Add device to LE Accept List +.TP +.B lealrm <\fIbdaddr\fP> +Remove device from LE Accept List +.TP +.B lealsz +Read size of LE Accept List +.TP +.B lealclr +Clear LE Accept List +.TP +.B lerladd [\-\-\fIlocal_irk\fP] [\-\-\fIpeer_irk\fP] [\-\-\fIrandom\fP] <\fIbdaddr\fP> +Add device to LE Resolving List +.TP +.B lerlrm <\fIbdaddr\fP> +Remove device from LE Resolving List +.TP +.B lerlclr +Clear LE Resolving List +.TP +.B lerlsz +Read size of LE Resolving List +.TP +.B lerlon +Enable LE Address Resolution +.TP +.B lerloff +Disable LE Address Resolution +.TP +.B lecc [\-\-\fIstatic\fP] [\-\-\fIrandom\fP] <\fIbdaddr\fP> | [\-\-\fIacceptlist\fP] +Create a LE Connection +.TP +.B ledc <\fIhandle\fP> [\fIreason\fP] +Disconnect a LE Connection +.TP +.B lecup <\fIhandle\fP> <\fImin\fP> <\fImax\fP> <\fIlatency\fP> <\fItimeout\fP> +LE Connection Update +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH AUTHOR +Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>, Fabrizio Gennari <fabrizio.gennari@philips.com> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/tools/hex2hcd.c b/tools/hex2hcd.c index e6dca5a8106b349ee64d93f5a7dd9f7aec484510..452ab2beb572d980168e1fa86cbff287c9027ddf 100644 --- a/tools/hex2hcd.c +++ b/tools/hex2hcd.c @@ -24,6 +24,7 @@ #include <stdlib.h> #include <stdbool.h> #include <sys/stat.h> +#include "tools/missing.h" static ssize_t process_record(int fd, const char *line, uint16_t *upper_addr) { diff --git a/tools/hid2hci.1 b/tools/hid2hci.1 new file mode 100644 index 0000000000000000000000000000000000000000..fbbef0244cbb7f87b06a5cf29da3651677989f62 --- /dev/null +++ b/tools/hid2hci.1 @@ -0,0 +1,70 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "HID2HCI" "1" "May 15, 2009" "BlueZ" "Linux System Administration" +.SH NAME +hid2hci \- Bluetooth HID to HCI mode switching utility +.SH SYNOPSIS +.sp +\fBhid2hci\fP [\fIOPTIONS\fP] +.SH DESCRIPTION +.sp +\fBhid2hci(1)\fP is used to set up switch supported Bluetooth devices into the +HCI mode and back. +.SH OPTIONS +.INDENT 0.0 +.TP +.B \-\-mode=[\fImode\fP] Sets the mode to the device into. The possible values +for \fImode\fP are \fBhid\fP, \fBhci\fP\&. +.TP +.B \-\-method=[\fImethod\fP] Which vendor method to use for switching the device. +The possible values for \fImethod\fP are \fBcsr\fP, \fBcsr2\fP, +\fBlogitech\-hdi\fP, \fBdell\fP\&. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-devpath +Specifies the device path in /sys +.TP +.B \-\-help +Gives a list of possible options. +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH AUTHOR +Marcel Holtmann <marcel@holtmann.org> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/tools/iso-tester.c b/tools/iso-tester.c index 269fbe2d6c62e00df157bdbf646235c09ba728c2..e80c2159c11d0dd7b4d440eccd0a32820a9c1565 100644 --- a/tools/iso-tester.c +++ b/tools/iso-tester.c @@ -4,6 +4,7 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2022 Intel Corporation. + * Copyright 2023-2024 NXP * */ @@ -17,19 +18,29 @@ #include <poll.h> #include <stdbool.h> +#include <linux/errqueue.h> +#include <linux/net_tstamp.h> + #include <glib.h> #include "lib/bluetooth.h" #include "lib/iso.h" #include "lib/mgmt.h" +#include "lib/uuid.h" #include "monitor/bt.h" +#include "emulator/vhci.h" #include "emulator/bthost.h" #include "emulator/hciemu.h" #include "src/shared/tester.h" #include "src/shared/mgmt.h" #include "src/shared/util.h" +#include "src/shared/queue.h" + +#include "tester.h" + +#define EIR_SERVICE_DATA_16 0x16 #define QOS_IO(_interval, _latency, _sdu, _phy, _rtn) \ { \ @@ -42,13 +53,15 @@ #define QOS_FULL(_cig, _cis, _in, _out) \ { \ - .cig = _cig, \ - .cis = _cis, \ - .sca = 0x07, \ - .packing = 0x00, \ - .framing = 0x00, \ - .in = _in, \ - .out = _out, \ + .ucast = { \ + .cig = _cig, \ + .cis = _cis, \ + .sca = 0x07, \ + .packing = 0x00, \ + .framing = 0x00, \ + .in = _in, \ + .out = _out, \ + },\ } #define QOS(_interval, _latency, _sdu, _phy, _rtn) \ @@ -61,11 +74,21 @@ QOS_IO(_interval, _latency, _sdu, _phy, _rtn), \ QOS_IO(_interval, _latency, _sdu, _phy, _rtn)) +#define QOS_2(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_FULL(0x02, BT_ISO_QOS_CIS_UNSET, \ + QOS_IO(_interval, _latency, _sdu, _phy, _rtn), \ + QOS_IO(_interval, _latency, _sdu, _phy, _rtn)) + #define QOS_1_1(_interval, _latency, _sdu, _phy, _rtn) \ QOS_FULL(0x01, 0x01, \ QOS_IO(_interval, _latency, _sdu, _phy, _rtn), \ QOS_IO(_interval, _latency, _sdu, _phy, _rtn)) +#define QOS_1_2(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_FULL(0x01, 0x02, \ + QOS_IO(_interval, _latency, _sdu, _phy, _rtn), \ + QOS_IO(_interval, _latency, _sdu, _phy, _rtn)) + #define QOS_OUT(_interval, _latency, _sdu, _phy, _rtn) \ QOS_FULL(BT_ISO_QOS_CIG_UNSET, BT_ISO_QOS_CIS_UNSET, \ {}, QOS_IO(_interval, _latency, _sdu, _phy, _rtn)) @@ -78,9 +101,29 @@ QOS_FULL(0x01, 0x01, \ {}, QOS_IO(_interval, _latency, _sdu, _phy, _rtn)) +#define QOS_OUT_1_2(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_FULL(0x01, 0x02, \ + {}, QOS_IO(_interval, _latency, _sdu, _phy, _rtn)) + +#define QOS_OUT_1_EF(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_FULL(0x01, 0xEF, \ + {}, QOS_IO(_interval, _latency, _sdu, _phy, _rtn)) + #define QOS_IN(_interval, _latency, _sdu, _phy, _rtn) \ QOS_FULL(BT_ISO_QOS_CIG_UNSET, BT_ISO_QOS_CIS_UNSET, \ QOS_IO(_interval, _latency, _sdu, _phy, _rtn), {}) +#define QOS_IN_1(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_FULL(0x01, BT_ISO_QOS_CIS_UNSET, \ + QOS_IO(_interval, _latency, _sdu, _phy, _rtn), {}) +#define QOS_IN_2(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_FULL(0x02, BT_ISO_QOS_CIS_UNSET, \ + QOS_IO(_interval, _latency, _sdu, _phy, _rtn), {}) +#define QOS_IN_1_1(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_FULL(0x01, 0x01, \ + QOS_IO(_interval, _latency, _sdu, _phy, _rtn), {}) +#define QOS_IN_1_2(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_FULL(0x01, 0x02, \ + QOS_IO(_interval, _latency, _sdu, _phy, _rtn), {}) /* QoS Configuration settings for low latency audio data */ #define QOS_8_1_1 QOS(7500, 8, 26, 0x02, 2) @@ -88,6 +131,7 @@ #define QOS_16_1_1 QOS(7500, 8, 30, 0x02, 2) #define QOS_16_2_1 QOS(10000, 10, 40, 0x02, 2) #define QOS_1_16_2_1 QOS_1(10000, 10, 40, 0x02, 2) +#define QOS_2_16_2_1 QOS_2(10000, 10, 40, 0x02, 2) #define QOS_1_1_16_2_1 QOS_1_1(10000, 10, 40, 0x02, 2) #define QOS_24_1_1 QOS(7500, 8, 45, 0x02, 2) #define QOS_24_2_1 QOS(10000, 10, 60, 0x02, 2) @@ -102,27 +146,319 @@ #define QOS_48_5_1 QOS_OUT(7500, 15, 117, 0x02, 5) #define QOS_48_6_1 QOS_OUT(10000, 20, 155, 0x02, 5) /* QoS Configuration settings for high reliability audio data */ -#define QOS_8_1_2 QOS(7500, 45, 26, 0x02, 41) -#define QOS_8_2_2 QOS(10000, 60, 30, 0x02, 53) -#define QOS_16_1_2 QOS(7500, 45, 30, 0x02, 41) -#define QOS_16_2_2 QOS(10000, 60, 40, 0x02, 47) -#define QOS_24_1_2 QOS(7500, 45, 45, 0x02, 35) -#define QOS_24_2_2 QOS(10000, 60, 60, 0x02, 41) -#define QOS_32_1_2 QOS(7500, 45, 60, 0x02, 29) -#define QOS_32_2_2 QOS(10000, 60, 80, 0x02, 35) -#define QOS_44_1_2 QOS_OUT(8163, 54, 98, 0x02, 23) -#define QOS_44_2_2 QOS_OUT(10884, 71, 130, 0x02, 23) -#define QOS_48_1_2 QOS_OUT(7500, 45, 75, 0x02, 23) -#define QOS_48_2_2 QOS_OUT(10000, 60, 100, 0x02, 23) -#define QOS_48_3_2 QOS_OUT(7500, 45, 90, 0x02, 23) -#define QOS_48_4_2 QOS_OUT(10000, 60, 120, 0x02, 23) -#define QOS_48_5_2 QOS_OUT(7500, 45, 117, 0x02, 23) -#define QOS_48_6_2 QOS_OUT(10000, 60, 155, 0x02, 23) - -#define QOS_OUT_16_2_1 QOS_OUT(10000, 10, 40, 0x02, 2) -#define QOS_OUT_1_16_2_1 QOS_OUT_1(10000, 10, 40, 0x02, 2) -#define QOS_OUT_1_1_16_2_1 QOS_OUT_1_1(10000, 10, 40, 0x02, 2) -#define QOS_IN_16_2_1 QOS_IN(10000, 10, 40, 0x02, 2) +#define QOS_8_1_2 QOS(7500, 75, 26, 0x02, 13) +#define QOS_8_2_2 QOS(10000, 95, 30, 0x02, 13) +#define QOS_16_1_2 QOS(7500, 75, 30, 0x02, 13) +#define QOS_16_2_2 QOS(10000, 95, 40, 0x02, 13) +#define QOS_24_1_2 QOS(7500, 75, 45, 0x02, 13) +#define QOS_24_2_2 QOS(10000, 95, 60, 0x02, 13) +#define QOS_32_1_2 QOS(7500, 65, 60, 0x02, 13) +#define QOS_32_2_2 QOS(10000, 95, 80, 0x02, 13) +#define QOS_44_1_2 QOS_OUT(8163, 80, 98, 0x02, 13) +#define QOS_44_2_2 QOS_OUT(10884, 85, 130, 0x02, 13) +#define QOS_48_1_2 QOS_OUT(7500, 75, 75, 0x02, 13) +#define QOS_48_2_2 QOS_OUT(10000, 95, 100, 0x02, 13) +#define QOS_48_3_2 QOS_OUT(7500, 75, 90, 0x02, 13) +#define QOS_48_4_2 QOS_OUT(10000, 100, 120, 0x02, 13) +#define QOS_48_5_2 QOS_OUT(7500, 75, 117, 0x02, 13) +#define QOS_48_6_2 QOS_OUT(10000, 100, 155, 0x02, 13) +/* QoS configuration support setting requirements for the UGG and UGT */ +#define QOS_16_1_gs QOS(7500, 15, 30, 0x02, 1) +#define QOS_16_2_gs QOS(10000, 20, 40, 0x02, 1) +#define QOS_32_1_gs QOS(7500, 15, 60, 0x02, 1) +#define QOS_32_2_gs QOS(10000, 20, 80, 0x02, 1) +#define QOS_48_1_gs QOS(7500, 15, 75, 0x02, 1) +#define QOS_48_2_gs QOS(10000, 20, 100, 0x02, 1) +#define QOS_32_1_gr QOS(7500, 15, 60, 0x02, 1) +#define QOS_32_2_gr QOS(10000, 20, 80, 0x02, 1) +#define QOS_48_1_gr QOS(7500, 15, 75, 0x02, 1) +#define QOS_48_2_gr QOS(10000, 20, 100, 0x02, 1) +#define QOS_48_3_gr QOS(7500, 15, 90, 0x02, 1) +#define QOS_48_4_gr QOS(10000, 20, 120, 0x02, 1) + +/* One unidirectional CIS. Unicast Server is Audio Sink */ +#define AC_1_4 QOS_OUT(10000, 10, 40, 0x02, 2) +/* One unidirectional CIS. Unicast Server is Audio Sink CIG 0x01 */ +#define AC_1_4_1 QOS_OUT_1(10000, 10, 40, 0x02, 2) +/* One unidirectional CIS. Unicast Server is Audio Source. */ +#define AC_2_10 QOS_IN(10000, 10, 40, 0x02, 2) +/* One unidirectional CIS. Unicast Server is Audio Source CIG 0x02 */ +#define AC_2_10_2 QOS_IN_2(10000, 10, 40, 0x02, 2) +/* One bidirectional CIS. Unicast Server is Audio Sink and Audio Source. */ +#define AC_3_5 QOS(10000, 10, 40, 0x02, 2) +/* Two unidirectional CISes. Unicast Server is Audio Sink. + * #1 - CIG 1 CIS 1 (output) + * #2 - CIG 1 CIS 2 (output) + */ +#define AC_6i_1 QOS_OUT_1_1(10000, 10, 40, 0x02, 2) +#define AC_6i_2 QOS_OUT_1_2(10000, 10, 40, 0x02, 2) +/* Two Unicast Servers. Unicast Server 1 is Audio Sink. Unicast Server 2 is + * Audio Sink. + * #1 - CIG 1 CIS auto (output) + * #2 - CIG 1 CIS auto (output) + */ +#define AC_6ii_1 QOS_OUT_1(10000, 10, 40, 0x02, 2) +#define AC_6ii_2 QOS_OUT_1(10000, 10, 40, 0x02, 2) +#define AC_6ii_1_EF QOS_OUT_1_EF(10000, 10, 40, 0x02, 2) /* different CIS ID */ +/* Two unidirectional CISes. Unicast Server is Audio Sink and Audio Source. + * #1 - CIG 1 CIS 1 (input) + * #2 - CIG 1 CIS 2 (output) + */ +#define AC_7i_1 QOS_OUT_1_1(10000, 10, 40, 0x02, 2) +#define AC_7i_2 QOS_IN_1_2(10000, 10, 40, 0x02, 2) +/* Two Unidirectional CISes. Two Unicast Servers. Unicast Server 1 is Audio + * Sink. Unicast Server 2 is Audio Source. + * #1 - CIG 1 CIS auto (output) + * #2 - CIG 1 CIS auto (output) + */ +#define AC_7ii_1 QOS_OUT_1(10000, 10, 40, 0x02, 2) +#define AC_7ii_2 QOS_IN_1(10000, 10, 40, 0x02, 2) +/* One bidirectional CIS and one unidirectional CIS. Unicast Server is Audio + * Sink and Audio Source. + * #1 - CIG 1 CIS 1 (output) + * #2 - CIG 1 CIS 2 (input/output) + */ +#define AC_8i_1 QOS_OUT_1_1(10000, 10, 40, 0x02, 2) +#define AC_8i_2 QOS_1_2(10000, 10, 40, 0x02, 2) +/* One bidirectional CIS and one unidirectional CIS. Two Unicast Servers. + * Unicast Server 1 is Audio Sink and Audio Source. Unicast Server 2 is + * Audio Sink. + * #1 - CIG 1 CIS auto (input/output) + * #2 - CIG 1 CIS auto (output) + */ +#define AC_8ii_1 QOS_1(10000, 10, 40, 0x02, 2) +#define AC_8ii_2 QOS_OUT_1(10000, 10, 40, 0x02, 2) +/* Two unidirectional CISes. Unicast Server is Audio Source. + * #1 - CIG 1 CIS 1 (input) + * #2 - CIG 1 CIS 2 (input) + */ +#define AC_9i_1 QOS_IN_1_1(10000, 10, 40, 0x02, 2) +#define AC_9i_2 QOS_IN_1_2(10000, 10, 40, 0x02, 2) +/* Two unidirectional CISes. Two Unicast Servers. Unicast Server 1 is Audio + * Source. Unicast Server 2 is Audio Source. + * #1 - CIG 1 CIS auto (input) + * #2 - CIG 1 CIS auto (input) + */ +#define AC_9ii_1 QOS_IN_1(10000, 10, 40, 0x02, 2) +#define AC_9ii_2 QOS_IN_1(10000, 10, 40, 0x02, 2) +/* Two bidirectional CISes. Unicast Server is Audio Sink and Audio Source. + * #1 - CIG 1 CIS 1 (input/output) + * #2 - CIG 1 CIS 2 (input/output) + */ +#define AC_11i_1 QOS_1_1(10000, 10, 40, 0x02, 2) +#define AC_11i_2 QOS_1_2(10000, 10, 40, 0x02, 2) +/* Two bidirectional CISes. Two Unicast Servers. Unicast Server 1 is Audio Sink + * and Audio Source. Unicast Server 2 is Audio Sink and Audio Source. + * #1 - CIG 1 CIS auto (input/output) + * #2 - CIG 1 CIS auto (input/output) + */ +#define AC_11ii_1 QOS_1(10000, 10, 40, 0x02, 2) +#define AC_11ii_2 QOS_1(10000, 10, 40, 0x02, 2) + +#define BCODE {0x01, 0x02, 0x68, 0x05, 0x53, 0xf1, 0x41, 0x5a, \ + 0xa2, 0x65, 0xbb, 0xaf, 0xc6, 0xea, 0x03, 0xb8} + +#define QOS_BCAST_FULL(_big, _bis, _encryption, _bcode, _in, _out) \ +{ \ + .bcast = { \ + .big = _big, \ + .bis = _bis, \ + .sync_factor = 0x07, \ + .packing = 0x00, \ + .framing = 0x00, \ + .in = _in, \ + .out = _out, \ + .encryption = _encryption, \ + .bcode = _bcode, \ + .options = 0x00, \ + .skip = 0x0000, \ + .sync_timeout = BT_ISO_SYNC_TIMEOUT, \ + .sync_cte_type = 0x00, \ + .mse = 0x00, \ + .timeout = BT_ISO_SYNC_TIMEOUT, \ + }, \ +} + +#define BCAST_QOS_OUT(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_BCAST_FULL(BT_ISO_QOS_BIG_UNSET, BT_ISO_QOS_BIS_UNSET, \ + 0x00, {0x00}, {}, \ + QOS_IO(_interval, _latency, _sdu, _phy, _rtn)) + +#define BCAST_QOS_OUT_ENC(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_BCAST_FULL(BT_ISO_QOS_BIG_UNSET, BT_ISO_QOS_BIS_UNSET, \ + 0x01, BCODE, {}, \ + QOS_IO(_interval, _latency, _sdu, _phy, _rtn)) + +#define BCAST_QOS_OUT_1(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_BCAST_FULL(0x01, BT_ISO_QOS_BIS_UNSET, \ + 0x00, {0x00}, {}, \ + QOS_IO(_interval, _latency, _sdu, _phy, _rtn)) + +#define BCAST_QOS_OUT_1_1(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_BCAST_FULL(0x01, 0x01, \ + 0x00, {0x00}, {}, \ + QOS_IO(_interval, _latency, _sdu, _phy, _rtn)) + +#define BCAST_QOS_IN(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_BCAST_FULL(BT_ISO_QOS_BIG_UNSET, BT_ISO_QOS_BIS_UNSET, \ + 0x00, {0x00}, \ + QOS_IO(_interval, _latency, _sdu, _phy, _rtn), {}) + +#define BCAST_QOS_IN_ENC(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_BCAST_FULL(BT_ISO_QOS_BIG_UNSET, BT_ISO_QOS_BIS_UNSET, \ + 0x01, BCODE, \ + QOS_IO(_interval, _latency, _sdu, _phy, _rtn), {}) + +#define QOS_OUT_16_2_1 BCAST_QOS_OUT(10000, 10, 40, 0x02, 2) +#define QOS_OUT_ENC_16_2_1 BCAST_QOS_OUT_ENC(10000, 10, 40, 0x02, 2) +#define QOS_OUT_1_16_2_1 BCAST_QOS_OUT_1(10000, 10, 40, 0x02, 2) +#define QOS_OUT_1_1_16_2_1 BCAST_QOS_OUT_1_1(10000, 10, 40, 0x02, 2) +#define QOS_IN_16_2_1 BCAST_QOS_IN(10000, 10, 40, 0x02, 2) +#define QOS_IN_ENC_16_2_1 BCAST_QOS_IN_ENC(10000, 10, 40, 0x02, 2) +#define QOS_OUT_48_1_g BCAST_QOS_OUT(7500, 8, 75, 0x02, 1) +#define QOS_OUT_48_2_g BCAST_QOS_OUT(10000, 10, 100, 0x02, 1) +#define QOS_OUT_48_3_g BCAST_QOS_OUT(7500, 8, 90, 0x02, 1) +#define QOS_OUT_48_4_g BCAST_QOS_OUT(10000, 10, 120, 0x02, 1) + +#define BASE(_pd, _sgrp, _nbis, _cfg...) \ +{ \ + _pd & 0xff, _pd >> 8, _pd >> 16, \ + _sgrp, \ + _nbis, \ + _cfg \ +} + +#define LC3_BASE(_pd, _sgrp, _nbis, _cc...) \ + BASE(_pd, _sgrp, _nbis, 0x06, 0x00, 0x00, 0x00, 0x00, _cc) + +/* 16 KHZ - 10 ms - Front Left - Frame Length 40 bytes */ +#define LC3_CONFIG_16_2_1 \ + 0x10, \ + 0x02, 0x01, 0x03, \ + 0x02, 0x02, 0x01, \ + 0x05, 0x03, 0x01, 0x00, 0x00, 0x00, \ + 0x03, 0x04, 0x28, 0x00 + +/* Audio Context: Convertional */ +#define CTXT_CONVERSIONAL \ + 0x04, \ + 0x03, 0x02, 0x02, 0x00 + +static const uint8_t base_lc3_16_2_1[] = + LC3_BASE(40000, 1, 1, LC3_CONFIG_16_2_1, CTXT_CONVERSIONAL, + 0x01, /* BIS */ + 0x00 /* Codec Specific Configuration */); + +#define LC3_CONFIG_G(_freq, _dur, _len) \ + 0x0a, \ + 0x02, 0x01, _freq, \ + 0x02, 0x02, _dur, \ + 0x03, 0x04, _len, _len >> 8 + +#define LC3_CONFIG_FRONT_LEFT \ + 0x06, \ + 0x05, 0x03, 0x01, 0x00, 0x00, 0x00 + +/* 48 KHZ - 7.5 ms - Frame Length 75 bytes */ +#define LC3_CONFIG_48_1_G \ + LC3_CONFIG_G(0x08, 0x00, 75) + +static const uint8_t base_lc3_48_1_g[] = + LC3_BASE(10000, 1, 1, LC3_CONFIG_48_1_G, CTXT_CONVERSIONAL, + 0x01, LC3_CONFIG_FRONT_LEFT); + +/* 48 KHZ - 10 ms Frame Length 100 bytes */ +#define LC3_CONFIG_48_2_G \ + LC3_CONFIG_G(0x08, 0x01, 100) + +static const uint8_t base_lc3_48_2_g[] = + LC3_BASE(10000, 1, 1, LC3_CONFIG_48_2_G, CTXT_CONVERSIONAL, + 0x01, LC3_CONFIG_FRONT_LEFT); + +/* 48 KHZ - 7.5 ms Frame Length 90 bytes */ +#define LC3_CONFIG_48_3_G \ + LC3_CONFIG_G(0x08, 0x00, 90) + +static const uint8_t base_lc3_48_3_g[] = + LC3_BASE(10000, 1, 1, LC3_CONFIG_48_3_G, CTXT_CONVERSIONAL, + 0x01, LC3_CONFIG_FRONT_LEFT); + +/* 48 KHZ - 7.5 ms Frame Length 90 bytes */ +#define LC3_CONFIG_48_4_G \ + LC3_CONFIG_G(0x08, 0x00, 120) + +static const uint8_t base_lc3_48_4_g[] = + LC3_BASE(10000, 1, 1, LC3_CONFIG_48_3_G, CTXT_CONVERSIONAL, + 0x01, LC3_CONFIG_FRONT_LEFT); + +/* Single Audio Channel. One BIS. */ +#define BCAST_AC_12 BCAST_QOS_OUT_1_1(10000, 10, 40, 0x02, 2) + +static const uint8_t base_lc3_ac_12[] = { + 0x28, 0x00, 0x00, /* Presentation Delay */ + 0x01, /* Number of Subgroups */ + 0x01, /* Number of BIS */ + 0x06, 0x00, 0x00, 0x00, 0x00, /* Code ID = LC3 (0x06) */ + 0x10, /* Codec Specific Configuration */ + 0x02, 0x01, 0x03, /* 16 KHZ */ + 0x02, 0x02, 0x01, /* 10 ms */ + 0x05, 0x03, 0x01, 0x00, 0x00, 0x00, /* Front Left */ + 0x03, 0x04, 0x28, 0x00, /* Frame Length 40 bytes */ + 0x04, /* Metadata */ + 0x03, 0x02, 0x02, 0x00, /* Audio Context: Convertional */ + 0x01, /* BIS */ + 0x00, /* Codec Specific Configuration */ +}; + +/* Multiple Audio Channels. Two BISes. */ +#define BCAST_AC_13_1_1 BCAST_QOS_OUT_1_1(10000, 10, 40, 0x02, 2) +#define BCAST_AC_13_1 BCAST_QOS_OUT_1(10000, 10, 40, 0x02, 2) + +static const uint8_t base_lc3_ac_13[] = { + 0x28, 0x00, 0x00, /* Presentation Delay */ + 0x01, /* Number of Subgroups */ + 0x02, /* Number of BIS */ + 0x06, 0x00, 0x00, 0x00, 0x00, /* Code ID = LC3 (0x06) */ + 0x10, /* Codec Specific Configuration */ + 0x02, 0x01, 0x03, /* 16 KHZ */ + 0x02, 0x02, 0x01, /* 10 ms */ + 0x05, 0x03, 0x01, 0x00, 0x00, 0x00, /* Front Left */ + 0x03, 0x04, 0x28, 0x00, /* Frame Length 40 bytes */ + 0x04, /* Metadata */ + 0x03, 0x02, 0x02, 0x00, /* Audio Context: Convertional */ + 0x01, /* BIS 1 */ + 0x06, /* Codec Specific Configuration */ + 0x05, 0x03, 0x01, 0x00, 0x00, 0x00, /* Audio_Channel_Allocation: + * Front left + */ + 0x01, /* BIS 2 */ + 0x06, /* Codec Specific Configuration */ + 0x05, 0x03, 0x02, 0x00, 0x00, 0x00, /* Audio_Channel_Allocation: + * Front right + */ +}; + +/* Multiple Audio Channels. One BIS. */ +#define BCAST_AC_14 BCAST_QOS_OUT_1_1(10000, 10, 40, 0x02, 2) + +static const uint8_t base_lc3_ac_14[] = { + 0x28, 0x00, 0x00, /* Presentation Delay */ + 0x01, /* Number of Subgroups */ + 0x01, /* Number of BIS */ + 0x06, 0x00, 0x00, 0x00, 0x00, /* Code ID = LC3 (0x06) */ + 0x10, /* Codec Specific Configuration */ + 0x02, 0x01, 0x03, /* 16 KHZ */ + 0x02, 0x02, 0x01, /* 10 ms */ + 0x05, 0x03, 0x01, 0x00, 0x00, 0x00, /* Front Left */ + 0x03, 0x04, 0x28, 0x00, /* Frame Length 40 bytes */ + 0x04, /* Metadata */ + 0x03, 0x02, 0x02, 0x00, /* Audio Context: Convertional */ + 0x01, /* BIS */ + 0x06, /* Codec Specific Configuration */ + 0x05, 0x03, 0x03, 0x00, 0x00, 0x00, /* Audio_Channel_Allocation: + * Front left, Front right + */ +}; struct test_data { const void *test_data; @@ -130,17 +466,21 @@ struct test_data { uint16_t mgmt_index; struct hciemu *hciemu; enum hciemu_type hciemu_type; + uint8_t accept_reason; uint16_t handle; uint16_t acl_handle; - GIOChannel *io; - unsigned int io_id[2]; + struct queue *io_queue; + unsigned int io_id[4]; uint8_t client_num; int step; bool reconnect; + bool suspending; + struct tx_tstamp_data tx_ts; }; struct iso_client_data { struct bt_iso_qos qos; + struct bt_iso_qos qos_2; int expect_err; const struct iovec *send; const struct iovec *recv; @@ -148,8 +488,38 @@ struct iso_client_data { bool bcast; bool defer; bool disconnect; + bool ts; + bool mconn; + bool suspend; + uint8_t pkt_status; + const uint8_t *base; + size_t base_len; + bool listen_bind; + bool pa_bind; + bool big; + + /* Enable SO_TIMESTAMPING with these flags */ + uint32_t so_timestamping; + + /* Enable SO_TIMESTAMPING using CMSG instead of setsockopt() */ + bool cmsg_timestamping; + + /* Number of additional packets to send, before SO_TIMESTAMPING. + * Used to test kernel timestamp TX queue logic. + */ + unsigned int repeat_send_pre_ts; + + /* Number of additional packets to send, after SO_TIMESTAMPING. + * Used for testing TX timestamping OPT_ID. + */ + unsigned int repeat_send; + + /* Disable BT_POLL_ERRQUEUE before enabling TX timestamping */ + bool no_poll_errqueue; }; +typedef bool (*iso_defer_accept_t)(struct test_data *data, GIOChannel *io); + static void mgmt_debug(const char *str, void *user_data) { const char *prefix = user_data; @@ -281,6 +651,18 @@ static const uint8_t reset_iso_socket_param[] = { 0x00, /* Action - disable */ }; +static const uint8_t set_poll_errqueue_param[] = { + 0x33, 0x57, 0x7b, 0xb4, 0x21, 0xc0, 0xc1, 0x8b, /* UUID */ + 0x79, 0x46, 0x9f, 0xb6, 0x4c, 0x8c, 0x51, 0x69, + 0x01, /* Action - enable */ +}; + +static const uint8_t reset_poll_errqueue_param[] = { + 0x33, 0x57, 0x7b, 0xb4, 0x21, 0xc0, 0xc1, 0x8b, /* UUID */ + 0x79, 0x46, 0x9f, 0xb6, 0x4c, 0x8c, 0x51, 0x69, + 0x00, /* Action - disable */ +}; + static void set_iso_socket_callback(uint8_t status, uint16_t length, const void *param, void *user_data) { @@ -292,9 +674,26 @@ static void set_iso_socket_callback(uint8_t status, uint16_t length, tester_print("ISO socket feature is enabled"); } +static void set_poll_errqueue_callback(uint8_t status, uint16_t length, + const void *param, void *user_data) +{ + if (status != MGMT_STATUS_SUCCESS) { + tester_print("Poll Errqueue feature could not be enabled"); + return; + } + + tester_print("Poll Errqueue feature is enabled"); +} + static void test_pre_setup(const void *test_data) { struct test_data *data = tester_get_data(); + const struct iso_client_data *isodata = test_data; + + if (isodata && isodata->so_timestamping) { + if (tester_pre_setup_skip_by_default()) + return; + } data->mgmt = mgmt_new_default(); if (!data->mgmt) { @@ -310,6 +709,13 @@ static void test_pre_setup(const void *test_data) sizeof(set_iso_socket_param), set_iso_socket_param, set_iso_socket_callback, NULL, NULL); + if (isodata && isodata->no_poll_errqueue) { + mgmt_send(data->mgmt, MGMT_OP_SET_EXP_FEATURE, MGMT_INDEX_NONE, + sizeof(set_poll_errqueue_param), + set_poll_errqueue_param, + set_poll_errqueue_callback, NULL, NULL); + } + mgmt_send(data->mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL, read_index_list_callback, NULL, NULL); } @@ -317,32 +723,46 @@ static void test_pre_setup(const void *test_data) static void test_post_teardown(const void *test_data) { struct test_data *data = tester_get_data(); + const struct iso_client_data *isodata = test_data; mgmt_send(data->mgmt, MGMT_OP_SET_EXP_FEATURE, MGMT_INDEX_NONE, sizeof(reset_iso_socket_param), reset_iso_socket_param, NULL, NULL, NULL); + if (isodata && isodata->no_poll_errqueue) { + mgmt_send(data->mgmt, MGMT_OP_SET_EXP_FEATURE, MGMT_INDEX_NONE, + sizeof(reset_poll_errqueue_param), + reset_poll_errqueue_param, + NULL, NULL, NULL); + } + hciemu_unref(data->hciemu); data->hciemu = NULL; } +static void io_free(void *data) +{ + GIOChannel *io = data; + + g_io_channel_unref(io); +} + static void test_data_free(void *test_data) { struct test_data *data = test_data; + unsigned int i; - if (data->io) - g_io_channel_unref(data->io); + if (data->io_queue) + queue_destroy(data->io_queue, io_free); - if (data->io_id[0] > 0) - g_source_remove(data->io_id[0]); - - if (data->io_id[1] > 0) - g_source_remove(data->io_id[1]); + for (i = 0; i < ARRAY_SIZE(data->io_id); ++i) + if (data->io_id[i] > 0) + g_source_remove(data->io_id[i]); free(data); } -#define test_iso_full(name, data, setup, func, num) \ +#define test_iso_full(name, data, setup, func, num, reason) \ do { \ struct test_data *user; \ user = new0(struct test_data, 1); \ @@ -351,16 +771,20 @@ static void test_data_free(void *test_data) user->hciemu_type = HCIEMU_TYPE_BREDRLE; \ user->test_data = data; \ user->client_num = num; \ + user->accept_reason = reason; \ tester_add_full(name, data, \ test_pre_setup, setup, func, NULL, \ test_post_teardown, 2, user, test_data_free); \ } while (0) #define test_iso(name, data, setup, func) \ - test_iso_full(name, data, setup, func, 1) + test_iso_full(name, data, setup, func, 1, 0x00) #define test_iso2(name, data, setup, func) \ - test_iso_full(name, data, setup, func, 2) + test_iso_full(name, data, setup, func, 2, 0x00) + +#define test_iso_rej(name, data, setup, func, reason) \ + test_iso_full(name, data, setup, func, 1, reason) static const struct iso_client_data connect_8_1_1 = { .qos = QOS_8_1_1, @@ -532,11 +956,91 @@ static const struct iso_client_data connect_48_6_2 = { .expect_err = 0 }; +static const struct iso_client_data connect_16_1_gs = { + .qos = QOS_16_1_gs, + .expect_err = 0 +}; + +static const struct iso_client_data connect_16_2_gs = { + .qos = QOS_16_2_gs, + .expect_err = 0 +}; + +static const struct iso_client_data connect_32_1_gs = { + .qos = QOS_32_1_gs, + .expect_err = 0 +}; + +static const struct iso_client_data connect_32_2_gs = { + .qos = QOS_32_2_gs, + .expect_err = 0 +}; + +static const struct iso_client_data connect_48_1_gs = { + .qos = QOS_48_1_gs, + .expect_err = 0 +}; + +static const struct iso_client_data connect_48_2_gs = { + .qos = QOS_48_2_gs, + .expect_err = 0 +}; + +static const struct iso_client_data connect_32_1_gr = { + .qos = QOS_32_1_gr, + .expect_err = 0 +}; + +static const struct iso_client_data connect_32_2_gr = { + .qos = QOS_32_2_gr, + .expect_err = 0 +}; + +static const struct iso_client_data connect_48_1_gr = { + .qos = QOS_48_1_gr, + .expect_err = 0 +}; + +static const struct iso_client_data connect_48_2_gr = { + .qos = QOS_48_2_gr, + .expect_err = 0 +}; + +static const struct iso_client_data connect_48_3_gr = { + .qos = QOS_48_3_gr, + .expect_err = 0 +}; + +static const struct iso_client_data connect_48_4_gr = { + .qos = QOS_48_4_gr, + .expect_err = 0 +}; + static const struct iso_client_data connect_invalid = { .qos = QOS(0, 0, 0, 0, 0), .expect_err = -EINVAL }; +static const struct iso_client_data connect_reject = { + .qos = QOS_16_1_2, + .expect_err = -ENOSYS +}; + +static const struct iso_client_data connect_suspend = { + .qos = QOS_16_2_1, + .expect_err = -ECONNRESET +}; + +static const struct iso_client_data connect_cig_f0_invalid = { + .qos = QOS_FULL(0xF0, 0x00, {}, QOS_IO(10000, 10, 40, 0x02, 2)), + .expect_err = -EINVAL +}; + +static const struct iso_client_data connect_cis_f0_invalid = { + .qos = QOS_FULL(0x00, 0xF0, {}, QOS_IO(10000, 10, 40, 0x02, 2)), + .expect_err = -EINVAL +}; + static const uint8_t data_16_2_1[40] = { [0 ... 39] = 0xff }; static const struct iovec send_16_2_1 = { .iov_base = (void *)data_16_2_1, @@ -555,6 +1059,48 @@ static const struct iso_client_data connect_16_2_1_send = { .send = &send_16_2_1, }; +static const struct iso_client_data connect_send_tx_timestamping = { + .qos = QOS_16_2_1, + .expect_err = 0, + .send = &send_16_2_1, + .so_timestamping = (SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_OPT_ID | + SOF_TIMESTAMPING_TX_SOFTWARE), + .repeat_send = 1, + .repeat_send_pre_ts = 2, +}; + +static const struct iso_client_data connect_send_tx_sched_timestamping = { + .qos = QOS_16_2_1, + .expect_err = 0, + .send = &send_16_2_1, + .so_timestamping = (SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_OPT_TSONLY | + SOF_TIMESTAMPING_TX_SCHED), + .repeat_send = 1, +}; + +static const struct iso_client_data connect_send_tx_cmsg_timestamping = { + .qos = QOS_16_2_1, + .expect_err = 0, + .send = &send_16_2_1, + .so_timestamping = (SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_TX_SOFTWARE), + .repeat_send = 1, + .cmsg_timestamping = true, +}; + +static const struct iso_client_data connect_send_tx_no_poll_timestamping = { + .qos = QOS_16_2_1, + .expect_err = 0, + .send = &send_16_2_1, + .so_timestamping = (SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_TX_SOFTWARE), + .repeat_send = 1, + .no_poll_errqueue = true, +}; + static const struct iso_client_data listen_16_2_1_recv = { .qos = QOS_16_2_1, .expect_err = 0, @@ -562,12 +1108,34 @@ static const struct iso_client_data listen_16_2_1_recv = { .server = true, }; +static const struct iso_client_data listen_16_2_1_recv_ts = { + .qos = QOS_16_2_1, + .expect_err = 0, + .recv = &send_16_2_1, + .server = true, + .ts = true, +}; + +static const struct iso_client_data listen_16_2_1_recv_pkt_status = { + .qos = QOS_16_2_1, + .expect_err = 0, + .recv = &send_16_2_1, + .server = true, + .pkt_status = 0x02, +}; + static const struct iso_client_data defer_16_2_1 = { .qos = QOS_16_2_1, .expect_err = 0, .defer = true, }; +static const struct iso_client_data defer_1_16_2_1 = { + .qos = QOS_1_16_2_1, + .expect_err = 0, + .defer = true, +}; + static const struct iso_client_data connect_16_2_1_defer_send = { .qos = QOS_16_2_1, .expect_err = 0, @@ -619,51 +1187,341 @@ static const struct iso_client_data disconnect_16_2_1 = { .disconnect = true, }; +static const struct iso_client_data suspend_16_2_1 = { + .qos = QOS_16_2_1, + .suspend = true, +}; + static const struct iso_client_data reconnect_16_2_1 = { .qos = QOS_16_2_1, .expect_err = 0, .disconnect = true, }; -static const struct iso_client_data bcast_16_2_1_send = { - .qos = QOS_OUT_16_2_1, +static const struct iso_client_data connect_ac_1_4 = { + .qos = AC_1_4, + .expect_err = 0 +}; + +static const struct iso_client_data connect_ac_2_10 = { + .qos = AC_2_10, + .expect_err = 0 +}; + +static const struct iso_client_data connect_ac_3_5 = { + .qos = AC_3_5, + .expect_err = 0 +}; + +static const struct iso_client_data connect_ac_6i = { + .qos = AC_6i_1, + .qos_2 = AC_6i_2, .expect_err = 0, - .send = &send_16_2_1, - .bcast = true, + .mconn = true, + .defer = true, }; -static const struct iso_client_data bcast_1_16_2_1_send = { - .qos = QOS_OUT_1_16_2_1, +static const struct iso_client_data reconnect_ac_6i = { + .qos = AC_6i_1, + .qos_2 = AC_6i_2, .expect_err = 0, - .send = &send_16_2_1, - .bcast = true, + .mconn = true, + .defer = true, + .disconnect = true, }; -static const struct iso_client_data bcast_1_1_16_2_1_send = { - .qos = QOS_OUT_1_1_16_2_1, +static const struct iso_client_data connect_ac_6ii = { + .qos = AC_6ii_1, + .qos_2 = AC_6ii_2, .expect_err = 0, - .send = &send_16_2_1, - .bcast = true, + .mconn = true, + .defer = true, }; -static const struct iso_client_data bcast_16_2_1_recv = { - .qos = QOS_IN_16_2_1, +static const struct iso_client_data reconnect_ac_6ii = { + .qos = AC_6ii_1, + .qos_2 = AC_6ii_2, .expect_err = 0, - .recv = &send_16_2_1, - .bcast = true, + .mconn = true, + .defer = true, + .disconnect = true, }; -static void client_connectable_complete(uint16_t opcode, uint8_t status, - const void *param, uint8_t len, - void *user_data) -{ - struct test_data *data = user_data; - static uint8_t client_num; +static const struct iso_client_data connect_ac_6ii_cis_ef_auto = { + .qos = AC_6ii_1_EF, + .qos_2 = AC_6ii_2, + .expect_err = 0, + .mconn = true, + .defer = true, +}; - if (opcode != BT_HCI_CMD_LE_SET_EXT_ADV_ENABLE) - return; +static const struct iso_client_data connect_ac_6ii_cis_ef_ef = { + .qos = AC_6ii_1_EF, + .qos_2 = AC_6ii_1_EF, + .expect_err = -EINVAL, + .mconn = true, + .defer = true, +}; - tester_print("Client %u set connectable status 0x%02x", client_num, +static const struct iso_client_data connect_ac_7i = { + .qos = AC_7i_1, + .qos_2 = AC_7i_2, + .expect_err = 0, + .mconn = true, + .defer = true, +}; + +static const struct iso_client_data connect_ac_7ii = { + .qos = AC_7ii_1, + .qos_2 = AC_7ii_2, + .expect_err = 0, + .mconn = true, + .defer = true, +}; + +static const struct iso_client_data connect_ac_8i = { + .qos = AC_8i_1, + .qos_2 = AC_8i_2, + .expect_err = 0, + .mconn = true, + .defer = true, +}; + +static const struct iso_client_data connect_ac_8ii = { + .qos = AC_8ii_1, + .qos_2 = AC_8ii_2, + .expect_err = 0, + .mconn = true, + .defer = true, +}; + +static const struct iso_client_data connect_ac_9i = { + .qos = AC_9i_1, + .qos_2 = AC_9i_2, + .expect_err = 0, + .mconn = true, + .defer = true, +}; + +static const struct iso_client_data connect_ac_9ii = { + .qos = AC_9ii_1, + .qos_2 = AC_9ii_2, + .expect_err = 0, + .mconn = true, + .defer = true, +}; + +static const struct iso_client_data connect_ac_11i = { + .qos = AC_11i_1, + .qos_2 = AC_11i_2, + .expect_err = 0, + .mconn = true, + .defer = true, +}; + +static const struct iso_client_data connect_ac_11ii = { + .qos = AC_11ii_1, + .qos_2 = AC_11ii_2, + .expect_err = 0, + .mconn = true, + .defer = true, +}; + +static const struct iso_client_data connect_ac_1_2 = { + .qos = AC_1_4, + .qos_2 = AC_2_10, + .expect_err = 0, + .mconn = true, +}; + +static const struct iso_client_data connect_ac_1_2_cig_1_2 = { + .qos = AC_1_4_1, + .qos_2 = AC_2_10_2, + .expect_err = 0, + .mconn = true, +}; + +static const struct iso_client_data bcast_48_1_g = { + .qos = QOS_OUT_48_1_g, + .expect_err = 0, + .bcast = true, + .base = base_lc3_48_1_g, + .base_len = sizeof(base_lc3_48_1_g), +}; + +static const struct iso_client_data bcast_48_2_g = { + .qos = QOS_OUT_48_2_g, + .expect_err = 0, + .bcast = true, + .base = base_lc3_48_2_g, + .base_len = sizeof(base_lc3_48_2_g), +}; + +static const struct iso_client_data bcast_48_3_g = { + .qos = QOS_OUT_48_3_g, + .expect_err = 0, + .bcast = true, + .base = base_lc3_48_3_g, + .base_len = sizeof(base_lc3_48_3_g), +}; + +static const struct iso_client_data bcast_48_4_g = { + .qos = QOS_OUT_48_4_g, + .expect_err = 0, + .bcast = true, + .base = base_lc3_48_4_g, + .base_len = sizeof(base_lc3_48_4_g), +}; + +static const struct iso_client_data bcast_16_2_1_send = { + .qos = QOS_OUT_16_2_1, + .expect_err = 0, + .send = &send_16_2_1, + .bcast = true, + .base = base_lc3_16_2_1, + .base_len = sizeof(base_lc3_16_2_1), +}; + +static const struct iso_client_data bcast_enc_16_2_1_send = { + .qos = QOS_OUT_ENC_16_2_1, + .expect_err = 0, + .send = &send_16_2_1, + .bcast = true, + .base = base_lc3_16_2_1, + .base_len = sizeof(base_lc3_16_2_1), +}; + +static const struct iso_client_data bcast_1_16_2_1_send = { + .qos = QOS_OUT_1_16_2_1, + .expect_err = 0, + .send = &send_16_2_1, + .bcast = true, + .base = base_lc3_16_2_1, + .base_len = sizeof(base_lc3_16_2_1), +}; + +static const struct iso_client_data bcast_1_1_16_2_1_send = { + .qos = QOS_OUT_1_1_16_2_1, + .expect_err = 0, + .send = &send_16_2_1, + .bcast = true, + .base = base_lc3_16_2_1, + .base_len = sizeof(base_lc3_16_2_1), +}; + +static const struct iso_client_data bcast_16_2_1_recv = { + .qos = QOS_IN_16_2_1, + .expect_err = 0, + .recv = &send_16_2_1, + .bcast = true, + .server = true, + .big = true, +}; + +static const struct iso_client_data bcast_enc_16_2_1_recv = { + .qos = QOS_IN_ENC_16_2_1, + .expect_err = 0, + .recv = &send_16_2_1, + .bcast = true, + .server = true, + .big = true, +}; + +static const struct iso_client_data bcast_16_2_1_recv_defer = { + .qos = QOS_IN_16_2_1, + .expect_err = 0, + .defer = true, + .recv = &send_16_2_1, + .bcast = true, + .server = true, + .listen_bind = true, + .big = true, +}; + +static const struct iso_client_data bcast_16_2_1_recv_defer_no_bis = { + .qos = QOS_IN_16_2_1, + .expect_err = 0, + .defer = true, + .bcast = true, + .server = true, + .big = true, +}; + +static const struct iso_client_data bcast_16_2_1_recv_defer_pa_bind = { + .qos = QOS_IN_16_2_1, + .expect_err = 0, + .defer = true, + .bcast = true, + .server = true, + .pa_bind = true, + .big = true, +}; + +static const struct iso_client_data bcast_16_2_1_recv_defer_get_base = { + .qos = QOS_IN_16_2_1, + .expect_err = 0, + .defer = true, + .bcast = true, + .server = true, + .base = base_lc3_ac_12, + .base_len = sizeof(base_lc3_ac_12), +}; + +static const struct iso_client_data bcast_ac_12 = { + .qos = BCAST_AC_12, + .expect_err = 0, + .bcast = true, + .base = base_lc3_ac_12, + .base_len = sizeof(base_lc3_ac_12), +}; + +static const struct iso_client_data bcast_ac_13_1_1 = { + .qos = BCAST_AC_13_1_1, + .expect_err = 0, + .bcast = true, + .mconn = true, + .base = base_lc3_ac_13, + .base_len = sizeof(base_lc3_ac_13), +}; + +static const struct iso_client_data bcast_ac_13_1_1_reconn = { + .qos = BCAST_AC_13_1_1, + .expect_err = 0, + .bcast = true, + .mconn = true, + .base = base_lc3_ac_13, + .base_len = sizeof(base_lc3_ac_13), + .disconnect = true, +}; + +static const struct iso_client_data bcast_ac_13_1 = { + .qos = BCAST_AC_13_1, + .expect_err = 0, + .bcast = true, + .mconn = true, + .base = base_lc3_ac_13, + .base_len = sizeof(base_lc3_ac_13), +}; + +static const struct iso_client_data bcast_ac_14 = { + .qos = BCAST_AC_14, + .expect_err = 0, + .bcast = true, + .base = base_lc3_ac_14, + .base_len = sizeof(base_lc3_ac_14), +}; + +static void client_connectable_complete(uint16_t opcode, uint8_t status, + const void *param, uint8_t len, + void *user_data) +{ + struct test_data *data = user_data; + static uint8_t client_num; + + if (opcode != BT_HCI_CMD_LE_SET_EXT_ADV_ENABLE) + return; + + tester_print("Client %u set connectable status 0x%02x", client_num, status); client_num++; @@ -681,14 +1539,17 @@ static void bthost_recv_data(const void *buf, uint16_t len, void *user_data) struct test_data *data = user_data; const struct iso_client_data *isodata = data->test_data; + --data->step; + tester_print("Client received %u bytes of data", len); if (isodata->send && (isodata->send->iov_len != len || memcmp(isodata->send->iov_base, buf, len))) { if (!isodata->recv->iov_base) tester_test_failed(); - } else + } else if (!data->step) { tester_test_passed(); + } } static void bthost_iso_disconnected(void *user_data) @@ -714,6 +1575,16 @@ static void iso_new_conn(uint16_t handle, void *user_data) bthost_iso_disconnected); } +static uint8_t iso_accept_conn(uint16_t handle, void *user_data) +{ + struct test_data *data = user_data; + + tester_print("Accept client connection with handle 0x%04x: 0x%02x", + handle, data->accept_reason); + + return data->accept_reason; +} + static void acl_new_conn(uint16_t handle, void *user_data) { struct test_data *data = user_data; @@ -751,13 +1622,24 @@ static void setup_powered_callback(uint8_t status, uint16_t length, if (!isodata) continue; - if (isodata->send || isodata->recv || isodata->disconnect) - bthost_set_iso_cb(host, iso_new_conn, data); + if (isodata->send || isodata->recv || isodata->disconnect || + isodata->suspend || data->accept_reason) + bthost_set_iso_cb(host, iso_accept_conn, iso_new_conn, + data); if (isodata->bcast) { bthost_set_pa_params(host); bthost_set_pa_enable(host, 0x01); - bthost_create_big(host, 1); + + if (isodata->base) + bthost_set_base(host, isodata->base, + isodata->base_len); + + if (isodata->big) + bthost_create_big(host, 1, + isodata->qos.bcast.encryption, + isodata->qos.bcast.bcode); + } else if (!isodata->send && isodata->recv) { const uint8_t *bdaddr; @@ -855,6 +1737,7 @@ static void test_setsockopt(const void *test_data) int sk, err; socklen_t len; struct bt_iso_qos qos = QOS_16_1_2; + int pkt_status = 1; sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO); if (sk < 0) { @@ -883,6 +1766,26 @@ static void test_setsockopt(const void *test_data) goto end; } + err = setsockopt(sk, SOL_BLUETOOTH, BT_PKT_STATUS, &pkt_status, + sizeof(pkt_status)); + if (err < 0) { + tester_warn("Can't set socket BT_PKT_STATUS option: " + "%s (%d)", strerror(errno), errno); + tester_test_failed(); + goto end; + } + + len = sizeof(pkt_status); + memset(&pkt_status, 0, len); + + err = getsockopt(sk, SOL_BLUETOOTH, BT_PKT_STATUS, &pkt_status, &len); + if (err < 0) { + tester_warn("Can't get socket option : %s (%d)", + strerror(errno), errno); + tester_test_failed(); + goto end; + } + tester_test_passed(); end: @@ -906,6 +1809,7 @@ static int create_iso_sock(struct test_data *data) master_bdaddr = hciemu_get_central_bdaddr(data->hciemu); if (!master_bdaddr) { tester_warn("No master bdaddr"); + close(sk); return -ENODEV; } @@ -925,46 +1829,42 @@ static int create_iso_sock(struct test_data *data) return sk; } -static const uint8_t base_lc3_16_2_1[] = { - 0x28, 0x00, 0x00, /* Presentation Delay */ - 0x01, /* Number of Subgroups */ - 0x01, /* Number of BIS */ - 0x06, 0x00, 0x00, 0x00, 0x00, /* Code ID = LC3 (0x06) */ - 0x11, /* Codec Specific Configuration */ - 0x02, 0x01, 0x03, /* 16 KHZ */ - 0x02, 0x02, 0x01, /* 10 ms */ - 0x05, 0x03, 0x01, 0x00, 0x00, 0x00, /* Front Left */ - 0x03, 0x04, 0x28, 0x00, /* Frame Length 40 bytes */ - 0x04, /* Metadata */ - 0x03, 0x02, 0x02, 0x00, /* Audio Context: Convertional */ - 0x01, /* BIS */ - 0x00, /* Codec Specific Configuration */ -}; - static int connect_iso_sock(struct test_data *data, uint8_t num, int sk) { const struct iso_client_data *isodata = data->test_data; struct hciemu_client *client; const uint8_t *client_bdaddr = NULL; + const struct bt_iso_qos *qos = &isodata->qos; struct sockaddr_iso addr; char str[18]; int err; client = hciemu_get_client(data->hciemu, num); if (!client) { - tester_warn("No client"); - return -ENODEV; + if (!isodata->mconn) { + tester_warn("No client"); + return -ENODEV; + } + + client = hciemu_get_client(data->hciemu, 0); + if (!client) { + tester_warn("No client"); + return -ENODEV; + } } + if (!isodata->bcast && num && isodata->mconn) + qos = &isodata->qos_2; + if (!isodata->bcast) { client_bdaddr = hciemu_client_bdaddr(client); if (!client_bdaddr) { tester_warn("No client bdaddr"); return -ENODEV; } - } else { + } else if (!isodata->server) { err = setsockopt(sk, SOL_BLUETOOTH, BT_ISO_BASE, - base_lc3_16_2_1, sizeof(base_lc3_16_2_1)); + isodata->base, isodata->base_len); if (err < 0) { tester_warn("Can't set socket BT_ISO_BASE option: " "%s (%d)", strerror(errno), errno); @@ -973,8 +1873,7 @@ static int connect_iso_sock(struct test_data *data, uint8_t num, int sk) } } - err = setsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &isodata->qos, - sizeof(isodata->qos)); + err = setsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, qos, sizeof(*qos)); if (err < 0) { tester_warn("Can't set socket BT_ISO_QOS option : %s (%d)", strerror(errno), errno); @@ -982,7 +1881,7 @@ static int connect_iso_sock(struct test_data *data, uint8_t num, int sk) return -EINVAL; } - if (isodata->defer) { + if (isodata->defer || (isodata->bcast && isodata->mconn && !num)) { int opt = 1; if (setsockopt(sk, SOL_BLUETOOTH, BT_DEFER_SETUP, &opt, @@ -1018,14 +1917,14 @@ static int connect_iso_sock(struct test_data *data, uint8_t num, int sk) static bool check_io_qos(const struct bt_iso_io_qos *io1, const struct bt_iso_io_qos *io2) { - if (io1->interval && io2->interval && io1->interval != io2->interval) { - tester_warn("Unexpected IO interval: %u != %u", + if (io1->interval && io2->interval && io1->interval > io2->interval) { + tester_warn("Unexpected IO interval: %u > %u", io1->interval, io2->interval); return false; } - if (io1->latency && io2->latency && io1->latency != io2->latency) { - tester_warn("Unexpected IO latency: %u != %u", + if (io1->latency && io2->latency && io1->latency > io2->latency) { + tester_warn("Unexpected IO latency: %u > %u", io1->latency, io2->latency); return false; } @@ -1049,43 +1948,62 @@ static bool check_io_qos(const struct bt_iso_io_qos *io1, return true; } -static bool check_qos(const struct bt_iso_qos *qos1, - const struct bt_iso_qos *qos2) +static bool check_ucast_qos(const struct bt_iso_qos *qos1, + const struct bt_iso_qos *qos2, + const struct bt_iso_qos *qos2_2) { - if (qos1->cig != BT_ISO_QOS_CIG_UNSET && - qos2->cig != BT_ISO_QOS_CIG_UNSET && - qos1->cig != qos2->cig) { + if (qos1->ucast.cig != BT_ISO_QOS_CIG_UNSET && + qos2->ucast.cig != BT_ISO_QOS_CIG_UNSET && + qos1->ucast.cig != qos2->ucast.cig) { + if (qos2_2) + return check_ucast_qos(qos1, qos2_2, NULL); + tester_warn("Unexpected CIG ID: 0x%02x != 0x%02x", - qos1->cig, qos2->cig); + qos1->ucast.cig, qos2->ucast.cig); return false; } - if (qos1->cis != BT_ISO_QOS_CIS_UNSET && - qos2->cis != BT_ISO_QOS_CIS_UNSET && - qos1->cis != qos2->cis) { + if (qos1->ucast.cis != BT_ISO_QOS_CIS_UNSET && + qos2->ucast.cis != BT_ISO_QOS_CIS_UNSET && + qos1->ucast.cis != qos2->ucast.cis) { + if (qos2_2) + return check_ucast_qos(qos1, qos2_2, NULL); + tester_warn("Unexpected CIS ID: 0x%02x != 0x%02x", - qos1->cis, qos2->cis); + qos1->ucast.cis, qos2->ucast.cis); return false; } - if (qos1->packing != qos2->packing) { + if (qos1->ucast.packing != qos2->ucast.packing) { + if (qos2_2) + return check_ucast_qos(qos1, qos2_2, NULL); + tester_warn("Unexpected QoS packing: 0x%02x != 0x%02x", - qos1->packing, qos2->packing); + qos1->ucast.packing, qos2->ucast.packing); return false; } - if (qos1->framing != qos2->framing) { + if (qos1->ucast.framing != qos2->ucast.framing) { + if (qos2_2) + return check_ucast_qos(qos1, qos2_2, NULL); + tester_warn("Unexpected QoS framing: 0x%02x != 0x%02x", - qos1->framing, qos2->framing); + qos1->ucast.framing, qos2->ucast.framing); return false; } - if (!check_io_qos(&qos1->in, &qos2->in)) { + if (!check_io_qos(&qos1->ucast.in, &qos2->ucast.in)) { + if (qos2_2) + return check_ucast_qos(qos1, qos2_2, NULL); + tester_warn("Unexpected Input QoS"); return false; } - if (!check_io_qos(&qos1->out, &qos2->out)) { + if (!check_io_qos(&qos1->ucast.out, &qos2->ucast.out)) { + if (qos2_2) + return check_ucast_qos(qos1, qos2_2, NULL); + tester_warn("Unexpected Output QoS"); return false; } @@ -1093,63 +2011,343 @@ static bool check_qos(const struct bt_iso_qos *qos1, return true; } -static gboolean iso_recv_data(GIOChannel *io, GIOCondition cond, - gpointer user_data) +static bool check_bcast_qos(const struct bt_iso_qos *qos1, + const struct bt_iso_qos *qos2) { - struct test_data *data = user_data; - const struct iso_client_data *isodata = data->test_data; - int sk = g_io_channel_unix_get_fd(io); - ssize_t ret; - char buf[1024]; + if (qos1->bcast.big != BT_ISO_QOS_BIG_UNSET && + qos2->bcast.big != BT_ISO_QOS_BIG_UNSET && + qos1->bcast.big != qos2->bcast.big) { + tester_warn("Unexpected BIG ID: 0x%02x != 0x%02x", + qos1->bcast.big, qos2->bcast.big); + return false; + } - data->io_id[0] = 0; + if (qos1->bcast.bis != BT_ISO_QOS_BIS_UNSET && + qos2->bcast.bis != BT_ISO_QOS_BIS_UNSET && + qos1->bcast.bis != qos2->bcast.bis) { + tester_warn("Unexpected BIS ID: 0x%02x != 0x%02x", + qos1->bcast.bis, qos2->bcast.bis); + return false; + } - ret = read(sk, buf, isodata->recv->iov_len); - if (ret < 0 || isodata->recv->iov_len != (size_t) ret) { - tester_warn("Failed to read %zu bytes: %s (%d)", - isodata->recv->iov_len, strerror(errno), errno); - tester_test_failed(); - return FALSE; + if (qos1->bcast.sync_factor != qos2->bcast.sync_factor) { + tester_warn("Unexpected QoS sync interval: 0x%02x != 0x%02x", + qos1->bcast.sync_factor, qos2->bcast.sync_factor); + return false; } - if (memcmp(buf, isodata->recv->iov_base, ret)) - tester_test_failed(); - else - tester_test_passed(); + if (qos1->bcast.packing != qos2->bcast.packing) { + tester_warn("Unexpected QoS packing: 0x%02x != 0x%02x", + qos1->bcast.packing, qos2->bcast.packing); + return false; + } - return FALSE; -} + if (qos1->bcast.framing != qos2->bcast.framing) { + tester_warn("Unexpected QoS framing: 0x%02x != 0x%02x", + qos1->bcast.framing, qos2->bcast.framing); + return false; + } -static void iso_recv(struct test_data *data, GIOChannel *io) -{ - const struct iso_client_data *isodata = data->test_data; - struct bthost *host; + if (!check_io_qos(&qos1->ucast.in, &qos2->ucast.in)) { + tester_warn("Unexpected Input QoS"); + return false; + } - tester_print("Receive %zu bytes of data", isodata->recv->iov_len); + if (!check_io_qos(&qos1->ucast.out, &qos2->ucast.out)) { + tester_warn("Unexpected Output QoS"); + return false; + } - if (!data->handle) { + if (qos1->bcast.encryption != qos2->bcast.encryption) { + tester_warn("Unexpected QoS encryption: 0x%02x != 0x%02x", + qos1->bcast.encryption, qos2->bcast.encryption); + return false; + } + + if (memcmp(qos1->bcast.bcode, qos2->bcast.bcode, + sizeof(qos1->bcast.bcode))) { + tester_warn("Unexpected QoS Broadcast Code"); + return false; + } + + if (qos1->bcast.options != qos2->bcast.options) { + tester_warn("Unexpected QoS options: 0x%02x != 0x%02x", + qos1->bcast.options, qos2->bcast.options); + return false; + } + + if (qos1->bcast.skip != qos2->bcast.skip) { + tester_warn("Unexpected QoS skip: 0x%04x != 0x%04x", + qos1->bcast.skip, qos2->bcast.skip); + return false; + } + + if (qos1->bcast.sync_timeout != qos2->bcast.sync_timeout) { + tester_warn("Unexpected QoS sync timeout: 0x%04x != 0x%04x", + qos1->bcast.sync_timeout, qos2->bcast.sync_timeout); + return false; + } + + if (qos1->bcast.sync_cte_type != qos2->bcast.sync_cte_type) { + tester_warn("Unexpected QoS sync cte type: 0x%02x != 0x%02x", + qos1->bcast.sync_cte_type, qos2->bcast.sync_cte_type); + return false; + } + + if (qos1->bcast.mse != qos2->bcast.mse) { + tester_warn("Unexpected QoS MSE: 0x%02x != 0x%02x", + qos1->bcast.mse, qos2->bcast.mse); + return false; + } + + if (qos1->bcast.timeout != qos2->bcast.timeout) { + tester_warn("Unexpected QoS MSE: 0x%04x != 0x%04x", + qos1->bcast.timeout, qos2->bcast.timeout); + return false; + } + + return true; +} + +static gboolean iso_recv_data(GIOChannel *io, GIOCondition cond, + gpointer user_data) +{ + struct test_data *data = user_data; + const struct iso_client_data *isodata = data->test_data; + int sk = g_io_channel_unix_get_fd(io); + unsigned char control[64]; + ssize_t ret; + char buf[1024]; + struct msghdr msg; + struct iovec iov; + + data->io_id[0] = 0; + + iov.iov_base = buf; + iov.iov_len = isodata->recv->iov_len; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = control; + msg.msg_controllen = sizeof(control); + + ret = recvmsg(sk, &msg, MSG_DONTWAIT); + if (ret < 0 || isodata->recv->iov_len != (size_t) ret) { + tester_warn("Failed to read %zu bytes: %s (%d)", + isodata->recv->iov_len, strerror(errno), errno); + tester_test_failed(); + return FALSE; + } + + if (isodata->pkt_status) { + struct cmsghdr *cmsg; + uint8_t pkt_status = 0; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level != SOL_BLUETOOTH) + continue; + + if (cmsg->cmsg_type == BT_SCM_PKT_STATUS) { + memcpy(&pkt_status, CMSG_DATA(cmsg), + sizeof(pkt_status)); + tester_debug("BT_SCM_PKT_STATUS = 0x%2.2x", + pkt_status); + break; + } + } + + if (isodata->pkt_status != pkt_status) { + tester_warn("isodata->pkt_status 0x%2.2x != 0x%2.2x " + "pkt_status", isodata->pkt_status, + pkt_status); + tester_test_failed(); + } else + tester_test_passed(); + + return FALSE; + } + + if (memcmp(buf, isodata->recv->iov_base, ret)) + tester_test_failed(); + else + tester_test_passed(); + + return FALSE; +} + +static void iso_recv(struct test_data *data, GIOChannel *io) +{ + const struct iso_client_data *isodata = data->test_data; + struct bthost *host; + static uint16_t sn; + + tester_print("Receive %zu bytes of data", isodata->recv->iov_len); + + if (!data->handle) { tester_warn("ISO handle not set"); tester_test_failed(); return; } host = hciemu_client_get_host(data->hciemu); - bthost_send_iso(host, data->handle, isodata->recv, 1); + bthost_send_iso(host, data->handle, isodata->ts, sn++, 0, + isodata->pkt_status, isodata->recv, 1); data->io_id[0] = g_io_add_watch(io, G_IO_IN, iso_recv_data, data); } -static void iso_send(struct test_data *data, GIOChannel *io) +static gboolean iso_recv_errqueue(GIOChannel *io, GIOCondition cond, + gpointer user_data) { + struct test_data *data = user_data; const struct iso_client_data *isodata = data->test_data; - ssize_t ret; + int sk = g_io_channel_unix_get_fd(io); + int err; + + data->step--; + + err = tx_tstamp_recv(&data->tx_ts, sk, isodata->send->iov_len); + if (err > 0) + return TRUE; + else if (!err && !data->step) + tester_test_passed(); + else + tester_test_failed(); + + data->io_id[2] = 0; + return FALSE; +} + +static gboolean iso_fail_errqueue(GIOChannel *io, GIOCondition cond, + gpointer user_data) +{ + struct test_data *data = user_data; + + tester_warn("Unexpected POLLERR"); + tester_test_failed(); + + data->io_id[3] = 0; + return FALSE; +} + +static gboolean iso_timer_errqueue(gpointer user_data) +{ + struct test_data *data = user_data; + GIOChannel *io; + gboolean ret; + + io = queue_peek_head(data->io_queue); + g_assert(io); + + ret = iso_recv_errqueue(io, G_IO_IN, data); + if (!ret) { + if (data->io_id[3]) + g_source_remove(data->io_id[3]); + data->io_id[3] = 0; + } + + return ret; +} + +static void iso_tx_timestamping(struct test_data *data, GIOChannel *io) +{ + const struct iso_client_data *isodata = data->test_data; + int so = isodata->so_timestamping; int sk; + int err; + unsigned int count; + + if (!(isodata->so_timestamping & SOF_TIMESTAMPING_TX_RECORD_MASK)) + return; + + tester_print("Enabling TX timestamping"); + + tx_tstamp_init(&data->tx_ts, isodata->so_timestamping); + + for (count = 0; count < isodata->repeat_send + 1; ++count) + data->step += tx_tstamp_expect(&data->tx_ts); sk = g_io_channel_unix_get_fd(io); + if (isodata->no_poll_errqueue) { + uint32_t flag = 0; + + err = setsockopt(sk, SOL_BLUETOOTH, BT_POLL_ERRQUEUE, + &flag, sizeof(flag)); + if (err < 0) { + tester_warn("setsockopt BT_POLL_ERRQUEUE: %s (%d)", + strerror(errno), errno); + tester_test_failed(); + return; + } + + if (!data->io_queue) + data->io_queue = queue_new(); + queue_push_head(data->io_queue, g_io_channel_ref(io)); + + data->io_id[2] = g_timeout_add(100, iso_timer_errqueue, data); + data->io_id[3] = g_io_add_watch(io, G_IO_ERR, iso_fail_errqueue, + data); + } else { + uint32_t flag = 1; + + err = setsockopt(sk, SOL_BLUETOOTH, BT_POLL_ERRQUEUE, + &flag, sizeof(flag)); + if (err >= 0) { + tester_warn("BT_POLL_ERRQUEUE available"); + tester_test_failed(); + return; + } + + data->io_id[2] = g_io_add_watch(io, G_IO_ERR, iso_recv_errqueue, + data); + } + + if (isodata->cmsg_timestamping) + so &= ~SOF_TIMESTAMPING_TX_RECORD_MASK; + + err = setsockopt(sk, SOL_SOCKET, SO_TIMESTAMPING, &so, sizeof(so)); + if (err < 0) { + tester_warn("setsockopt SO_TIMESTAMPING: %s (%d)", + strerror(errno), errno); + tester_test_failed(); + return; + } +} + +static void iso_send_data(struct test_data *data, GIOChannel *io) +{ + const struct iso_client_data *isodata = data->test_data; + char control[CMSG_SPACE(sizeof(uint32_t))]; + struct msghdr msg = { + .msg_iov = (struct iovec *)isodata->send, + .msg_iovlen = 1, + }; + struct cmsghdr *cmsg; + ssize_t ret; + int sk; + tester_print("Writing %zu bytes of data", isodata->send->iov_len); - ret = writev(sk, isodata->send, 1); + sk = g_io_channel_unix_get_fd(io); + + if (isodata->cmsg_timestamping) { + memset(control, 0, sizeof(control)); + msg.msg_control = control; + msg.msg_controllen = sizeof(control); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SO_TIMESTAMPING; + cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t)); + + *((uint32_t *)CMSG_DATA(cmsg)) = (isodata->so_timestamping & + SOF_TIMESTAMPING_TX_RECORD_MASK); + } + + ret = sendmsg(sk, &msg, 0); if (ret < 0 || isodata->send->iov_len != (size_t) ret) { tester_warn("Failed to write %zu bytes: %s (%d)", isodata->send->iov_len, strerror(errno), errno); @@ -1157,6 +2355,22 @@ static void iso_send(struct test_data *data, GIOChannel *io) return; } + data->step++; +} + +static void iso_send(struct test_data *data, GIOChannel *io) +{ + const struct iso_client_data *isodata = data->test_data; + unsigned int count; + + for (count = 0; count < isodata->repeat_send_pre_ts; ++count) + iso_send_data(data, io); + + iso_tx_timestamping(data, io); + + for (count = 0; count < isodata->repeat_send + 1; ++count) + iso_send_data(data, io); + if (isodata->bcast) { tester_test_passed(); return; @@ -1166,23 +2380,29 @@ static void iso_send(struct test_data *data, GIOChannel *io) iso_recv(data, io); } -static void setup_connect(struct test_data *data, uint8_t num, GIOFunc func); +static void test_connect(const void *test_data); static gboolean iso_connect_cb(GIOChannel *io, GIOCondition cond, gpointer user_data); +static gboolean iso_accept_cb(GIOChannel *io, GIOCondition cond, + gpointer user_data); static gboolean iso_disconnected(GIOChannel *io, GIOCondition cond, gpointer user_data) { struct test_data *data = user_data; + const struct iso_client_data *isodata = data->test_data; data->io_id[0] = 0; - if ((cond & G_IO_HUP) && !data->handle) { + if (cond & G_IO_HUP) { + if (!isodata->bcast && data->handle) + tester_test_failed(); + tester_print("Successfully disconnected"); if (data->reconnect) { data->reconnect = false; - setup_connect(data, 0, iso_connect_cb); + test_connect(data->test_data); return FALSE; } @@ -1209,6 +2429,46 @@ static void iso_shutdown(struct test_data *data, GIOChannel *io) tester_print("Disconnecting..."); } +static bool hook_set_event_mask(const void *msg, uint16_t len, void *user_data) +{ + struct test_data *data = user_data; + + tester_print("Set Event Mask"); + + --data->step; + if (!data->step) + tester_test_passed(); + + return true; +} + +static void trigger_force_suspend(void *user_data) +{ + struct test_data *data = tester_get_data(); + struct vhci *vhci = hciemu_get_vhci(data->hciemu); + int err; + + /* Make sure suspend is only triggered once */ + if (data->suspending) + return; + + data->suspending = true; + + /* Triggers the suspend */ + tester_print("Set the system into Suspend via force_suspend"); + err = vhci_set_force_suspend(vhci, true); + if (err) { + tester_warn("Unable to enable the force_suspend"); + return; + } + + data->step++; + + hciemu_add_hook(data->hciemu, HCIEMU_HOOK_PRE_CMD, + BT_HCI_CMD_SET_EVENT_MASK, + hook_set_event_mask, data); +} + static gboolean iso_connect(GIOChannel *io, GIOCondition cond, gpointer user_data) { @@ -1217,6 +2477,8 @@ static gboolean iso_connect(GIOChannel *io, GIOCondition cond, int err, sk_err, sk; socklen_t len; struct bt_iso_qos qos; + bool ret = true; + uint8_t base[BASE_MAX_LENGTH] = {0}; sk = g_io_channel_unix_get_fd(io); @@ -1227,16 +2489,45 @@ static gboolean iso_connect(GIOChannel *io, GIOCondition cond, if (err < 0) { tester_warn("Can't get socket option : %s (%d)", strerror(errno), errno); + data->step = 0; tester_test_failed(); return FALSE; } - if (!check_qos(&qos, &isodata->qos)) { + if (!isodata->bcast) { + ret = check_ucast_qos(&qos, &isodata->qos, + isodata->mconn ? &isodata->qos_2 : NULL); + } else if (!isodata->server) + ret = check_bcast_qos(&qos, &isodata->qos); + + if (!ret) { tester_warn("Unexpected QoS parameter"); + data->step = 0; tester_test_failed(); return FALSE; } + if (isodata->bcast && isodata->server && isodata->base) { + len = BASE_MAX_LENGTH; + + if (getsockopt(sk, SOL_BLUETOOTH, BT_ISO_BASE, + base, &len) < 0) { + tester_warn("Can't get socket option : %s (%d)", + strerror(errno), errno); + data->step = 0; + tester_test_failed(); + return FALSE; + } + + if (len != isodata->base_len || + memcmp(base, isodata->base, len)) { + tester_warn("Unexpected BASE"); + data->step = 0; + tester_test_failed(); + return FALSE; + } + } + len = sizeof(sk_err); if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0) @@ -1249,10 +2540,11 @@ static gboolean iso_connect(GIOChannel *io, GIOCondition cond, else tester_print("Successfully connected"); - if (-err != isodata->expect_err) { + if (err != isodata->expect_err) { tester_warn("Expect error: %s (%d) != %s (%d)", strerror(-isodata->expect_err), -isodata->expect_err, strerror(-err), -err); + data->step = 0; tester_test_failed(); } else { data->step--; @@ -1264,6 +2556,8 @@ static gboolean iso_connect(GIOChannel *io, GIOCondition cond, iso_recv(data, io); else if (isodata->disconnect) iso_shutdown(data, io); + else if (isodata->suspend) + trigger_force_suspend(data); else tester_test_passed(); } @@ -1291,13 +2585,9 @@ static gboolean iso_connect2_cb(GIOChannel *io, GIOCondition cond, return iso_connect(io, cond, user_data); } -static void setup_connect(struct test_data *data, uint8_t num, GIOFunc func) +static int setup_sock(struct test_data *data, uint8_t num) { - const struct iso_client_data *isodata = data->test_data; - GIOChannel *io; int sk, err; - char c; - struct pollfd pfd; sk = create_iso_sock(data); if (sk < 0) { @@ -1305,7 +2595,8 @@ static void setup_connect(struct test_data *data, uint8_t num, GIOFunc func) tester_test_abort(); else tester_test_failed(); - return; + + return sk; } err = connect_iso_sock(data, num, sk); @@ -1319,73 +2610,122 @@ static void setup_connect(struct test_data *data, uint8_t num, GIOFunc func) else tester_test_failed(); - return; + return err; } - if (isodata->defer) { - int defer; - socklen_t len; - - /* Check if socket has DEFER_SETUP set */ - len = sizeof(defer); - if (getsockopt(sk, SOL_BLUETOOTH, BT_DEFER_SETUP, &defer, - &len) < 0) { - tester_warn("getsockopt: %s (%d)", strerror(errno), - errno); + return sk; +} + +static int connect_deferred(int sk) +{ + int defer; + socklen_t len; + struct pollfd pfd; + char c; + + /* Check if socket has DEFER_SETUP set */ + len = sizeof(defer); + if (getsockopt(sk, SOL_BLUETOOTH, BT_DEFER_SETUP, &defer, + &len) < 0) { + tester_warn("getsockopt: %s (%d)", strerror(errno), + errno); + tester_test_failed(); + return 0; + } + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = sk; + pfd.events = POLLOUT; + + if (poll(&pfd, 1, 0) < 0) { + tester_warn("poll: %s (%d)", strerror(errno), errno); + tester_test_failed(); + return -EIO; + } + + if (!(pfd.revents & POLLOUT)) { + if (read(sk, &c, 1) < 0) { + tester_warn("read: %s (%d)", strerror(errno), + errno); tester_test_failed(); - return; + return -EIO; } + } - memset(&pfd, 0, sizeof(pfd)); - pfd.fd = sk; - pfd.events = POLLOUT; + return 0; +} - if (poll(&pfd, 1, 0) < 0) { - tester_warn("poll: %s (%d)", strerror(errno), errno); - tester_test_failed(); +static void setup_connect_many(struct test_data *data, uint8_t n, uint8_t *num, + GIOFunc *func) +{ + const struct iso_client_data *isodata = data->test_data; + int sk[256]; + GIOChannel *io; + unsigned int i; + + for (i = 0; i < n; ++i) { + sk[i] = setup_sock(data, num[i]); + if (sk[i] < 0) return; - } + } - if (!(pfd.revents & POLLOUT)) { - if (read(sk, &c, 1) < 0) { - tester_warn("read: %s (%d)", strerror(errno), - errno); - tester_test_failed(); + if (isodata->defer) { + for (i = 0; i < n; ++i) + if (connect_deferred(sk[i]) < 0) return; - } - } } - io = g_io_channel_unix_new(sk); - g_io_channel_set_close_on_unref(io, TRUE); + for (i = 0; i < n; ++i) { + io = g_io_channel_unix_new(sk[i]); + g_io_channel_set_close_on_unref(io, TRUE); - data->io_id[num] = g_io_add_watch(io, G_IO_OUT, func, NULL); + data->io_id[num[i]] = g_io_add_watch(io, G_IO_OUT, func[i], + NULL); - g_io_channel_unref(io); + if (!isodata->bcast || !data->reconnect) + g_io_channel_unref(io); + else if (data->io_queue) + /* For the broadcast reconnect scenario, do not + * unref channel here, to avoid closing the + * socket. All queued channels will be closed + * by test_data_free. + */ + queue_push_tail(data->io_queue, io); - tester_print("Connect in progress"); + tester_print("Connect %d in progress", num[i]); - data->step++; + data->step++; + } +} + +static void setup_connect(struct test_data *data, uint8_t num, GIOFunc func) +{ + return setup_connect_many(data, 1, &num, &func); } static void test_connect(const void *test_data) { struct test_data *data = tester_get_data(); + const struct iso_client_data *isodata = test_data; + uint8_t n = 0; + GIOFunc func[2]; + uint8_t num[2] = {0, 1}; - setup_connect(data, 0, iso_connect_cb); -} + func[n++] = iso_connect_cb; -static void setup_reconnect(struct test_data *data, uint8_t num, GIOFunc func) -{ - data->reconnect = true; - setup_connect(data, num, func); + /* Check if configuration requires multiple CIS setup */ + if (!isodata->bcast && isodata->mconn) + func[n++] = iso_connect2_cb; + + setup_connect_many(data, n, num, func); } static void test_reconnect(const void *test_data) { struct test_data *data = tester_get_data(); - setup_reconnect(data, 0, iso_connect_cb); + data->reconnect = true; + test_connect(test_data); } static void test_defer(const void *test_data) @@ -1463,8 +2803,11 @@ static int listen_iso_sock(struct test_data *data) bacpy(&addr->iso_bc->bc_bdaddr, (void *) dst); addr->iso_bc->bc_bdaddr_type = BDADDR_LE_PUBLIC; - addr->iso_bc->bc_num_bis = 1; - addr->iso_bc->bc_bis[0] = 1; + + if (!isodata->defer || isodata->listen_bind) { + addr->iso_bc->bc_num_bis = 1; + addr->iso_bc->bc_bis[0] = 1; + } err = bind(sk, (struct sockaddr *) addr, sizeof(*addr) + sizeof(*addr->iso_bc)); @@ -1482,173 +2825,511 @@ static int listen_iso_sock(struct test_data *data) if (isodata->defer) { int opt = 1; - if (setsockopt(sk, SOL_BLUETOOTH, BT_DEFER_SETUP, &opt, - sizeof(opt)) < 0) { - tester_print("Can't enable deferred setup: %s (%d)", - strerror(errno), errno); - goto fail; - } - } + if (setsockopt(sk, SOL_BLUETOOTH, BT_DEFER_SETUP, &opt, + sizeof(opt)) < 0) { + tester_print("Can't enable deferred setup: %s (%d)", + strerror(errno), errno); + goto fail; + } + } + + if (setsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &isodata->qos, + sizeof(isodata->qos)) < 0) { + tester_print("Can't set socket BT_ISO_QOS option: %s (%d)", + strerror(errno), errno); + goto fail; + } + + if (listen(sk, 10)) { + err = -errno; + tester_warn("Can't listen socket: %s (%d)", strerror(errno), + errno); + goto fail; + } + + free(addr); + + return sk; + +fail: + free(addr); + close(sk); + return err; +} + +static void setup_listen(struct test_data *data, uint8_t num, GIOFunc func) +{ + const struct iso_client_data *isodata = data->test_data; + GIOChannel *io; + int sk; + + sk = listen_iso_sock(data); + if (sk < 0) { + if (sk == -EPROTONOSUPPORT) + tester_test_abort(); + else + tester_test_failed(); + return; + } + + io = g_io_channel_unix_new(sk); + g_io_channel_set_close_on_unref(io, TRUE); + + data->io_id[num] = g_io_add_watch(io, G_IO_IN, func, NULL); + + g_io_channel_unref(io); + + tester_print("Listen in progress"); + + data->step++; + + if (!isodata->bcast) { + struct hciemu_client *client; + struct bthost *host; + + if (!data->acl_handle) { + tester_print("ACL handle not set"); + tester_test_failed(); + return; + } + + client = hciemu_get_client(data->hciemu, 0); + host = hciemu_client_host(client); + + bthost_set_cig_params(host, 0x01, 0x01, &isodata->qos); + bthost_create_cis(host, 257, data->acl_handle); + } +} + +static bool iso_defer_accept_bcast(struct test_data *data, GIOChannel *io) +{ + int sk; + char c; + const struct iso_client_data *isodata = data->test_data; + struct sockaddr_iso *addr = NULL; + + sk = g_io_channel_unix_get_fd(io); + + if (isodata->pa_bind) { + addr = malloc(sizeof(*addr) + sizeof(*addr->iso_bc)); + memset(addr, 0, sizeof(*addr) + sizeof(*addr->iso_bc)); + addr->iso_family = AF_BLUETOOTH; + + addr->iso_bc->bc_num_bis = 1; + addr->iso_bc->bc_bis[0] = 1; + + if (bind(sk, (struct sockaddr *) addr, sizeof(*addr) + + sizeof(*addr->iso_bc)) < 0) { + tester_warn("bind: %s (%d)", strerror(errno), errno); + free(addr); + return false; + } + + free(addr); + } + + if (read(sk, &c, 1) < 0) { + tester_warn("read: %s (%d)", strerror(errno), errno); + return false; + } + + tester_print("Accept deferred setup"); + + data->io_queue = queue_new(); + if (data->io_queue) + queue_push_tail(data->io_queue, io); + + data->io_id[0] = g_io_add_watch(io, G_IO_IN, + iso_accept_cb, NULL); + + return true; +} + +static bool iso_defer_accept_ucast(struct test_data *data, GIOChannel *io) +{ + int sk; + char c; + struct pollfd pfd; + + sk = g_io_channel_unix_get_fd(io); + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = sk; + pfd.events = POLLOUT; + + if (poll(&pfd, 1, 0) < 0) { + tester_warn("poll: %s (%d)", strerror(errno), errno); + return false; + } + + if (!(pfd.revents & POLLOUT)) { + if (read(sk, &c, 1) < 0) { + tester_warn("read: %s (%d)", strerror(errno), errno); + return false; + } + } + + tester_print("Accept deferred setup"); + + data->io_queue = queue_new(); + if (data->io_queue) + queue_push_tail(data->io_queue, io); + + data->io_id[0] = g_io_add_watch(io, G_IO_OUT, + iso_connect_cb, NULL); + + return true; +} + +static gboolean iso_accept_cb(GIOChannel *io, GIOCondition cond, + gpointer user_data) +{ + struct test_data *data = tester_get_data(); + const struct iso_client_data *isodata = data->test_data; + int sk, new_sk; + iso_defer_accept_t iso_accept = isodata->bcast ? + iso_defer_accept_bcast : + iso_defer_accept_ucast; + + data->io_id[0] = 0; + + sk = g_io_channel_unix_get_fd(io); + + new_sk = accept(sk, NULL, NULL); + if (new_sk < 0) { + tester_test_failed(); + return false; + } + + io = g_io_channel_unix_new(new_sk); + g_io_channel_set_close_on_unref(io, TRUE); + + if (isodata->defer) { + if (isodata->expect_err < 0) { + g_io_channel_unref(io); + tester_test_passed(); + return false; + } + + if (isodata->bcast) { + iso_connect(io, cond, user_data); + + if (!data->step) + return false; + } + + if (!iso_accept(data, io)) { + tester_warn("Unable to accept deferred setup"); + tester_test_failed(); + } + return false; + } + + if (isodata->pkt_status) { + int opt = 1; + + if (setsockopt(new_sk, SOL_BLUETOOTH, BT_PKT_STATUS, &opt, + sizeof(opt)) < 0) { + tester_print("Can't set socket BT_PKT_STATUS option: " + "%s (%d)", strerror(errno), errno); + tester_test_failed(); + return false; + } + } + + return iso_connect(io, cond, user_data); +} + +static void test_listen(const void *test_data) +{ + struct test_data *data = tester_get_data(); + + setup_listen(data, 0, iso_accept_cb); +} + +static void test_connect2(const void *test_data) +{ + struct test_data *data = tester_get_data(); + uint8_t num[2] = {0, 1}; + GIOFunc funcs[2] = {iso_connect_cb, iso_connect2_cb}; + + setup_connect_many(data, 2, num, funcs); +} + +static gboolean iso_connect2_seq_cb(GIOChannel *io, GIOCondition cond, + gpointer user_data) +{ + struct test_data *data = tester_get_data(); + + data->io_id[0] = 0; + + setup_connect(data, 1, iso_connect2_cb); + + return iso_connect(io, cond, user_data); +} + +static void test_connect2_seq(const void *test_data) +{ + struct test_data *data = tester_get_data(); + + setup_connect(data, 0, iso_connect2_seq_cb); +} + +static gboolean test_connect2_busy_done(gpointer user_data) +{ + struct test_data *data = tester_get_data(); + + if (data->io_id[0] > 0) { + /* First connection still exists */ + g_source_remove(data->io_id[0]); + data->io_id[0] = 0; + tester_test_passed(); + } else { + tester_test_failed(); + } + + return FALSE; +} + +static gboolean iso_connect_cb_busy_disc(GIOChannel *io, GIOCondition cond, + gpointer user_data) +{ + struct test_data *data = tester_get_data(); + + data->io_id[0] = 0; + + tester_print("Disconnected 1"); + tester_test_failed(); + return FALSE; +} + +static gboolean iso_connect_cb_busy_2(GIOChannel *io, GIOCondition cond, + gpointer user_data) +{ + struct test_data *data = tester_get_data(); + int err, sk_err, sk; + socklen_t len; + + data->io_id[1] = 0; + + sk = g_io_channel_unix_get_fd(io); + + len = sizeof(sk_err); + + if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0) + err = -errno; + else + err = -sk_err; + + tester_print("Connected 2: %d", err); + + if (err == -EBUSY && data->io_id[0] > 0) { + /* Wait in case first connection still gets disconnected */ + data->io_id[1] = g_timeout_add(250, test_connect2_busy_done, + data); + } else { + tester_test_failed(); + } + + return FALSE; +} + +static gboolean iso_connect_cb_busy(GIOChannel *io, GIOCondition cond, + gpointer user_data) +{ + struct test_data *data = tester_get_data(); + + /* First connection shall not be disconnected */ + data->io_id[0] = g_io_add_watch(io, G_IO_ERR | G_IO_HUP, + iso_connect_cb_busy_disc, data); + + /* Second connect shall fail since CIG is now busy */ + setup_connect(data, 1, iso_connect_cb_busy_2); + + return iso_connect(io, cond, user_data); +} + +static void test_connect2_busy(const void *test_data) +{ + struct test_data *data = tester_get_data(); + + setup_connect(data, 0, iso_connect_cb_busy); +} + +static gboolean iso_connect_close_cb(GIOChannel *io, GIOCondition cond, + gpointer user_data) +{ + struct test_data *data = user_data; + + data->io_id[0] = 0; + + tester_print("Disconnected"); + + --data->step; + if (!data->step) + tester_test_passed(); + + return FALSE; +} - if (listen(sk, 10)) { - err = -errno; - tester_warn("Can't listen socket: %s (%d)", strerror(errno), - errno); - goto fail; - } +static bool hook_remove_cig(const void *msg, uint16_t len, void *user_data) +{ + struct test_data *data = user_data; - free(addr); + tester_print("Remove CIG"); - return sk; + --data->step; + if (!data->step) + tester_test_passed(); -fail: - free(addr); - close(sk); - return err; + return true; } -static void setup_listen(struct test_data *data, uint8_t num, GIOFunc func) +static void test_connect_close(const void *test_data) { - const struct iso_client_data *isodata = data->test_data; - GIOChannel *io; + struct test_data *data = tester_get_data(); int sk; + GIOChannel *io; - sk = listen_iso_sock(data); - if (sk < 0) { - if (sk == -EPROTONOSUPPORT) - tester_test_abort(); - else - tester_test_failed(); + data->step = 2; + + hciemu_add_hook(data->hciemu, HCIEMU_HOOK_PRE_CMD, + BT_HCI_CMD_LE_REMOVE_CIG, + hook_remove_cig, data); + + sk = setup_sock(data, 0); + if (sk < 0) return; - } io = g_io_channel_unix_new(sk); g_io_channel_set_close_on_unref(io, TRUE); + data->io_id[0] = g_io_add_watch(io, G_IO_HUP, iso_connect_close_cb, + data); - data->io_id[num] = g_io_add_watch(io, G_IO_IN, func, NULL); + shutdown(sk, SHUT_RDWR); +} - g_io_channel_unref(io); +static gboolean iso_connect_wait_close_cb(GIOChannel *io, GIOCondition cond, + gpointer user_data) +{ + struct test_data *data = tester_get_data(); + int sk; - tester_print("Listen in progress"); + tester_print("Connected"); - data->step++; + sk = g_io_channel_unix_get_fd(io); - if (!isodata->bcast) { - struct hciemu_client *client; - struct bthost *host; + data->io_id[0] = g_io_add_watch(io, G_IO_HUP, iso_connect_close_cb, + data); - if (!data->acl_handle) { - tester_print("ACL handle not set"); - tester_test_failed(); - return; - } + shutdown(sk, SHUT_RDWR); - client = hciemu_get_client(data->hciemu, 0); - host = hciemu_client_host(client); + return FALSE; +} - bthost_set_cig_params(host, 0x01, 0x01, &isodata->qos); - bthost_create_cis(host, 257, data->acl_handle); - } +static void test_connect_wait_close(const void *test_data) +{ + struct test_data *data = tester_get_data(); + + data->step = 1; + + hciemu_add_hook(data->hciemu, HCIEMU_HOOK_PRE_CMD, + BT_HCI_CMD_LE_REMOVE_CIG, + hook_remove_cig, data); + + setup_connect(data, 0, iso_connect_wait_close_cb); } -static bool iso_defer_accept(struct test_data *data, GIOChannel *io) +static void test_connect_suspend(const void *test_data) { - int sk; - char c; - struct pollfd pfd; + test_connect(test_data); + trigger_force_suspend((void *)test_data); +} - sk = g_io_channel_unix_get_fd(io); +static bool hook_acl_disc(const void *msg, uint16_t len, void *user_data) +{ + const uint8_t *msg_data = msg; + const struct bt_hci_evt_le_enhanced_conn_complete *ev; + struct test_data *data = tester_get_data(); + struct bthost *bthost; - memset(&pfd, 0, sizeof(pfd)); - pfd.fd = sk; - pfd.events = POLLOUT; + if (msg_data[0] != BT_HCI_EVT_LE_ENHANCED_CONN_COMPLETE) + return true; - if (poll(&pfd, 1, 0) < 0) { - tester_warn("poll: %s (%d)", strerror(errno), errno); - return false; - } + ev = (void *) &msg_data[1]; - if (!(pfd.revents & POLLOUT)) { - if (read(sk, &c, 1) < 0) { - tester_warn("read: %s (%d)", strerror(errno), errno); - return false; - } - } + tester_print("Disconnect ACL"); - tester_print("Accept deferred setup"); + bthost = hciemu_client_get_host(data->hciemu); + bthost_hci_disconnect(bthost, le16_to_cpu(ev->handle), 0x13); - data->io = io; - data->io_id[0] = g_io_add_watch(io, G_IO_OUT, iso_connect_cb, NULL); + hciemu_flush_client_events(data->hciemu); return true; } -static gboolean iso_accept_cb(GIOChannel *io, GIOCondition cond, - gpointer user_data) +static void test_connect_acl_disc(const void *test_data) { struct test_data *data = tester_get_data(); - const struct iso_client_data *isodata = data->test_data; - int sk, new_sk; - data->io_id[0] = 0; - - sk = g_io_channel_unix_get_fd(io); - - new_sk = accept(sk, NULL, NULL); - if (new_sk < 0) { - tester_test_failed(); - return false; - } - - io = g_io_channel_unix_new(new_sk); - g_io_channel_set_close_on_unref(io, TRUE); + /* ACL disconnected before ISO is created */ + hciemu_add_hook(data->hciemu, HCIEMU_HOOK_POST_EVT, + BT_HCI_EVT_LE_META_EVENT, + hook_acl_disc, NULL); - if (isodata->defer) { - if (isodata->expect_err < 0) { - g_io_channel_unref(io); - tester_test_passed(); - return false; - } + test_connect(test_data); +} - if (!iso_defer_accept(data, io)) { - tester_warn("Unable to accept deferred setup"); - tester_test_failed(); - } - return false; - } +static void test_bcast(const void *test_data) +{ + struct test_data *data = tester_get_data(); - return iso_connect(io, cond, user_data); + setup_connect(data, 0, iso_connect_cb); } -static void test_listen(const void *test_data) +static void test_bcast2(const void *test_data) { struct test_data *data = tester_get_data(); + uint8_t num[2] = {0, 1}; + GIOFunc funcs[2] = {iso_connect_cb, iso_connect2_cb}; - setup_listen(data, 0, iso_accept_cb); + setup_connect_many(data, 2, num, funcs); } -static void test_connect2(const void *test_data) +static void test_bcast2_reconn(const void *test_data) { struct test_data *data = tester_get_data(); + uint8_t num[2] = {0, 1}; + GIOFunc funcs[2] = {iso_connect_cb, iso_connect2_cb}; - setup_connect(data, 0, iso_connect_cb); - setup_connect(data, 1, iso_connect2_cb); + data->io_queue = queue_new(); + + data->reconnect = true; + setup_connect_many(data, 2, num, funcs); } -static void test_bcast(const void *test_data) +static void test_bcast_recv(const void *test_data) { struct test_data *data = tester_get_data(); - setup_connect(data, 0, iso_connect_cb); + setup_listen(data, 0, iso_accept_cb); } -static void test_bcast_recv(const void *test_data) +static void test_bcast_recv_defer(const void *test_data) { struct test_data *data = tester_get_data(); + data->step = 1; + setup_listen(data, 0, iso_accept_cb); } +static void test_connect2_suspend(const void *test_data) +{ + test_connect2(test_data); + trigger_force_suspend((void *)test_data); +} + int main(int argc, char *argv[]) { tester_init(&argc, &argv); @@ -1770,22 +3451,149 @@ int main(int argc, char *argv[]) test_iso("ISO QoS 48_6_2 - Success", &connect_48_6_2, setup_powered, test_connect); + test_iso("ISO QoS 16_1_gs - Success", &connect_16_1_gs, setup_powered, + test_connect); + + test_iso("ISO QoS 16_2_gs - Success", &connect_16_2_gs, setup_powered, + test_connect); + + test_iso("ISO QoS 32_1_gs - Success", &connect_32_1_gs, setup_powered, + test_connect); + + test_iso("ISO QoS 32_2_gs - Success", &connect_32_2_gs, setup_powered, + test_connect); + + test_iso("ISO QoS 48_1_gs - Success", &connect_48_1_gs, setup_powered, + test_connect); + + test_iso("ISO QoS 48_2_gs - Success", &connect_48_2_gs, setup_powered, + test_connect); + + test_iso("ISO QoS 32_1_gr - Success", &connect_32_1_gr, setup_powered, + test_connect); + + test_iso("ISO QoS 32_2_gr - Success", &connect_32_2_gr, setup_powered, + test_connect); + + test_iso("ISO QoS 48_1_gr - Success", &connect_48_1_gr, setup_powered, + test_connect); + + test_iso("ISO QoS 48_2_gr - Success", &connect_48_2_gr, setup_powered, + test_connect); + + test_iso("ISO QoS 48_3_gr - Success", &connect_48_3_gr, setup_powered, + test_connect); + + test_iso("ISO QoS 48_4_gr - Success", &connect_48_4_gr, setup_powered, + test_connect); + + test_iso("ISO QoS 48_1_g - Success", &bcast_48_1_g, + setup_powered, test_bcast); + + test_iso("ISO QoS 48_2_g - Success", &bcast_48_2_g, + setup_powered, test_bcast); + + test_iso("ISO QoS 48_3_g - Success", &bcast_48_3_g, + setup_powered, test_bcast); + + test_iso("ISO QoS 48_4_g - Success", &bcast_48_4_g, + setup_powered, test_bcast); + test_iso("ISO QoS - Invalid", &connect_invalid, setup_powered, test_connect); - test_iso2("ISO Connect2 CIG 0x01 - Success", &connect_1_16_2_1, - setup_powered, - test_connect2); + test_iso("ISO QoS CIG 0xF0 - Invalid", &connect_cig_f0_invalid, + setup_powered, test_connect); + + test_iso("ISO QoS CIS 0xF0 - Invalid", &connect_cis_f0_invalid, + setup_powered, test_connect); + + test_iso_rej("ISO Connect - Reject", &connect_reject, setup_powered, + test_connect, BT_HCI_ERR_CONN_FAILED_TO_ESTABLISH); test_iso("ISO Send - Success", &connect_16_2_1_send, setup_powered, test_connect); + /* Test basic TX timestamping */ + test_iso("ISO Send - TX Timestamping", &connect_send_tx_timestamping, + setup_powered, test_connect); + + /* Test schedule-time TX timestamps are emitted */ + test_iso("ISO Send - TX Sched Timestamping", + &connect_send_tx_sched_timestamping, setup_powered, + test_connect); + + /* Test TX timestamping with flags set via per-packet CMSG */ + test_iso("ISO Send - TX CMSG Timestamping", + &connect_send_tx_cmsg_timestamping, setup_powered, + test_connect); + + /* Test TX timestamping and disabling POLLERR wakeup */ + test_iso("ISO Send - TX No Poll Timestamping", + &connect_send_tx_no_poll_timestamping, setup_powered, + test_connect); + test_iso("ISO Receive - Success", &listen_16_2_1_recv, setup_powered, test_listen); + test_iso("ISO Receive Timestamped - Success", &listen_16_2_1_recv_ts, + setup_powered, + test_listen); + + test_iso("ISO Receive Packet Status - Success", + &listen_16_2_1_recv_pkt_status, + setup_powered, test_listen); + test_iso("ISO Defer - Success", &defer_16_2_1, setup_powered, test_defer); + test_iso("ISO Defer Connect - Success", &defer_16_2_1, setup_powered, + test_connect); + + test_iso("ISO Defer Close - Success", &defer_16_2_1, setup_powered, + test_connect_close); + + test_iso("ISO Connect Close - Success", &connect_16_2_1, setup_powered, + test_connect_close); + + test_iso("ISO Defer Wait Close - Success", &defer_16_2_1, + setup_powered, test_connect_wait_close); + + test_iso("ISO Connect Wait Close - Success", &connect_16_2_1, + setup_powered, test_connect_wait_close); + + test_iso("ISO Connect Suspend - Success", &connect_suspend, + setup_powered, + test_connect_suspend); + + test_iso("ISO Connected Suspend - Success", &suspend_16_2_1, + setup_powered, + test_connect); + + test_iso2("ISO Connect2 CIG 0x01 - Success", &connect_1_16_2_1, + setup_powered, + test_connect2); + + test_iso2("ISO Connect2 Busy CIG 0x01 - Success/Invalid", + &connect_1_16_2_1, setup_powered, + test_connect2_busy); + + test_iso2("ISO Defer Connect2 CIG 0x01 - Success", &defer_1_16_2_1, + setup_powered, + test_connect2); + + test_iso2("ISO Connect2 Suspend - Success", &connect_suspend, + setup_powered, + test_connect2_suspend); + + test_iso2("ISO Connected2 Suspend - Success", &suspend_16_2_1, + setup_powered, + test_connect2); + + test_iso("ISO Connect ACL Disconnect - Failure", &connect_suspend, + setup_powered, + test_connect_acl_disc); + test_iso("ISO Defer Send - Success", &connect_16_2_1_defer_send, setup_powered, test_connect); @@ -1816,8 +3624,74 @@ int main(int argc, char *argv[]) setup_powered, test_reconnect); + test_iso("ISO AC 1 & 4 - Success", &connect_ac_1_4, setup_powered, + test_connect); + + test_iso("ISO AC 2 & 10 - Success", &connect_ac_2_10, setup_powered, + test_connect); + + test_iso("ISO AC 3 & 5 - Success", &connect_ac_3_5, setup_powered, + test_connect); + + test_iso("ISO AC 6(i) - Success", &connect_ac_6i, setup_powered, + test_connect); + + test_iso2("ISO AC 6(ii) - Success", &connect_ac_6ii, setup_powered, + test_connect2); + + test_iso("ISO AC 7(i) - Success", &connect_ac_7i, setup_powered, + test_connect); + + test_iso2("ISO AC 7(ii) - Success", &connect_ac_7ii, setup_powered, + test_connect2); + + test_iso("ISO AC 8(i) - Success", &connect_ac_8i, setup_powered, + test_connect); + + test_iso2("ISO AC 8(ii) - Success", &connect_ac_8ii, setup_powered, + test_connect2); + + test_iso("ISO AC 9(i) - Success", &connect_ac_9i, setup_powered, + test_connect); + + test_iso2("ISO AC 9(ii) - Success", &connect_ac_9ii, setup_powered, + test_connect2); + + test_iso("ISO AC 11(i) - Success", &connect_ac_11i, setup_powered, + test_connect); + + test_iso2("ISO AC 11(ii) - Success", &connect_ac_11ii, setup_powered, + test_connect2); + + test_iso2("ISO AC 1 + 2 - Success", &connect_ac_1_2, setup_powered, + test_connect2_seq); + + test_iso2("ISO AC 1 + 2 CIG 0x01/0x02 - Success", + &connect_ac_1_2_cig_1_2, + setup_powered, + test_connect2_seq); + + test_iso2("ISO Reconnect AC 6(i) - Success", &reconnect_ac_6i, + setup_powered, + test_reconnect); + + test_iso2("ISO Reconnect AC 6(ii) - Success", &reconnect_ac_6ii, + setup_powered, + test_reconnect); + + test_iso2("ISO AC 6(ii) CIS 0xEF/auto - Success", + &connect_ac_6ii_cis_ef_auto, + setup_powered, test_connect); + + test_iso2("ISO AC 6(ii) CIS 0xEF/0xEF - Invalid", + &connect_ac_6ii_cis_ef_ef, + setup_powered, test_connect); + test_iso("ISO Broadcaster - Success", &bcast_16_2_1_send, setup_powered, test_bcast); + test_iso("ISO Broadcaster Encrypted - Success", &bcast_enc_16_2_1_send, + setup_powered, + test_bcast); test_iso("ISO Broadcaster BIG 0x01 - Success", &bcast_1_16_2_1_send, setup_powered, test_bcast); @@ -1829,6 +3703,44 @@ int main(int argc, char *argv[]) test_iso("ISO Broadcaster Receiver - Success", &bcast_16_2_1_recv, setup_powered, test_bcast_recv); + test_iso("ISO Broadcaster Receiver Encrypted - Success", + &bcast_enc_16_2_1_recv, + setup_powered, + test_bcast_recv); + test_iso("ISO Broadcaster Receiver Defer - Success", + &bcast_16_2_1_recv_defer, + setup_powered, + test_bcast_recv_defer); + test_iso("ISO Broadcaster Receiver Defer No BIS - Success", + &bcast_16_2_1_recv_defer_no_bis, + setup_powered, + test_bcast_recv); + test_iso("ISO Broadcaster Receiver Defer PA Bind - Success", + &bcast_16_2_1_recv_defer_pa_bind, + setup_powered, + test_bcast_recv_defer); + test_iso("ISO Broadcaster Receiver Defer Get BASE - Success", + &bcast_16_2_1_recv_defer_get_base, + setup_powered, + test_bcast_recv); + + test_iso("ISO Broadcaster AC 12 - Success", &bcast_ac_12, setup_powered, + test_bcast); + + test_iso("ISO Broadcaster AC 13 BIG 0x01 BIS 0x01 - Success", + &bcast_ac_13_1_1, + setup_powered, + test_bcast2); + + test_iso("ISO Broadcaster AC 13 BIG 0x01 - Success", &bcast_ac_13_1, + setup_powered, test_bcast2); + + test_iso("ISO Broadcaster AC 13 Reconnect - Success", + &bcast_ac_13_1_1_reconn, setup_powered, + test_bcast2_reconn); + + test_iso("ISO Broadcaster AC 14 - Success", &bcast_ac_14, setup_powered, + test_bcast); return tester_run(); } diff --git a/tools/isotest.1 b/tools/isotest.1 new file mode 100644 index 0000000000000000000000000000000000000000..1628581df1cfb57fd9ab3493ab2c5ff7503fcf58 --- /dev/null +++ b/tools/isotest.1 @@ -0,0 +1,329 @@ +'\" t +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "ISOTEST" "1" "May 4, 2022" "BlueZ" "Linux System Administration" +.SH NAME +isotest \- ISO testing +.SH SYNOPSIS +.sp +\fBisotest\fP <\fIMODE\fP> [\fIOPTIONS\fP] [\fIbdaddr\fP] [\fIbdaddr1\fP]... +.SH DESCRIPTION +.sp +\fBisotest(1)\fP is used to test Isochronous (CIS/BIS) communications on the +BlueZ stack +.SH MODES +.INDENT 0.0 +.TP +.B \-d, \-\-dump=[FILE] Listen and dump incoming data +(CIS server/BIS broadcaster) and optionally save the +contents to \fIFILE\fP\&. +.UNINDENT +.INDENT 0.0 +.TP +.B \-c\fP,\fB \-\-reconnect +Reconnect (CIS client). +.TP +.B \-m\fP,\fB \-\-multiple +Multiple connects (CIS client). +.UNINDENT +.INDENT 0.0 +.TP +.B \-r, \-\-receive=[FILE] Receive (CIS server/BIS broadcast receiver) and +optionally save the contents to \fIFILE\fP\&. +.TP +.B \-s, \-\-send=[FILE] Connect and send (CIS client/BIS broadcaster), can +optionally use contents from \fIFILE\fP\&. +.UNINDENT +.INDENT 0.0 +.TP +.B \-n\fP,\fB \-\-silent +Connect and be silent (CIS client/BIS broadcaster). +.UNINDENT +.SH OPTIONS +.INDENT 0.0 +.TP +.BI \-b\fP,\fB \-\-bytes\fB= <SIZE> +Send or Receive packet size +.TP +.BI \-i\fP,\fB \-\-index\fB= <NUM> +Select the specified HCI device index. \fIhciNUM\fP is +also acceptable. +.TP +.BI \-j\fP,\fB \-\-jitter\fB= <JITTER> +Socket jitter buffer. +.UNINDENT +.sp +\-h, \-\-help +.INDENT 0.0 +.TP +.B \-q\fP,\fB \-\-quiet +Disables packet logging. +.TP +.BI \-t\fP,\fB \-\-timeout\fB= <USEC> +Socket send timeout. +.TP +.B \-C\fP,\fB \-\-continue +Continuously send packets starting over in case of a +file. +.TP +.BI \-W\fP,\fB \-\-defer\fB= <SEC> +Enable deferred setup. +.TP +.BI \-M\fP,\fB \-\-mtu\fB= <SDU> +Socket QoS SDU. +.UNINDENT +.INDENT 0.0 +.TP +.B \-S, \-\-sca/adv\-interval=<SCA/INTERVAL> +Socket QoS CIS SCA/BIS advertising interval. +.UNINDENT +.INDENT 0.0 +.TP +.BI \-P\fP,\fB \-\-packing\fB= <PACKING> +Socket QoS Packing. +.UNINDENT +.TS +box center; +l|l. +T{ +\fIPACKING\fP +T} T{ +Description +T} +_ +T{ +\fB0x00\fP +T} T{ +Sequential +T} +_ +T{ +\fB0x01\fP +T} T{ +Interleaved +T} +.TE +.INDENT 0.0 +.TP +.BI \-F\fP,\fB \-\-framing\fB= <FRAMING> +Socket QoS Framing. +.UNINDENT +.TS +box center; +l|l. +T{ +\fIFRAMING\fP +T} T{ +Description +T} +_ +T{ +\fB0x00\fP +T} T{ +Unframed +T} +_ +T{ +\fB0x01\fP +T} T{ +Framed +T} +.TE +.INDENT 0.0 +.TP +.BI \-I\fP,\fB \-\-interval\fB= <USEC> +Socket QoS Interval. +.TP +.BI \-L\fP,\fB \-\-latency\fB= <MSEC> +Socket QoS Latency. +.TP +.BI \-Y\fP,\fB \-\-phy\fB= <PHY> +Socket QoS PHY. +.UNINDENT +.TS +box center; +l|l. +T{ +\fIPHY\fP +T} T{ +Description +T} +_ +T{ +\fB0x01\fP +T} T{ +LE 1M +T} +_ +T{ +\fB0x02\fP +T} T{ +LE 2M +T} +_ +T{ +\fB0x03\fP +T} T{ +LE Coded +T} +.TE +.INDENT 0.0 +.TP +.BI \-R\fP,\fB \-\-rtn\fB= <NUM> +Socket QoS retransmissions. +.TP +.BI \-B\fP,\fB \-\-preset\fB= <PRESET> +Socket QoS preset. +.UNINDENT +.sp +\-G, \-\-CIG/BIG=<ID> Socket QoS CIG/BIG ID. +.sp +\-T, \-\-CIS/BIS=<ID> Socket QoS CIS/BIS ID. +.INDENT 0.0 +.TP +.BI \-V\fP,\fB \-\-type\fB= <TYPE> +Socket destination address type: +.UNINDENT +.TS +box center; +l|l. +T{ +\fITYPE\fP +T} T{ +Description +T} +_ +T{ +\fBle_public\fP +T} T{ +LE Public Address +T} +_ +T{ +\fBle_random\fP +T} T{ +LE Random Address +T} +.TE +.INDENT 0.0 +.TP +.BI \-e\fP,\fB \-\-enc\fB= <ENCRYPTION> +Socket QoS BIG Encryption +.UNINDENT +.TS +box center; +l|l. +T{ +\fIENCRYPTION\fP +T} T{ +Description +T} +_ +T{ +\fB0x00\fP +T} T{ +BIG unencrypted +T} +_ +T{ +\fB0x01\fP +T} T{ +BIG encrypted +T} +.TE +.INDENT 0.0 +.TP +.BI \-k\fP,\fB \-\-bcode\fB= <BCODE> +Socket QoS Broadcast Code +.TP +.BI \-N\fP,\fB \-\-nbis\fB= <NBIS> +Number of BISes to create as part of a +BIG (BIS broadcaster) or to synchronize +to (BIS broadcast receiver) +.UNINDENT +.SH EXAMPLES +.SS Unicast Central +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +$ tools/isotest \-s XX:XX:XX:XX:XX:XX +.EE +.UNINDENT +.UNINDENT +.SS Unicast Central connecting to 2 peers using CIG 0x01 +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +$ tools/isotest \-G 0x01 \-s XX:XX:XX:XX:XX:XX YY:YY:YY:YY:YY:YY +.EE +.UNINDENT +.UNINDENT +.SS Unicast Peripheral +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +$ tools/isotest \-d +.EE +.UNINDENT +.UNINDENT +.SS Broadcaster +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +$ tools/isotest \-s 00:00:00:00:00:00 +.EE +.UNINDENT +.UNINDENT +.SS Broadcast Receiver using hci1 +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +$ tools/isotest \-i hci1 \-d XX:XX:XX:XX:XX:XX +.EE +.UNINDENT +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH AUTHOR +Luiz Augusto Von Dentz <luiz.von.dentz@intel.com> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/tools/isotest.c b/tools/isotest.c index 8a50bfee87f8a686f2de8defd720fb9fdbc1f384..2cac0e49cc3982592d50b7e331b4c05161602302 100644 --- a/tools/isotest.c +++ b/tools/isotest.c @@ -4,6 +4,7 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2022 Intel Corporation. + * Copyright 2023 NXP * */ @@ -30,6 +31,9 @@ #include <sys/uio.h> #include <linux/sockios.h> #include <time.h> +#include <inttypes.h> +#include <sys/wait.h> +#include <poll.h> #include "lib/bluetooth.h" #include "lib/hci.h" @@ -42,6 +46,12 @@ #define NSEC_USEC(_t) (_t / 1000L) #define SEC_USEC(_t) (_t * 1000000L) #define TS_USEC(_ts) (SEC_USEC((_ts)->tv_sec) + NSEC_USEC((_ts)->tv_nsec)) +#define ROUND_CLOSEST(_x, _y) (((_x) + (_y / 2)) / (_y)) + +#define DEFAULT_BIG_ID 0x01 +#define DEFAULT_BIS_ID 0x01 + +#define MAX_DATA_SIZE 0x40000000 /* Test modes */ enum { @@ -70,6 +80,8 @@ static bool quiet; struct bt_iso_qos *iso_qos; static bool inout; +static uint8_t num_bis = 1; + struct lookup_table { const char *name; int flag; @@ -238,7 +250,7 @@ fail: return err < 0 ? err : 0; } -static void print_qos(int sk, struct sockaddr_iso *addr) +static void print_ucast_qos(int sk) { struct bt_iso_qos qos; socklen_t len; @@ -253,21 +265,60 @@ static void print_qos(int sk, struct sockaddr_iso *addr) return; } - if (!bacmp(&addr->iso_bdaddr, BDADDR_ANY)) { - syslog(LOG_INFO, "QoS BIG 0x%02x BIS 0x%02x Packing 0x%02x " - "Framing 0x%02x]", qos.big, qos.bis, qos.packing, - qos.framing); - } else { - syslog(LOG_INFO, "QoS CIG 0x%02x CIS 0x%02x Packing 0x%02x " - "Framing 0x%02x]", qos.cig, qos.cis, qos.packing, - qos.framing); - syslog(LOG_INFO, "Input QoS [Interval %u us Latency %u " - "ms SDU %u PHY 0x%02x RTN %u]", qos.in.interval, - qos.in.latency, qos.in.sdu, qos.in.phy, qos.in.rtn); + syslog(LOG_INFO, "QoS CIG 0x%02x CIS 0x%02x Packing 0x%02x " + "Framing 0x%02x]", qos.ucast.cig, qos.ucast.cis, + qos.ucast.packing, qos.ucast.framing); + + syslog(LOG_INFO, "Input QoS [Interval %u us Latency %u " + "ms SDU %u PHY 0x%02x RTN %u]", qos.ucast.in.interval, + qos.ucast.in.latency, qos.ucast.in.sdu, qos.ucast.in.phy, + qos.ucast.in.rtn); + + syslog(LOG_INFO, "Output QoS [Interval %u us Latency %u " + "ms SDU %u PHY 0x%02x RTN %u]", qos.ucast.out.interval, + qos.ucast.out.latency, qos.ucast.out.sdu, qos.ucast.out.phy, + qos.ucast.out.rtn); +} + +static void print_bcast_qos(int sk) +{ + struct bt_iso_qos qos; + socklen_t len; + + /* Read Out QOS */ + memset(&qos, 0, sizeof(qos)); + len = sizeof(qos); + + if (getsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &qos, &len) < 0) { + syslog(LOG_ERR, "Can't get QoS socket option: %s (%d)", + strerror(errno), errno); + return; } + + syslog(LOG_INFO, "QoS [BIG 0x%02x BIS 0x%02x Packing 0x%02x " + "Framing 0x%02x Encryption 0x%02x]", qos.bcast.big, + qos.bcast.bis, qos.bcast.packing, qos.bcast.framing, + qos.bcast.encryption); + + if (qos.bcast.encryption == 0x01) + syslog(LOG_INFO, "Broadcast Code 0x%02x 0x%02x 0x%02x 0x%02x " + "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x " + "0x%02x 0x%02x 0x%02x 0x%02x", qos.bcast.bcode[0], + qos.bcast.bcode[1], qos.bcast.bcode[2], qos.bcast.bcode[3], + qos.bcast.bcode[4], qos.bcast.bcode[5], qos.bcast.bcode[6], + qos.bcast.bcode[7], qos.bcast.bcode[8], qos.bcast.bcode[9], + qos.bcast.bcode[10], qos.bcast.bcode[11], qos.bcast.bcode[12], + qos.bcast.bcode[13], qos.bcast.bcode[14], qos.bcast.bcode[15]); + + syslog(LOG_INFO, "Input QoS [Interval %u us Latency %u " + "ms SDU %u PHY 0x%02x RTN %u]", qos.bcast.in.interval, + qos.bcast.in.latency, qos.bcast.in.sdu, + qos.bcast.in.phy, qos.bcast.in.rtn); + syslog(LOG_INFO, "Output QoS [Interval %u us Latency %u " - "ms SDU %u PHY 0x%02x RTN %u]", qos.out.interval, - qos.out.latency, qos.out.sdu, qos.out.phy, qos.out.rtn); + "ms SDU %u PHY 0x%02x RTN %u]", qos.bcast.out.interval, + qos.bcast.out.latency, qos.bcast.out.sdu, + qos.bcast.out.phy, qos.bcast.out.rtn); } static int do_connect(char *peer) @@ -275,8 +326,6 @@ static int do_connect(char *peer) struct sockaddr_iso addr; int sk; - mgmt_set_experimental(); - /* Create socket */ sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO); if (sk < 0) { @@ -301,8 +350,8 @@ static int do_connect(char *peer) /* Set QoS if available */ if (iso_qos) { if (!inout || !strcmp(peer, "00:00:00:00:00:00")) { - iso_qos->in.phy = 0x00; - iso_qos->in.sdu = 0; + iso_qos->ucast.in.phy = 0x00; + iso_qos->ucast.in.sdu = 0; } if (setsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, iso_qos, @@ -337,7 +386,10 @@ static int do_connect(char *peer) syslog(LOG_INFO, "Connected [%s]", peer); - print_qos(sk, &addr); + if (!strcmp(peer, "00:00:00:00:00:00")) + print_bcast_qos(sk); + else + print_ucast_qos(sk); return sk; @@ -346,13 +398,99 @@ error: return -1; } -static void do_listen(char *filename, void (*handler)(int fd, int sk), - char *peer) +static int *bcast_do_connect_mbis(uint8_t count, char *peer) +{ + int *sk; + uint8_t sk_cnt = 0; + + sk = malloc(count * sizeof(*sk)); + if (!sk) { + syslog(LOG_ERR, "Can't allocate socket array"); + return NULL; + } + + defer_setup = 1; + + for (int i = 0; i < count; i++) { + if (i == count - 1) + defer_setup = 0; + + sk[i] = do_connect(peer); + if (sk[i] < 0) { + syslog(LOG_ERR, "Can't create socket: %s (%d)", + strerror(errno), errno); + + goto error; + } + + sk_cnt++; + } + + return sk; + +error: + for (int i = 0; i < sk_cnt; i++) + close(sk[i]); + + free(sk); + return NULL; + +} + +static int accept_conn(int sk, struct sockaddr_iso *addr, char *peer) +{ + socklen_t optlen; + int nsk, err, sk_err; + struct pollfd fds; + socklen_t len; + + memset(addr, 0, sizeof(*addr) + sizeof(*addr->iso_bc)); + optlen = sizeof(*addr); + + if (peer) + optlen += sizeof(*addr->iso_bc); + + nsk = accept(sk, (struct sockaddr *) addr, &optlen); + if (nsk < 0) { + syslog(LOG_ERR, "Accept failed: %s (%d)", + strerror(errno), errno); + return -1; + } + + /* Check if connection was successful */ + memset(&fds, 0, sizeof(fds)); + fds.fd = nsk; + fds.events = POLLERR; + + if (poll(&fds, 1, 0) > 0 && (fds.revents & POLLERR)) { + len = sizeof(sk_err); + + if (getsockopt(nsk, SOL_SOCKET, SO_ERROR, + &sk_err, &len) < 0) + err = -errno; + else + err = -sk_err; + + if (err < 0) + syslog(LOG_ERR, "Connection failed: %s (%d)", + strerror(-err), -err); + + close(nsk); + return -1; + } + + return nsk; +} + +static void do_listen(char *filename, + void (*handler)(int fd, int sk, char *peer), + char *peer) { struct sockaddr_iso *addr = NULL; socklen_t optlen; int sk, nsk, fd = -1; char ba[18]; + int read_len; if (filename) { fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, 0644); @@ -387,8 +525,11 @@ static void do_listen(char *filename, void (*handler)(int fd, int sk), if (peer) { str2ba(peer, &addr->iso_bc->bc_bdaddr); addr->iso_bc->bc_bdaddr_type = bdaddr_type; - addr->iso_bc->bc_num_bis = 1; - addr->iso_bc->bc_bis[0] = 1; + addr->iso_bc->bc_num_bis = num_bis; + + for (int i = 0; i < num_bis; i++) + addr->iso_bc->bc_bis[i] = i + 1; + optlen += sizeof(*addr->iso_bc); } @@ -406,6 +547,16 @@ static void do_listen(char *filename, void (*handler)(int fd, int sk), goto error; } + /* Set QoS if available */ + if (iso_qos) { + if (setsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, iso_qos, + sizeof(*iso_qos)) < 0) { + syslog(LOG_ERR, "Can't set QoS socket option: " + "%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)", @@ -415,19 +566,27 @@ static void do_listen(char *filename, void (*handler)(int fd, int sk), syslog(LOG_INFO, "Waiting for connection %s...", peer ? peer : ""); - while (1) { - memset(addr, 0, sizeof(*addr) + sizeof(*addr->iso_bc)); - optlen = sizeof(*addr); + /* Handle deferred setup */ + if (defer_setup && peer) { + nsk = accept_conn(sk, addr, peer); + if (nsk < 0) + goto error; - if (peer) - optlen += sizeof(*addr->iso_bc); + close(sk); + sk = nsk; - nsk = accept(sk, (struct sockaddr *) addr, &optlen); - if (nsk < 0) { - syslog(LOG_ERR, "Accept failed: %s (%d)", - strerror(errno), errno); - goto error; - } + read_len = read(sk, buf, data_size); + if (read_len < 0) + syslog(LOG_ERR, "Initial read error: %s (%d)", + strerror(errno), errno); + else + syslog(LOG_INFO, "Initial bytes %d", read_len); + } + + while (1) { + nsk = accept_conn(sk, addr, peer); + if (nsk < 0) + continue; if (fork()) { /* Parent */ @@ -440,7 +599,10 @@ static void do_listen(char *filename, void (*handler)(int fd, int sk), ba2str(&addr->iso_bdaddr, ba); syslog(LOG_INFO, "Connected [%s]", ba); - print_qos(nsk, addr); + if (peer) + print_bcast_qos(nsk); + else + print_ucast_qos(nsk); /* Handle deferred setup */ if (defer_setup) { @@ -454,7 +616,7 @@ static void do_listen(char *filename, void (*handler)(int fd, int sk), } } - handler(fd, nsk); + handler(fd, nsk, peer); syslog(LOG_INFO, "Disconnect"); exit(0); @@ -469,11 +631,11 @@ error: exit(1); } -static void dump_mode(int fd, int sk) +static void dump_mode(int fd, int sk, char *peer) { int len; - if (defer_setup) { + if (defer_setup && !peer) { len = read(sk, buf, data_size); if (len < 0) syslog(LOG_ERR, "Initial read error: %s (%d)", @@ -483,7 +645,7 @@ static void dump_mode(int fd, int sk) } syslog(LOG_INFO, "Receiving ..."); - while ((len = read(sk, buf, data_size)) > 0) { + while ((len = read(sk, buf, data_size)) >= 0) { if (fd >= 0) { len = write(fd, buf, len); if (len < 0) { @@ -496,14 +658,14 @@ static void dump_mode(int fd, int sk) } } -static void recv_mode(int fd, int sk) +static void recv_mode(int fd, int sk, char *peer) { struct timeval tv_beg, tv_end, tv_diff; long total; int len; uint32_t seq; - if (defer_setup) { + if (defer_setup && !peer) { len = read(sk, buf, data_size); if (len < 0) syslog(LOG_ERR, "Initial read error: %s (%d)", @@ -521,12 +683,13 @@ static void recv_mode(int fd, int sk) int r; r = recv(sk, buf, data_size, 0); - if (r <= 0) { + if (r < 0) { if (r < 0) syslog(LOG_ERR, "Read failed: %s (%d)", strerror(errno), errno); if (errno != ENOTCONN) return; + r = 0; } @@ -560,7 +723,7 @@ static int open_file(const char *filename) syslog(LOG_INFO, "Opening %s ...", filename); fd = open(filename, O_RDONLY); - if (fd <= 0) { + if (fd < 0) { syslog(LOG_ERR, "Can't open file %s: %s\n", filename, strerror(errno)); } @@ -584,17 +747,21 @@ static void send_wait(struct timespec *t_start, uint32_t us) } t_diff.tv_sec = t_now.tv_sec - t_start->tv_sec; + if (t_start->tv_nsec > t_now.tv_nsec) { + t_diff.tv_sec--; + t_now.tv_nsec += 1000000000L; + } t_diff.tv_nsec = t_now.tv_nsec - t_start->tv_nsec; delta_us = us - TS_USEC(&t_diff); if (delta_us < 0) { - syslog(LOG_INFO, "Send is behind: %zd us", delta_us); + syslog(LOG_INFO, "Send is behind: %" PRId64 " us", delta_us); delta_us = 1000; } if (!quiet) - syslog(LOG_INFO, "Waiting (%zd us)...", delta_us); + syslog(LOG_INFO, "Waiting (%" PRId64 " us)...", delta_us); usleep(delta_us); @@ -643,12 +810,67 @@ static int read_file(int fd, ssize_t count, bool rewind) return len; } -static void do_send(int sk, int fd, struct bt_iso_qos *qos, uint32_t num, - bool repeat) +static void do_send(int sk, int fd, char *peer, bool repeat) { uint32_t seq; struct timespec t_start; - int len, used; + int send_len, used; + socklen_t len; + struct bt_iso_qos qos; + uint32_t num; + struct bt_iso_io_qos *out; + + syslog(LOG_INFO, "Sending ..."); + + /* Read QoS */ + if (!strcmp(peer, "00:00:00:00:00:00")) + out = &qos.bcast.out; + else + out = &qos.ucast.out; + + memset(&qos, 0, sizeof(qos)); + len = sizeof(qos); + if (getsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &qos, &len) < 0) { + syslog(LOG_ERR, "Can't get Output QoS socket option: %s (%d)", + strerror(errno), errno); + out->sdu = ISO_DEFAULT_MTU; + } + + /* num of packets = latency (ms) / interval (us) */ + num = ROUND_CLOSEST(out->latency * 1000, out->interval); + if (!num) + num = 1; + + syslog(LOG_INFO, "Number of packets: %d", num); + + if (!sndbuf) + /* Use socket buffer as a jitter buffer for the entire buffer + * latency: + * jitter buffer = 2 * (SDU * subevents) + */ + sndbuf = 2 * (num * out->sdu); + + len = sizeof(sndbuf); + if (setsockopt(sk, SOL_SOCKET, SO_SNDBUF, &sndbuf, len) < 0) { + syslog(LOG_ERR, "Can't set socket SO_SNDBUF option: %s (%d)", + strerror(errno), errno); + } + + syslog(LOG_INFO, "Socket jitter buffer: %d buffer", sndbuf); + + if (sndto.tv_usec) { + len = sizeof(sndto); + if (setsockopt(sk, SOL_SOCKET, SO_SNDTIMEO, &sndto, len) < 0) { + syslog(LOG_ERR, "Can't set socket SO_SNDTIMEO option: " + "%s (%d)", strerror(errno), errno); + } else { + syslog(LOG_INFO, "Socket send timeout: %ld usec", + sndto.tv_usec); + } + } + + for (int i = 6; i < out->sdu; i++) + buf[i] = 0x7f; if (clock_gettime(CLOCK_MONOTONIC, &t_start) < 0) { perror("clock_gettime"); @@ -657,17 +879,17 @@ static void do_send(int sk, int fd, struct bt_iso_qos *qos, uint32_t num, for (seq = 0; ; seq++) { if (fd >= 0) { - len = read_file(fd, qos->out.sdu, repeat); - if (len < 0) { + send_len = read_file(fd, out->sdu, repeat); + if (send_len < 0) { syslog(LOG_ERR, "read failed: %s (%d)", - strerror(-len), -len); + strerror(-send_len), -send_len); exit(1); } } else - len = qos->out.sdu; + send_len = out->sdu; - len = send(sk, buf, len, 0); - if (len <= 0) { + send_len = send(sk, buf, send_len, 0); + if (send_len <= 0) { syslog(LOG_ERR, "send failed: %s (%d)", strerror(errno), errno); exit(1); @@ -678,19 +900,20 @@ static void do_send(int sk, int fd, struct bt_iso_qos *qos, uint32_t num, if (!quiet) syslog(LOG_INFO, "[seq %d] %d bytes buffered %d (%d bytes)", - seq, len, used / len, used); + seq, send_len, used / send_len, used); if (seq && !((seq + 1) % num)) - send_wait(&t_start, num * qos->out.interval); + send_wait(&t_start, num * out->interval); } } static void send_mode(char *filename, char *peer, int i, bool repeat) { - struct bt_iso_qos qos; - socklen_t len; int sk, fd = -1; - uint32_t num; + int *sk_arr; + uint8_t nconn = strcmp(peer, "00:00:00:00:00:00") ? 1 : num_bis; + + mgmt_set_experimental(); if (filename) { char altername[PATH_MAX]; @@ -703,10 +926,39 @@ static void send_mode(char *filename, char *peer, int i, bool repeat) if (!err) fd = open_file(altername); - if (fd <= 0) + if (fd < 0) fd = open_file(filename); } + if (nconn > 1) { + sk_arr = bcast_do_connect_mbis(nconn, peer); + if (!sk_arr) + exit(1); + + for (int i = 0; i < nconn; i++) { + if (fork()) { + /* Parent */ + continue; + } + + /* Child */ + do_send(sk_arr[i], fd, peer, repeat); + exit(0); + } + + /* Wait for children to exit */ + while (wait(NULL) > 0) + ; + + for (int i = 0; i < nconn; i++) + close(sk_arr[i]); + + free(sk_arr); + if (fd >= 0) + close(fd); + return; + } + sk = do_connect(peer); if (sk < 0) { syslog(LOG_ERR, "Can't connect to the server: %s (%d)", @@ -720,57 +972,13 @@ static void send_mode(char *filename, char *peer, int i, bool repeat) sleep(abs(defer_setup) - 1); } - syslog(LOG_INFO, "Sending ..."); - - /* Read QoS */ - memset(&qos, 0, sizeof(qos)); - len = sizeof(qos); - if (getsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &qos, &len) < 0) { - syslog(LOG_ERR, "Can't get Output QoS socket option: %s (%d)", - strerror(errno), errno); - qos.out.sdu = ISO_DEFAULT_MTU; - } - - /* num of packets = latency (ms) / interval (us) */ - num = (qos.out.latency * 1000 / qos.out.interval); - - syslog(LOG_INFO, "Number of packets: %d", num); - - if (!sndbuf) - /* Use socket buffer as a jitter buffer for the entire buffer - * latency: - * jitter buffer = 2 * (SDU * subevents) - */ - sndbuf = 2 * ((qos.out.latency * 1000 / qos.out.interval) * - qos.out.sdu); - - len = sizeof(sndbuf); - if (setsockopt(sk, SOL_SOCKET, SO_SNDBUF, &sndbuf, len) < 0) { - syslog(LOG_ERR, "Can't set socket SO_SNDBUF option: %s (%d)", - strerror(errno), errno); - } - - syslog(LOG_INFO, "Socket jitter buffer: %d buffer", sndbuf); - - if (sndto.tv_usec) { - len = sizeof(sndto); - if (setsockopt(sk, SOL_SOCKET, SO_SNDTIMEO, &sndto, len) < 0) { - syslog(LOG_ERR, "Can't set socket SO_SNDTIMEO option: " - "%s (%d)", strerror(errno), errno); - } else { - syslog(LOG_INFO, "Socket send timeout: %ld usec", - sndto.tv_usec); - } - } - - for (i = 6; i < qos.out.sdu; i++) - buf[i] = 0x7f; - - do_send(sk, fd, &qos, num, repeat); + do_send(sk, fd, peer, repeat); } static void reconnect_mode(char *peer) { + mgmt_set_experimental(); + while (1) { int sk; @@ -789,6 +997,8 @@ static void reconnect_mode(char *peer) static void multy_connect_mode(char *peer) { + mgmt_set_experimental(); + while (1) { int i, sk; @@ -821,12 +1031,22 @@ static void multy_connect_mode(char *peer) #define QOS(_interval, _latency, _sdu, _phy, _rtn) \ { \ - .cig = BT_ISO_QOS_CIG_UNSET, \ - .cis = BT_ISO_QOS_CIS_UNSET, \ - .sca = 0x07, \ - .packing = 0x00, \ - .framing = 0x00, \ - .out = QOS_IO(_interval, _latency, _sdu, _phy, _rtn), \ + .bcast = { \ + .big = BT_ISO_QOS_BIG_UNSET, \ + .bis = BT_ISO_QOS_BIS_UNSET, \ + .sync_factor = 0x07, \ + .packing = 0x00, \ + .framing = 0x00, \ + .out = QOS_IO(_interval, _latency, _sdu, _phy, _rtn), \ + .encryption = 0x00, \ + .bcode = {0}, \ + .options = 0x00, \ + .skip = 0x0000, \ + .sync_timeout = 0x4000, \ + .sync_cte_type = 0x00, \ + .mse = 0x00, \ + .timeout = 0x4000, \ + }, \ } #define QOS_PRESET(_name, _inout, _interval, _latency, _sdu, _phy, _rtn) \ @@ -859,22 +1079,35 @@ static struct qos_preset { QOS_PRESET("48_5_1", false, 7500, 15, 117, 0x02, 5), QOS_PRESET("44_6_1", false, 10000, 20, 155, 0x02, 5), /* QoS Configuration settings for high reliability audio data */ - QOS_PRESET("8_1_2", true, 7500, 45, 26, 0x02, 41), - QOS_PRESET("8_2_2", true, 10000, 60, 30, 0x02, 53), - QOS_PRESET("16_1_2", true, 7500, 45, 30, 0x02, 41), - QOS_PRESET("16_2_2", true, 10000, 60, 40, 0x02, 47), - QOS_PRESET("24_1_2", true, 7500, 45, 45, 0x02, 35), - QOS_PRESET("24_2_2", true, 10000, 60, 60, 0x02, 41), - QOS_PRESET("32_1_2", true, 7500, 45, 60, 0x02, 29), - QOS_PRESET("32_2_1", true, 10000, 60, 80, 0x02, 35), - QOS_PRESET("44_1_2", false, 8163, 54, 98, 0x02, 23), - QOS_PRESET("44_2_2", false, 10884, 71, 130, 0x02, 23), - QOS_PRESET("48_1_2", false, 7500, 45, 75, 0x02, 23), - QOS_PRESET("48_2_2", false, 10000, 60, 100, 0x02, 23), - QOS_PRESET("48_3_2", false, 7500, 45, 90, 0x02, 23), - QOS_PRESET("48_4_2", false, 10000, 60, 120, 0x02, 23), - QOS_PRESET("48_5_2", false, 7500, 45, 117, 0x02, 23), - QOS_PRESET("44_6_2", false, 10000, 60, 155, 0x02, 23), + QOS_PRESET("8_1_2", true, 7500, 75, 26, 0x02, 13), + QOS_PRESET("8_2_2", true, 10000, 95, 30, 0x02, 13), + QOS_PRESET("16_1_2", true, 7500, 75, 30, 0x02, 13), + QOS_PRESET("16_2_2", true, 10000, 95, 40, 0x02, 13), + QOS_PRESET("24_1_2", true, 7500, 75, 45, 0x02, 13), + QOS_PRESET("24_2_2", true, 10000, 95, 60, 0x02, 13), + QOS_PRESET("32_1_2", true, 7500, 75, 60, 0x02, 13), + QOS_PRESET("32_2_2", true, 10000, 95, 80, 0x02, 13), + QOS_PRESET("44_1_2", false, 8163, 80, 97, 0x02, 13), + QOS_PRESET("44_2_2", false, 10884, 85, 130, 0x02, 13), + QOS_PRESET("48_1_2", false, 7500, 75, 75, 0x02, 13), + QOS_PRESET("48_2_2", false, 10000, 95, 100, 0x02, 13), + QOS_PRESET("48_3_2", false, 7500, 75, 90, 0x02, 13), + QOS_PRESET("48_4_2", false, 10000, 100, 120, 0x02, 13), + QOS_PRESET("48_5_2", false, 7500, 75, 117, 0x02, 13), + QOS_PRESET("44_6_2", false, 10000, 100, 155, 0x02, 13), + /* QoS configuration support setting requirements for the UGG and UGT */ + QOS_PRESET("16_1_gs", true, 7500, 15, 30, 0x02, 1), + QOS_PRESET("16_2_gs", true, 10000, 20, 40, 0x02, 1), + QOS_PRESET("32_1_gs", true, 7500, 15, 60, 0x02, 1), + QOS_PRESET("32_2_gs", true, 10000, 20, 80, 0x02, 1), + QOS_PRESET("48_1_gs", true, 7500, 15, 75, 0x02, 1), + QOS_PRESET("48_2_gs", true, 10000, 20, 100, 0x02, 1), + QOS_PRESET("32_1_gr", true, 7500, 15, 60, 0x02, 1), + QOS_PRESET("32_2_gr", true, 10000, 20, 80, 0x02, 1), + QOS_PRESET("48_1_gr", true, 7500, 15, 75, 0x02, 1), + QOS_PRESET("48_2_gr", true, 10000, 20, 100, 0x02, 1), + QOS_PRESET("48_3_gr", true, 7500, 15, 90, 0x02, 1), + QOS_PRESET("48_4_gr", true, 10000, 20, 120, 0x02, 1), }; #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) @@ -912,7 +1145,8 @@ static void usage(void) "\t[-B, --preset <value>]\n" "\t[-G, --CIG/BIG <value>]\n" "\t[-T, --CIS/BIS <value>]\n" - "\t[-V, --type <value>] address type (help for list)\n"); + "\t[-V, --type <value>] address type (help for list)\n" + "\t[-N, --nbis <value>] Number of BISes to create/synchronize to\n"); } static const struct option main_options[] = { @@ -942,9 +1176,29 @@ static const struct option main_options[] = { { "CIG/BIG", required_argument, NULL, 'G'}, { "CIS/BIS", required_argument, NULL, 'T'}, { "type", required_argument, NULL, 'V'}, + { "nbis", required_argument, NULL, 'N'}, {} }; +static bool str2hex(const char *str, uint16_t in_len, uint8_t *out, + uint16_t out_len) +{ + uint16_t i; + + if (in_len < out_len * 2) + return false; + + if (!strncasecmp(str, "0x", 2)) + str += 2; + + for (i = 0; i < out_len; i++) { + if (sscanf(&str[i * 2], "%02hhx", &out[i]) != 1) + return false; + } + + return true; +} + int main(int argc, char *argv[]) { struct sigaction sa; @@ -952,6 +1206,8 @@ int main(int argc, char *argv[]) char *filename = NULL; bool repeat = false; unsigned int i; + uint8_t nconn = 1; + char *peer; iso_qos = malloc(sizeof(*iso_qos)); /* Default to 16_2_1 */ @@ -962,7 +1218,7 @@ int main(int argc, char *argv[]) int opt; opt = getopt_long(argc, argv, - "d::cmr::s::nb:i:j:hqt:CV:W:M:S:P:F:I:L:Y:R:B:G:T:", + "d::cmr::s::nb:i:j:hqt:CV:W:M:S:P:F:I:L:Y:R:B:G:T:e:k:N:", main_options, NULL); if (opt < 0) break; @@ -999,7 +1255,7 @@ int main(int argc, char *argv[]) break; case 'b': - if (optarg) + if (optarg && atoi(optarg) < MAX_DATA_SIZE) data_size = atoi(optarg); break; @@ -1052,43 +1308,43 @@ int main(int argc, char *argv[]) case 'M': if (optarg) - iso_qos->out.sdu = atoi(optarg); + iso_qos->ucast.out.sdu = atoi(optarg); break; case 'S': if (optarg) - iso_qos->sca = atoi(optarg); + iso_qos->ucast.sca = atoi(optarg); break; case 'P': if (optarg) - iso_qos->packing = atoi(optarg); + iso_qos->ucast.packing = atoi(optarg); break; case 'F': if (optarg) - iso_qos->framing = atoi(optarg); + iso_qos->ucast.framing = atoi(optarg); break; case 'I': if (optarg) - iso_qos->out.interval = atoi(optarg); + iso_qos->ucast.out.interval = atoi(optarg); break; case 'L': if (optarg) - iso_qos->out.latency = atoi(optarg); + iso_qos->ucast.out.latency = atoi(optarg); break; case 'Y': if (optarg) - iso_qos->out.phy = atoi(optarg); + iso_qos->ucast.out.phy = atoi(optarg); break; case 'R': if (optarg) - iso_qos->out.rtn = atoi(optarg); + iso_qos->ucast.out.rtn = atoi(optarg); break; case 'B': @@ -1107,12 +1363,42 @@ int main(int argc, char *argv[]) case 'G': if (optarg) - iso_qos->cig = atoi(optarg); + iso_qos->ucast.cig = atoi(optarg); break; case 'T': if (optarg) - iso_qos->cis = atoi(optarg); + iso_qos->ucast.cis = atoi(optarg); + break; + + case 'e': + if (optarg) + iso_qos->bcast.encryption = + strtol(optarg, NULL, 16); + break; + + case 'k': + if (optarg) + if (!str2hex(optarg, strlen(optarg), + iso_qos->bcast.bcode, 16)) + exit(1); + break; + + case 'N': + if (optarg) + num_bis = atoi(optarg); + + if (num_bis > 1) { + /* If the user requested multiple BISes, + * make sure that all BISes are bound + * for the same BIG and advertising set + */ + if (iso_qos->bcast.big == BT_ISO_QOS_BIG_UNSET) + iso_qos->bcast.big = DEFAULT_BIG_ID; + + if (iso_qos->bcast.bis == BT_ISO_QOS_BIS_UNSET) + iso_qos->bcast.bis = DEFAULT_BIS_ID; + } break; /* fall through */ @@ -1123,11 +1409,11 @@ int main(int argc, char *argv[]) } if (inout) { - iso_qos->in = iso_qos->out; + iso_qos->ucast.in = iso_qos->ucast.out; } else { /* Align interval and latency even if is unidirectional */ - iso_qos->in.interval = iso_qos->out.interval; - iso_qos->in.latency = iso_qos->out.latency; + iso_qos->ucast.in.interval = iso_qos->ucast.out.interval; + iso_qos->ucast.in.latency = iso_qos->ucast.out.latency; } buf = malloc(data_size); @@ -1174,9 +1460,18 @@ int main(int argc, char *argv[]) switch (mode) { case SEND: - send_mode(filename, argv[optind + i], i, repeat); - if (filename && strchr(filename, ',')) - filename = strchr(filename, ',') + 1; + peer = argv[optind + i]; + if (bachk(peer) < 0) { + fprintf(stderr, "Invalid peer address '%s'\n", + peer); + exit(1); + } + send_mode(filename, peer, i, repeat); + if (filename && strchr(filename, ',')) { + char *tmp = filename; + filename = strdup(strchr(filename, ',') + 1); + free(tmp); + } break; case RECONNECT: @@ -1188,10 +1483,59 @@ int main(int argc, char *argv[]) break; case CONNECT: - sk = do_connect(argv[optind + i]); - if (sk < 0) + peer = argv[optind + i]; + if (bachk(peer) < 0) { + fprintf(stderr, "Invalid peer address '%s'\n", + peer); exit(1); - dump_mode(-1, sk); + } + + mgmt_set_experimental(); + + if (!strcmp(peer, "00:00:00:00:00:00")) + nconn = num_bis; + + if (nconn > 1) { + int *sk_arr = bcast_do_connect_mbis(nconn, + peer); + + if (!sk_arr) + exit(1); + + for (int i = 0; i < nconn; i++) { + if (fork()) { + /* Parent */ + continue; + } + + /* Child */ + if (!strcmp(peer, "00:00:00:00:00:00")) + dump_mode(-1, sk_arr[i], peer); + else + dump_mode(-1, sk_arr[i], NULL); + + exit(0); + } + + /* Wait for children to exit */ + while (wait(NULL) > 0) + ; + + for (int i = 0; i < nconn; i++) + close(sk_arr[i]); + + free(sk_arr); + } else { + sk = do_connect(peer); + if (sk < 0) + exit(1); + + if (!strcmp(peer, "00:00:00:00:00:00")) + dump_mode(-1, sk, peer); + else + dump_mode(-1, sk, NULL); + } + break; case RECV: diff --git a/tools/isotest.rst b/tools/isotest.rst index b2f4e4b385945f449ceef4f00bc1503755c9625c..fc5b3c56fe1b16bdf694787106b27f07e557e2ce 100644 --- a/tools/isotest.rst +++ b/tools/isotest.rst @@ -153,6 +153,29 @@ OPTIONS * - **le_random** - LE Random Address +-e, --enc=<ENCRYPTION> Socket QoS BIG Encryption + +.. list-table:: + :header-rows: 1 + :widths: auto + :stub-columns: 1 + :align: left + + * - *ENCRYPTION* + - Description + + * - **0x00** + - BIG unencrypted + + * - **0x01** + - BIG encrypted + +-k, --bcode=<BCODE> Socket QoS Broadcast Code + +-N, --nbis=<NBIS> Number of BISes to create as part of a + BIG (BIS broadcaster) or to synchronize + to (BIS broadcast receiver) + EXAMPLES ======== diff --git a/tools/l2cap-tester.c b/tools/l2cap-tester.c index 3f04640131faefa5218244e2cc921ff2019209b0..1780c9fbd83b13ffc86843fb76806c8fa3336427 100644 --- a/tools/l2cap-tester.c +++ b/tools/l2cap-tester.c @@ -15,6 +15,7 @@ #include <stdlib.h> #include <unistd.h> #include <errno.h> +#include <poll.h> #include <stdbool.h> #include <glib.h> @@ -29,6 +30,9 @@ #include "src/shared/tester.h" #include "src/shared/mgmt.h" +#include "src/shared/util.h" + +#include "tester.h" struct test_data { const void *test_data; @@ -37,12 +41,16 @@ struct test_data { struct hciemu *hciemu; enum hciemu_type hciemu_type; unsigned int io_id; + unsigned int err_io_id; uint16_t handle; uint16_t scid; uint16_t dcid; + struct l2cap_options l2o; int sk; int sk2; bool host_disconnected; + int step; + struct tx_tstamp_data tx_ts; }; struct l2cap_data { @@ -50,7 +58,11 @@ struct l2cap_data { uint16_t server_psm; uint16_t cid; uint8_t mode; + uint16_t mtu; + uint16_t mps; + uint16_t credits; int expect_err; + int timeout; uint8_t send_cmd_code; const void *send_cmd; @@ -81,8 +93,15 @@ struct l2cap_data { bool server_not_advertising; bool direct_advertising; bool close_1; + bool defer; bool shut_sock_wr; + + /* Enable SO_TIMESTAMPING with these flags */ + uint32_t so_timestamping; + + /* Number of additional packets to send. */ + unsigned int repeat_send; }; static void print_debug(const char *str, void *user_data) @@ -199,6 +218,12 @@ static void read_index_list_callback(uint8_t status, uint16_t length, static void test_pre_setup(const void *test_data) { struct test_data *data = tester_get_data(); + const struct l2cap_data *l2data = test_data; + + if (l2data && l2data->so_timestamping) { + if (tester_pre_setup_skip_by_default()) + return; + } data->mgmt = mgmt_new_default(); if (!data->mgmt) { @@ -223,6 +248,11 @@ static void test_post_teardown(const void *test_data) data->io_id = 0; } + if (data->err_io_id > 0) { + g_source_remove(data->err_io_id); + data->err_io_id = 0; + } + hciemu_unref(data->hciemu); data->hciemu = NULL; } @@ -242,6 +272,7 @@ static void test_data_free(void *test_data) break; \ user->hciemu_type = HCIEMU_TYPE_BREDR; \ user->io_id = 0; \ + user->err_io_id = 0; \ user->test_data = data; \ tester_add_full(name, data, \ test_pre_setup, setup, func, NULL, \ @@ -256,6 +287,7 @@ static void test_data_free(void *test_data) break; \ user->hciemu_type = HCIEMU_TYPE_LE; \ user->io_id = 0; \ + user->err_io_id = 0; \ user->test_data = data; \ tester_add_full(name, data, \ test_pre_setup, setup, func, NULL, \ @@ -269,6 +301,15 @@ static const struct l2cap_data client_connect_success_test = { .server_psm = 0x1001, }; +static const struct l2cap_data client_connect_close_test = { + .client_psm = 0x1001, +}; + +static const struct l2cap_data client_connect_timeout_test = { + .client_psm = 0x1001, + .timeout = 1 +}; + static const struct l2cap_data client_connect_ssp_success_test_1 = { .client_psm = 0x1001, .server_psm = 0x1001, @@ -295,6 +336,16 @@ static const struct l2cap_data client_connect_pin_success_test = { static uint8_t l2_data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; +const uint8_t l2_data_32k[32768] = { [0 ... 4095] = 0x00, + [4096 ... 8191] = 0x01, + [8192 ... 12287] = 0x02, + [12288 ... 16383] = 0x03, + [16384 ... 20479] = 0x04, + [20480 ... 24575] = 0x05, + [24576 ... 28671] = 0x06, + [28672 ... 32767] = 0x07, +}; + static const struct l2cap_data client_connect_read_success_test = { .client_psm = 0x1001, .server_psm = 0x1001, @@ -302,6 +353,13 @@ static const struct l2cap_data client_connect_read_success_test = { .data_len = sizeof(l2_data), }; +static const struct l2cap_data client_connect_read_32k_success_test = { + .client_psm = 0x1001, + .server_psm = 0x1001, + .read_data = l2_data_32k, + .data_len = sizeof(l2_data_32k), +}; + static const struct l2cap_data client_connect_write_success_test = { .client_psm = 0x1001, .server_psm = 0x1001, @@ -309,6 +367,24 @@ static const struct l2cap_data client_connect_write_success_test = { .data_len = sizeof(l2_data), }; +static const struct l2cap_data client_connect_write_32k_success_test = { + .client_psm = 0x1001, + .server_psm = 0x1001, + .write_data = l2_data_32k, + .data_len = sizeof(l2_data_32k), +}; + +static const struct l2cap_data client_connect_tx_timestamping_test = { + .client_psm = 0x1001, + .server_psm = 0x1001, + .write_data = l2_data, + .data_len = sizeof(l2_data), + .so_timestamping = (SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_OPT_ID | + SOF_TIMESTAMPING_TX_SOFTWARE), + .repeat_send = 2, +}; + static const struct l2cap_data client_connect_shut_wr_success_test = { .client_psm = 0x1001, .server_psm = 0x1001, @@ -351,6 +427,16 @@ static const struct l2cap_data l2cap_server_read_success_test = { .data_len = sizeof(l2_data), }; +static const struct l2cap_data l2cap_server_read_32k_success_test = { + .server_psm = 0x1001, + .send_cmd_code = BT_L2CAP_PDU_CONN_REQ, + .send_cmd = l2cap_connect_req, + .send_cmd_len = sizeof(l2cap_connect_req), + .expect_cmd_code = BT_L2CAP_PDU_CONN_RSP, + .read_data = l2_data_32k, + .data_len = sizeof(l2_data_32k), +}; + static const struct l2cap_data l2cap_server_write_success_test = { .server_psm = 0x1001, .send_cmd_code = BT_L2CAP_PDU_CONN_REQ, @@ -361,6 +447,16 @@ static const struct l2cap_data l2cap_server_write_success_test = { .data_len = sizeof(l2_data), }; +static const struct l2cap_data l2cap_server_write_32k_success_test = { + .server_psm = 0x1001, + .send_cmd_code = BT_L2CAP_PDU_CONN_REQ, + .send_cmd = l2cap_connect_req, + .send_cmd_len = sizeof(l2cap_connect_req), + .expect_cmd_code = BT_L2CAP_PDU_CONN_RSP, + .write_data = l2_data_32k, + .data_len = sizeof(l2_data_32k), +}; + static const uint8_t l2cap_sec_block_rsp[] = { 0x00, 0x00, /* dcid */ 0x41, 0x00, /* scid */ 0x03, 0x00, /* Sec Block */ @@ -436,6 +532,71 @@ static const struct l2cap_data le_client_connect_success_test_1 = { .server_psm = 0x0080, }; +static const struct l2cap_data le_client_connect_close_test_1 = { + .client_psm = 0x0080, +}; + +static const struct l2cap_data le_client_connect_timeout_test_1 = { + .client_psm = 0x0080, + .timeout = 1, +}; + +static const struct l2cap_data le_client_connect_read_success_test = { + .client_psm = 0x0080, + .server_psm = 0x0080, + .read_data = l2_data, + .data_len = sizeof(l2_data), +}; + +static const struct l2cap_data le_client_connect_read_32k_success_test = { + .client_psm = 0x0080, + .server_psm = 0x0080, + .mtu = 672, + .mps = 251, + /* Given enough credits to complete the transfer without waiting for + * more credits. + * credits = round_up(data size / mtu) * round_up(mtu / mps) + * credits = 49 * 3 + * credits = 147 + */ + .credits = 147, + .read_data = l2_data_32k, + .data_len = sizeof(l2_data_32k), +}; + +static const struct l2cap_data le_client_connect_write_success_test = { + .client_psm = 0x0080, + .server_psm = 0x0080, + .write_data = l2_data, + .data_len = sizeof(l2_data), +}; + +static const struct l2cap_data le_client_connect_write_32k_success_test = { + .client_psm = 0x0080, + .server_psm = 0x0080, + .mtu = 672, + .mps = 251, + /* Given enough credits to complete the transfer without waiting for + * more credits. + * credits = round_up(data size / mtu) * round_up(mtu / mps) + * credits = 49 * 3 + * credits = 147 + */ + .credits = 147, + .write_data = l2_data_32k, + .data_len = sizeof(l2_data_32k), +}; + +static const struct l2cap_data le_client_connect_tx_timestamping_test = { + .client_psm = 0x0080, + .server_psm = 0x0080, + .write_data = l2_data, + .data_len = sizeof(l2_data), + .so_timestamping = (SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_OPT_ID | + SOF_TIMESTAMPING_TX_SOFTWARE), +}; + static const struct l2cap_data le_client_connect_adv_success_test_1 = { .client_psm = 0x0080, .server_psm = 0x0080, @@ -540,6 +701,64 @@ static const struct l2cap_data le_server_nval_scid_test = { .expect_cmd_len = sizeof(nval_le_connect_rsp), }; +static const uint8_t ecred_connect_req[] = { 0x80, 0x00, /* PSM */ + 0x40, 0x00, /* MTU */ + 0x40, 0x00, /* MPS */ + 0x05, 0x00, /* Credits */ + 0x41, 0x00, /* SCID #1 */ + 0x42, 0x00, /* SCID #2 */ + 0x43, 0x00, /* SCID #3 */ + 0x44, 0x00, /* SCID #4 */ + 0x45, 0x00, /* SCID #5 */ +}; + +static const uint8_t ecred_connect_rsp[] = { 0xa0, 0x02, /* MTU */ + 0xbc, 0x00, /* MPS */ + 0x04, 0x00, /* Credits */ + 0x00, 0x00, /* Result */ + 0x40, 0x00, /* DCID #1 */ + 0x41, 0x00, /* DCID #2 */ + 0x42, 0x00, /* DCID #3 */ + 0x43, 0x00, /* DCID #4 */ + 0x44, 0x00, /* DCID #5 */ +}; + +static const struct l2cap_data ext_flowctl_server_success_test = { + .server_psm = 0x0080, + .send_cmd_code = BT_L2CAP_PDU_ECRED_CONN_REQ, + .send_cmd = ecred_connect_req, + .send_cmd_len = sizeof(ecred_connect_req), + .expect_cmd_code = BT_L2CAP_PDU_ECRED_CONN_RSP, + .expect_cmd = ecred_connect_rsp, + .expect_cmd_len = sizeof(ecred_connect_rsp), +}; + +static const uint8_t nval_ecred_connect_req[] = { + 0x80, 0x00, /* PSM */ + 0x40, 0x00, /* MTU */ + 0x40, 0x00, /* MPS */ + 0x05, 0x00, /* Credits */ + 0x01, 0x00, /* SCID #1 */ +}; + +static const uint8_t nval_ecred_connect_rsp[] = { + 0x00, 0x00, /* MTU */ + 0x00, 0x00, /* MPS */ + 0x00, 0x00, /* Credits */ + 0x09, 0x00, /* Result */ + 0x00, 0x00, /* DCID #1 */ +}; + +static const struct l2cap_data ext_flowctl_server_nval_scid_test = { + .server_psm = 0x0080, + .send_cmd_code = BT_L2CAP_PDU_ECRED_CONN_REQ, + .send_cmd = nval_ecred_connect_req, + .send_cmd_len = sizeof(nval_ecred_connect_req), + .expect_cmd_code = BT_L2CAP_PDU_ECRED_CONN_RSP, + .expect_cmd = nval_ecred_connect_rsp, + .expect_cmd_len = sizeof(nval_ecred_connect_rsp), +}; + static const struct l2cap_data le_att_client_connect_success_test_1 = { .cid = 0x0004, .sec_level = BT_SECURITY_LOW, @@ -549,12 +768,86 @@ static const struct l2cap_data le_att_server_success_test_1 = { .cid = 0x0004, }; +static const struct l2cap_data le_eatt_client_connect_success_test_1 = { + .client_psm = 0x0027, + .server_psm = 0x0027, + .mode = BT_MODE_EXT_FLOWCTL, + .sec_level = BT_SECURITY_LOW, +}; + +static const uint8_t eatt_connect_req[] = { 0x27, 0x00, /* PSM */ + 0x40, 0x00, /* MTU */ + 0x40, 0x00, /* MPS */ + 0x05, 0x00, /* Credits */ + 0x41, 0x00, /* SCID #1 */ +}; + +static const uint8_t eatt_connect_rsp[] = { 0xa0, 0x02, /* MTU */ + 0xbc, 0x00, /* MPS */ + 0x04, 0x00, /* Credits */ + 0x00, 0x00, /* Result */ + 0x40, 0x00, /* DCID #1 */ +}; + +static const struct l2cap_data le_eatt_server_success_test_1 = { + .server_psm = 0x0027, + .mode = BT_MODE_EXT_FLOWCTL, + .send_cmd_code = BT_L2CAP_PDU_ECRED_CONN_REQ, + .send_cmd = eatt_connect_req, + .send_cmd_len = sizeof(eatt_connect_req), + .expect_cmd_code = BT_L2CAP_PDU_ECRED_CONN_RSP, + .expect_cmd = eatt_connect_rsp, + .expect_cmd_len = sizeof(eatt_connect_rsp), + .defer = true, +}; + +static const uint8_t eatt_reject_req[] = { 0x27, 0x00, /* PSM */ + 0x40, 0x00, /* MTU */ + 0x40, 0x00, /* MPS */ + 0x05, 0x00, /* Credits */ + 0x41, 0x00, /* SCID #1 */ + 0x42, 0x00, /* SCID #2 */ + 0x43, 0x00, /* SCID #3 */ + 0x44, 0x00, /* SCID #4 */ + 0x45, 0x00, /* SCID #5 */ +}; + +static const uint8_t eatt_reject_rsp[] = { 0xa0, 0x02, /* MTU */ + 0xbc, 0x00, /* MPS */ + 0x04, 0x00, /* Credits */ + 0x06, 0x00, /* Result */ +}; + +static const struct l2cap_data le_eatt_server_reject_test_1 = { + .server_psm = 0x0027, + .mode = BT_MODE_EXT_FLOWCTL, + .send_cmd_code = BT_L2CAP_PDU_ECRED_CONN_REQ, + .send_cmd = eatt_reject_req, + .send_cmd_len = sizeof(eatt_reject_req), + .expect_cmd_code = BT_L2CAP_PDU_ECRED_CONN_RSP, + .expect_cmd = eatt_reject_rsp, + .expect_cmd_len = sizeof(eatt_reject_rsp), + .defer = true, + .expect_err = -1, +}; + static const struct l2cap_data ext_flowctl_client_connect_success_test_1 = { .client_psm = 0x0080, .server_psm = 0x0080, .mode = BT_MODE_EXT_FLOWCTL, }; +static const struct l2cap_data ext_flowctl_client_connect_close_test_1 = { + .client_psm = 0x0080, + .mode = BT_MODE_EXT_FLOWCTL, +}; + +static const struct l2cap_data ext_flowctl_client_connect_timeout_test_1 = { + .client_psm = 0x0080, + .mode = BT_MODE_EXT_FLOWCTL, + .timeout = 1, +}; + static const struct l2cap_data ext_flowctl_client_connect_adv_success_test_1 = { .client_psm = 0x0080, .server_psm = 0x0080, @@ -657,6 +950,11 @@ static void setup_powered_client_callback(uint8_t status, uint16_t length, tester_print("Controller powered on"); + if (l2data && l2data->timeout) { + tester_setup_complete(); + return; + } + bthost = hciemu_client_get_host(data->hciemu); bthost_set_cmd_complete_cb(bthost, client_cmd_complete, user_data); @@ -886,48 +1184,54 @@ static void test_basic(const void *test_data) tester_test_passed(); } -static gboolean client_received_data(GIOChannel *io, GIOCondition cond, - gpointer user_data) +static void received_data(struct test_data *tdata, const void *buf, + uint16_t len, const void *data, + uint16_t data_len) { - struct test_data *data = tester_get_data(); - const struct l2cap_data *l2data = data->test_data; - char buf[1024]; - int sk; + static struct iovec iov; - sk = g_io_channel_unix_get_fd(io); - if (read(sk, buf, l2data->data_len) != l2data->data_len) { - tester_warn("Unable to read %u bytes", l2data->data_len); - tester_test_failed(); - return FALSE; - } + util_iov_append(&iov, buf, len); - if (memcmp(buf, l2data->read_data, l2data->data_len)) + tester_debug("read: %d/%zu", len, iov.iov_len); + + /* Check if all the data has been received */ + if (iov.iov_len < data_len) + return; + + --tdata->step; + + if (iov.iov_len != data_len || memcmp(iov.iov_base, data, data_len)) tester_test_failed(); - else + else if (!tdata->step) tester_test_passed(); - return FALSE; + free(iov.iov_base); + iov.iov_base = NULL; + iov.iov_len = 0; } -static gboolean server_received_data(GIOChannel *io, GIOCondition cond, +static gboolean sock_received_data(GIOChannel *io, GIOCondition cond, gpointer user_data) { struct test_data *data = tester_get_data(); const struct l2cap_data *l2data = data->test_data; char buf[1024]; int sk; + ssize_t len; sk = g_io_channel_unix_get_fd(io); - if (read(sk, buf, l2data->data_len) != l2data->data_len) { - tester_warn("Unable to read %u bytes", l2data->data_len); + + len = read(sk, buf, sizeof(buf)); + if (len < 0) { + tester_warn("Unable to read: %s (%d)", strerror(errno), errno); tester_test_failed(); return FALSE; } - if (memcmp(buf, l2data->read_data, l2data->data_len)) - tester_test_failed(); - else - tester_test_passed(); + received_data(data, buf, len, l2data->read_data, l2data->data_len); + + if (data->step) + return TRUE; return FALSE; } @@ -938,32 +1242,7 @@ static void bthost_received_data(const void *buf, uint16_t len, struct test_data *data = tester_get_data(); const struct l2cap_data *l2data = data->test_data; - if (len != l2data->data_len) { - tester_test_failed(); - return; - } - - if (memcmp(buf, l2data->write_data, l2data->data_len)) - tester_test_failed(); - else - tester_test_passed(); -} - -static void server_bthost_received_data(const void *buf, uint16_t len, - void *user_data) -{ - struct test_data *data = tester_get_data(); - const struct l2cap_data *l2data = data->test_data; - - if (len != l2data->data_len) { - tester_test_failed(); - return; - } - - if (memcmp(buf, l2data->write_data, l2data->data_len)) - tester_test_failed(); - else - tester_test_passed(); + received_data(data, buf, len, l2data->write_data, l2data->data_len); } static gboolean socket_closed_cb(GIOChannel *io, GIOCondition cond, @@ -971,6 +1250,10 @@ static gboolean socket_closed_cb(GIOChannel *io, GIOCondition cond, { struct test_data *data = tester_get_data(); const struct l2cap_data *l2data = data->test_data; + int err, sk_err, sk; + socklen_t len = sizeof(sk_err); + + tester_print("Disconnected"); if (l2data->shut_sock_wr) { /* if socket is closed using SHUT_WR, L2CAP disconnection @@ -984,51 +1267,202 @@ static gboolean socket_closed_cb(GIOChannel *io, GIOCondition cond, } } + data->io_id = 0; + + sk = g_io_channel_unix_get_fd(io); + + if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0) + err = -errno; + else + err = -sk_err; + + if (!l2data->timeout && -err != l2data->expect_err) { + tester_print("err %d != %d expected_err", -err, + l2data->expect_err); + tester_test_failed(); + } else + tester_test_passed(); + return FALSE; } static bool check_mtu(struct test_data *data, int sk) { const struct l2cap_data *l2data = data->test_data; - struct l2cap_options l2o; socklen_t len; - memset(&l2o, 0, sizeof(l2o)); + memset(&data->l2o, 0, sizeof(data->l2o)); if (data->hciemu_type == HCIEMU_TYPE_LE && (l2data->client_psm || l2data->server_psm)) { /* LE CoC enabled kernels should support BT_RCVMTU and * BT_SNDMTU. */ - len = sizeof(l2o.imtu); + len = sizeof(data->l2o.imtu); if (getsockopt(sk, SOL_BLUETOOTH, BT_RCVMTU, - &l2o.imtu, &len) < 0) { + &data->l2o.imtu, &len) < 0) { tester_warn("getsockopt(BT_RCVMTU): %s (%d)", strerror(errno), errno); return false; } - len = sizeof(l2o.omtu); + len = sizeof(data->l2o.omtu); if (getsockopt(sk, SOL_BLUETOOTH, BT_SNDMTU, - &l2o.omtu, &len) < 0) { + &data->l2o.omtu, &len) < 0) { tester_warn("getsockopt(BT_SNDMTU): %s (%d)", strerror(errno), errno); return false; } + + /* Take SDU len into account */ + data->l2o.imtu -= 2; + data->l2o.omtu -= 2; } else { /* For non-LE CoC enabled kernels we need to fall back to * L2CAP_OPTIONS, so test support for it as well */ - len = sizeof(l2o); - if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0) { + len = sizeof(data->l2o); + if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &data->l2o, + &len) < 0) { tester_warn("getsockopt(L2CAP_OPTIONS): %s (%d)", strerror(errno), errno); return false; - } + } } return true; } +static gboolean recv_errqueue(GIOChannel *io, GIOCondition cond, + gpointer user_data) +{ + struct test_data *data = user_data; + const struct l2cap_data *l2data = data->test_data; + int sk = g_io_channel_unix_get_fd(io); + int err; + + data->step--; + + err = tx_tstamp_recv(&data->tx_ts, sk, l2data->data_len); + if (err > 0) + return TRUE; + else if (!err && !data->step) + tester_test_passed(); + else + tester_test_failed(); + + data->err_io_id = 0; + return FALSE; +} + +static void l2cap_tx_timestamping(struct test_data *data, GIOChannel *io) +{ + const struct l2cap_data *l2data = data->test_data; + int so = l2data->so_timestamping; + int sk; + int err; + unsigned int count; + + if (!(l2data->so_timestamping & SOF_TIMESTAMPING_TX_RECORD_MASK)) + return; + + sk = g_io_channel_unix_get_fd(io); + + tester_print("Enabling TX timestamping"); + + tx_tstamp_init(&data->tx_ts, l2data->so_timestamping); + + for (count = 0; count < l2data->repeat_send + 1; ++count) + data->step += tx_tstamp_expect(&data->tx_ts); + + err = setsockopt(sk, SOL_SOCKET, SO_TIMESTAMPING, &so, sizeof(so)); + if (err < 0) { + tester_warn("setsockopt SO_TIMESTAMPING: %s (%d)", + strerror(errno), errno); + tester_test_failed(); + return; + } + + data->err_io_id = g_io_add_watch(io, G_IO_ERR, recv_errqueue, data); +} + +static int l2cap_send(int sk, const void *data, size_t len, uint16_t mtu) +{ + struct iovec iov = { (void *)data, len }; + int err; + size_t total = 0; + + len = MIN(mtu, len); + + while (iov.iov_len) { + size_t l = MIN(iov.iov_len, len); + + err = write(sk, util_iov_pull_mem(&iov, l), l); + if (err < 0) + return -errno; + + total += err; + tester_debug("write: %d/%zu", err, total); + } + + return total; +} + +static void l2cap_read_data(struct test_data *data, GIOChannel *io, + uint16_t cid) +{ + const struct l2cap_data *l2data = data->test_data; + struct bthost *bthost; + struct iovec iov = { (void *)l2data->read_data, l2data->data_len }; + size_t len; + + data->step = 0; + + bthost = hciemu_client_get_host(data->hciemu); + g_io_add_watch(io, G_IO_IN, sock_received_data, NULL); + + len = MIN(iov.iov_len, data->l2o.imtu); + + while (iov.iov_len) { + size_t l = MIN(iov.iov_len, len); + + bthost_send_cid(bthost, data->handle, cid, + util_iov_pull_mem(&iov, l), l); + } + + ++data->step; +} + +static void l2cap_write_data(struct test_data *data, GIOChannel *io, + uint16_t cid) +{ + const struct l2cap_data *l2data = data->test_data; + struct bthost *bthost; + ssize_t ret; + int sk; + unsigned int count; + + sk = g_io_channel_unix_get_fd(io); + + data->step = 0; + + bthost = hciemu_client_get_host(data->hciemu); + bthost_add_cid_hook(bthost, data->handle, cid, bthost_received_data, + NULL); + + l2cap_tx_timestamping(data, io); + + for (count = 0; count < l2data->repeat_send + 1; ++count) { + ret = l2cap_send(sk, l2data->write_data, l2data->data_len, + data->l2o.omtu); + if (ret != l2data->data_len) { + tester_warn("Unable to write all data: " + "%zd != %u", ret, l2data->data_len); + tester_test_failed(); + } + ++data->step; + } +} + static gboolean l2cap_connect_cb(GIOChannel *io, GIOCondition cond, gpointer user_data) { @@ -1051,7 +1485,7 @@ static gboolean l2cap_connect_cb(GIOChannel *io, GIOCondition cond, goto failed; } - tester_print("Successfully connected"); + tester_print("Successfully connected to CID 0x%04x", data->dcid); if (!check_mtu(data, sk)) { tester_test_failed(); @@ -1059,29 +1493,10 @@ static gboolean l2cap_connect_cb(GIOChannel *io, GIOCondition cond, } if (l2data->read_data) { - struct bthost *bthost; - - bthost = hciemu_client_get_host(data->hciemu); - g_io_add_watch(io, G_IO_IN, client_received_data, NULL); - - bthost_send_cid(bthost, data->handle, data->dcid, - l2data->read_data, l2data->data_len); - + l2cap_read_data(data, io, data->dcid); return FALSE; } else if (l2data->write_data) { - struct bthost *bthost; - ssize_t ret; - - bthost = hciemu_client_get_host(data->hciemu); - bthost_add_cid_hook(bthost, data->handle, data->dcid, - bthost_received_data, NULL); - - ret = write(sk, l2data->write_data, l2data->data_len); - if (ret != l2data->data_len) { - tester_warn("Unable to write all data"); - tester_test_failed(); - } - + l2cap_write_data(data, io, data->dcid); return FALSE; } else if (l2data->shut_sock_wr) { g_io_add_watch(io, G_IO_HUP, socket_closed_cb, NULL); @@ -1235,6 +1650,8 @@ static void client_l2cap_connect_cb(uint16_t handle, uint16_t cid, { struct test_data *data = user_data; + tester_debug("Client connect CID 0x%04x handle 0x%04x", cid, handle); + data->dcid = cid; data->handle = handle; } @@ -1295,9 +1712,20 @@ static void test_connect(const void *test_data) if (l2data->shut_sock_wr) host_disconnect_cb = client_l2cap_disconnect_cb; - bthost_add_l2cap_server(bthost, l2data->server_psm, - host_connect_cb, host_disconnect_cb, - data); + if (l2data->mtu || l2data->mps || l2data->credits) + bthost_add_l2cap_server_custom(bthost, + l2data->server_psm, + l2data->mtu, + l2data->mps, + l2data->credits, + host_connect_cb, + host_disconnect_cb, + data); + else + bthost_add_l2cap_server(bthost, l2data->server_psm, + host_connect_cb, + host_disconnect_cb, + data); } if (l2data->direct_advertising) @@ -1331,6 +1759,82 @@ static void test_connect(const void *test_data) tester_print("Connect in progress"); } +static void test_connect_close(const void *test_data) +{ + struct test_data *data = tester_get_data(); + const struct l2cap_data *l2data = data->test_data; + GIOChannel *io; + int sk; + + sk = create_l2cap_sock(data, 0, l2data->cid, l2data->sec_level, + l2data->mode); + if (sk < 0) { + if (sk == -ENOPROTOOPT) + tester_test_abort(); + else + tester_test_failed(); + return; + } + + if (connect_l2cap_sock(data, sk, l2data->client_psm, + l2data->cid) < 0) { + close(sk); + tester_test_failed(); + return; + } + + io = g_io_channel_unix_new(sk); + g_io_channel_set_close_on_unref(io, TRUE); + data->io_id = g_io_add_watch(io, G_IO_HUP, socket_closed_cb, NULL); + g_io_channel_unref(io); + + shutdown(sk, SHUT_RDWR); +} + +static void test_connect_timeout(const void *test_data) +{ + struct test_data *data = tester_get_data(); + const struct l2cap_data *l2data = data->test_data; + GIOChannel *io; + int sk; + struct timeval sndto; + socklen_t len; + + sk = create_l2cap_sock(data, 0, l2data->cid, l2data->sec_level, + l2data->mode); + if (sk < 0) { + if (sk == -ENOPROTOOPT) + tester_test_abort(); + else + tester_test_failed(); + return; + } + + memset(&sndto, 0, sizeof(sndto)); + + sndto.tv_sec = l2data->timeout; + len = sizeof(sndto); + if (setsockopt(sk, SOL_SOCKET, SO_SNDTIMEO, &sndto, len) < 0) { + tester_print("Can't set SO_SNDTIMEO: %s (%d)", strerror(errno), + errno); + close(sk); + tester_test_failed(); + return; + } + + if (connect_l2cap_sock(data, sk, l2data->client_psm, + l2data->cid) < 0) { + close(sk); + tester_test_failed(); + return; + } + + io = g_io_channel_unix_new(sk); + g_io_channel_set_close_on_unref(io, TRUE); + data->io_id = g_io_add_watch(io, G_IO_HUP, socket_closed_cb, NULL); + g_io_channel_unref(io); +} + static void test_connect_reject(const void *test_data) { struct test_data *data = tester_get_data(); @@ -1689,71 +2193,103 @@ static void test_connect_2(const void *test_data) defer); } -static gboolean l2cap_listen_cb(GIOChannel *io, GIOCondition cond, +static gboolean l2cap_accept_cb(GIOChannel *io, GIOCondition cond, gpointer user_data) { struct test_data *data = tester_get_data(); const struct l2cap_data *l2data = data->test_data; - int sk, new_sk; - - data->io_id = 0; + int sk; sk = g_io_channel_unix_get_fd(io); - new_sk = accept(sk, NULL, NULL); - if (new_sk < 0) { - tester_warn("accept failed: %s (%u)", strerror(errno), errno); + if (!check_mtu(data, sk)) { tester_test_failed(); return FALSE; } - if (!check_mtu(data, new_sk)) { - tester_test_failed(); - close(new_sk); + if (l2data->read_data) { + l2cap_read_data(data, io, data->dcid); + return FALSE; + } else if (l2data->write_data) { + l2cap_write_data(data, io, data->scid); return FALSE; } - if (l2data->read_data) { - struct bthost *bthost; - GIOChannel *new_io; + tester_print("Successfully connected"); - new_io = g_io_channel_unix_new(new_sk); - g_io_channel_set_close_on_unref(new_io, TRUE); + tester_test_passed(); - bthost = hciemu_client_get_host(data->hciemu); - g_io_add_watch(new_io, G_IO_IN, server_received_data, NULL); - bthost_send_cid(bthost, data->handle, data->dcid, - l2data->read_data, l2data->data_len); + return FALSE; +} - g_io_channel_unref(new_io); +static bool defer_accept(struct test_data *data, GIOChannel *io) +{ + int sk; + char c; + struct pollfd pfd; - return FALSE; - } else if (l2data->write_data) { - struct bthost *bthost; - ssize_t ret; + sk = g_io_channel_unix_get_fd(io); - bthost = hciemu_client_get_host(data->hciemu); - bthost_add_cid_hook(bthost, data->handle, data->scid, - server_bthost_received_data, NULL); + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = sk; + pfd.events = POLLOUT; - ret = write(new_sk, l2data->write_data, l2data->data_len); - close(new_sk); + if (poll(&pfd, 1, 0) < 0) { + tester_warn("poll: %s (%d)", strerror(errno), errno); + return false; + } - if (ret != l2data->data_len) { - tester_warn("Unable to write all data"); - tester_test_failed(); + if (!(pfd.revents & POLLOUT)) { + if (read(sk, &c, 1) < 0) { + tester_warn("read: %s (%d)", strerror(errno), errno); + return false; } + } + + data->io_id = g_io_add_watch(io, G_IO_OUT, l2cap_accept_cb, NULL); + + g_io_channel_unref(io); + + tester_print("Accept deferred setup"); + + return true; +} + +static gboolean l2cap_listen_cb(GIOChannel *io, GIOCondition cond, + gpointer user_data) +{ + struct test_data *data = tester_get_data(); + const struct l2cap_data *l2data = data->test_data; + int sk, new_sk; + + data->io_id = 0; + + sk = g_io_channel_unix_get_fd(io); + new_sk = accept(sk, NULL, NULL); + if (new_sk < 0) { + tester_warn("accept failed: %s (%u)", strerror(errno), errno); + tester_test_failed(); return FALSE; } - tester_print("Successfully connected"); + io = g_io_channel_unix_new(new_sk); + g_io_channel_set_close_on_unref(io, TRUE); - close(new_sk); + if (l2data->defer) { + if (l2data->expect_err < 0) { + g_io_channel_unref(io); + return FALSE; + } - tester_test_passed(); + if (!defer_accept(data, io)) { + tester_warn("Unable to accept deferred setup"); + tester_test_failed(); + } + return FALSE; + } - return FALSE; + return l2cap_accept_cb(io, cond, user_data); } static void client_l2cap_rsp(uint8_t code, const void *data, uint16_t len, @@ -1767,7 +2303,7 @@ static void client_l2cap_rsp(uint8_t code, const void *data, uint16_t len, if (code != l2data->expect_cmd_code) { tester_warn("Unexpected L2CAP response code (expected 0x%02x)", l2data->expect_cmd_code); - return; + goto failed; } if (code == BT_L2CAP_PDU_CONN_RSP) { @@ -1844,6 +2380,8 @@ static void test_server(const void *test_data) int sk; if (l2data->server_psm || l2data->cid) { + int opt = 1; + sk = create_l2cap_sock(data, l2data->server_psm, l2data->cid, l2data->sec_level, l2data->mode); @@ -1852,6 +2390,15 @@ static void test_server(const void *test_data) return; } + if (l2data->defer && setsockopt(sk, SOL_BLUETOOTH, + BT_DEFER_SETUP, &opt, sizeof(opt)) < 0) { + tester_warn("Can't enable deferred setup: %s (%d)", + strerror(errno), errno); + tester_test_failed(); + close(sk); + return; + } + if (listen(sk, 5) < 0) { tester_warn("listening on socket failed: %s (%u)", strerror(errno), errno); @@ -1935,6 +2482,15 @@ int main(int argc, char *argv[]) &client_connect_success_test, setup_powered_client, test_connect); + test_l2cap_bredr("L2CAP BR/EDR Client - Close", + &client_connect_close_test, + setup_powered_client, + test_connect_close); + test_l2cap_bredr("L2CAP BR/EDR Client - Timeout", + &client_connect_timeout_test, + setup_powered_client, + test_connect_timeout); + test_l2cap_bredr("L2CAP BR/EDR Client SSP - Success 1", &client_connect_ssp_success_test_1, setup_powered_client, test_connect); @@ -1949,10 +2505,22 @@ int main(int argc, char *argv[]) &client_connect_read_success_test, setup_powered_client, test_connect); + test_l2cap_bredr("L2CAP BR/EDR Client - Read 32k Success", + &client_connect_read_32k_success_test, + setup_powered_client, test_connect); + test_l2cap_bredr("L2CAP BR/EDR Client - Write Success", &client_connect_write_success_test, setup_powered_client, test_connect); + test_l2cap_bredr("L2CAP BR/EDR Client - Write 32k Success", + &client_connect_write_32k_success_test, + setup_powered_client, test_connect); + + test_l2cap_bredr("L2CAP BR/EDR Client - TX Timestamping", + &client_connect_tx_timestamping_test, + setup_powered_client, test_connect); + test_l2cap_bredr("L2CAP BR/EDR Client - Invalid PSM 1", &client_connect_nval_psm_test_1, setup_powered_client, test_connect); @@ -1977,10 +2545,18 @@ int main(int argc, char *argv[]) &l2cap_server_read_success_test, setup_powered_server, test_server); + test_l2cap_bredr("L2CAP BR/EDR Server - Read 32k Success", + &l2cap_server_read_32k_success_test, + setup_powered_server, test_server); + test_l2cap_bredr("L2CAP BR/EDR Server - Write Success", &l2cap_server_write_success_test, setup_powered_server, test_server); + test_l2cap_bredr("L2CAP BR/EDR Server - Write 32k Success", + &l2cap_server_write_32k_success_test, + setup_powered_server, test_server); + test_l2cap_bredr("L2CAP BR/EDR Server - Security Block", &l2cap_server_sec_block_test, setup_powered_server, test_server); @@ -2001,6 +2577,27 @@ int main(int argc, char *argv[]) test_l2cap_le("L2CAP LE Client - Success", &le_client_connect_success_test_1, setup_powered_client, test_connect); + test_l2cap_le("L2CAP LE Client - Close", + &le_client_connect_close_test_1, + setup_powered_client, test_connect_close); + test_l2cap_le("L2CAP LE Client - Timeout", + &le_client_connect_timeout_test_1, + setup_powered_client, test_connect_timeout); + test_l2cap_le("L2CAP LE Client - Read Success", + &le_client_connect_read_success_test, + setup_powered_client, test_connect); + test_l2cap_le("L2CAP LE Client - Read 32k Success", + &le_client_connect_read_32k_success_test, + setup_powered_client, test_connect); + test_l2cap_le("L2CAP LE Client - Write Success", + &le_client_connect_write_success_test, + setup_powered_client, test_connect); + test_l2cap_le("L2CAP LE Client - Write 32k Success", + &le_client_connect_write_32k_success_test, + setup_powered_client, test_connect); + test_l2cap_le("L2CAP LE Client - TX Timestamping", + &le_client_connect_tx_timestamping_test, + setup_powered_client, test_connect); test_l2cap_le("L2CAP LE Client, Direct Advertising - Success", &le_client_connect_adv_success_test_1, setup_powered_client, test_connect); @@ -2046,6 +2643,12 @@ int main(int argc, char *argv[]) test_l2cap_le("L2CAP Ext-Flowctl Client - Success", &ext_flowctl_client_connect_success_test_1, setup_powered_client, test_connect); + test_l2cap_le("L2CAP Ext-Flowctl Client - Close", + &ext_flowctl_client_connect_close_test_1, + setup_powered_client, test_connect_close); + test_l2cap_le("L2CAP Ext-Flowctl Client - Timeout", + &ext_flowctl_client_connect_timeout_test_1, + setup_powered_client, test_connect_timeout); test_l2cap_le("L2CAP Ext-Flowctl Client, Direct Advertising - Success", &ext_flowctl_client_connect_adv_success_test_1, setup_powered_client, test_connect); @@ -2066,6 +2669,13 @@ int main(int argc, char *argv[]) setup_powered_client, test_connect_2); + test_l2cap_le("L2CAP Ext-Flowctl Server - Success", + &ext_flowctl_server_success_test, + setup_powered_server, test_server); + test_l2cap_le("L2CAP Ext-Flowctl Server - Nval SCID", + &ext_flowctl_server_nval_scid_test, + setup_powered_server, test_server); + test_l2cap_le("L2CAP LE ATT Client - Success", &le_att_client_connect_success_test_1, setup_powered_client, test_connect); @@ -2073,5 +2683,15 @@ int main(int argc, char *argv[]) &le_att_server_success_test_1, setup_powered_server, test_server); + test_l2cap_le("L2CAP LE EATT Client - Success", + &le_eatt_client_connect_success_test_1, + setup_powered_client, test_connect); + test_l2cap_le("L2CAP LE EATT Server - Success", + &le_eatt_server_success_test_1, + setup_powered_server, test_server); + test_l2cap_le("L2CAP LE EATT Server - Reject", + &le_eatt_server_reject_test_1, + setup_powered_server, test_server); + return tester_run(); } diff --git a/tools/l2ping.1 b/tools/l2ping.1 new file mode 100644 index 0000000000000000000000000000000000000000..9585c968575cd77e8572786c83cea61d1c656e05 --- /dev/null +++ b/tools/l2ping.1 @@ -0,0 +1,92 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "L2PING" "1" "Jan 22, 2002" "BlueZ" "Linux System Administration" +.SH NAME +l2ping \- Send L2CAP echo request and receive answer +.SH SYNOPSIS +.sp +\fBl2ping\fP [\fIOPTIONS\fP] \fIbd_addr\fP +.SH DESCRIPTION +.sp +\fBl2ping(1)\fP sends a L2CAP echo request to the Bluetooth MAC address bd_addr +given in dotted hex notation. +.SH OPTIONS +.INDENT 0.0 +.TP +.BI \-i \ <hciX> +The command is applied to device \fIhciX\fP, 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 size of the data packets to be sent. +.TP +.BI \-c \ count +Send count number of packets then exit. +.TP +.BI \-t \ timeout +Wait timeout seconds for the response. +.TP +.BI \-d \ delay +Wait delay seconds between pings. +.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 +.B \-v +Verify response payload is identical to request payload. +It is not required for remote stacks to return the request +payload, but most stacks do (including Bluez). +.UNINDENT +.INDENT 0.0 +.TP +.B bd_addr +The Bluetooth MAC address to be pinged in dotted hex notation +like \fB01:02:03:ab:cd:ef\fP or \fB01:EF:cd:aB:02:03\fP +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH AUTHOR +Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>, Nils Faerber <nils@kernelconcepts.de>, Adam Laurie <adam@algroup.co.uk>. +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/tools/l2test.c b/tools/l2test.c index 5aae4b6875186f2168302022d88183162b025c95..4c22968999c9ee3df7e904785a58b715d14b4913 100644 --- a/tools/l2test.c +++ b/tools/l2test.c @@ -155,6 +155,24 @@ static struct lookup_table bdaddr_types[] = { { NULL, 0 }, }; +static int bt_mode_to_l2cap_mode(int mode) +{ + switch (mode) { + case BT_MODE_BASIC: + return L2CAP_MODE_BASIC; + case BT_MODE_ERTM: + return L2CAP_MODE_ERTM; + case BT_MODE_STREAMING: + return L2CAP_MODE_STREAMING; + case BT_MODE_LE_FLOWCTL: + return L2CAP_MODE_LE_FLOWCTL; + case BT_MODE_EXT_FLOWCTL: + return L2CAP_MODE_FLOWCTL; + default: + return mode; + } +} + static int get_lookup_flag(struct lookup_table *table, char *name) { int i; @@ -287,9 +305,11 @@ static int getopts(int sk, struct l2cap_options *opts, bool connected) static int setopts(int sk, struct l2cap_options *opts) { - if (bdaddr_type == BDADDR_BREDR) + if (bdaddr_type == BDADDR_BREDR) { + opts->mode = bt_mode_to_l2cap_mode(opts->mode); return setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, opts, sizeof(*opts)); + } if (opts->mode) { if (setsockopt(sk, SOL_BLUETOOTH, BT_MODE, &opts->mode, @@ -893,7 +913,7 @@ static void recv_mode(int sk) timestamp = 0; memset(ts, 0, sizeof(ts)); } else { - sprintf(ts, "[%lld.%lld] ", + snprintf(ts, sizeof(ts), "[%lld.%lld] ", (long long)tv.tv_sec, (long long)tv.tv_usec); } @@ -955,6 +975,11 @@ static void do_send(int sk) buflen = (size > omtu) ? omtu : size; len = send(sk, buf + sent, buflen, 0); + if (len < 0) { + syslog(LOG_ERR, "Send failed: %s (%d)", + strerror(errno), errno); + exit(1); + } sent += len; size -= len; @@ -1416,7 +1441,7 @@ int main(int argc, char *argv[]) break; case 'P': - psm = atoi(optarg); + psm = strtoul(optarg, NULL, 0); break; case 'I': diff --git a/tools/mesh-cfgclient.c b/tools/mesh-cfgclient.c index 237afbb5f3993049059db7dcb3202427f421e99b..e64950a9cc652827541d0e1351b56c3274958262 100644 --- a/tools/mesh-cfgclient.c +++ b/tools/mesh-cfgclient.c @@ -38,11 +38,15 @@ #include "tools/mesh/model.h" #include "tools/mesh/remote.h" -#define PROMPT_ON COLOR_BLUE "[mesh-cfgclient]" COLOR_OFF "# " +#define PROMPT_ON "[mesh-cfgclient]# " #define PROMPT_OFF "Waiting to connect to bluetooth-meshd..." #define CFG_SRV_MODEL 0x0000 #define CFG_CLI_MODEL 0x0001 +#define RPR_SVR_MODEL 0x0004 +#define RPR_CLI_MODEL 0x0005 +#define PRV_BEACON_SVR 0x0008 +#define PRV_BEACON_CLI 0x0009 #define UNPROV_SCAN_MAX_SECS 300 @@ -57,7 +61,7 @@ struct meshcfg_el { const char *path; uint8_t index; - uint16_t mods[2]; + uint16_t mods[4]; }; struct meshcfg_app { @@ -83,8 +87,12 @@ struct meshcfg_node { struct unprov_device { time_t last_seen; - int16_t rssi; + int id; + uint32_t uri_hash; uint8_t uuid[16]; + int16_t rssi; + uint16_t server; + uint16_t oob_info; }; struct generic_request { @@ -96,8 +104,16 @@ struct generic_request { const char *str; }; +struct scan_data { + uint16_t dst; + uint16_t secs; +}; + +static void *finalized = L_UINT_TO_PTR(-1); + static struct l_dbus *dbus; +static struct l_timeout *scan_timeout; static struct l_queue *node_proxies; static struct l_dbus_proxy *net_proxy; static struct meshcfg_node *local; @@ -130,7 +146,8 @@ static struct meshcfg_app app = { .ele = { .path = "/mesh/cfgclient/ele0", .index = 0, - .mods = {CFG_SRV_MODEL, CFG_CLI_MODEL} + .mods = {CFG_SRV_MODEL, CFG_CLI_MODEL, + PRV_BEACON_SVR, PRV_BEACON_CLI} } }; @@ -197,23 +214,57 @@ static bool parse_argument_on_off(int argc, char *argv[], bool *value) static bool match_device_uuid(const void *a, const void *b) { const struct unprov_device *dev = a; - const uint8_t *uuid = b; - return (memcmp(dev->uuid, uuid, 16) == 0); + if (a == finalized) + return false; + + return memcmp(dev->uuid, b, 16) == 0; } -static void print_device(void *a, void *b) +static bool match_by_id(const void *a, const void *b) { const struct unprov_device *dev = a; - struct tm *tm = localtime(&dev->last_seen); + int id = L_PTR_TO_UINT(b); + + if (a == finalized) + return false; + + l_info("test %d %d", dev->id, id); + return dev->id == id; +} + +static bool match_by_srv_uuid(const void *a, const void *b) +{ + const struct unprov_device *dev = a; + const struct unprov_device *new_dev = b; + + if (a == finalized) + return false; + + return (dev->server == new_dev->server) && + (memcmp(dev->uuid, new_dev->uuid, 16) == 0); +} + +static void print_device(void *a, void *b) +{ + struct unprov_device *dev = a; + int *cnt = b; + struct tm *tm; char buf[80]; char *str; + if (a == finalized) + return; + + tm = localtime(&dev->last_seen); assert(strftime(buf, sizeof(buf), "%c", tm)); + (*cnt)++; + dev->id = *cnt; str = l_util_hexstring_upper(dev->uuid, sizeof(dev->uuid)); - bt_shell_printf("UUID: %s, RSSI %d, Seen: %s\n", - str, dev->rssi, buf); + bt_shell_printf(COLOR_YELLOW "#%d" COLOR_OFF + " UUID: %s, RSSI %d, Server: %4.4x\n Seen: %s\n", + *cnt, str, dev->rssi, dev->server, buf); l_free(str); } @@ -725,6 +776,10 @@ static void attach_node_reply(struct l_dbus_proxy *proxy, remote_clear_rejected_addresses(ivi); } + /* Read own node composition */ + if (!cfgcli_get_comp(0x0001, 128)) + l_error("Failed to read own composition"); + return; fail: @@ -794,15 +849,56 @@ static void scan_reply(struct l_dbus_proxy *proxy, struct l_dbus_message *msg, static void scan_setup(struct l_dbus_message *msg, void *user_data) { - uint16_t secs = (uint16_t) L_PTR_TO_UINT(user_data); + struct scan_data *data = user_data; struct l_dbus_message_builder *builder; builder = l_dbus_message_builder_new(msg); l_dbus_message_builder_enter_array(builder, "{sv}"); - append_dict_entry_basic(builder, "Seconds", "q", &secs); + append_dict_entry_basic(builder, "Seconds", "q", &data->secs); + append_dict_entry_basic(builder, "Server", "q", &data->dst); l_dbus_message_builder_leave_array(builder); l_dbus_message_builder_finalize(builder); l_dbus_message_builder_destroy(builder); + + /* Destination info not needed after call */ + l_free(data); +} + +static void scan_start(void *user_data, uint16_t dst, uint32_t model) +{ + struct scan_data *data; + + if (model != (0xffff0000 | RPR_SVR_MODEL)) + return; + + data = l_malloc(sizeof(struct scan_data)); + data->secs = L_PTR_TO_UINT(user_data); + data->dst = dst; + + if (!l_dbus_proxy_method_call(local->mgmt_proxy, "UnprovisionedScan", + scan_setup, scan_reply, data, NULL)) + l_free(data); +} + +static void scan_to(struct l_timeout *timeout, void *user_data) +{ + int cnt = 0; + + if (l_queue_peek_head(devices) != finalized) + l_queue_push_head(devices, finalized); + + l_timeout_remove(timeout); + scan_timeout = NULL; + bt_shell_printf(COLOR_YELLOW "Unprovisioned devices:\n" COLOR_OFF); + l_queue_foreach(devices, print_device, &cnt); +} + +static void free_devices(void *a) +{ + if (a == finalized) + return; + + l_free(a); } static void cmd_scan_unprov(int argc, char *argv[]) @@ -820,21 +916,28 @@ static void cmd_scan_unprov(int argc, char *argv[]) return bt_shell_noninteractive_quit(EXIT_FAILURE); } - if (argc == 3) + if (argc == 3) { sscanf(argv[2], "%u", &secs); - if (secs > UNPROV_SCAN_MAX_SECS) - secs = UNPROV_SCAN_MAX_SECS; + if (secs > UNPROV_SCAN_MAX_SECS) + secs = UNPROV_SCAN_MAX_SECS; + } else + secs = 60; - if (enable) - l_dbus_proxy_method_call(local->mgmt_proxy, "UnprovisionedScan", - scan_setup, scan_reply, - L_UINT_TO_PTR(secs), NULL); - else + l_timeout_remove(scan_timeout); + scan_timeout = NULL; + + if (enable) { + l_queue_clear(devices, free_devices); + remote_foreach_model(scan_start, L_UINT_TO_PTR(secs)); + scan_timeout = l_timeout_create(secs, scan_to, NULL, NULL); + } else { + /* Mark devices queue as finalized */ + l_queue_push_head(devices, finalized); l_dbus_proxy_method_call(local->mgmt_proxy, "UnprovisionedScanCancel", NULL, NULL, NULL, NULL); - + } } static uint8_t *parse_key(struct l_dbus_message_iter *iter, uint16_t id, @@ -1030,8 +1133,10 @@ static void cmd_export_db(int argc, char *argv[]) static void cmd_list_unprov(int argc, char *argv[]) { + int cnt = 0; + bt_shell_printf(COLOR_YELLOW "Unprovisioned devices:\n" COLOR_OFF); - l_queue_foreach(devices, print_device, NULL); + l_queue_foreach(devices, print_device, &cnt); } static void cmd_list_nodes(int argc, char *argv[]) @@ -1505,32 +1610,56 @@ static void add_node_reply(struct l_dbus_proxy *proxy, bt_shell_printf("Provisioning started\n"); } -static void add_node_setup(struct l_dbus_message *msg, void *user_data) +static void reprov_reply(struct l_dbus_proxy *proxy, + struct l_dbus_message *msg, void *user_data) { - char *str = user_data; - size_t sz; - unsigned char *uuid; - struct l_dbus_message_builder *builder; + if (l_dbus_message_is_error(msg)) { + const char *name; - uuid = l_util_from_hexstring(str, &sz); - if (!uuid || sz != 16 || !l_uuid_is_valid(uuid)) { - l_error("Failed to generate UUID array from %s", str); + prov_in_progress = false; + l_dbus_message_get_error(msg, &name, NULL); + l_error("Failed to start provisioning: %s", name); return; } + bt_shell_printf("Reprovisioning started\n"); +} + +static void reprovision_setup(struct l_dbus_message *msg, void *user_data) +{ + uint16_t target = L_PTR_TO_UINT(user_data); + uint8_t nppi = L_PTR_TO_UINT(user_data) >> 16; + struct l_dbus_message_builder *builder; + builder = l_dbus_message_builder_new(msg); - append_byte_array(builder, uuid, 16); + l_dbus_message_builder_append_basic(builder, 'q', &target); l_dbus_message_builder_enter_array(builder, "{sv}"); /* TODO: populate with options when defined */ + append_dict_entry_basic(builder, "NPPI", "y", &nppi); l_dbus_message_builder_leave_array(builder); l_dbus_message_builder_finalize(builder); l_dbus_message_builder_destroy(builder); +} - l_free(uuid); +static void add_node_setup(struct l_dbus_message *msg, void *user_data) +{ + struct unprov_device *dev = user_data; + struct l_dbus_message_builder *builder; + + builder = l_dbus_message_builder_new(msg); + append_byte_array(builder, dev->uuid, 16); + l_dbus_message_builder_enter_array(builder, "{sv}"); + /* TODO: populate with options when defined */ + l_dbus_message_builder_leave_array(builder); + l_dbus_message_builder_finalize(builder); + l_dbus_message_builder_destroy(builder); } static void cmd_start_prov(int argc, char *argv[]) { + struct unprov_device *dev = NULL; + int id; + if (!local || !local->proxy || !local->mgmt_proxy) { bt_shell_printf("Node is not attached\n"); return; @@ -1541,14 +1670,96 @@ static void cmd_start_prov(int argc, char *argv[]) return; } - if (!argv[1] || (strlen(argv[1]) != 32)) { + if (!argv[1]) { + bt_shell_printf(COLOR_RED "Requires UUID\n" COLOR_RED); + return; + } + + if (*(argv[1]) == '#') { + if (sscanf(argv[1] + 1, "%d", &id) == 1) + dev = l_queue_find(devices, match_by_id, + L_UINT_TO_PTR(id)); + + if (!dev) { + bt_shell_printf(COLOR_RED "unknown id\n" COLOR_RED); + return; + } + } else if (strlen(argv[1]) == 32) { + size_t sz; + uint8_t *uuid = l_util_from_hexstring(argv[1], &sz); + + if (sz != 16) { + bt_shell_printf(COLOR_RED "Invalid UUID\n" COLOR_RED); + return; + } + + dev = l_queue_find(devices, match_device_uuid, uuid); + + if (!dev) { + dev = l_new(struct unprov_device, 1); + memcpy(dev->uuid, uuid, 16); + l_queue_push_tail(devices, dev); + } + + l_free(uuid); + + } else { bt_shell_printf(COLOR_RED "Requires UUID\n" COLOR_RED); return; } if (l_dbus_proxy_method_call(local->mgmt_proxy, "AddNode", add_node_setup, add_node_reply, - argv[1], NULL)) + dev, NULL)) + prov_in_progress = true; +} + +static void cmd_start_reprov(int argc, char *argv[]) +{ + uint16_t target = 0; + uint8_t nppi = 0; + + if (!local || !local->proxy || !local->mgmt_proxy) { + bt_shell_printf("Node is not attached\n"); + return; + } + + if (prov_in_progress) { + bt_shell_printf("Provisioning is already in progress\n"); + return; + } + + if (!argv[1]) { + bt_shell_printf(COLOR_RED "Requires Unicast\n" COLOR_RED); + return; + } + + if (argv[2]) { + char *end; + + nppi = strtol(argv[2], &end, 16); + } + + if (strlen(argv[1]) == 4) { + char *end; + + target = strtol(argv[1], &end, 16); + + if (end != (argv[1] + 4)) { + bt_shell_printf(COLOR_RED "Invalid Unicast\n" + COLOR_RED); + return; + } + + } else { + bt_shell_printf(COLOR_RED "Requires Unicast\n" COLOR_RED); + return; + } + + if (l_dbus_proxy_method_call(local->mgmt_proxy, "Reprovision", + reprovision_setup, reprov_reply, + L_UINT_TO_PTR(target + (nppi << 16)), + NULL)) prov_in_progress = true; } @@ -1581,6 +1792,8 @@ static const struct bt_shell_menu main_menu = { "List unprovisioned devices" }, { "provision", "<uuid>", cmd_start_prov, "Initiate provisioning"}, + { "reprovision", "<unicast> [0|1|2]", cmd_start_reprov, + "Refresh Device Key"}, { "node-import", "<uuid> <net_idx> <primary> <ele_count> <dev_key>", cmd_import_node, "Import an externally provisioned remote node"}, @@ -1684,6 +1897,8 @@ static bool mod_getter(struct l_dbus *dbus, l_dbus_message_builder_enter_array(builder, "(qa{sv})"); build_model(builder, app.ele.mods[0], false, false); build_model(builder, app.ele.mods[1], false, false); + build_model(builder, app.ele.mods[2], false, false); + build_model(builder, app.ele.mods[3], false, false); l_dbus_message_builder_leave_array(builder); return true; @@ -1758,18 +1973,34 @@ static void setup_ele_iface(struct l_dbus_interface *iface) /* TODO: Other methods */ } +static int sort_rssi(const void *a, const void *b, void *user_data) +{ + const struct unprov_device *new_dev = a; + const struct unprov_device *dev = b; + + if (b == finalized) + return 1; + + return dev->rssi - new_dev->rssi; +} + static struct l_dbus_message *scan_result_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { - struct l_dbus_message_iter iter, opts; + struct l_dbus_message_iter iter, opts, var; + struct unprov_device result, *dev; int16_t rssi; + uint16_t server = 0; uint32_t n; uint8_t *prov_data; - char *str; - struct unprov_device *dev; + const char *key; const char *sig = "naya{sv}"; + if (finalized == l_queue_peek_head(devices)) + goto done; + + if (!l_dbus_message_get_arguments(msg, sig, &rssi, &iter, &opts)) { l_error("Cannot parse scan results"); return l_dbus_message_new_error(msg, dbus_err_args, NULL); @@ -1781,42 +2012,71 @@ static struct l_dbus_message *scan_result_call(struct l_dbus *dbus, return l_dbus_message_new_error(msg, dbus_err_args, NULL); } - bt_shell_printf("Scan result:\n"); - bt_shell_printf("\t" COLOR_GREEN "rssi = %d\n" COLOR_OFF, rssi); - str = l_util_hexstring_upper(prov_data, 16); - bt_shell_printf("\t" COLOR_GREEN "UUID = %s\n" COLOR_OFF, str); - l_free(str); - - if (n >= 18) { - str = l_util_hexstring_upper(prov_data + 16, 2); - bt_shell_printf("\t" COLOR_GREEN "OOB = %s\n" COLOR_OFF, str); - l_free(str); + while (l_dbus_message_iter_next_entry(&opts, &key, &var)) { + if (!strcmp(key, "Server")) + l_dbus_message_iter_get_variant(&var, "q", &server); } - if (n >= 22) { - str = l_util_hexstring_upper(prov_data + 18, 4); - bt_shell_printf("\t" COLOR_GREEN "URI Hash = %s\n" COLOR_OFF, - str); - l_free(str); - } + memcpy(result.uuid, prov_data, 16); + result.server = server; + result.rssi = rssi; + result.id = 0; + result.last_seen = time(NULL); + + if (n > 16 && n <= 18) + result.oob_info = l_get_be16(prov_data + 16); + else + result.oob_info = 0; - /* TODO: Handle the rest of provisioning data if present */ + if (n > 18 && n <= 22) + result.uri_hash = l_get_be32(prov_data + 18); + else + result.uri_hash = 0; + + dev = l_queue_remove_if(devices, match_by_srv_uuid, &result); - dev = l_queue_find(devices, match_device_uuid, prov_data); if (!dev) { - dev = l_new(struct unprov_device, 1); - memcpy(dev->uuid, prov_data, sizeof(dev->uuid)); - /* TODO: timed self-destructor */ - l_queue_push_tail(devices, dev); - } + bt_shell_printf("\r" COLOR_YELLOW "Results = %d\n" COLOR_OFF, + l_queue_length(devices) + 1); + dev = l_malloc(sizeof(struct unprov_device)); + *dev = result; + + } else if (dev->rssi < result.rssi) + *dev = result; - /* Update with the latest rssi */ - dev->rssi = rssi; - dev->last_seen = time(NULL); + l_queue_insert(devices, dev, sort_rssi, NULL); +done: return l_dbus_message_new_method_return(msg); } +static struct l_dbus_message *req_reprov_call(struct l_dbus *dbus, + struct l_dbus_message *msg, + void *user_data) +{ + uint8_t cnt; + uint16_t unicast, original; + struct l_dbus_message *reply; + + + if (!l_dbus_message_get_arguments(msg, "qy", &original, &cnt) || + !IS_UNICAST(original)) { + l_error("Cannot parse request for reprov data"); + return l_dbus_message_new_error(msg, dbus_err_args, NULL); + + } + + unicast = remote_get_next_unicast(low_addr, high_addr, cnt); + + bt_shell_printf("Assign addresses for %u elements\n", cnt); + bt_shell_printf("Original: %4.4x New: %4.4x\n", original, unicast); + + reply = l_dbus_message_new_method_return(msg); + l_dbus_message_set_arguments(reply, "q", unicast); + + return reply; +} + static struct l_dbus_message *req_prov_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) @@ -1825,6 +2085,7 @@ static struct l_dbus_message *req_prov_call(struct l_dbus *dbus, uint16_t unicast; struct l_dbus_message *reply; + /* Both calls handled identicaly except for parameter list */ if (!l_dbus_message_get_arguments(msg, "y", &cnt)) { l_error("Cannot parse request for prov data"); return l_dbus_message_new_error(msg, dbus_err_args, NULL); @@ -1833,14 +2094,14 @@ static struct l_dbus_message *req_prov_call(struct l_dbus *dbus, unicast = remote_get_next_unicast(low_addr, high_addr, cnt); - if (unicast == 0) { + if (!IS_UNICAST(unicast)) { l_error("Failed to allocate addresses for %u elements\n", cnt); return l_dbus_message_new_error(msg, "org.freedesktop.DBus.Error." "Failed to allocate address", NULL); } - bt_shell_printf("Assign addresses for %u elements\n", cnt); + bt_shell_printf("Assign addresses: %4.4x (cnt: %d)\n", unicast, cnt); reply = l_dbus_message_new_method_return(msg); l_dbus_message_set_arguments(reply, "qq", prov_net_idx, unicast); @@ -1852,11 +2113,13 @@ static void remove_device(uint8_t *uuid) { struct unprov_device *dev; - dev = l_queue_remove_if(devices, match_device_uuid, uuid); - l_free(dev); + do { + dev = l_queue_remove_if(devices, match_device_uuid, uuid); + l_free(dev); + } while (dev); } -static struct l_dbus_message *add_node_cmplt_call(struct l_dbus *dbus, +static struct l_dbus_message *prov_cmplt_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { @@ -1866,6 +2129,7 @@ static struct l_dbus_message *add_node_cmplt_call(struct l_dbus *dbus, uint32_t n; uint8_t *uuid; + l_debug("ProvComplete"); if (!prov_in_progress) return l_dbus_message_new_error(msg, dbus_err_fail, NULL); @@ -1896,7 +2160,49 @@ static struct l_dbus_message *add_node_cmplt_call(struct l_dbus *dbus, return l_dbus_message_new_method_return(msg); } -static struct l_dbus_message *add_node_fail_call(struct l_dbus *dbus, +static struct l_dbus_message *reprov_cmplt_call(struct l_dbus *dbus, + struct l_dbus_message *msg, + void *user_data) +{ + uint16_t unicast, original; + uint8_t old_cnt, cnt, nppi; + + l_debug("ReprovComplete"); + if (!prov_in_progress) + return l_dbus_message_new_error(msg, dbus_err_fail, NULL); + + prov_in_progress = false; + + if (!l_dbus_message_get_arguments(msg, "qyqy", &original, &nppi, + &unicast, &cnt)) { + l_error("Cannot parse reprov complete message"); + return l_dbus_message_new_error(msg, dbus_err_args, NULL); + + } + + l_debug("ReprovComplete org: %4.4x, nppi: %d, new: %4.4x, cnt: %d", + original, nppi, unicast, cnt); + old_cnt = remote_ele_cnt(original); + + if (nppi != 1 && (original != unicast || cnt != old_cnt)) { + l_error("Invalid reprov complete message (NPPI == %d)", nppi); + return l_dbus_message_new_error(msg, dbus_err_args, NULL); + } + + if (nppi) + remote_reset_node(original, unicast, cnt, + mesh_db_get_iv_index()); + + bt_shell_printf("Reprovisioning done (nppi: %d):\n", nppi); + remote_print_node(unicast); + + if (!mesh_db_reset_node(original, unicast, cnt)) + l_error("Failed to reset remote node"); + + return l_dbus_message_new_method_return(msg); +} + +static struct l_dbus_message *prov_fail_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { @@ -1911,24 +2217,49 @@ static struct l_dbus_message *add_node_fail_call(struct l_dbus *dbus, prov_in_progress = false; if (!l_dbus_message_get_arguments(msg, "ays", &iter, &reason)) { - l_error("Cannot parse add node failed message"); + l_error("Cannot parse failed message"); return l_dbus_message_new_error(msg, dbus_err_args, NULL); - } - if (!l_dbus_message_iter_get_fixed_array(&iter, &uuid, &n) || - n != 16) { - l_error("Cannot parse add node failed message: uuid"); + if (!l_dbus_message_iter_get_fixed_array(&iter, &uuid, &n) || n != 16) { + l_error("Cannot parse failed message: uuid"); return l_dbus_message_new_error(msg, dbus_err_args, NULL); } bt_shell_printf("Provisioning failed:\n"); + str = l_util_hexstring_upper(uuid, 16); bt_shell_printf("\t" COLOR_RED "UUID = %s\n" COLOR_OFF, str); l_free(str); + remove_device(uuid); bt_shell_printf("\t" COLOR_RED "%s\n" COLOR_OFF, reason); - remove_device(uuid); + return l_dbus_message_new_method_return(msg); +} + +static struct l_dbus_message *reprov_fail_call(struct l_dbus *dbus, + struct l_dbus_message *msg, + void *user_data) +{ + struct l_dbus_message_iter iter; + uint16_t original = UNASSIGNED_ADDRESS; + char *reason; + + if (!prov_in_progress) + return l_dbus_message_new_error(msg, dbus_err_fail, NULL); + + prov_in_progress = false; + + if (!l_dbus_message_get_arguments(msg, "qs", &iter, &reason) || + !IS_UNICAST(original)) { + + l_error("Cannot parse Reprov failed message"); + return l_dbus_message_new_error(msg, dbus_err_args, NULL); + } + + bt_shell_printf("Reprovisioning failed:\n"); + bt_shell_printf("\t" COLOR_RED "UNICAST = %4.4x\n" COLOR_OFF, original); + bt_shell_printf("\t" COLOR_RED "%s\n" COLOR_OFF, reason); return l_dbus_message_new_method_return(msg); } @@ -1941,12 +2272,23 @@ static void setup_prov_iface(struct l_dbus_interface *iface) l_dbus_interface_method(iface, "RequestProvData", 0, req_prov_call, "qq", "y", "net_index", "unicast", "count"); + l_dbus_interface_method(iface, "RequestReprovData", 0, req_reprov_call, + "q", "qy", "unicast", + "original", "count"); + l_dbus_interface_method(iface, "AddNodeComplete", 0, - add_node_cmplt_call, "", "ayqy", + prov_cmplt_call, "", "ayqy", "uuid", "unicast", "count"); - l_dbus_interface_method(iface, "AddNodeFailed", 0, add_node_fail_call, + l_dbus_interface_method(iface, "ReprovComplete", 0, + reprov_cmplt_call, "", "qyqy", + "original", "nppi", "unicast", "count"); + + l_dbus_interface_method(iface, "AddNodeFailed", 0, prov_fail_call, "", "ays", "uuid", "reason"); + + l_dbus_interface_method(iface, "ReprovFailed", 0, reprov_fail_call, + "", "qs", "unicast", "reason"); } static bool cid_getter(struct l_dbus *dbus, @@ -2140,7 +2482,7 @@ static void client_ready(struct l_dbus_client *client, void *user_data) static void client_connected(struct l_dbus *dbus, void *user_data) { bt_shell_printf("D-Bus client connected\n"); - bt_shell_set_prompt(PROMPT_ON); + bt_shell_set_prompt(PROMPT_ON, COLOR_BLUE); } static void client_disconnected(struct l_dbus *dbus, void *user_data) @@ -2300,7 +2642,7 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - bt_shell_set_prompt(PROMPT_OFF); + bt_shell_set_prompt(PROMPT_OFF, NULL); dbus = l_dbus_new_default(L_DBUS_SYSTEM_BUS); diff --git a/tools/mesh-cfgtest.c b/tools/mesh-cfgtest.c index 116ab7f1642fb23ad5b60a16ae5db711785825dc..739d1d972bca5fe9aa4b6323399073191006d92f 100644 --- a/tools/mesh-cfgtest.c +++ b/tools/mesh-cfgtest.c @@ -38,14 +38,21 @@ #define MAX_CRPL_SIZE 0x7fff #define CFG_SRV_MODEL 0x0000 #define CFG_CLI_MODEL 0x0001 +#define RMT_PROV_SRV_MODEL 0x0004 +#define RMT_PROV_CLI_MODEL 0x0005 +#define PVT_BEACON_SRV_MODEL 0x0008 #define DEFAULT_IV_INDEX 0x0000 -#define IS_CONFIG_MODEL(x) ((x) == CFG_SRV_MODEL || (x) == CFG_CLI_MODEL) +#define IS_CONFIG_MODEL(x) (((x) == (CFG_SRV_MODEL)) || \ + ((x) == (CFG_CLI_MODEL)) || \ + ((x) == (RMT_PROV_SRV_MODEL)) || \ + ((x) == (RMT_PROV_CLI_MODEL))) struct meshcfg_el { const char *path; uint8_t index; - uint16_t mods[2]; + uint16_t location; + uint16_t mods[4]; uint32_t vmods[2]; }; @@ -77,6 +84,11 @@ struct msg_data { uint8_t data[MAX_MSG_LEN]; }; +struct exp_rsp { + uint8_t test_id; + void *rsp; +}; + struct key_data { uint16_t idx; bool update; @@ -140,7 +152,9 @@ static struct meshcfg_app client_app = { { .path = cli_ele_path_00, .index = PRIMARY_ELE_IDX, - .mods = {CFG_SRV_MODEL, CFG_CLI_MODEL}, + .location = 0x0001, + .mods = {CFG_SRV_MODEL, CFG_CLI_MODEL, + RMT_PROV_SRV_MODEL, PVT_BEACON_SRV_MODEL}, .vmods = {0xffffffff, 0xffffffff} } } @@ -158,13 +172,16 @@ static struct meshcfg_app server_app = { { .path = srv_ele_path_00, .index = PRIMARY_ELE_IDX, - .mods = {CFG_SRV_MODEL, 0xffff}, + .location = 0x0001, + .mods = {CFG_SRV_MODEL, RMT_PROV_SRV_MODEL, + PVT_BEACON_SRV_MODEL, 0xffff}, .vmods = {0xffffffff, 0xffffffff} }, { .path = srv_ele_path_01, .index = PRIMARY_ELE_IDX + 1, - .mods = {0x1000, 0xffff}, + .location = 0x0002, + .mods = {0x1000, 0xffff, 0xffff, 0xffff}, .vmods = {0x5F10001, 0xffffffff} } } @@ -262,6 +279,11 @@ static struct msg_data test_add_appkey_rsp = { .data = {0x80, 0x03, 0x00, 0x01, 0x20, 0x00} }; +static struct exp_rsp test_add_appkey_expected = { + .test_id = 1, + .rsp = &test_add_appkey_rsp, +}; + static struct key_data test_add_appkey_req = { .idx = 0x002, .update = false @@ -285,6 +307,11 @@ static struct msg_data test_set_ttl_rsp = { .data = { 0x80, 0x0E, 0x7} }; +static struct exp_rsp test_set_ttl_expected = { + .test_id = 2, + .rsp = &test_set_ttl_rsp +}; + static struct msg_data test_set_ttl_req = { .len = 3, .data = { 0x80, 0x0D, 0x7} @@ -295,27 +322,42 @@ static struct msg_data test_bind_rsp = { .data = { 0x80, 0x3E, 0x00, 0xCE, 0x0B, 0x01, 0x00, 0x00, 0x10}, }; +static struct exp_rsp test_bind_expected = { + .test_id = 3, + .rsp = &test_bind_rsp +}; + static struct msg_data test_bind_req = { .len = 8, .data = { 0x80, 0x3D, 0xCE, 0x0B, 0x01, 0x00, 0x00, 0x10} }; - static struct msg_data test_bind_inv_mod_rsp = { .len = 9, .data = { 0x80, 0x3E, 0x02, 0xCE, 0x0B, 0x01, 0x00, 0x00, 0x11}, }; +static struct exp_rsp test_bind_inv_mod_expected = { + .test_id = 4, + .rsp = &test_bind_inv_mod_rsp +}; + static struct msg_data test_bind_inv_mod_req = { .len = 8, .data = { 0x80, 0x3D, 0xCE, 0x0B, 0x01, 0x00, 0x00, 0x11} }; static struct msg_data test_dev_comp_rsp = { - .len = 28, - .data = { 0x02, 0x00, 0xf1, 0x05, 0x02, 0x00, 0x01, 0x00, 0xff, 0x7f, - 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x01, 0x00, 0x10, 0xf1, 0x05, 0x01, 0x00} + .len = 32, + .data = { 0x02, 0x00, 0xf1, 0x05, 0x02, 0x00, 0x01, 0x00, + 0xff, 0x7f, 0x05, 0x00, + 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, + 0x02, 0x00, 0x01, 0x01, 0x00, 0x10, 0xf1, 0x05, 0x01, 0x00} +}; + +static struct exp_rsp test_dev_comp_expected = { + .test_id = 5, + .rsp = &test_dev_comp_rsp }; static struct msg_data test_dev_comp_req = { @@ -955,11 +997,101 @@ static bool ele_idx_getter(struct l_dbus *dbus, return true; } +static bool location_getter(struct l_dbus *dbus, + struct l_dbus_message *message, + struct l_dbus_message_builder *builder, + void *user_data) +{ + struct meshcfg_el *ele = user_data; + + l_dbus_message_builder_append_basic(builder, 'q', &ele->location); + + return true; +} + +static bool find_model(uint8_t *buf, uint32_t len, uint8_t *mod, uint8_t sz) +{ + bool found = false; + + while (len >= sz) { + if (!memcmp(buf, mod, sz)) { + /* Disallow duplicates */ + if (found) + return false; + + found = true; + } + + buf += sz; + len -= sz; + } + + return found; +} + +static bool check_device_composition(struct msg_data *rsp, uint32_t len, + uint8_t *data) +{ + uint32_t cnt; + + if (len != rsp->len) + return false; + + if (!memcmp(data, rsp->data, len)) + return true; + + /* Allow for a different ordering of model IDs */ + + /* First, check that the fixed length data matches */ + if (memcmp(data, rsp->data, 12)) + return false; + + cnt = 12; + data += 12; + + while (cnt < len) { + uint8_t s, v, i; + + if ((len - cnt) < 4) + return false; + + /* Check element index, location and model count */ + if (memcmp(data, rsp->data + cnt, 4)) + return false; + + s = data[2]; + v = data[3]; + + if ((cnt + s * 2 + v * 4) > len) + return false; + + data += 4; + cnt += 4; + + for (i = 0; i < s; i++) { + if (!find_model(&rsp->data[cnt], s * 2, data, 2)) + return false; + data += 2; + } + + cnt += s * 2; + + for (i = 0; i < v; i++) { + if (!find_model(&rsp->data[cnt], v * 4, data, 4)) + return false; + data += 4; + } + + cnt += v * 4; + } + + return true; +} + static struct l_dbus_message *dev_msg_recv_call(struct l_dbus *dbus, struct l_dbus_message *msg, void *user_data) { - struct msg_data *rsp; struct l_dbus_message_iter iter; uint16_t src, idx; uint8_t *data; @@ -983,7 +1115,7 @@ static struct l_dbus_message *dev_msg_recv_call(struct l_dbus *dbus, uint32_t i; for (i = 0; i < n; i++) - printf("%x ", data[i]); + printf("%02x ", data[i]); printf("\n"); } @@ -999,9 +1131,24 @@ static struct l_dbus_message *dev_msg_recv_call(struct l_dbus *dbus, l_tester_pre_setup_failed(tester); } } else { - rsp = l_tester_get_data(tester); + struct exp_rsp *exp = l_tester_get_data(tester); + bool res = false; + + if (exp && exp->rsp) { + if (exp->test_id == 5) + /* Check device composition */ + res = check_device_composition(exp->rsp, n, + data); + else { + struct msg_data *rsp = exp->rsp; + + if (n == rsp->len && + !memcmp(data, rsp->data, n)) + res = true; + } + } - if (rsp && rsp->len == n && !memcmp(data, rsp->data, n)) + if (res) l_idle_oneshot(test_success, NULL, NULL); else l_idle_oneshot(test_fail, NULL, NULL); @@ -1019,7 +1166,8 @@ static void setup_ele_iface(struct l_dbus_interface *iface) vmod_getter, NULL); l_dbus_interface_property(iface, "Models", 0, "a(qa{sv})", mod_getter, NULL); - + l_dbus_interface_property(iface, "Location", 0, "q", location_getter, + NULL); /* Methods */ l_dbus_interface_method(iface, "DevKeyMessageReceived", 0, dev_msg_recv_call, "", "qbqay", "source", @@ -1411,23 +1559,23 @@ int main(int argc, char *argv[]) l_tester_add_full(tester, "Config AppKey Add: Success", &test_add_appkey, init_test, create_appkey, add_appkey, - NULL, NULL, 2, &test_add_appkey_rsp, NULL); + NULL, NULL, 2, &test_add_appkey_expected, NULL); tester_add_with_response("Config Default TTL Set: Success", &test_set_ttl_req, send_cfg_msg, - &test_set_ttl_rsp); + &test_set_ttl_expected); tester_add_with_response("Config Get Device Composition: Success", &test_dev_comp_req, send_cfg_msg, - &test_dev_comp_rsp); + &test_dev_comp_expected); tester_add_with_response("Config Bind: Success", &test_bind_req, send_cfg_msg, - &test_bind_rsp); + &test_bind_expected); tester_add_with_response("Config Bind: Error Invalid Model", &test_bind_inv_mod_req, send_cfg_msg, - &test_bind_inv_mod_rsp); + &test_bind_inv_mod_expected); l_tester_start(tester, done_callback); diff --git a/tools/mesh-gatt/README b/tools/mesh-gatt/README deleted file mode 100644 index 44d633313707b028080296c7ee9b226fa720cf84..0000000000000000000000000000000000000000 --- a/tools/mesh-gatt/README +++ /dev/null @@ -1,43 +0,0 @@ -MeshCtl - BlueZ GATT based Bluetooth Mesh Provisioner -***************************************************** - -Copyright (C) 2017 Intel Corporation. All rights reserved. - -Compilation and installation -============================ - -In addition to main BlueZ requirements, MeshCtl needs the following: - - JSON library - -Configuration and options -========================= - - --enable-mesh - - Build meshctl and other Bluetooth Mesh based tools and utils - -Example configuration files -=========================== - -The MeshCtl tool requires two input configuration files in JSON format: - - local_node.json - Local mesh node configuration - - prov_db.json - Provisoner's database for all the configured nodes in the mesh - -The default directory for MeshCtl configuration files is -/home/<username>/.config/meshctl - -To use .json configuration files either copy them to the default directory -or, to specify a custom storage directory, run meshctl tool as: - - meshctl -c <config_dir_name> - -Information -=========== - -Mailing lists: - linux-bluetooth@vger.kernel.org - -For additional information about the project visit BlueZ web site: - http://www.bluez.org diff --git a/tools/mesh-gatt/local_node.json b/tools/mesh-gatt/local_node.json deleted file mode 100644 index 5ffa7ada1f65f7f32320036610402d0ce581833c..0000000000000000000000000000000000000000 --- a/tools/mesh-gatt/local_node.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "$schema":"file:\/\/\/BlueZ\/Mesh\/local_schema\/mesh.jsonschema", - "meshName":"BT Mesh", - "netKeys":[ - { - "index": 0, - "keyRefresh": 0 - } - ], - "appKeys":[ - { - "index": 0, - "boundNetKey": 0 - }, - { - "index": 1, - "boundNetKey": 0 - } - ], -"node": { - "IVindex":"00000005", - "IVupdate":"0", - "sequenceNumber": 0, - "composition": { - "cid": "0002", - "pid": "0010", - "vid": "0001", - "crpl": "000a", - "features": { - "relay": false, - "proxy": true, - "friend": false, - "lowPower": false - }, - "elements": [ - { - "elementIndex": 0, - "location": "0001", - "models": ["0000", "0001", "1001"] - } - ] - }, - "configuration":{ - "netKeys": [0], - "appKeys": [ 0, 1], - "defaultTTL": 10, - "elements": [ - { - "elementIndex": 0, - "unicastAddress":"0077", - "models": [ - { - "modelId": "1001", - "bind": [1] - } - ] - } - ] - } - } -} diff --git a/tools/mesh-gatt/prov_db.json b/tools/mesh-gatt/prov_db.json deleted file mode 100644 index 74a03128d4d57358b65a4ad992c7e49fa13a4e2b..0000000000000000000000000000000000000000 --- a/tools/mesh-gatt/prov_db.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "$schema":"file:\/\/\/BlueZ\/Mesh\/schema\/mesh.jsonschema", - "meshName":"BT Mesh", - "IVindex":5, - "IVupdate":0, - "netKeys":[ - { - "index":0, - "keyRefresh":0, - "key":"18eed9c2a56add85049ffc3c59ad0e12" - } - ], - "appKeys":[ - { - "index":0, - "boundNetKey":0, - "key":"4f68ad85d9f48ac8589df665b6b49b8a" - }, - { - "index":1, - "boundNetKey":0, - "key":"2aa2a6ded5a0798ceab5787ca3ae39fc" - } - ], - "provisioners":[ - { - "provisionerName":"BT Mesh Provisioner", - "unicastAddress":"0077", - "allocatedUnicastRange":[ - { - "lowAddress":"0100", - "highAddress":"7fff" - } - ] - } - ], -} diff --git a/tools/mesh-gatt/util.c b/tools/mesh-gatt/util.c index eb8b8eb29467571bc2526cd8b1f5012312efc622..58f240a7748e2d006ca6dbb73d4c75d61bb82539 100644 --- a/tools/mesh-gatt/util.c +++ b/tools/mesh-gatt/util.c @@ -29,9 +29,9 @@ void set_menu_prompt(const char *name, const char *id) { char *prompt; - prompt = g_strdup_printf(COLOR_BLUE "[%s%s%s]" COLOR_OFF "# ", name, + prompt = g_strdup_printf("[%s%s%s]# ", name, id ? ": Target = " : "", id ? id : ""); - bt_shell_set_prompt(prompt); + bt_shell_set_prompt(prompt, COLOR_BLUE); g_free(prompt); } diff --git a/tools/mesh/README b/tools/mesh/README deleted file mode 100644 index 3830d1b176410050586c895f961c22b4704cba8b..0000000000000000000000000000000000000000 --- a/tools/mesh/README +++ /dev/null @@ -1,54 +0,0 @@ -MeshCfgclient - BlueZ PB-Adv based Bluetooth Mesh Provisioner -************************************************************* - -Copyright (C) 2019 Intel Corporation. All rights reserved. - -Compilation and installation -============================ - -In addition to main BlueZ requirements, MeshCfgclient needs the following: - - JSON library - -Configuration and options -========================= - - --enable-mesh - - Build mesh-cfgclient and other Bluetooth Mesh based tools - -Storage for mesh configuration file -=================================== - -The mesh-cfgclient tool generates a mesh configuration file in JSON format: - - mesh_db.json -that contains information about the current state of the configured mesh -network. - -The default directory for mesh-cfgclient configuration file is -$HOME/.config/meshcfg - -To specify a custom file, run mesh-cfgclient tool as: - - mesh-cfgclient -c <config_file_name> - -If a configuration file is not found, it is assumed that a mesh network -does not exist. In this case, the tool may be used to generate a new mesh -network by invoking "create" command from the main menu and, on a successful -completion of this command, an initial configuration file is written. - -If the configuration file is present, then "create" command will fail. This -is done so that the existing configuration is not accidentally overwritten. -If the intention is to create a new network then, the existing mesh -configuration file has to be either moved or dleted prior to running the -mesh-cfgclient tool. Also, a new custom storage location may be -specified for a new network on the start up as a command line option. - - -Information -=========== - -Mailing lists: - linux-bluetooth@vger.kernel.org - -For additional information about the project visit BlueZ web site: - http://www.bluez.org diff --git a/tools/mesh/cfgcli.c b/tools/mesh/cfgcli.c index a48eace745cc38f09ecdba505cae97083fa5f333..1a404af38ebd966d20de1705b24dc644adba2413 100644 --- a/tools/mesh/cfgcli.c +++ b/tools/mesh/cfgcli.c @@ -21,6 +21,7 @@ #include "src/shared/util.h" #include "mesh/mesh-defs.h" +#include "mesh/prv-beacon.h" #include "mesh/util.h" #include "mesh/crypto.h" @@ -73,9 +74,12 @@ static struct cfg_cmd cmds[] = { { OP_APPKEY_UPDATE, OP_APPKEY_STATUS, "AppKeyUpdate" }, { OP_DEV_COMP_GET, OP_DEV_COMP_STATUS, "DeviceCompositionGet" }, { OP_DEV_COMP_STATUS, NO_RESPONSE, "DeviceCompositionStatus" }, - { OP_CONFIG_BEACON_GET, OP_CONFIG_BEACON_STATUS, "BeaconGet" }, - { OP_CONFIG_BEACON_SET, OP_CONFIG_BEACON_STATUS, "BeaconSet" }, - { OP_CONFIG_BEACON_STATUS, NO_RESPONSE, "BeaconStatus" }, + { OP_CONFIG_BEACON_GET, OP_CONFIG_BEACON_STATUS, "SNBGet" }, + { OP_CONFIG_BEACON_SET, OP_CONFIG_BEACON_STATUS, "SNBSet" }, + { OP_CONFIG_BEACON_STATUS, NO_RESPONSE, "SNBStatus" }, + { OP_PRIVATE_BEACON_GET, OP_PRIVATE_BEACON_STATUS, "MPBGet" }, + { OP_PRIVATE_BEACON_SET, OP_PRIVATE_BEACON_STATUS, "MPBSet" }, + { OP_PRIVATE_BEACON_STATUS, NO_RESPONSE, "MPBStatus" }, { OP_CONFIG_DEFAULT_TTL_GET, OP_CONFIG_DEFAULT_TTL_STATUS, "DefaultTTLGet" }, { OP_CONFIG_DEFAULT_TTL_SET, OP_CONFIG_DEFAULT_TTL_STATUS, @@ -266,14 +270,21 @@ static uint32_t print_mod_id(uint8_t *data, bool vendor, const char *offset) return mod_id; } -static void print_composition(uint8_t *data, uint16_t len) +static uint8_t print_composition(uint8_t *data, uint16_t len) { uint16_t features; int i = 0; + bool nppi = false; - bt_shell_printf("Received composion:\n"); + bt_shell_printf("Received composition:\n"); + + /* We only support Pages 0 && 128 */ + if (*data == 128) { + bt_shell_printf("Dev Key Refresh (NPPI) required\n"); + nppi = true; + } else if (*data != 0) + return 0; - /* skip page -- We only support Page Zero */ data++; len--; @@ -328,6 +339,11 @@ static void print_composition(uint8_t *data, uint16_t len) i++; } + + if (nppi) + return (uint8_t) i; + else + return 0; } static void print_pub(uint16_t ele_addr, uint32_t mod_id, @@ -402,6 +418,7 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data, const struct cfg_cmd *cmd; uint16_t app_idx, net_idx, addr, ele_addr, features; struct mesh_group *grp; + uint8_t page128_cnt; struct model_pub pub; int n; struct pending_req *req; @@ -431,7 +448,19 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data, if (len < MIN_COMPOSITION_LEN) return true; - print_composition(data, len); + page128_cnt = print_composition(data, len); + if (page128_cnt) { + if (page128_cnt != remote_ele_cnt(src)) { + bt_shell_printf("Ele count was %d, now %d\n", + remote_ele_cnt(src), page128_cnt); + bt_shell_printf("Reprovision with NPPI-1\n"); + } else { + bt_shell_printf("Models or Features changed\n"); + bt_shell_printf("Reprovision with NPPI-2\n"); + } + + break; + } saved = mesh_db_node_set_composition(src, data, len); if (saved) @@ -592,12 +621,20 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data, if (len != 1) return true; - bt_shell_printf("Node %4.4x: Config Beacon Status 0x%02x\n", + bt_shell_printf("Node %4.4x: SecBeacon Status 0x%02x\n", src, data[0]); saved = mesh_db_node_set_beacon(src, data[0] != 0); break; + case OP_PRIVATE_BEACON_STATUS: + if (len != 2) + return true; + + bt_shell_printf("Node %4.4x: PrivBeacon Status 0x%02x 0x%02x\n", + src, data[0], data[1]); + break; + case OP_CONFIG_RELAY_STATUS: if (len != 2) return true; @@ -1044,6 +1081,21 @@ static void cmd_default(uint32_t opcode) return bt_shell_noninteractive_quit(EXIT_SUCCESS); } + +bool cfgcli_get_comp(uint16_t unicast, uint8_t page) +{ + uint16_t n; + uint8_t msg[32]; + + n = mesh_opcode_set(OP_DEV_COMP_GET, msg); + + msg[n++] = page; + + target = unicast; + + return config_send(msg, n, OP_DEV_COMP_GET); +} + static void cmd_composition_get(int argc, char *argv[]) { uint16_t n; @@ -1051,8 +1103,8 @@ static void cmd_composition_get(int argc, char *argv[]) n = mesh_opcode_set(OP_DEV_COMP_GET, msg); - /* By default, use page 0 */ - msg[n++] = (read_input_parameters(argc, argv) == 1) ? parms[0] : 0; + /* By default, use page 128 */ + msg[n++] = (read_input_parameters(argc, argv) == 1) ? parms[0] : 128; if (!config_send(msg, n, OP_DEV_COMP_GET)) return bt_shell_noninteractive_quit(EXIT_FAILURE); @@ -1320,7 +1372,7 @@ static void cmd_del_binding(int argc, char *argv[]) cmd_bind(OP_MODEL_APP_UNBIND, argc, argv); } -static void cmd_beacon_set(int argc, char *argv[]) +static void cmd_snb_set(int argc, char *argv[]) { uint16_t n; uint8_t msg[2 + 1]; @@ -1342,11 +1394,41 @@ static void cmd_beacon_set(int argc, char *argv[]) return bt_shell_noninteractive_quit(EXIT_SUCCESS); } -static void cmd_beacon_get(int argc, char *argv[]) +static void cmd_mpb_set(int argc, char *argv[]) +{ + uint16_t n; + uint8_t msg[2 + 2]; + uint32_t parm_cnt; + + n = mesh_opcode_set(OP_PRIVATE_BEACON_SET, msg); + + parm_cnt = read_input_parameters(argc, argv); + if (parm_cnt != 1 && parm_cnt != 2) { + bt_shell_printf("bad arguments\n"); + return bt_shell_noninteractive_quit(EXIT_FAILURE); + } + + msg[n++] = parms[0]; + + if (parm_cnt == 2) + msg[n++] = parms[1]; + + if (!config_send(msg, n, OP_PRIVATE_BEACON_SET)) + return bt_shell_noninteractive_quit(EXIT_FAILURE); + + return bt_shell_noninteractive_quit(EXIT_SUCCESS); +} + +static void cmd_snb_get(int argc, char *argv[]) { cmd_default(OP_CONFIG_BEACON_GET); } +static void cmd_mpb_get(int argc, char *argv[]) +{ + cmd_default(OP_PRIVATE_BEACON_GET); +} + static void cmd_ident_set(int argc, char *argv[]) { uint16_t n; @@ -2052,10 +2134,10 @@ static const struct bt_shell_menu cfg_menu = { "Set node identity state"}, {"ident-get", "<net_idx>", cmd_ident_get, "Get node identity state"}, - {"beacon-set", "<state>", cmd_beacon_set, - "Set node identity state"}, - {"beacon-get", NULL, cmd_beacon_get, - "Get node beacon state"}, + {"snb-set", "<state>", cmd_snb_set, "Set node SNB state"}, + {"snb-get", NULL, cmd_snb_get, "Get node SNB state"}, + {"mpb-set", "<state> <period>", cmd_mpb_set, "Set node MPB state"}, + {"mpb-get", NULL, cmd_mpb_get, "Get node MPB state"}, {"relay-set", "<relay> <rexmt count> <rexmt steps>", cmd_relay_set, "Set relay"}, {"relay-get", NULL, cmd_relay_get, diff --git a/tools/mesh/cfgcli.h b/tools/mesh/cfgcli.h index 7281caa46381f0bfd008b492d962b3c63c623d1e..621dd0259cd2a2301cc32ebe419e18fdeba82e0c 100644 --- a/tools/mesh/cfgcli.h +++ b/tools/mesh/cfgcli.h @@ -19,4 +19,6 @@ typedef void (*delete_remote_func_t) (uint16_t primary, uint8_t ele_cnt); struct model_info *cfgcli_init(key_send_func_t key_func, delete_remote_func_t del_node, void *user_data); + +bool cfgcli_get_comp(uint16_t unicast, uint8_t page); void cfgcli_cleanup(void); diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c index 896ff722c38b10c9fa4c4f2f05bc8a596861f558..fb9c436d1d062c198125aa79122401ebe91d55d6 100644 --- a/tools/mesh/mesh-db.c +++ b/tools/mesh/mesh-db.c @@ -503,7 +503,8 @@ static void load_remotes(json_object *jcfg) uint8_t uuid[16]; uint16_t unicast, key_idx; const char *str; - int ele_cnt, key_cnt; + uint8_t ele_cnt; + int key_cnt; int j; jnode = json_object_array_get_idx(jnodes, i); @@ -528,14 +529,13 @@ static void load_remotes(json_object *jcfg) continue; json_object_object_get_ex(jnode, "elements", &jarray); - if (!jarray || json_object_get_type(jarray) != json_type_array) + if (!jarray || + json_object_get_type(jarray) != json_type_array || + json_object_array_length(jarray) > MAX_ELE_COUNT) continue; ele_cnt = json_object_array_length(jarray); - if (ele_cnt > MAX_ELE_COUNT) - continue; - json_object_object_get_ex(jnode, "netKeys", &jarray); if (!jarray || json_object_get_type(jarray) != json_type_array) continue; @@ -1702,6 +1702,29 @@ static json_object *init_elements(uint8_t num_els) return jelements; } +bool mesh_db_reset_node(uint16_t original, uint16_t unicast, uint8_t num_els) +{ + json_object *jnode, *jelements; + + if (!cfg || !cfg->jcfg) + return false; + + jnode = get_node_by_unicast(cfg->jcfg, original); + if (!jnode) { + l_error("Node %4.4x does not exist", original); + return false; + } + + if (!write_uint16_hex(jnode, "unicastAddress", unicast)) + return false; + + json_object_object_del(jnode, "elements"); + jelements = init_elements(num_els); + json_object_object_add(jnode, "elements", jelements); + + return save_config(); +} + bool mesh_db_add_node(uint8_t uuid[16], uint8_t num_els, uint16_t unicast, uint16_t net_idx) { @@ -1864,13 +1887,11 @@ bool mesh_db_node_set_composition(uint16_t unicast, uint8_t *data, uint16_t len) if (!jnode) return false; - /* skip page -- We only support Page Zero */ - data++; - len--; + /* This is for page-0 only */ + if (*data++ != 0) + return false; - /* If "crpl" property is present, composition is already recorded */ - if (json_object_object_get_ex(jnode, "crpl", &jobj)) - return true; + len--; if (!write_uint16_hex(jnode, "cid", l_get_le16(&data[0]))) return false; @@ -1943,29 +1964,35 @@ bool mesh_db_node_set_composition(uint16_t unicast, uint8_t *data, uint16_t len) while (len >= 2 && m--) { mod_id = l_get_le16(data); + data += 2; + len -= 2; + + jobj = get_model(unicast, unicast + i, mod_id, false); + if (jobj) + continue; jobj = init_model(mod_id); if (!jobj) goto fail; json_object_array_add(jmods, jobj); - data += 2; - len -= 2; } while (len >= 4 && v--) { - jobj = json_object_new_object(); mod_id = l_get_le16(data + 2); mod_id = l_get_le16(data) << 16 | mod_id; + data += 4; + len -= 4; + + jobj = get_model(unicast, unicast + i, mod_id, true); + if (jobj) + continue; jobj = init_vendor_model(mod_id); if (!jobj) goto fail; json_object_array_add(jmods, jobj); - - data += 4; - len -= 4; } i++; @@ -1984,7 +2011,8 @@ bool mesh_db_node_set_composition(uint16_t unicast, uint8_t *data, uint16_t len) fail: /* Reset elements array */ json_object_object_del(jnode, "elements"); - init_elements(sz); + jelements = init_elements(sz); + json_object_object_add(jnode, "elements", jelements); return false; } diff --git a/tools/mesh/mesh-db.h b/tools/mesh/mesh-db.h index 4b6b2adb3d180d35e0c9fd46b9f1979bc223613d..0e45112b7c0b6e1f3e002c44d4c86039ef03e00a 100644 --- a/tools/mesh/mesh-db.h +++ b/tools/mesh/mesh-db.h @@ -29,6 +29,7 @@ bool mesh_db_del_app_key(uint16_t app_idx); bool mesh_db_get_addr_range(uint16_t *low, uint16_t *high); bool mesh_db_add_node(uint8_t uuid[16], uint8_t num_els, uint16_t unicast, uint16_t net_idx); +bool mesh_db_reset_node(uint16_t original, uint16_t unicast, uint8_t num_els); bool mesh_db_del_node(uint16_t unicast); bool mesh_db_node_set_composition(uint16_t unicast, uint8_t *data, uint16_t len); diff --git a/tools/mesh/remote.c b/tools/mesh/remote.c index 6ec220a6fa3fb1c1c224e8a9480213099cd634ca..b917ae9df22740aba9175020f995eca5a56b43be 100644 --- a/tools/mesh/remote.c +++ b/tools/mesh/remote.c @@ -30,6 +30,12 @@ struct remote_key { bool updated; }; +struct foreach_data { + remote_foreach_t each; + void *user_data; + uint16_t dst; +}; + struct remote_node { uint16_t unicast; struct l_queue *net_keys; @@ -48,6 +54,11 @@ struct rejected_addr { static struct l_queue *nodes; static struct l_queue *reject_list; +static bool match_mod_id(const void *a, const void *b) +{ + return a == b; +} + static int compare_mod_id(const void *a, const void *b, void *user_data) { uint32_t id1 = L_PTR_TO_UINT(a); @@ -138,6 +149,40 @@ uint8_t remote_del_node(uint16_t unicast) return num_ele; } +bool remote_reset_node(uint16_t original, uint16_t unicast, uint8_t ele_cnt, + uint32_t iv_index) +{ + struct remote_node *rmt; + bool reject = true; + int i; + + rmt = l_queue_remove_if(nodes, match_node_addr, + L_UINT_TO_PTR(original)); + if (!rmt) + return false; + + if (unicast == rmt->unicast) + reject = false; + + for (i = 0; i < rmt->num_ele; ++i) { + l_queue_destroy(rmt->els[i], NULL); + if (reject) + remote_add_rejected_address(rmt->unicast + i, + iv_index, true); + } + + if (ele_cnt != rmt->num_ele) { + l_free(rmt->els); + rmt->els = l_new(struct l_queue *, ele_cnt); + } else + memset(rmt->els, 0, sizeof(struct l_queue *) * ele_cnt); + + rmt->unicast = unicast; + rmt->num_ele = ele_cnt; + l_queue_insert(nodes, rmt, compare_unicast, NULL); + return true; +} + bool remote_add_node(const uint8_t uuid[16], uint16_t unicast, uint8_t ele_cnt, uint16_t net_idx) { @@ -187,6 +232,10 @@ bool remote_set_model(uint16_t unicast, uint8_t ele_idx, uint32_t mod_id, if (!vendor) mod_id = VENDOR_ID_MASK | mod_id; + if (l_queue_find(rmt->els[ele_idx], match_mod_id, + L_UINT_TO_PTR(mod_id))) + return true; + l_queue_insert(rmt->els[ele_idx], L_UINT_TO_PTR(mod_id), compare_mod_id, NULL); @@ -526,6 +575,76 @@ void remote_print_all(void) l_queue_foreach(nodes, print_node, NULL); } +static void each_node(void *rmt, void *user_data) +{ + struct remote_node *node = rmt; + struct foreach_data *data = user_data; + + data->each(data->user_data, node->unicast, (uint32_t) -1); +} + +static void each_addr(void *rmt, void *user_data) +{ + struct remote_node *node = rmt; + struct foreach_data *data = user_data; + uint16_t cnt; + + for (cnt = 0; cnt <= node->num_ele; cnt++) + data->each(data->user_data, node->unicast + cnt, (uint32_t) -1); +} + +static void parse_model(void *model, void *user_data) +{ + struct foreach_data *data = user_data; + + data->each(data->user_data, data->dst, L_PTR_TO_UINT(model)); +} + +static void each_model(void *rmt, void *user_data) +{ + struct remote_node *node = rmt; + struct foreach_data *data = user_data; + uint16_t cnt; + + for (cnt = 0; cnt < node->num_ele; cnt++) { + data->dst = node->unicast + cnt; + l_queue_foreach(node->els[cnt], parse_model, data); + } +} + +void remote_foreach(remote_foreach_t each, void *user_data) +{ + struct foreach_data data = { + .each = each, + .user_data = user_data + }; + + if (each) + l_queue_foreach(nodes, each_node, &data); +} + +void remote_foreach_unicast(remote_foreach_t each, void *user_data) +{ + struct foreach_data data = { + .each = each, + .user_data = user_data + }; + + if (each) + l_queue_foreach(nodes, each_addr, &data); +} + +void remote_foreach_model(remote_foreach_t each, void *user_data) +{ + struct foreach_data data = { + .each = each, + .user_data = user_data + }; + + if (each) + l_queue_foreach(nodes, each_model, &data); +} + uint16_t remote_get_next_unicast(uint16_t low, uint16_t high, uint8_t ele_cnt) { struct remote_node *rmt; @@ -598,3 +717,15 @@ void remote_clear_rejected_addresses(uint32_t iv_index) mesh_db_clear_rejected(iv_index); } + +uint8_t remote_ele_cnt(uint16_t unicast) +{ + struct remote_node *rmt; + + rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(unicast)); + + if (rmt) + return rmt->num_ele; + + return 0; +} diff --git a/tools/mesh/remote.h b/tools/mesh/remote.h index 66457237ec8f8f04853204f2590e8b17553c4b7e..2a3947b582f9b727ad021b85c7c7099c39d4880d 100644 --- a/tools/mesh/remote.h +++ b/tools/mesh/remote.h @@ -8,8 +8,13 @@ * */ +typedef void (*remote_foreach_t)(void *user_data, uint16_t dst, + uint32_t model); + bool remote_add_node(const uint8_t uuid[16], uint16_t unicast, uint8_t ele_cnt, uint16_t net_idx); +bool remote_reset_node(uint16_t original, uint16_t unicast, uint8_t ele_cnt, + uint32_t iv_index); uint8_t remote_del_node(uint16_t unicast); bool remote_set_model(uint16_t unicast, uint8_t ele_idx, uint32_t mod_id, bool vendor); @@ -30,3 +35,7 @@ bool remote_has_composition(uint16_t addr); uint16_t remote_get_subnet_idx(uint16_t addr); void remote_print_node(uint16_t addr); void remote_print_all(void); +void remote_foreach(remote_foreach_t each, void *user_data); +void remote_foreach_unicast(remote_foreach_t each, void *user_data); +void remote_foreach_model(remote_foreach_t each, void *user_data); +uint8_t remote_ele_cnt(uint16_t unicast); diff --git a/tools/mesh/util.c b/tools/mesh/util.c index 29641439ffc27dc1d7669b86bfdae8b63cb4e79f..310aae0c63e6bd7a729eabd3b61d7aae470b3753 100644 --- a/tools/mesh/util.c +++ b/tools/mesh/util.c @@ -20,6 +20,7 @@ #include "src/shared/util.h" #include "mesh/mesh-defs.h" +#include "mesh/prv-beacon.h" #include "tools/mesh/util.h" @@ -27,9 +28,9 @@ void set_menu_prompt(const char *name, const char *id) { char *prompt; - prompt = l_strdup_printf(COLOR_BLUE "[%s%s%s]" COLOR_OFF "# ", name, + prompt = l_strdup_printf("[%s%s%s]# ", name, id ? ": Target = " : "", id ? id : ""); - bt_shell_set_prompt(prompt); + bt_shell_set_prompt(prompt, COLOR_BLUE); l_free(prompt); } @@ -137,6 +138,10 @@ const char *sig_model_string(uint16_t sig_model_id) case 0x0001: return "Configuration Client"; case 0x0002: return "Health Server"; case 0x0003: return "Health Client"; + case 0x0004: return "Remote Provisioning Server"; + case 0x0005: return "Remote Provisioning Client"; + case 0x0008: return "Private Beacon Server"; + case 0x0009: return "Private Beacon Client"; case 0x1000: return "Generic OnOff Server"; case 0x1001: return "Generic OnOff Client"; case 0x1002: return "Generic Level Server"; diff --git a/tools/meshctl.c b/tools/meshctl.c index 38ffd35f3c9b829c5d98aa1a7d681bbd40ad43f2..00a68a3d1d574e5279f578656ac506070bc55bde 100644 --- a/tools/meshctl.c +++ b/tools/meshctl.c @@ -54,7 +54,7 @@ #define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF #define COLORED_DEL COLOR_RED "DEL" COLOR_OFF -#define PROMPT_ON COLOR_BLUE "[meshctl]" COLOR_OFF "# " +#define PROMPT_ON "[meshctl]# " #define PROMPT_OFF "Waiting to connect to bluetoothd..." #define MESH_PROV_DATA_IN_UUID_STR "00002adb-0000-1000-8000-00805f9b34fb" @@ -172,14 +172,14 @@ static void proxy_leak(gpointer data) static void connect_handler(DBusConnection *connection, void *user_data) { - bt_shell_set_prompt(PROMPT_ON); + bt_shell_set_prompt(PROMPT_ON, COLOR_BLUE); } static void disconnect_handler(DBusConnection *connection, void *user_data) { bt_shell_detach(); - bt_shell_set_prompt(PROMPT_OFF); + bt_shell_set_prompt(PROMPT_OFF, NULL); g_list_free_full(ctrl_list, proxy_leak); ctrl_list = NULL; @@ -608,7 +608,7 @@ static void set_connected_device(GDBusProxy *proxy) mesh ? buf : ""); done: - bt_shell_set_prompt(desc ? desc : PROMPT_ON); + bt_shell_set_prompt(desc ? desc : PROMPT_ON, COLOR_BLUE); g_free(desc); /* If disconnected, return to main menu */ @@ -1901,7 +1901,7 @@ int main(int argc, char *argv[]) bt_shell_init(argc, argv, &opt); bt_shell_set_menu(&main_menu); - bt_shell_set_prompt(PROMPT_OFF); + bt_shell_set_prompt(PROMPT_OFF, NULL); if (!config_dir) { char *home; diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c index a56c38173fb71a961b6637247336b1d57a84ec9d..1d5c82ae0745c2046c310dc11de49839432b4945 100644 --- a/tools/mgmt-tester.c +++ b/tools/mgmt-tester.c @@ -290,6 +290,20 @@ static void index_removed_callback(uint16_t index, uint16_t length, tester_post_teardown_complete(); } +#define MAX_COREDUMP_LINE_LEN 40 + +struct devcoredump_test_data { + enum devcoredump_state { + HCI_DEVCOREDUMP_IDLE, + HCI_DEVCOREDUMP_ACTIVE, + HCI_DEVCOREDUMP_DONE, + HCI_DEVCOREDUMP_ABORT, + HCI_DEVCOREDUMP_TIMEOUT, + } state; + unsigned int timeout; + char data[MAX_COREDUMP_LINE_LEN]; +}; + struct hci_cmd_data { uint16_t opcode; uint8_t len; @@ -362,6 +376,8 @@ struct generic_data { bool set_adv; const uint8_t *adv_data; uint8_t adv_data_len; + const struct devcoredump_test_data *dump_data; + const char (*expect_dump_data)[MAX_COREDUMP_LINE_LEN]; }; static const uint8_t set_exp_feat_param_debug[] = { @@ -1672,53 +1688,6 @@ static const struct generic_data set_sc_only_on_success_test_2 = { .expect_hci_len = sizeof(set_sc_on_write_sc_support_param), }; -static const char set_hs_on_param[] = { 0x01 }; -static const char set_hs_invalid_param[] = { 0x02 }; -static const char set_hs_garbage_param[] = { 0x01, 0x00 }; -static const char set_hs_settings_param_1[] = { 0xc0, 0x01, 0x00, 0x00 }; - -static const struct generic_data set_hs_on_success_test = { - .setup_settings = settings_ssp, - .send_opcode = MGMT_OP_SET_HS, - .send_param = set_hs_on_param, - .send_len = sizeof(set_hs_on_param), - .expect_status = MGMT_STATUS_SUCCESS, - .expect_param = set_hs_settings_param_1, - .expect_len = sizeof(set_hs_settings_param_1), - .expect_settings_set = MGMT_SETTING_HS, -}; - -static const struct generic_data set_hs_on_invalid_param_test_1 = { - .setup_settings = settings_ssp, - .send_opcode = MGMT_OP_SET_HS, - .expect_status = MGMT_STATUS_INVALID_PARAMS, -}; - -static const struct generic_data set_hs_on_invalid_param_test_2 = { - .setup_settings = settings_ssp, - .send_opcode = MGMT_OP_SET_HS, - .send_param = set_hs_invalid_param, - .send_len = sizeof(set_hs_invalid_param), - .expect_status = MGMT_STATUS_INVALID_PARAMS, -}; - -static const struct generic_data set_hs_on_invalid_param_test_3 = { - .setup_settings = settings_ssp, - .send_opcode = MGMT_OP_SET_HS, - .send_param = set_hs_garbage_param, - .send_len = sizeof(set_hs_garbage_param), - .expect_status = MGMT_STATUS_INVALID_PARAMS, -}; - -static const struct generic_data set_hs_on_invalid_index_test = { - .setup_settings = settings_ssp, - .send_index_none = true, - .send_opcode = MGMT_OP_SET_HS, - .send_param = set_hs_on_param, - .send_len = sizeof(set_hs_on_param), - .expect_status = MGMT_STATUS_INVALID_INDEX, -}; - static uint16_t settings_le[] = { MGMT_OP_SET_LE, 0 }; static const char set_le_on_param[] = { 0x01 }; @@ -1870,14 +1839,13 @@ static const char set_adv_set_local_name_param[260] = { 'T', 'e', 's', 't', ' ', 'n', 'a', 'm', 'e' }; static const uint8_t set_adv_scan_rsp_data_name_1[] = { - 0x0c, /* Scan rsp data len */ - 0x0b, /* Local name data len */ + 0x0b, /* Scan rsp data len */ + 0x0a, /* Local name data len */ 0x09, /* Complete name */ 0x54, 0x65, 0x73, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, /* "Test name" */ - 0x00, /* null */ /* padding */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const struct generic_data set_adv_on_local_name_test_1 = { @@ -1910,17 +1878,16 @@ static const struct setup_mgmt_cmd set_advertising_mgmt_cmd_arr[] = { }; static const uint8_t set_adv_scan_rsp_data_name_and_appearance[] = { - 0x10, /* scan rsp data len */ + 0x0f, /* scan rsp data len */ 0x03, /* appearance data len */ 0x19, /* eir_appearance */ 0x54, 0x65, /* appearance value */ - 0x0b, /* local name data len */ + 0x0a, /* local name data len */ 0x09, /* complete name */ 0x54, 0x65, 0x73, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, /* "test name" */ - 0x00, /* null */ /* padding */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; @@ -3200,7 +3167,7 @@ static const struct generic_data pair_device_power_off_test_1 = { .send_opcode = MGMT_OP_PAIR_DEVICE, .send_func = pair_device_send_param_func, .force_power_off = true, - .expect_status = MGMT_STATUS_NOT_POWERED, + .expect_status = MGMT_STATUS_DISCONNECTED, .expect_func = pair_device_expect_param_func, }; @@ -4666,6 +4633,16 @@ static const struct generic_data remove_device_success_6 = { .expect_status = MGMT_STATUS_SUCCESS, }; +static const struct generic_data add_remove_device_nowait = { + .setup_settings = settings_powered_le, + .expect_param = remove_device_param_2, + .expect_len = sizeof(remove_device_param_2), + .expect_status = MGMT_STATUS_SUCCESS, + .expect_alt_ev = MGMT_EV_DEVICE_REMOVED, + .expect_alt_ev_param = remove_device_param_2, + .expect_alt_ev_len = sizeof(remove_device_param_2), +}; + static const struct generic_data read_adv_features_invalid_param_test = { .send_opcode = MGMT_OP_READ_ADV_FEATURES, .send_param = dummy_data, @@ -5642,7 +5619,7 @@ static const char ext_ctrl_info1[] = { 0x00, 0x00, 0x00, 0x01, 0xaa, 0x00, /* btaddr */ 0x09, /* version */ 0xf1, 0x05, /* manufacturer */ - 0xff, 0xbf, 0x01, 0x00, /* supported settings */ + 0xff, 0xbe, 0x01, 0x00, /* supported settings */ 0x80, 0x00, 0x00, 0x00, /* current settings */ 0x09, 0x00, /* eir length */ 0x04, /* dev class length */ @@ -5682,7 +5659,7 @@ static const char ext_ctrl_info2[] = { 0x00, 0x00, 0x00, 0x01, 0xaa, 0x00, /* btaddr */ 0x09, /* version */ 0xf1, 0x05, /* manufacturer */ - 0xff, 0xbf, 0x01, 0x00, /* supported settings */ + 0xff, 0xbe, 0x01, 0x00, /* supported settings */ 0x81, 0x02, 0x00, 0x00, /* current settings */ 0x0D, 0x00, /* eir length */ 0x04, /* dev class length */ @@ -5714,7 +5691,7 @@ static const char ext_ctrl_info3[] = { 0x00, 0x00, 0x00, 0x01, 0xaa, 0x00, /* btaddr */ 0x09, /* version */ 0xf1, 0x05, /* manufacturer */ - 0xff, 0xbf, 0x01, 0x00, /* supported settings */ + 0xff, 0xbe, 0x01, 0x00, /* supported settings */ 0x80, 0x02, 0x00, 0x00, /* current settings */ 0x16, 0x00, /* eir length */ 0x04, /* dev class length */ @@ -5749,7 +5726,7 @@ static const char ext_ctrl_info4[] = { 0x00, 0x00, 0x00, 0x01, 0xaa, 0x00, /* btaddr */ 0x09, /* version */ 0xf1, 0x05, /* manufacturer */ - 0xff, 0xbf, 0x01, 0x00, /* supported settings */ + 0xff, 0xbe, 0x01, 0x00, /* supported settings */ 0x80, 0x02, 0x00, 0x00, /* current settings */ 0x1a, 0x00, /* eir length */ 0x04, /* dev class length */ @@ -5803,7 +5780,7 @@ static const char ext_ctrl_info5[] = { 0x00, 0x00, 0x00, 0x01, 0xaa, 0x00, /* btaddr */ 0x09, /* version */ 0xf1, 0x05, /* manufacturer */ - 0xff, 0xbf, 0x01, 0x00, /* supported settings */ + 0xff, 0xbe, 0x01, 0x00, /* supported settings */ 0x81, 0x02, 0x00, 0x00, /* current settings */ 0x1a, 0x00, /* eir len */ 0x04, /* dev class len */ @@ -5878,8 +5855,8 @@ static const char ext_adv_hci_params_valid[] = { static const char ext_adv_params_mgmt_rsp_valid_50[] = { 0x01, /* instance */ 0x00, /* tx_power defaults to 0 on BT5 platform*/ - 0x1f, /* max_adv_data_len */ - 0x1f, /* max_scan_rsp_len */ + 0xfb, /* max_adv_data_len */ + 0xfb, /* max_scan_rsp_len */ }; static const char ext_adv_params_mgmt_rsp_valid[] = { @@ -7699,6 +7676,23 @@ static const uint8_t add_advertising_param_scrsp_data_only_too_long[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; @@ -7752,6 +7746,29 @@ static const uint8_t add_advertising_param_scrsp_appear_data_too_long[] = { /* scan rsp data: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; @@ -7833,8 +7850,8 @@ static const uint8_t add_advertising_param_name[] = { }; static const uint8_t set_scan_rsp_data_name_fits_in_scrsp[] = { - 0x0c, /* Scan rsp data len */ - 0x0b, /* Local name data len */ + 0x0b, /* Scan rsp data len */ + 0x0a, /* Local name data len */ 0x09, /* Complete name */ 0x54, 0x65, 0x73, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, /* "Test name" */ /* padding */ @@ -7859,8 +7876,8 @@ static const struct generic_data add_advertising_name_fits_in_scrsp = { }; static const uint8_t set_scan_rsp_data_shortened_name_fits[] = { - 0x0d, /* Scan rsp data len */ - 0x0c, /* Local name data len */ + 0x0c, /* Scan rsp data len */ + 0x0b, /* Local name data len */ 0x08, /* Short name */ 0x54, 0x65, 0x73, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x31, /* "Test name1" */ @@ -7886,8 +7903,8 @@ static const struct generic_data add_advertising_shortened_name_in_scrsp = { }; static const uint8_t set_scan_rsp_data_short_name_fits[] = { - 0x07, /* Scan rsp data len */ - 0x06, /* Local name data len */ + 0x06, /* Scan rsp data len */ + 0x05, /* Local name data len */ 0x08, /* Short name */ 0x54, 0x65, 0x73, 0x74, /* "Test*/ @@ -7927,16 +7944,16 @@ static const uint8_t add_advertising_param_name_data_ok[] = { }; static const uint8_t set_scan_rsp_data_param_name_data_ok[] = { - 0x1e, /* Scan rsp data len */ + 0x1d, /* Scan rsp data len */ /* scan rsp data */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0b, /* Local name data len */ + 0x0a, /* Local name data len */ 0x09, /* Complete name */ - 0x54, 0x65, 0x73, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x00, + 0x54, 0x65, 0x73, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, /* "Test name" */ /* padding */ - 0x00, + 0x00, 0x00, }; static const struct generic_data add_advertising_name_data_ok = { @@ -7965,6 +7982,29 @@ static const uint8_t add_advertising_param_name_data_inv[] = { /* adv data: */ /* scan rsp data: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -8008,19 +8048,19 @@ static const struct setup_mgmt_cmd add_advertising_mgmt_cmd_arr[] = { }; static const uint8_t set_scan_rsp_data_name_data_appear[] = { - 0x1e, /* Scan rsp data len */ + 0x1d, /* Scan rsp data len */ 0x03, /* appearance len */ 0x19, /* EIR_APPEARANCE */ 0x54, 0x65, /* appearance value */ /* scan rsp data */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0b, /* Local name data len */ + 0x0a, /* Local name data len */ 0x09, /* Complete name */ - 0x54, 0x65, 0x73, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x00, + 0x54, 0x65, 0x73, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, /* "Test name" */ /* padding */ - 0x00, + 0x00, 0x00, }; static const struct generic_data add_advertising_name_data_appear = { @@ -8058,8 +8098,8 @@ static const struct generic_data set_appearance_success = { static const uint8_t read_adv_features_rsp_3[] = { 0xff, 0xff, 0x01, 0x00, /* supported flags */ - 0x1f, /* max_adv_data_len */ - 0x1f, /* max_scan_rsp_len */ + 0xfb, /* max_adv_data_len */ + 0xfb, /* max_scan_rsp_len */ 0x03, /* max_instances */ 0x00, /* num_instances */ }; @@ -8709,6 +8749,7 @@ static const struct hci_cmd_data multi_ext_adv_add_second_hci_cmds[] = { .len = sizeof(le_set_ext_adv_enable_inst_2), .param = le_set_ext_adv_enable_inst_2, }, + {}, }; static const struct generic_data multi_ext_advertising_add_second_2 = { @@ -8756,6 +8797,7 @@ static const struct hci_cmd_data multi_ext_adv_remove_adv_hci_cmds[] = { .len = sizeof(advertising_instance1_param), .param = advertising_instance1_param, }, + {}, }; static const struct generic_data multi_ext_advertising_remove = { @@ -8788,6 +8830,7 @@ static const struct hci_cmd_data multi_ext_adv_remove_all_adv_hci_cmds[] = { { .opcode = BT_HCI_CMD_LE_CLEAR_ADV_SETS, }, + {}, }; static const struct generic_data multi_ext_advertising_remove_all = { @@ -8824,6 +8867,7 @@ static const struct hci_cmd_data multi_ext_adv_add_2_advs_hci_cmds[] = { .len = sizeof(set_ext_adv_data_test1), .param = set_ext_adv_data_test1, }, + {}, }; static const struct generic_data multi_ext_advertising_add_no_power = { @@ -8930,11 +8974,11 @@ static const uint8_t set_ext_scan_rsp_data_name_fits_in_scrsp[] = { 0x01, /* handle */ 0x03, /* complete data */ 0x01, /* controller should not fragment */ - 0x0c, /* Scan rsp data len */ - 0x0b, /* Local name data len */ + 0x0b, /* Scan rsp data len */ + 0x0a, /* Local name data len */ 0x09, /* Complete name */ /* "Test name" */ - 0x54, 0x65, 0x73, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x00, + 0x54, 0x65, 0x73, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, }; static const struct generic_data add_ext_advertising_name_fits_in_scrsp = { @@ -8957,11 +9001,11 @@ static const uint8_t set_ext_scan_rsp_data_shortened_name_fits[] = { 0x01, /* handle */ 0x03, /* complete data */ 0x01, /* controller should not fragment */ - 0x0d, /* Scan rsp data len */ - 0x0c, /* Local name data len */ + 0x0c, /* Scan rsp data len */ + 0x0b, /* Local name data len */ 0x08, /* Short name */ /* "Test name1" */ - 0x54, 0x65, 0x73, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x31, 0x00, + 0x54, 0x65, 0x73, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x31, }; static const struct generic_data add_ext_advertising_shortened_name_in_scrsp = { @@ -8984,13 +9028,13 @@ static const uint8_t set_ext_scan_rsp_data_param_name_data_ok[] = { 0x01, /* handle */ 0x03, /* complete data */ 0x01, /* controller should not fragment */ - 0x1e, /* Scan rsp data len */ + 0x1d, /* Scan rsp data len */ /* scan rsp data */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0b, /* Local name data len */ + 0x0a, /* Local name data len */ 0x09, /* Complete name */ - 0x54, 0x65, 0x73, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x00, + 0x54, 0x65, 0x73, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, /* "Test name" */ }; @@ -9027,16 +9071,16 @@ static const uint8_t set_ext_scan_rsp_data_name_data_appear[] = { 0x01, /* handle */ 0x03, /* complete data */ 0x01, /* controller should not fragment */ - 0x1e, /* Scan rsp data len */ + 0x1d, /* Scan rsp data len */ 0x03, /* appearance len */ 0x19, /* EIR_APPEARANCE */ 0x54, 0x65, /* appearance value */ /* scan rsp data */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0b, /* Local name data len */ + 0x0a, /* Local name data len */ 0x09, /* Complete name */ - 0x54, 0x65, 0x73, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x00, + 0x54, 0x65, 0x73, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, /* "Test name" */ }; @@ -9429,7 +9473,7 @@ static const struct generic_data add_ext_advertising_conn_off_1m = { static const uint8_t get_phy_param[] = { 0xff, 0x7f, 0x00, 0x00, /* All PHYs */ 0xfe, 0x79, 0x00, 0x00, /* All PHYs except BR 1M 1SLOT, LE 1M TX & LE 1M RX */ - 0xff, 0x07, 0x00, 0x00, /* All BREDR PHYs and LE 1M TX & LE 1M RX */ + 0xff, 0x7f, 0x00, 0x00, /* All PHYs */ }; static const struct generic_data get_phy_success = { @@ -9492,26 +9536,6 @@ static const uint8_t set_phy_all_param[] = { 0xff, 0x7f, 0x00, 0x00 /* All PHYs */ }; -static const uint8_t set_default_phy_all_param[] = { - 0x00, /* preference is there for tx and rx */ - 0x07, /* 1m 2m coded tx */ - 0x07, /* 1m 2m coded rx */ -}; - -static const struct generic_data set_phy_all_success = { - .setup_settings = settings_powered_le, - .send_opcode = MGMT_OP_SET_PHY_CONFIGURATION, - .send_param = set_phy_all_param, - .send_len = sizeof(set_phy_all_param), - .expect_status = MGMT_STATUS_SUCCESS, - .expect_hci_command = BT_HCI_CMD_LE_SET_DEFAULT_PHY, - .expect_hci_param = set_default_phy_all_param, - .expect_hci_len = sizeof(set_default_phy_all_param), - .expect_alt_ev = MGMT_EV_PHY_CONFIGURATION_CHANGED, - .expect_alt_ev_param = set_phy_all_param, - .expect_alt_ev_len = sizeof(set_phy_all_param), -}; - static const uint8_t set_phy_2m_tx_param[] = { 0xff, 0x0f, 0x00, 0x00 /* 1mtxrx, 2m tx */ }; @@ -9619,13 +9643,16 @@ static const struct generic_data start_discovery_le_ext_scan_enable = { .expect_alt_ev_len = sizeof(start_discovery_le_evt), }; -static const char start_discovery_valid_ext_scan_param[] = { +static const char start_discovery_ext_scan_param[] = { 0x01, /* Own Addr type*/ 0x00, /* Scan filter policy*/ - 0x01, /*Phys - 1m */ + 0x05, /* Phys - 1m and Coded*/ 0x01, /* Type */ 0x12, 0x00, /* Interval */ 0x12, 0x00, /* Window */ + 0x01, /* Type */ + 0x36, 0x00, /* Interval */ + 0x36, 0x00, /* Window */ }; static const struct generic_data start_discovery_le_ext_scan_param = { @@ -9637,8 +9664,8 @@ static const struct generic_data start_discovery_le_ext_scan_param = { .expect_param = start_discovery_le_param, .expect_len = sizeof(start_discovery_le_param), .expect_hci_command = BT_HCI_CMD_LE_SET_EXT_SCAN_PARAMS, - .expect_hci_param = start_discovery_valid_ext_scan_param, - .expect_hci_len = sizeof(start_discovery_valid_ext_scan_param), + .expect_hci_param = start_discovery_ext_scan_param, + .expect_hci_len = sizeof(start_discovery_ext_scan_param), .expect_alt_ev = MGMT_EV_DISCOVERING, .expect_alt_ev_param = start_discovery_le_evt, .expect_alt_ev_len = sizeof(start_discovery_le_evt), @@ -9670,6 +9697,15 @@ static const struct generic_data stop_discovery_le_ext_scan_disable = { .expect_alt_ev_len = sizeof(stop_discovery_evt), }; +static const char start_discovery_2m_ext_scan_param[] = { + 0x01, /* Own Addr type*/ + 0x00, /* Scan filter policy*/ + 0x01, /* Phys - 1m and Coded*/ + 0x01, /* Type */ + 0x12, 0x00, /* Interval */ + 0x12, 0x00, /* Window */ +}; + static const struct generic_data start_discovery_le_2m_scan_param = { .setup_settings = settings_powered_le, .setup_send_opcode = MGMT_OP_SET_PHY_CONFIGURATION, @@ -9682,8 +9718,8 @@ static const struct generic_data start_discovery_le_2m_scan_param = { .expect_param = start_discovery_bredrle_param, .expect_len = sizeof(start_discovery_bredrle_param), .expect_hci_command = BT_HCI_CMD_LE_SET_EXT_SCAN_PARAMS, - .expect_hci_param = start_discovery_valid_ext_scan_param, - .expect_hci_len = sizeof(start_discovery_valid_ext_scan_param), + .expect_hci_param = start_discovery_2m_ext_scan_param, + .expect_hci_len = sizeof(start_discovery_2m_ext_scan_param), .expect_alt_ev = MGMT_EV_DISCOVERING, .expect_alt_ev_param = start_discovery_evt, .expect_alt_ev_len = sizeof(start_discovery_evt), @@ -9697,8 +9733,8 @@ static const char start_discovery_valid_coded_scan_param[] = { 0x12, 0x00, /* Interval */ 0x12, 0x00, /* Window */ 0x01, /* Type */ - 0x12, 0x00, /* Interval */ - 0x12, 0x00, /* Window */ + 0x36, 0x00, /* Interval */ + 0x36, 0x00, /* Window */ }; static const struct generic_data start_discovery_le_coded_scan_param = { @@ -9728,8 +9764,8 @@ static const char start_discovery_valid_1m_2m_coded_scan_param[] = { 0x12, 0x00, /* Interval */ 0x12, 0x00, /* Window */ 0x01, /* Type */ - 0x12, 0x00, /* Interval */ - 0x12, 0x00, /* Window */ + 0x36, 0x00, /* Interval */ + 0x36, 0x00, /* Window */ }; static const struct generic_data start_discovery_le_1m_coded_scan_param = { @@ -10297,6 +10333,7 @@ static const struct hci_cmd_data ll_privacy_add_device_3_hci_list[] = { .param = set_resolv_on_param, .len = sizeof(set_resolv_on_param), }, + {}, }; static const struct generic_data ll_privacy_add_device_3 = { @@ -10414,6 +10451,7 @@ static const struct hci_cmd_data ll_privacy_add_device_9_hci_list[] = { .len = sizeof(le_add_to_resolv_list_param), .param = le_add_to_resolv_list_param }, + {}, }; static const struct generic_data ll_privacy_add_device_9 = { @@ -10742,6 +10780,7 @@ static const struct hci_cmd_data ll_privacy_set_device_flags_1_hci_list[] = { .param = set_resolv_on_param, .len = sizeof(set_resolv_on_param), }, + {}, }; static const uint8_t device_flags_changed_params_1[] = { @@ -11452,6 +11491,41 @@ static void test_remove_device(const void *test_data) test_add_condition(data); } +static bool hook_delay_cmd(const void *data, uint16_t len, void *user_data) +{ + tester_print("Delaying emulator response..."); + g_usleep(250000); + tester_print("Delaying emulator response... Done."); + return true; +} + +static void test_add_remove_device_nowait(const void *test_data) +{ + struct test_data *data = tester_get_data(); + + /* Add and remove LE device with autoconnect without waiting for reply, + * while delaying emulator response to better hit a race condition. + * This shall not crash the kernel (but eg Linux 6.4-rc4 crashes). + */ + + tester_print("Adding and removing a device"); + + test_add_condition(data); + + hciemu_add_hook(data->hciemu, HCIEMU_HOOK_PRE_CMD, + BT_HCI_CMD_LE_ADD_TO_ACCEPT_LIST, + hook_delay_cmd, NULL); + + mgmt_send_nowait(data->mgmt, MGMT_OP_ADD_DEVICE, data->mgmt_index, + sizeof(add_device_success_param_3), + add_device_success_param_3, NULL, NULL, NULL); + + mgmt_send_nowait(data->mgmt, MGMT_OP_REMOVE_DEVICE, data->mgmt_index, + sizeof(remove_device_param_2), + remove_device_param_2, + command_generic_callback, NULL, NULL); +} + static void trigger_device_found(void *user_data) { struct test_data *data = tester_get_data(); @@ -12511,6 +12585,143 @@ static void test_suspend_resume_success_10(const void *test_data) tester_wait(2, trigger_force_resume, NULL); } +#define MAX_COREDUMP_BUF_LEN 512 + +static const struct devcoredump_test_data data_complete_dump = { + .state = HCI_DEVCOREDUMP_DONE, + .data = "test data", +}; + +static const char expected_complete_dump[][MAX_COREDUMP_LINE_LEN] = { + "Bluetooth devcoredump", + "State: 2", + "Controller Name: vhci_ctrl", + "Firmware Version: vhci_fw", + "Driver: vhci_drv", + "Vendor: vhci", + "--- Start dump ---", + "", /* end of header data */ +}; + +static const struct generic_data dump_complete = { + .dump_data = &data_complete_dump, + .expect_dump_data = expected_complete_dump, +}; + +static const struct devcoredump_test_data data_abort_dump = { + .state = HCI_DEVCOREDUMP_ABORT, + .data = "test data", +}; + +static const char expected_abort_dump[][MAX_COREDUMP_LINE_LEN] = { + "Bluetooth devcoredump", + "State: 3", + "Controller Name: vhci_ctrl", + "Firmware Version: vhci_fw", + "Driver: vhci_drv", + "Vendor: vhci", + "--- Start dump ---", + "", /* end of header data */ +}; + +static const struct generic_data dump_abort = { + .dump_data = &data_abort_dump, + .expect_dump_data = expected_abort_dump, +}; + +static const struct devcoredump_test_data data_timeout_dump = { + .state = HCI_DEVCOREDUMP_TIMEOUT, + .timeout = 1, + .data = "test data", +}; + +static const char expected_timeout_dump[][MAX_COREDUMP_LINE_LEN] = { + "Bluetooth devcoredump", + "State: 4", + "Controller Name: vhci_ctrl", + "Firmware Version: vhci_fw", + "Driver: vhci_drv", + "Vendor: vhci", + "--- Start dump ---", + "", /* end of header data */ +}; + +static const struct generic_data dump_timeout = { + .dump_data = &data_timeout_dump, + .expect_dump_data = expected_timeout_dump, +}; + +static void verify_devcd(void *user_data) +{ + struct test_data *data = tester_get_data(); + const struct generic_data *test = data->test_data; + struct vhci *vhci = hciemu_get_vhci(data->hciemu); + char buf[MAX_COREDUMP_BUF_LEN + 1] = {0}; + int read; + char delim[] = "\n"; + char *line; + char *saveptr; + int i = 0; + + /* Read the generated devcoredump file */ + read = vhci_read_devcd(vhci, buf, MAX_COREDUMP_BUF_LEN); + if (read <= 0) { + tester_warn("Unable to read devcoredump"); + tester_test_failed(); + return; + } + /* Make sure buf is nul-terminated */ + buf[read] = '\0'; + + /* Verify if all devcoredump header fields are present */ + line = strtok_r(buf, delim, &saveptr); + while (strlen(test->expect_dump_data[i])) { + if (!line || strcmp(line, test->expect_dump_data[i])) { + tester_warn("Incorrect coredump data: %s (expected %s)", + line, test->expect_dump_data[i]); + tester_test_failed(); + return; + } + + if (!strcmp(strtok(line, ":"), "State")) { + /* After updating the devcoredump state, the HCI + * devcoredump API adds a `\0` at the end. Skip it + * before reading the next line. + */ + saveptr++; + } + + line = strtok_r(NULL, delim, &saveptr); + i++; + } + + /* Verify the devcoredump data */ + if (!line || strcmp(line, test->dump_data->data)) { + tester_warn("Incorrect coredump data: %s (expected %s)", line, + test->dump_data->data); + tester_test_failed(); + return; + } + + tester_test_passed(); +} + +static void test_hci_devcd(const void *test_data) +{ + struct test_data *data = tester_get_data(); + const struct generic_data *test = data->test_data; + struct vhci *vhci = hciemu_get_vhci(data->hciemu); + + /* Triggers the devcoredump */ + if (vhci_force_devcd(vhci, test->dump_data, sizeof(*test->dump_data))) { + tester_warn("Unable to set force_devcoredump"); + tester_test_abort(); + return; + } + + tester_wait(test->dump_data->timeout + 1, verify_devcd, NULL); +} + int main(int argc, char *argv[]) { tester_init(&argc, &argv); @@ -12832,22 +13043,6 @@ int main(int argc, char *argv[]) &set_sc_only_on_success_test_2, NULL, test_command_generic); - test_hs("Set High Speed on - Success", - &set_hs_on_success_test, - NULL, test_command_generic); - test_hs("Set High Speed on - Invalid parameters 1", - &set_hs_on_invalid_param_test_1, - NULL, test_command_generic); - test_hs("Set High Speed on - Invalid parameters 2", - &set_hs_on_invalid_param_test_2, - NULL, test_command_generic); - test_hs("Set High Speed on - Invalid parameters 3", - &set_hs_on_invalid_param_test_3, - NULL, test_command_generic); - test_hs("Set High Speed on - Invalid index", - &set_hs_on_invalid_index_test, - NULL, test_command_generic); - test_bredrle("Set Low Energy on - Success 1", &set_le_on_success_test_1, NULL, test_command_generic); @@ -13399,6 +13594,10 @@ int main(int argc, char *argv[]) &remove_device_success_6, setup_add_device, test_remove_device); + test_le("Add + Remove Device Nowait - Success", + &add_remove_device_nowait, + NULL, test_add_remove_device_nowait); + test_bredrle("Read Advertising Features - Invalid parameters", &read_adv_features_invalid_param_test, NULL, test_command_generic); @@ -14018,9 +14217,6 @@ int main(int argc, char *argv[]) test_bredrle50("Set PHY coded Succcess", &set_phy_coded_success, NULL, test_command_generic); - test_bredrle50("Set PHY 1m 2m coded Succcess", &set_phy_all_success, - NULL, test_command_generic); - test_bredrle50("Set PHY 2m tx success", &set_phy_2m_tx_success, NULL, test_command_generic); @@ -14651,5 +14847,29 @@ int main(int argc, char *argv[]) setup_ll_privacy_add_device, test_command_generic); + /* HCI Devcoredump + * Setup : Power on + * Run: Trigger devcoredump via force_devcoredump + * Expect: Devcoredump is generated with correct data + */ + test_bredrle("HCI Devcoredump - Dump Complete", &dump_complete, NULL, + test_hci_devcd); + + /* HCI Devcoredump + * Setup : Power on + * Run: Trigger devcoredump via force_devcoredump + * Expect: Devcoredump is generated with correct data + */ + test_bredrle("HCI Devcoredump - Dump Abort", &dump_abort, NULL, + test_hci_devcd); + + /* HCI Devcoredump + * Setup : Power on + * Run: Trigger devcoredump via force_devcoredump + * Expect: Devcoredump is generated with correct data + */ + test_bredrle_full("HCI Devcoredump - Dump Timeout", &dump_timeout, NULL, + test_hci_devcd, 3); + return tester_run(); } diff --git a/tools/missing.h b/tools/missing.h new file mode 100644 index 0000000000000000000000000000000000000000..464df9b1c30cb280322e7c620ebbd70f04de95b4 --- /dev/null +++ b/tools/missing.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2024 Khem Raj <raj.khem@gmail.com> + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#if !HAVE_DECL_BASENAME +#include <string.h> +static inline const char *basename(const char *path) +{ + const char *base = strrchr(path, '/'); + + return base ? base + 1 : path; +} +#endif diff --git a/tools/mpris-proxy.service.in b/tools/mpris-proxy.service.in new file mode 100644 index 0000000000000000000000000000000000000000..530749094725500c31c85d550a8c3b4c72e115bb --- /dev/null +++ b/tools/mpris-proxy.service.in @@ -0,0 +1,13 @@ +[Unit] +Description=Bluetooth mpris proxy +Documentation=man:mpris-proxy(1) + +Wants=dbus.socket +After=dbus.socket + +[Service] +Type=simple +ExecStart=@PKGBINDIR@/mpris-proxy + +[Install] +WantedBy=default.target diff --git a/tools/obexctl.c b/tools/obexctl.c index 56a76915cd93222d6afa106c4c1cc7860d33e413..a398b095b9ffc27ebc4f03cd8ca03e68e01d719c 100644 --- a/tools/obexctl.c +++ b/tools/obexctl.c @@ -33,8 +33,7 @@ #define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF #define COLORED_DEL COLOR_RED "DEL" COLOR_OFF -#define PROMPT_ON COLOR_BLUE "[obex]" COLOR_OFF "# " -#define PROMPT_OFF "[obex]# " +#define PROMPT "[obex]# " #define OBEX_SESSION_INTERFACE "org.bluez.obex.Session1" #define OBEX_TRANSFER_INTERFACE "org.bluez.obex.Transfer1" @@ -64,13 +63,13 @@ struct transfer_data { static void connect_handler(DBusConnection *connection, void *user_data) { bt_shell_attach(fileno(stdin)); - bt_shell_set_prompt(PROMPT_ON); + bt_shell_set_prompt(PROMPT, COLOR_BLUE); } static void disconnect_handler(DBusConnection *connection, void *user_data) { bt_shell_detach(); - bt_shell_set_prompt(PROMPT_OFF); + bt_shell_set_prompt(PROMPT, NULL); } static char *generic_generator(const char *text, int state, GList *source) @@ -114,7 +113,7 @@ static void connect_reply(DBusMessage *message, void *user_data) struct connect_args { char *dev; char *target; - uint8_t channel; + uint16_t channel; }; static void connect_args_free(void *data) @@ -144,9 +143,14 @@ static void connect_setup(DBusMessageIter *iter, void *user_data) g_dbus_dict_append_entry(&dict, "Target", DBUS_TYPE_STRING, &args->target); - if (args->channel) - g_dbus_dict_append_entry(&dict, "Channel", + if (args->channel) { + if (args->channel > 31) + g_dbus_dict_append_entry(&dict, "PSM", + DBUS_TYPE_UINT16, &args->channel); + else + g_dbus_dict_append_entry(&dict, "Channel", DBUS_TYPE_BYTE, &args->channel); + } dbus_message_iter_close_container(iter, &dict); } @@ -169,8 +173,8 @@ static void cmd_connect(int argc, char *argv[]) char *endptr = NULL; channel = strtol(argv[3], &endptr, 0); - if (!endptr || *endptr != '\0' || channel > UINT8_MAX) { - bt_shell_printf("Invalid channel\n"); + if (!endptr || *endptr != '\0' || channel > UINT16_MAX) { + bt_shell_printf("Invalid channel or PSM\n"); return bt_shell_noninteractive_quit(EXIT_FAILURE); } } @@ -404,15 +408,15 @@ static void set_default_session(GDBusProxy *proxy) default_session = proxy; if (!g_dbus_proxy_get_property(proxy, "Destination", &iter)) { - desc = g_strdup(PROMPT_ON); + desc = g_strdup(PROMPT); goto done; } dbus_message_iter_get_basic(&iter, &desc); - desc = g_strdup_printf(COLOR_BLUE "[%s]" COLOR_OFF "# ", desc); + desc = g_strdup_printf("[%s] #", desc); done: - bt_shell_set_prompt(desc); + bt_shell_set_prompt(desc, COLOR_BLUE); g_free(desc); } @@ -1846,7 +1850,7 @@ static void cmd_mkdir(int argc, char *argv[]) static const struct bt_shell_menu main_menu = { .name = "main", .entries = { - { "connect", "<dev> [uuid] [channel]", cmd_connect, + { "connect", "<dev> [uuid] [channel|PSM]", cmd_connect, "Connect session" }, { "disconnect", "[session]", cmd_disconnect, "Disconnect session", session_generator }, @@ -2152,7 +2156,7 @@ int main(int argc, char *argv[]) bt_shell_init(argc, argv, NULL); bt_shell_set_menu(&main_menu); - bt_shell_set_prompt(PROMPT_OFF); + bt_shell_set_prompt(PROMPT, NULL); dbus_conn = g_dbus_setup_bus(DBUS_BUS_SESSION, NULL, NULL); diff --git a/tools/parse_companies.pl b/tools/parse_companies.pl deleted file mode 100755 index 9006492b4a4ad98a096c910eb6bfc00b0341cc51..0000000000000000000000000000000000000000 --- a/tools/parse_companies.pl +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/perl -# SPDX-License-Identifier: GPL-2.0-or-later - -# parse companies from -# https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers - -use strict; -# use URI::Encode qw(uri_decode); - -my %known_entities = ( - 'nbsp' => ' ', - 'aacute' => 'á', - 'eacute' => 'é', - 'iacute' => 'Ã', - 'oacute' => 'ó', - 'uacute' => 'ú', - 'auml' => 'ä', - 'uuml' => 'ü', - 'Uuml' => 'Ü', -); - -# better to use URI::Encode if you have it -sub uri_decode { - my $name = $_[0]; - foreach my $entity (keys %known_entities) { - my $to = $known_entities{$entity}; - $name =~ s/&$entity;/$to/g; - } - foreach my $entity (map { lc $_ } $name =~ /&([^;]+);/g) { - if ($entity ne 'amp') { - die "\nparse_companies.pl: Unable to convert &$entity; giving up\n"; - } - } - $name =~ s/&/&/ig; - $name =~ s/ / /ig; - return $name; -} - -# never parse HTML with regex! -# except when you should - -my $identifier; -my $next_is_name = 0; - -while (<>) { - s/\xe2\x80\x8b//g; # kill zero width space - - # grab identifier (in hex) - if (/\<td.*(0x[0-9A-F]{4})/i) { - $identifier = $1; - $next_is_name = 1; - - # next <td> should be company name - } elsif ($next_is_name && m|\<td.*\>(.*)\<|) { - my $name = uri_decode($1); - $name =~ s/^\s+//g; # kill leading - $name =~ s/\s+$//g; # and trailing space - $name =~ s/"/\\"/g; # escape double quotes - my $id = hex($identifier); - if ($id != 65535) { - print "\tcase $id:\n"; - print "\t\treturn \"$name\";\n"; - } - $next_is_name = 0; - } -} diff --git a/tools/parser/avrcp.c b/tools/parser/avrcp.c index e73a6317e5621da9c538d6b9e26171d4e9bbf338..d574c7ee3cd607b6373e665832ab07a318ea9710 100644 --- a/tools/parser/avrcp.c +++ b/tools/parser/avrcp.c @@ -160,6 +160,7 @@ #define AVRCP_MEDIA_ATTRIBUTE_TOTAL 0x5 #define AVRCP_MEDIA_ATTRIBUTE_GENRE 0x6 #define AVRCP_MEDIA_ATTRIBUTE_DURATION 0x7 +#define AVRCP_MEDIA_ATTRIBUTE_IMG_HANDLE 0x08 /* play status */ #define AVRCP_PLAY_STATUS_STOPPED 0x00 @@ -933,6 +934,8 @@ static const char *mediattr2str(uint32_t attr) return "Genre"; case AVRCP_MEDIA_ATTRIBUTE_DURATION: return "Track duration"; + case AVRCP_MEDIA_ATTRIBUTE_IMG_HANDLE: + return "Imaging handle"; default: return "Reserved"; } diff --git a/tools/rctest.1 b/tools/rctest.1 new file mode 100644 index 0000000000000000000000000000000000000000..4bfd9fa83699a0c76f0dd8807cd07dc853a75a92 --- /dev/null +++ b/tools/rctest.1 @@ -0,0 +1,126 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "RCTEST" "1" "Jul 6, 2009" "BlueZ" "Linux System Administration" +.SH NAME +rctest \- RFCOMM testing +.SH SYNOPSIS +.sp +\fBrctest\fP <\fIMODE\fP> [\fIOPTIONS\fP] [\fIbdaddr\fP] +.SH DESCRIPTION +.sp +\fBrctest(1)\fP is used to test RFCOMM communications on the BlueZ stack +.SH MODES +.INDENT 0.0 +.TP +.B \-r +listen and receive +.TP +.B \-w +listen and send +.TP +.B \-d +listen and dump incoming data +.TP +.B \-s +connect and send +.TP +.B \-u +connect and receive +.TP +.B \-n +connect and be silent +.TP +.B \-c +connect, disconnect, connect, ... +.TP +.B \-m +multiple connects +.UNINDENT +.SH OPTIONS +.INDENT 0.0 +.TP +.BI \-b \ bytes +send/receive bytes +.TP +.BI \-i \ device +select the specified device +.TP +.BI \-P \ channel +select the specified channel +.TP +.BI \-U \ uuid +select the specified uuid +.TP +.BI \-L \ seconds +enable SO_LINGER options for seconds +.TP +.BI \-W \ seconds +enable deferred setup for seconds +.TP +.BI \-B \ filename +use data packets from filename +.TP +.BI \-N \ num +send num frames +.TP +.BI \-C \ num +send num frames before delay (default: 1) +.TP +.BI \-D \ milliseconds +delay milliseconds after sending num frames (default: 0) +.TP +.B \-A +request authentication +.TP +.B \-E +request encryption +.TP +.B \-S +secure connection +.TP +.B \-M +become central +.TP +.B \-T +enable timestamps +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH AUTHOR +Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>, Filippo Giunchedi <filippo@debian.org> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/tools/rctest.c b/tools/rctest.c index d31180880ef4c9f8fac878ad94fd1e8f0ba9654e..367e41e3c7e9d0ca72dbe2ad1aea4a5f79e895a9 100644 --- a/tools/rctest.c +++ b/tools/rctest.c @@ -41,6 +41,8 @@ #define SIOCGSTAMP_OLD SIOCGSTAMP #endif +#define MAX_DATA_SIZE 0x40000000 + /* Test modes */ enum { SEND, @@ -500,7 +502,7 @@ static void recv_mode(int sk) timestamp = 0; memset(ts, 0, sizeof(ts)); } else { - sprintf(ts, "[%lld.%lld] ", + snprintf(ts, sizeof(ts), "[%lld.%lld] ", (long long)tv.tv_sec, (long long)tv.tv_usec); } @@ -554,7 +556,8 @@ static void do_send(int sk) exit(1); } len = read(fd, buf, data_size); - send(sk, buf, len, 0); + if (len > 0) + send(sk, buf, len, 0); close(fd); return; } else { @@ -739,6 +742,9 @@ int main(int argc, char *argv[]) break; case 'a': + if (!optarg) + break; + mode = AUTO; if (!strncasecmp(optarg, "hci", 3)) @@ -748,10 +754,14 @@ int main(int argc, char *argv[]) break; case 'b': - data_size = atoi(optarg); + if (optarg && atoi(optarg) < MAX_DATA_SIZE) + data_size = atoi(optarg); break; case 'i': + if (!optarg) + break; + if (!strncasecmp(optarg, "hci", 3)) hci_devba(atoi(optarg + 3), &bdaddr); else @@ -759,10 +769,14 @@ int main(int argc, char *argv[]) break; case 'P': - channel = atoi(optarg); + if (optarg) + channel = atoi(optarg); break; case 'U': + if (!optarg) + break; + if (!strcasecmp(optarg, "spp")) uuid = SERIAL_PORT_SVCLASS_ID; else if (!strncasecmp(optarg, "0x", 2)) @@ -788,11 +802,13 @@ int main(int argc, char *argv[]) break; case 'L': - linger = atoi(optarg); + if (optarg) + linger = atoi(optarg); break; case 'W': - defer_setup = atoi(optarg); + if (optarg) + defer_setup = atoi(optarg); break; case 'B': @@ -804,19 +820,23 @@ int main(int argc, char *argv[]) break; case 'N': - num_frames = atoi(optarg); + if (optarg) + num_frames = atoi(optarg); break; case 'C': - count = atoi(optarg); + if (optarg) + count = atoi(optarg); break; case 'D': - delay = atoi(optarg) * 1000; + if (optarg) + delay = atoi(optarg) * 1000; break; case 'Y': - priority = atoi(optarg); + if (optarg) + priority = atoi(optarg); break; case 'T': diff --git a/tools/rfcomm-tester.c b/tools/rfcomm-tester.c index a9adf7f0f52d11c1b7ebd0c4fa5099baaf36c683..b78b50537e4a9e75be47469a26942b946804457e 100644 --- a/tools/rfcomm-tester.c +++ b/tools/rfcomm-tester.c @@ -30,6 +30,7 @@ #include "src/shared/tester.h" #include "src/shared/mgmt.h" +#include "src/shared/util.h" struct test_data { struct mgmt *mgmt; @@ -815,9 +816,7 @@ static void test_server(const void *test_data) #define test_rfcomm(name, data, setup, func) \ do { \ struct test_data *user; \ - user = malloc(sizeof(struct test_data)); \ - if (!user) \ - break; \ + user = new0(struct test_data, 1); \ user->hciemu_type = HCIEMU_TYPE_BREDRLE52; \ user->test_data = data; \ user->io_id = 0; \ diff --git a/tools/rfcomm.1 b/tools/rfcomm.1 new file mode 100644 index 0000000000000000000000000000000000000000..9f5fe3b35bb3f2e8973e23eb212dc49358ede1f9 --- /dev/null +++ b/tools/rfcomm.1 @@ -0,0 +1,128 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "RFCOMM" "1" "April 28, 2002" "BlueZ" "Linux System Administration" +.SH NAME +rfcomm \- RFCOMM configuration utility +.SH SYNOPSIS +.sp +\fBrfcomm\fP [\fIOPTIONS\fP] <\fICOMMAND\fP> <\fIdev\fP> +.SH DESCRIPTION +.sp +\fBrfcomm(1)\fP is used to set up, maintain, and inspect the RFCOMM configuration +of the Bluetooth subsystem in the Linux kernel. If no \fBcommand\fP is given, +or if the option \fB\-a\fP is used, \fBrfcomm\fP prints information about the +configured RFCOMM devices. +.SH OPTIONS +.INDENT 0.0 +.TP +.B \-h +Gives a list of possible commands. +.TP +.B \-a +Prints information about all configured RFCOMM devices. +.TP +.B \-r +Switch TTY into raw mode (doesn\(aqt work with \(dqbind\(dq). +.UNINDENT +.INDENT 0.0 +.TP +.B \-i <\fIhciX\fP> | <\fIbdaddr\fP> +The command is applied to device \fIhciX\fP, 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. +.UNINDENT +.INDENT 0.0 +.TP +.B \-A +Enable authentication +.TP +.B \-E +Enable encryption +.TP +.B \-S +Secure connection +.TP +.B \-C +Become the central of a piconet +.TP +.BI \-L \ <seconds> +Set linger timeout +.UNINDENT +.SH COMMANDS +.INDENT 0.0 +.TP +.B show <\fIdev\fP> +Display the information about the specified device. +.TP +.B connect <\fIdev\fP> [\fIbdaddr\fP] [\fIchannel\fP] +Connect the RFCOMM device to the remote Bluetooth device on the specified +channel. If no channel is specified, it will use the channel +number \fB1\fP\&. This command can be terminated with the key sequence CTRL\-C. +.TP +.B listen <\fIdev\fP> [\fIchannel\fP] [\fIcmd\fP] +Listen on a specified RFCOMM channel for incoming connections. If no +channel is specified, it will use the channel number \fB1\fP, 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. Occurrences of {} in cmd will be +replaced by the name of the device used by the connection. This command +can be terminated with the key sequence CTRL\-C. +.TP +.B watch <\fIdev\fP> [\fIchannel\fP] [\fIcmd\fP] +Watch is identical to listen except that when the child process +terminates or the client disconnect, the command will restart listening +with the same parameters. +.TP +.B bind <\fIdev\fP> [\fIbdaddr\fP] [\fIchannel\fP] +This binds the RFCOMM device to a remote Bluetooth device. The command +does not establish a connection to the remote device, it only creates +the binding. The connection will be established right after an application +tries to open the RFCOMM device. If no channel number is specified, it +uses the channel number \fB1\fP\&. +.TP +.B release <\fIdev\fP> +This command releases a defined RFCOMM binding. +.sp +If \fBall\fP is specified for the RFCOMM device, then all bindings will be +removed. +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH AUTHOR +Marcel Holtmann <marcel@holtmann.org> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/tools/rfcomm.c b/tools/rfcomm.c index e013ff588e98a18f0bad5b5f10ac5dd3ad80b0c8..0139fe69b9eb668354a753016d3328a18fd6d8bd 100644 --- a/tools/rfcomm.c +++ b/tools/rfcomm.c @@ -212,6 +212,7 @@ static void run_cmdline(struct pollfd *p, sigset_t *sigs, char *devname, int i; pid_t pid; char **cmdargv; + struct sigaction sa; cmdargv = malloc((argc + 1) * sizeof(char *)); if (!cmdargv) @@ -225,10 +226,15 @@ static void run_cmdline(struct pollfd *p, sigset_t *sigs, char *devname, switch (pid) { case 0: + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &sa, NULL); + sigaction(SIGPIPE, &sa, NULL); + i = execvp(cmdargv[0], cmdargv); fprintf(stderr, "Couldn't execute command %s (errno=%d:%s)\n", cmdargv[0], errno, strerror(errno)); - break; + _exit(EXIT_FAILURE); case -1: fprintf(stderr, "Couldn't fork to execute command %s\n", cmdargv[0]); diff --git a/tools/sco-tester.c b/tools/sco-tester.c index 44606328a927e6ddf8468ce284d01d7d5cbc61d9..a56cb915369a1993633a19b5843e199fa940bf93 100644 --- a/tools/sco-tester.c +++ b/tools/sco-tester.c @@ -29,6 +29,9 @@ #include "src/shared/tester.h" #include "src/shared/mgmt.h" +#include "src/shared/util.h" + +#include "tester.h" struct test_data { const void *test_data; @@ -37,14 +40,24 @@ struct test_data { struct hciemu *hciemu; enum hciemu_type hciemu_type; unsigned int io_id; + unsigned int err_io_id; + int sk; bool disable_esco; bool enable_codecs; + int step; + struct tx_tstamp_data tx_ts; }; struct sco_client_data { int expect_err; const uint8_t *send_data; uint16_t data_len; + + /* Enable SO_TIMESTAMPING with these flags */ + uint32_t so_timestamping; + + /* Number of additional packets to send. */ + unsigned int repeat_send; }; static void print_debug(const char *str, void *user_data) @@ -184,6 +197,12 @@ static void read_index_list_callback(uint8_t status, uint16_t length, static void test_pre_setup(const void *test_data) { struct test_data *data = tester_get_data(); + const struct sco_client_data *scodata = test_data; + + if (scodata && scodata->so_timestamping) { + if (tester_pre_setup_skip_by_default()) + return; + } data->mgmt = mgmt_new_default(); if (!data->mgmt) { @@ -225,7 +244,10 @@ static void test_data_free(void *test_data) break; \ user->hciemu_type = HCIEMU_TYPE_BREDRLE; \ user->io_id = 0; \ + user->err_io_id = 0; \ + user->sk = -1; \ user->test_data = data; \ + user->step = 0; \ user->disable_esco = _disable_esco; \ user->enable_codecs = _enable_codecs; \ tester_add_full(name, data, \ @@ -250,6 +272,10 @@ static const struct sco_client_data connect_failure = { .expect_err = EOPNOTSUPP }; +static const struct sco_client_data connect_failure_reset = { + .expect_err = ECONNRESET +}; + const uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; static const struct sco_client_data connect_send_success = { @@ -258,6 +284,16 @@ static const struct sco_client_data connect_send_success = { .send_data = data }; +static const struct sco_client_data connect_send_tx_timestamping = { + .expect_err = 0, + .data_len = sizeof(data), + .send_data = data, + .so_timestamping = (SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_OPT_ID | + SOF_TIMESTAMPING_TX_SOFTWARE), + .repeat_send = 2, +}; + static void client_connectable_complete(uint16_t opcode, uint8_t status, const void *param, uint8_t len, void *user_data) @@ -588,6 +624,59 @@ static int connect_sco_sock(struct test_data *data, int sk) return 0; } +static gboolean recv_errqueue(GIOChannel *io, GIOCondition cond, + gpointer user_data) +{ + struct test_data *data = user_data; + const struct sco_client_data *scodata = data->test_data; + int sk = g_io_channel_unix_get_fd(io); + int err; + + data->step--; + + err = tx_tstamp_recv(&data->tx_ts, sk, scodata->data_len); + if (err > 0) + return TRUE; + else if (!err && !data->step) + tester_test_passed(); + else + tester_test_failed(); + + data->err_io_id = 0; + return FALSE; +} + +static void sco_tx_timestamping(struct test_data *data, GIOChannel *io) +{ + const struct sco_client_data *scodata = data->test_data; + int so = scodata->so_timestamping; + int sk; + int err; + unsigned int count; + + if (!(scodata->so_timestamping & SOF_TIMESTAMPING_TX_RECORD_MASK)) + return; + + sk = g_io_channel_unix_get_fd(io); + + tester_print("Enabling TX timestamping"); + + tx_tstamp_init(&data->tx_ts, scodata->so_timestamping); + + for (count = 0; count < scodata->repeat_send + 1; ++count) + data->step += tx_tstamp_expect(&data->tx_ts); + + err = setsockopt(sk, SOL_SOCKET, SO_TIMESTAMPING, &so, sizeof(so)); + if (err < 0) { + tester_warn("setsockopt SO_TIMESTAMPING: %s (%d)", + strerror(errno), errno); + tester_test_failed(); + return; + } + + data->err_io_id = g_io_add_watch(io, G_IO_ERR, recv_errqueue, data); +} + static gboolean sco_connect_cb(GIOChannel *io, GIOCondition cond, gpointer user_data) { @@ -611,11 +700,21 @@ static gboolean sco_connect_cb(GIOChannel *io, GIOCondition cond, tester_print("Successfully connected"); if (scodata->send_data) { - ssize_t ret; + ssize_t ret = 0; + unsigned int count; + + data->step = 0; + + sco_tx_timestamping(data, io); - tester_print("Writing %u bytes of data", scodata->data_len); + tester_print("Writing %u*%u bytes of data", + scodata->repeat_send + 1, scodata->data_len); - ret = write(sk, scodata->send_data, scodata->data_len); + for (count = 0; count < scodata->repeat_send + 1; ++count) { + ret = write(sk, scodata->send_data, scodata->data_len); + if (scodata->data_len != ret) + break; + } if (scodata->data_len != ret) { tester_warn("Failed to write %u bytes: %zu %s (%d)", scodata->data_len, ret, strerror(errno), @@ -626,7 +725,7 @@ static gboolean sco_connect_cb(GIOChannel *io, GIOCondition cond, if (-err != scodata->expect_err) tester_test_failed(); - else + else if (!data->step) tester_test_passed(); return FALSE; @@ -650,6 +749,8 @@ static void test_connect(const void *test_data) return; } + data->sk = sk; + io = g_io_channel_unix_new(sk); g_io_channel_set_close_on_unref(io, TRUE); @@ -745,6 +846,82 @@ static void test_connect_offload_msbc(const void *test_data) end: close(sk); } + +static bool hook_simult_disc(const void *msg, uint16_t len, void *user_data) +{ + const struct bt_hci_evt_sync_conn_complete *ev = msg; + struct test_data *data = tester_get_data(); + struct bthost *bthost; + + tester_print("Simultaneous disconnect"); + + if (len != sizeof(struct bt_hci_evt_sync_conn_complete)) { + tester_test_failed(); + return true; + } + + /* Disconnect from local and remote sides at the same time */ + bthost = hciemu_client_get_host(data->hciemu); + bthost_hci_disconnect(bthost, le16_to_cpu(ev->handle), 0x13); + + shutdown(data->sk, SHUT_RDWR); + + return true; +} + +static bool hook_delay_cmd(const void *data, uint16_t len, void *user_data) +{ + tester_print("Delaying emulator response..."); + g_usleep(250000); + tester_print("Delaying emulator response... Done."); + return true; +} + +static void test_connect_simult_disc(const void *test_data) +{ + struct test_data *data = tester_get_data(); + + /* Kernel shall not crash, but <= 6.5-rc1 crash */ + hciemu_add_hook(data->hciemu, HCIEMU_HOOK_POST_EVT, + BT_HCI_EVT_SYNC_CONN_COMPLETE, + hook_simult_disc, NULL); + hciemu_add_hook(data->hciemu, HCIEMU_HOOK_PRE_CMD, + BT_HCI_CMD_CREATE_CONN_CANCEL, + hook_delay_cmd, NULL); + + test_connect(test_data); +} + +static bool hook_acl_disc(const void *msg, uint16_t len, void *user_data) +{ + const struct bt_hci_evt_conn_complete *ev = msg; + struct test_data *data = tester_get_data(); + struct bthost *bthost; + + tester_print("Disconnect ACL"); + + bthost = hciemu_client_get_host(data->hciemu); + bthost_hci_disconnect(bthost, le16_to_cpu(ev->handle), 0x13); + + hciemu_flush_client_events(data->hciemu); + + return true; +} + +static void test_connect_acl_disc(const void *test_data) +{ + struct test_data *data = tester_get_data(); + + /* ACL disconnected before SCO is established seen. + * Kernel shall not crash, but <= 6.5-rc5 crash. + */ + hciemu_add_hook(data->hciemu, HCIEMU_HOOK_POST_EVT, + BT_HCI_EVT_CONN_COMPLETE, + hook_acl_disc, NULL); + + test_connect(test_data); +} + int main(int argc, char *argv[]) { tester_init(&argc, &argv); @@ -767,6 +944,14 @@ int main(int argc, char *argv[]) test_sco("eSCO mSBC - Success", &connect_success, setup_powered, test_connect_transp); + test_sco("eSCO Simultaneous Disconnect - Failure", + &connect_failure_reset, setup_powered, + test_connect_simult_disc); + + test_sco("eSCO ACL Disconnect - Failure", + &connect_failure_reset, setup_powered, + test_connect_acl_disc); + test_sco_11("SCO CVSD 1.1 - Success", &connect_success, setup_powered, test_connect); @@ -776,6 +961,10 @@ int main(int argc, char *argv[]) test_sco("SCO CVSD Send - Success", &connect_send_success, setup_powered, test_connect); + test_sco("SCO CVSD Send - TX Timestamping", + &connect_send_tx_timestamping, + setup_powered, test_connect); + test_offload_sco("Basic SCO Get Socket Option - Offload - Success", NULL, setup_powered, test_codecs_getsockopt); diff --git a/tools/sdptool.1 b/tools/sdptool.1 new file mode 100644 index 0000000000000000000000000000000000000000..717fbc726b4578811535c13e3acdf22e49ee7018 --- /dev/null +++ b/tools/sdptool.1 @@ -0,0 +1,122 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "SDPTOOL" "1" "" "BlueZ" "Linux System Administration" +.SH NAME +sdptool \- control and interrogate SDP servers +.SH SYNOPSIS +.sp +\fBsdptool\fP [\fIOPTIONS\fP] [\fICOMMAND\fP [\fIPARAMETERS\fP]] +.SH DESCRIPTION +.sp +\fBsdptool(1)\fP provides the interface for performing SDP queries on Bluetooth +devices, and administering a local SDP database. +.SH COMMANDS +.sp +The following commands are available. In all cases \fBbdaddr\fP specifies the +device to search or browse. If \fIlocal\fP is used for \fBbdaddr\fP, then the local +SDP database is searched. +.sp +Services are identified and manipulated with a 4\-byte \fBrecord_handle\fP (NOT +the service name). To find a service\(aqs \fBrecord_handle\fP, look for the +\(dqService RecHandle\(dq line in the \fBsearch\fP or \fBbrowse\fP results +.INDENT 0.0 +.TP +.B search [\-\-bdaddr bdaddr] [\-\-tree] [\-\-raw] [\-\-xml] service_name +Search for services.. +.sp +Known service names are \fBDID\fP, \fBSP\fP, \fBDUN\fP, \fBLAN\fP, \fBFAX\fP, +\fBOPUSH\fP, \fBFTP\fP, \fBHS\fP, \fBHF\fP, \fBHFAG\fP, \fBSAP\fP, \fBNAP\fP, \fBGN\fP, +\fBPANU\fP, \fBHCRP\fP, \fBHID\fP, \fBCIP\fP, \fBA2SRC\fP, \fBA2SNK\fP, \fBAVRCT\fP, +\fBAVRTG\fP, \fBUDIUE\fP, \fBUDITE\fP and \fBSYNCML\fP\&. +.TP +.B browse [\-\-tree] [\-\-raw] [\-\-xml] [bdaddr] +Browse all available services on the device specified by a Bluetooth +address as a parameter. +.TP +.B records [\-\-tree] [\-\-raw] [\-\-xml] bdaddr +Retrieve all possible service records. +.TP +.B add [ \-\-handle=N \-\-channel=N ] +Add a service to the local SDP database. +.sp +You can specify a handle for this record using the \fB\-\-handle\fP option. +.sp +You can specify a channel to add the service on using the \fB\-\-channel\fP +option. +.sp +NOTE: Local adapters configuration will not be updated and this command +should be used only for SDP testing. +.TP +.B del record_handle +Remove a service from the local SDP database. +.sp +NOTE: Local adapters configuration will not be updated and this command +should be used only for SDP testing. +.TP +.B get [\-\-tree] [\-\-raw] [\-\-xml] [\-\-bdaddr bdaddr] record_handle +Retrieve a service from the local SDP database. +.TP +.B setattr record_handle attrib_id attrib_value +Set or add an attribute to an SDP record. +.TP +.B setseq record_handle attrib_id attrib_values +Set or add an attribute sequence to an SDP record. +.UNINDENT +.SH OPTIONS +.INDENT 0.0 +.TP +.B \-\-help +Displays help on using sdptool. +.UNINDENT +.SH EXAMPLES +.INDENT 0.0 +.INDENT 3.5 +.sp +.EX +$ sdptool browse 00:80:98:24:15:6D +$ sdptool browse local +$ sdptool add DUN +$ sdptool del 0x10000 +.EE +.UNINDENT +.UNINDENT +.SH RESOURCES +.sp + <http://www.bluez.org> +.SH REPORTING BUGS +.sp + <linux\-bluetooth@vger.kernel.org> +.SH AUTHOR +Maxim Krasnyansky <maxk@qualcomm.com>, Edd Dumbill <ejad@debian.org> +.SH COPYRIGHT +Free use of this software is granted under ther terms of the GNU +Lesser General Public Licenses (LGPL). +.\" Generated by docutils manpage writer. +. diff --git a/tools/test-runner.c b/tools/test-runner.c index 6660ea8de9bf2688ab9ec58bd6750a1296ae6b32..f0dbb4c481bbba1b0a9271c9a0f8aa46eb6743f7 100644 --- a/tools/test-runner.c +++ b/tools/test-runner.c @@ -23,6 +23,7 @@ #include <string.h> #include <getopt.h> #include <poll.h> +#include <limits.h> #include <sys/wait.h> #include <sys/stat.h> #include <sys/types.h> @@ -54,7 +55,7 @@ static bool start_monitor = false; static int num_devs = 0; static const char *qemu_binary = NULL; static const char *kernel_image = NULL; -static bool audio_support; +static char *audio_server; static const char *qemu_table[] = { "qemu-system-x86_64", @@ -136,6 +137,24 @@ static const char *config_table[] = { NULL }; +static void enable_printk(void) +{ + FILE *f; + + f = fopen("/proc/sys/kernel/printk", "w"); + if (!f) { + perror("Failed to set printk"); + return; + } + + /* Restore printk loglevel, undoing 'quiet' in cmdline (suppress early + * on-boot messages), to show WARN_ON etc. Suppress level>=6(INFO), set + * default_msg:4(WARN) & min:1, default:7. See man 2 syslog. + */ + fprintf(f, "6 4 1 7"); + fclose(f); +} + static void prepare_sandbox(void) { int i; @@ -181,6 +200,8 @@ static void prepare_sandbox(void) "mode=0755") < 0) perror("Failed to create filesystem"); } + + enable_printk(); } static char *const qemu_argv[] = { @@ -247,21 +268,20 @@ static void start_qemu(void) snprintf(cmdline, sizeof(cmdline), "console=ttyS0,115200n8 earlyprintk=serial " - "rootfstype=9p " + "no_hash_pointers=1 rootfstype=9p " "rootflags=trans=virtio,version=9p2000.u " "acpi=off pci=noacpi noapic quiet ro init=%s " "TESTHOME=%s TESTDBUS=%u TESTDAEMON=%u " "TESTDBUSSESSION=%u XDG_RUNTIME_DIR=/run/user/0 " - "TESTAUDIO=%u " "TESTMONITOR=%u TESTEMULATOR=%u TESTDEVS=%d " - "TESTAUTO=%u TESTARGS=\'%s\'", + "TESTAUTO=%u TESTAUDIO='%s' TESTARGS=\'%s\'", initcmd, cwd, start_dbus, start_daemon, - start_dbus_session, audio_support, + start_dbus_session, start_monitor, start_emulator, num_devs, - run_auto, testargs); + run_auto, audio_server ? audio_server : "", + testargs); argv = alloca(sizeof(qemu_argv) + - (audio_support ? 4 : 0) + (sizeof(char *) * (4 + (num_devs * 4)))); memcpy(argv, qemu_argv, sizeof(qemu_argv)); @@ -274,24 +294,6 @@ static void start_qemu(void) } argv[0] = (char *) qemu_binary; - if (audio_support) { - char *xdg_runtime_dir, *audiodev; - - xdg_runtime_dir = getenv("XDG_RUNTIME_DIR"); - if (!xdg_runtime_dir) { - fprintf(stderr, "XDG_RUNTIME_DIR not set\n"); - exit(1); - } - audiodev = alloca(40 + strlen(xdg_runtime_dir)); - sprintf(audiodev, "id=audio,driver=pa,server=%s/pulse/native", - xdg_runtime_dir); - - argv[pos++] = "-audiodev"; - argv[pos++] = audiodev; - argv[pos++] = "-device"; - argv[pos++] = "AC97,audiodev=audio"; - } - argv[pos++] = "-kernel"; argv[pos++] = (char *) kernel_image; argv[pos++] = "-append"; @@ -301,10 +303,10 @@ static void start_qemu(void) const char *path = "/tmp/bt-server-bredr"; char *chrdev, *serdev; - chrdev = alloca(32 + strlen(path)); + chrdev = alloca(48 + strlen(path)); sprintf(chrdev, "socket,path=%s,id=bt%d", path, i); - serdev = alloca(32); + serdev = alloca(48); sprintf(serdev, "pci-serial,chardev=bt%d", i); argv[pos++] = "-chardev"; @@ -640,7 +642,7 @@ static const char *monitor_table[] = { static pid_t start_btmon(const char *home) { const char *monitor = NULL; - char *argv[3], *envp[2]; + char *argv[3]; pid_t pid; int i; @@ -678,7 +680,7 @@ static pid_t start_btmon(const char *home) } if (pid == 0) { - execve(argv[0], argv, envp); + execv(argv[0], argv); exit(EXIT_SUCCESS); } @@ -697,7 +699,7 @@ static const char *btvirt_table[] = { static pid_t start_btvirt(const char *home) { const char *btvirt = NULL; - char *argv[3], *envp[2]; + char *argv[3]; pid_t pid; int i; @@ -735,7 +737,7 @@ static pid_t start_btvirt(const char *home) } if (pid == 0) { - execve(argv[0], argv, envp); + execv(argv[0], argv); exit(EXIT_SUCCESS); } @@ -744,61 +746,110 @@ static pid_t start_btvirt(const char *home) return pid; } -static void trigger_udev(void) +static int create_pipewire_conf(void) { - char *argv[3], *envp[1]; - pid_t pid; + static const char *const dirs[] = { + "/run/conf", + "/run/conf/wireplumber", + "/run/conf/wireplumber/bluetooth.lua.d", + "/run/conf/wireplumber/main.lua.d", + NULL + }; + int i; + FILE *f; - argv[0] = "/bin/udevadm"; - argv[1] = "trigger"; - argv[2] = NULL; + for (i = 0; dirs[i]; ++i) + mkdir(dirs[i], 0755); - envp[0] = NULL; + /* Enable only Bluetooth part, disable whatever requires user DBus */ + f = fopen("/run/conf/wireplumber/main.lua.d/51-custom.lua", "w"); + if (!f) + goto fail; - printf("Triggering udev events\n"); + fprintf(f, "alsa_monitor.enabled = false\n" + "v4l2_monitor.enabled = false\n" + "libcamera_monitor.enabled = false\n" + "default_access.properties[\"enable-flatpak-portal\"]" + " = false\n"); + fclose(f); - pid = fork(); - if (pid < 0) { - perror("Failed to fork new process"); - return; - } + f = fopen("/run/conf/wireplumber/bluetooth.lua.d/51-custom.lua", "w"); + if (!f) + goto fail; - if (pid == 0) { - execve(argv[0], argv, envp); - exit(EXIT_SUCCESS); - } + fprintf(f, "bluez_monitor.properties[\"with-logind\"] = false\n" + "bluez_midi_monitor.enabled = false\n"); + fclose(f); - printf("udev trigger process %d created\n", pid); + return 0; + +fail: + perror("Failed to create Pipewire config"); + return -1; } -static pid_t start_udevd(void) +static int start_audio_server(pid_t pids[2]) { - char *argv[2], *envp[1]; - pid_t pid; + char *daemons[2] = {NULL, NULL}; + char wp_exe[PATH_MAX]; + char *ptr; + char *envp[5]; + int i; - argv[0] = "/lib/systemd/systemd-udevd"; - argv[1] = NULL; + for (i = 0; i < 2; ++i) + pids[i] = -1; - envp[0] = NULL; + daemons[0] = audio_server; + + ptr = strrchr(audio_server, '/'); + if (ptr && !strcmp(ptr, "/pipewire")) { + if (create_pipewire_conf()) + return -1; - printf("Starting udevd daemon\n"); + snprintf(wp_exe, sizeof(wp_exe), "%.*s/wireplumber", + (int)(ptr - audio_server), audio_server); + daemons[1] = wp_exe; - pid = fork(); - if (pid < 0) { - perror("Failed to fork new process"); - return -1; + setenv("PIPEWIRE_RUNTIME_DIR", "/run", 1); } - if (pid == 0) { - execve(argv[0], argv, envp); - exit(EXIT_SUCCESS); - } + envp[0] = "DBUS_SYSTEM_BUS_ADDRESS=unix:" + "path=/run/dbus/system_bus_socket"; + envp[1] = "XDG_CONFIG_HOME=/run/conf"; + envp[2] = "XDG_STATE_HOME=/run"; + envp[3] = "XDG_RUNTIME_DIR=/run"; + envp[4] = NULL; - printf("udevd daemon process %d created\n", pid); + for (i = 0; i < 2; ++i) { + const char *daemon = daemons[i]; + char *argv[2]; + pid_t pid; - trigger_udev(); + if (!daemon) + continue; - return pid; + printf("Starting audio server %s\n", daemon); + + argv[0] = (char *) daemon; + argv[1] = NULL; + + pid = fork(); + if (pid < 0) { + perror("Failed to fork new process"); + return -1; + } + + if (pid == 0) { + execve(argv[0], argv, envp); + exit(EXIT_SUCCESS); + } + + pids[i] = pid; + + printf("Audio server process %d created\n", pid); + } + + return 0; } static void run_command(char *cmdname, char *home) @@ -807,7 +858,8 @@ static void run_command(char *cmdname, char *home) int pos = 0, idx = 0; int serial_fd; pid_t pid, dbus_pid, daemon_pid, monitor_pid, emulator_pid, - dbus_session_pid, udevd_pid; + dbus_session_pid, audio_pid[2]; + int i; if (!home) { perror("Invalid parameter: TESTHOME"); @@ -828,11 +880,6 @@ static void run_command(char *cmdname, char *home) } else serial_fd = -1; - if (audio_support) - udevd_pid = start_udevd(); - else - udevd_pid = -1; - if (start_dbus) { create_dbus_system_conf(); dbus_pid = start_dbus_daemon(false); @@ -860,7 +907,17 @@ static void run_command(char *cmdname, char *home) else emulator_pid = -1; + if (audio_server) + start_audio_server(audio_pid); + else + audio_pid[0] = audio_pid[1] = -1; + start_next: + if (!run_auto && !cmdname) { + fprintf(stderr, "Missing command argument\n"); + return; + } + if (run_auto) { if (chdir(home + 5) < 0) { perror("Failed to change home test directory"); @@ -896,6 +953,8 @@ start_next: pid = fork(); if (pid < 0) { perror("Failed to fork new process"); + if (serial_fd >= 0) + close(serial_fd); return; } @@ -961,9 +1020,11 @@ start_next: monitor_pid = -1; } - if (corpse == udevd_pid) { - printf("udevd terminated\n"); - udevd_pid = -1; + for (i = 0; i < 2; ++i) { + if (corpse == audio_pid[i]) { + printf("Audio server %d terminated\n", i); + audio_pid[i] = -1; + } } if (corpse == pid) @@ -975,6 +1036,11 @@ start_next: goto start_next; } + for (i = 0; i < 2; ++i) { + if (audio_pid[i] > 0) + kill(audio_pid[i], SIGTERM); + } + if (daemon_pid > 0) kill(daemon_pid, SIGTERM); @@ -990,9 +1056,6 @@ start_next: if (monitor_pid > 0) kill(monitor_pid, SIGTERM); - if (udevd_pid > 0) - kill(udevd_pid, SIGTERM); - if (serial_fd >= 0) close(serial_fd); } @@ -1073,10 +1136,15 @@ static void run_tests(void) start_emulator = true; } - ptr = strstr(cmdline, "TESTAUDIO=1"); + ptr = strstr(cmdline, "TESTAUDIO='"); if (ptr) { - printf("Audio support requested\n"); - audio_support = true; + const char *start = ptr + 11; + const char *end = strchr(start, '\''); + + if (end && end != start) { + audio_server = strndup(start, end - start); + printf("Audio server %s requested\n", audio_server); + } } ptr = strstr(cmdline, "TESTHOME="); @@ -1102,10 +1170,10 @@ static void usage(void) "\t-d, --daemon Start bluetoothd\n" "\t-m, --monitor Start btmon\n" "\t-l, --emulator Start btvirt\n" + "\t-A, --audio[=path] Start audio server\n" "\t-u, --unix [path] Provide serial device\n" "\t-q, --qemu <path> QEMU binary\n" "\t-k, --kernel <image> Kernel image (bzImage)\n" - "\t-A, --audio Add audio support\n" "\t-h, --help Show help options\n"); } @@ -1120,7 +1188,7 @@ static const struct option main_options[] = { { "monitor", no_argument, NULL, 'm' }, { "qemu", required_argument, NULL, 'q' }, { "kernel", required_argument, NULL, 'k' }, - { "audio", no_argument, NULL, 'A' }, + { "audio", optional_argument, NULL, 'A' }, { "version", no_argument, NULL, 'v' }, { "help", no_argument, NULL, 'h' }, { } @@ -1140,7 +1208,7 @@ int main(int argc, char *argv[]) for (;;) { int opt; - opt = getopt_long(argc, argv, "aubdslmq:k:Avh", main_options, + opt = getopt_long(argc, argv, "aubdslmq:k:A::vh", main_options, NULL); if (opt < 0) break; @@ -1175,7 +1243,7 @@ int main(int argc, char *argv[]) kernel_image = optarg; break; case 'A': - audio_support = true; + audio_server = optarg ? optarg : "/usr/bin/pipewire"; break; case 'v': printf("%s\n", VERSION); diff --git a/tools/tester.h b/tools/tester.h new file mode 100644 index 0000000000000000000000000000000000000000..b6de084a4e6a259475e29ba47b607434fa4eb867 --- /dev/null +++ b/tools/tester.h @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2022 Intel Corporation. + * + */ + +#include <stdbool.h> +#include <stdlib.h> +#include <stdint.h> +#include <time.h> +#include <sys/socket.h> +#include <linux/errqueue.h> +#include <linux/net_tstamp.h> + +#include <glib.h> + +#define SEC_NSEC(_t) ((_t) * 1000000000LL) +#define TS_NSEC(_ts) (SEC_NSEC((_ts)->tv_sec) + (_ts)->tv_nsec) + +struct tx_tstamp_data { + struct { + uint32_t id; + uint32_t type; + } expect[16]; + unsigned int pos; + unsigned int count; + unsigned int sent; + uint32_t so_timestamping; +}; + +static inline void tx_tstamp_init(struct tx_tstamp_data *data, + uint32_t so_timestamping) +{ + memset(data, 0, sizeof(*data)); + memset(data->expect, 0xff, sizeof(data->expect)); + + data->so_timestamping = so_timestamping; +} + +static inline int tx_tstamp_expect(struct tx_tstamp_data *data) +{ + unsigned int pos = data->count; + int steps; + + if (data->so_timestamping & SOF_TIMESTAMPING_TX_SCHED) { + g_assert(pos < ARRAY_SIZE(data->expect)); + data->expect[pos].type = SCM_TSTAMP_SCHED; + data->expect[pos].id = data->sent; + pos++; + } + + if (data->so_timestamping & SOF_TIMESTAMPING_TX_SOFTWARE) { + g_assert(pos < ARRAY_SIZE(data->expect)); + data->expect[pos].type = SCM_TSTAMP_SND; + data->expect[pos].id = data->sent; + pos++; + } + + data->sent++; + + steps = pos - data->count; + data->count = pos; + return steps; +} + +static inline int tx_tstamp_recv(struct tx_tstamp_data *data, int sk, int len) +{ + unsigned char control[512]; + ssize_t ret; + char buf[1024]; + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsg; + struct scm_timestamping *tss = NULL; + struct sock_extended_err *serr = NULL; + struct timespec now; + + iov.iov_base = buf; + iov.iov_len = sizeof(buf); + + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = control; + msg.msg_controllen = sizeof(control); + + ret = recvmsg(sk, &msg, MSG_ERRQUEUE); + if (ret < 0) { + if (ret == EAGAIN || ret == EWOULDBLOCK) + return data->count - data->pos; + + tester_warn("Failed to read from errqueue: %s (%d)", + strerror(errno), errno); + return -EINVAL; + } + + if (data->so_timestamping & SOF_TIMESTAMPING_OPT_TSONLY) { + if (ret != 0) { + tester_warn("Packet copied back to errqueue"); + return -EINVAL; + } + } else if (len > ret) { + tester_warn("Packet not copied back to errqueue: %zd", ret); + return -EINVAL; + } + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_TIMESTAMPING) { + tss = (void *)CMSG_DATA(cmsg); + } else if (cmsg->cmsg_level == SOL_BLUETOOTH && + cmsg->cmsg_type == BT_SCM_ERROR) { + serr = (void *)CMSG_DATA(cmsg); + } + } + + if (!tss) { + tester_warn("SCM_TIMESTAMPING not found"); + return -EINVAL; + } + + if (!serr) { + tester_warn("BT_SCM_ERROR not found"); + return -EINVAL; + } + + if (serr->ee_errno != ENOMSG || + serr->ee_origin != SO_EE_ORIGIN_TIMESTAMPING) { + tester_warn("BT_SCM_ERROR wrong for timestamping"); + return -EINVAL; + } + + clock_gettime(CLOCK_REALTIME, &now); + + if (TS_NSEC(&now) < TS_NSEC(tss->ts) || + TS_NSEC(&now) > TS_NSEC(tss->ts) + SEC_NSEC(10)) { + tester_warn("nonsense in timestamp"); + return -EINVAL; + } + + if (data->pos >= data->count) { + tester_warn("Too many timestamps"); + return -EINVAL; + } + + if ((data->so_timestamping & SOF_TIMESTAMPING_OPT_ID) && + serr->ee_data != data->expect[data->pos].id) { + tester_warn("Bad timestamp id %u", serr->ee_data); + return -EINVAL; + } + + if (serr->ee_info != data->expect[data->pos].type) { + tester_warn("Bad timestamp type %u", serr->ee_info); + return -EINVAL; + } + + tester_print("Got valid TX timestamp %u", data->pos); + + ++data->pos; + + return data->count - data->pos; +} diff --git a/tools/update_compids.sh b/tools/update_compids.sh deleted file mode 100755 index 606d6cf9c485446a9bb5175828e0bcfb4f08ab3c..0000000000000000000000000000000000000000 --- a/tools/update_compids.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: GPL-2.0-or-later -# Download the list of company IDs from bluetooth.org and generate a diff which -# can be applied to source tree to update bt_compidtostr(). Usage: -# -# 1) ./tools/update_compids.sh | git apply -p0 -# 2) Inspect changes to make sure they are sane -# 3) git commit -m "lib: Update list of company identifiers" lib/bluetooth.c -# -# Requires html2text: http://www.mbayer.de/html2text/ -# -set -e -u - -tmpdir=$(mktemp -d) -trap "rm -rf $tmpdir" EXIT - -scriptdir=$(pwd) - -mkdir $tmpdir/lib -cp lib/bluetooth.c $tmpdir/lib/bluetooth.c.orig -cp lib/bluetooth.c $tmpdir/lib/bluetooth.c - -cd $tmpdir - -echo -e 'const char *bt_compidtostr(int compid)\n{\n\tswitch (compid) {' > new.c - -path=specifications/assigned-numbers/company-identifiers/ -# Use "iconv -c" to strip unwanted unicode characters -curl --insecure https://www.bluetooth.com/$path | \ - $scriptdir/tools/parse_companies.pl >> new.c - -if ! grep -q "return \"" new.c; then - echo "ERROR: could not parse company IDs from bluetooth.org" >&2 - exit 1 -fi -echo -e '\tcase 65535:\n\t\treturn "internal use";' >> new.c -echo -e '\tdefault:\n\t\treturn "not assigned";\n\t}\n}' >> new.c - -sed -n '/^const char \*bt_compidtostr(int compid)/,/^}/p' \ - lib/bluetooth.c > old.c - -diff -Naur old.c new.c | patch -sp0 lib/bluetooth.c -diff -Naur lib/bluetooth.c.orig lib/bluetooth.c diff --git a/tools/valgrind.supp b/tools/valgrind.supp deleted file mode 100644 index d264657012a6aeef631269aac728629f6ca1dc0c..0000000000000000000000000000000000000000 --- a/tools/valgrind.supp +++ /dev/null @@ -1,34 +0,0 @@ -{ - ecb_bind - Memcheck:Param - socketcall.bind(my_addr.sa_data) - fun:bind - fun:ecb_aes_setup -} -{ - cmac_bind - Memcheck:Param - socketcall.bind(my_addr.sa_data) - fun:bind - fun:cmac_aes_setup -} -{ - logging_open - Memcheck:Param - socketcall.bind(my_addr.rc_bdaddr) - fun:bind - fun:logging_open -} -{ - bind - Memcheck:Param - socketcall.bind(my_addr.rc_channel) - fun:bind -} -{ - bt_log_open - Memcheck:Param - socketcall.bind(my_addr.rc_bdaddr) - fun:bind - fun:bt_log_open -} diff --git a/unit/test-bap.c b/unit/test-bap.c new file mode 100644 index 0000000000000000000000000000000000000000..0c190d7fe15a45576002240aee0f33969b5edf3c --- /dev/null +++ b/unit/test-bap.c @@ -0,0 +1,7380 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2022 Intel Corporation. + * Copyright 2024 NXP + * + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <unistd.h> +#include <string.h> +#include <sys/socket.h> +#include <fcntl.h> + +#include <glib.h> + +#include "lib/bluetooth.h" +#include "lib/uuid.h" +#include "src/shared/util.h" +#include "src/shared/io.h" +#include "src/shared/tester.h" +#include "src/shared/queue.h" +#include "src/shared/att.h" +#include "src/shared/gatt-db.h" +#include "src/shared/gatt-client.h" +#include "src/shared/bap.h" +#include "src/shared/lc3.h" + +struct test_config { + struct bt_bap_pac_qos pqos; + struct iovec cc; + struct iovec base; + struct bt_bap_qos qos; + bool snk; + bool src; + bool vs; + uint8_t state; + bt_bap_state_func_t state_func; + uint8_t streams; +}; + +struct test_data { + struct bt_gatt_client *client; + struct gatt_db *db; + struct bt_bap *bap; + struct bt_bap_pac *snk; + struct bt_bap_pac *src; + struct bt_bap_pac *bsrc; + struct bt_bap_pac *bsnk; + struct iovec *base; + struct iovec *caps; + struct test_config *cfg; + struct queue *streams; + size_t iovcnt; + struct iovec *iov; +}; + +/* + * Frequencies: 8Khz 11Khz 16Khz 22Khz 24Khz 32Khz 44.1Khz 48Khz + * Duration: 7.5 ms 10 ms + * Channel count: 3 + * Frame length: 26-240 + */ +static struct iovec lc3_caps = LC3_CAPABILITIES(LC3_FREQ_ANY, LC3_DURATION_ANY, + 3u, 26, 240); + +#define iov_data(args...) ((const struct iovec[]) { args }) + +#define define_test(name, setup, function, _cfg, args...) \ + do { \ + const struct iovec iov[] = { args }; \ + static struct test_data data; \ + data.caps = &lc3_caps; \ + data.cfg = _cfg; \ + data.iovcnt = ARRAY_SIZE(iov_data(args)); \ + data.iov = util_iov_dup(iov, ARRAY_SIZE(iov_data(args))); \ + data.streams = queue_new(); \ + tester_add(name, &data, setup, function, \ + test_teardown); \ + } while (0) + +static void client_ready_cb(bool success, uint8_t att_ecode, void *user_data) +{ + if (!success) + tester_setup_failed(); + else + tester_setup_complete(); +} + +/* GATT Discover All procedure */ +static const struct iovec setup_data[] = { + /* ATT: Exchange MTU Response (0x03) len 2 + * Server RX MTU: 64 + */ + IOV_DATA(0x02, 0x40, 0x00), + /* ATT: Exchange MTU Request (0x02) len 2 + * Client RX MTU: 64 + */ + IOV_DATA(0x03, 0x40, 0x00), + /* ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0001-0xffff + * Attribute type: Server Supported Features (0x2b3a) + */ + IOV_DATA(0x08, 0x01, 0x00, 0xff, 0xff, 0x3a, 0x2b), + /* ATT: Error Response (0x01) len 4 + * Read By Type Request (0x08) + * Handle: 0x0001 + * Error: Attribute Not Found (0x0a) + */ + IOV_DATA(0x01, 0x08, 0x01, 0x00, 0x0a), + /* + * ATT: Read By Group Type Request (0x10) len 6 + * Handle range: 0x0001-0xffff + * Attribute group type: Primary Service (0x2800) + */ + IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28), + /* + * ATT: Read By Group Type Response (0x11) len 37 + * Attribute data length: 6 + * Attribute group list: 2 entries + * Handle range: 0x0001-0x0013 + * UUID: Published Audio Capabilities (0x1850) + * Handle range: 0x0014-0x0023 + * UUID: Audio Stream Control (0x184e) + */ + IOV_DATA(0x11, 0x06, + 0x01, 0x00, 0x13, 0x00, 0x50, 0x18, + 0x14, 0x00, 0x23, 0x00, 0x4e, 0x18), + /* ATT: Read By Group Type Request (0x10) len 6 + * Handle range: 0x0024-0xffff + * Attribute group type: Primary Service (0x2800) + */ + IOV_DATA(0x10, 0x24, 0x00, 0xff, 0xff, 0x00, 0x28), + /* ATT: Error Response (0x01) len 4 + * Read By Group Type Request (0x10) + * Handle: 0x0024 + * Error: Attribute Not Found (0x0a) + */ + IOV_DATA(0x01, 0x10, 0x24, 0x00, 0x0a), + /* ATT: Read By Group Type Request (0x10) len 6 + * Handle range: 0x0001-0xffff + * Attribute group type: Secondary Service (0x2801) + */ + IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28), + /* ATT: Error Response (0x01) len 4 + * Read By Group Type Request (0x10) + * Handle: 0x0001 + * Error: Attribute Not Found (0x0a) + */ + IOV_DATA(0x01, 0x10, 0x01, 0x00, 0x0a), + /* ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0001-0x0023 + * Attribute group type: Include (0x2802) + */ + IOV_DATA(0x08, 0x01, 0x00, 0x23, 0x00, 0x02, 0x28), + /* ATT: Error Response (0x01) len 4 + * Read By Group Type Request (0x10) + * Handle: 0x0001 + * Error: Attribute Not Found (0x0a) + */ + IOV_DATA(0x01, 0x08, 0x01, 0x00, 0x0a), + /* ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0001-0x0023 + * Attribute type: Characteristic (0x2803) + */ + IOV_DATA(0x08, 0x01, 0x00, 0x23, 0x00, 0x03, 0x28), + /* ATT: Read By Type Response (0x09) len 57 + * Attribute data length: 7 + * Attribute data list: 8 entries + * Handle: 0x0002 + * Value: 120300c92b + * Properties: 0x12 + * Read (0x02) + * Notify (0x10) + * Value Handle: 0x0003 + * Value UUID: Sink PAC (0x2bc9) + * Handle: 0x0005 + * Value: 120600ca2b + * Properties: 0x12 + * Read (0x02) + * Notify (0x10) + * Value Handle: 0x0006 + * Value UUID: Sink Audio Locations (0x2bca) + * Handle: 0x0008 + * Value: 120900cb2b + * Properties: 0x12 + * Read (0x02) + * Notify (0x10) + * Value Handle: 0x0009 + * Value UUID: Source PAC (0x2bcb) + * Handle: 0x000b + * Value: 120c00cc2b + * Properties: 0x12 + * Read (0x02) + * Notify (0x10) + * Value Handle: 0x000c + * Value UUID: Source Audio Locations (0x2bcc) + * Handle: 0x000e + * Value: 120f00cd2b + * Properties: 0x12 + * Read (0x02) + * Notify (0x10) + * Value Handle: 0x000f + * Value UUID: Available Audio Contexts (0x2bcd) + * Handle: 0x0011 + * Value: 121200ce2b + * Properties: 0x12 + * Read (0x02) + * Notify (0x10) + * Value Handle: 0x0012 + * Value UUID: Supported Audio Contexts (0x2bce) + * Handle: 0x0015 + * Value: 121600c42b + * Properties: 0x12 + * Read (0x02) + * Notify (0x10) + * Value Handle: 0x0016 + * Value UUID: Sink ASE (0x2bc4) + * Handle: 0x0018 + * Value: 121900c42b + * Properties: 0x12 + * Read (0x02) + * Notify (0x10) + * Value Handle: 0x0019 + * Value UUID: Sink ASE (0x2bc4) + */ + IOV_DATA(0x09, 0x07, + 0x02, 0x00, 0x12, 0x03, 0x00, 0xc9, 0x2b, + 0x05, 0x00, 0x12, 0x06, 0x00, 0xca, 0x2b, + 0x08, 0x00, 0x12, 0x09, 0x00, 0xcb, 0x2b, + 0x0b, 0x00, 0x12, 0x0c, 0x00, 0xcc, 0x2b, + 0x0e, 0x00, 0x12, 0x0f, 0x00, 0xcd, 0x2b, + 0x11, 0x00, 0x12, 0x12, 0x00, 0xce, 0x2b, + 0x15, 0x00, 0x12, 0x16, 0x00, 0xc4, 0x2b, + 0x18, 0x00, 0x12, 0x19, 0x00, 0xc4, 0x2b), + /* ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0001-0x0023 + * Attribute type: Characteristic (0x2803) + */ + IOV_DATA(0x08, 0x19, 0x00, 0x23, 0x00, 0x03, 0x28), + /* ATT: Read By Type Response (0x09) len 22 + * Attribute data length: 7 + * Attribute data list: 3 entries + * Handle: 0x001b + * Value: 121c00c52b + * Properties: 0x12 + * Read (0x02) + * Notify (0x10) + * Value Handle: 0x001c + * Value UUID: Source ASE (0x2bc5) + * Handle: 0x001e + * Value: 121f00c52b + * Properties: 0x12 + * Read (0x02) + * Notify (0x10) + * Value Handle: 0x001f + * Value UUID: Source ASE (0x2bc5) + * Handle: 0x0021 + * Value: 182200c62b + * Properties: 0x18 + * Write (0x08) + * Notify (0x10) + * Value Handle: 0x0022 + * Value UUID: ASE Control Point (0x2bc6) + */ + IOV_DATA(0x09, 0x07, + 0x1b, 0x00, 0x12, 0x1c, 0x00, 0xc5, 0x2b, + 0x1e, 0x00, 0x12, 0x1f, 0x00, 0xc5, 0x2b, + 0x21, 0x00, 0x18, 0x22, 0x00, 0xc6, 0x2b), + /* ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0022-0x0023 + * Attribute type: Characteristic (0x2803) + */ + IOV_DATA(0x08, 0x22, 0x00, 0x23, 0x00, 0x03, 0x28), + /* ATT: Error Response (0x01) len 4 + * Read By Type Request (0x08) + * Handle: 0x0022 + * Error: Attribute Not Found (0x0a) + */ + IOV_DATA(0x01, 0x08, 0x23, 0x00, 0x0a), + /* ACL Data TX: Handle 42 flags 0x00 dlen 11 + * ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0001-0xffff + * Attribute type: Database Hash (0x2b2a) + */ + IOV_DATA(0x08, 0x01, 0x00, 0xff, 0xff, 0x2a, 0x2b), + /* ATT: Error Response (0x01) len 4 + * Read By Type Request (0x08) + * Handle: 0x0001 + * Error: Attribute Not Found (0x0a) + */ + IOV_DATA(0x01, 0x08, 0x01, 0x00, 0x0a), +}; + +static void print_debug(const char *str, void *user_data) +{ + const char *prefix = user_data; + + if (tester_use_debug()) + tester_debug("%s%s", prefix, str); +} + +static void test_setup(const void *user_data) +{ + struct test_data *data = (void *)user_data; + struct bt_att *att; + struct gatt_db *db; + struct io *io; + + io = tester_setup_io(setup_data, ARRAY_SIZE(setup_data)); + g_assert(io); + + att = bt_att_new(io_get_fd(io), false); + g_assert(att); + + bt_att_set_debug(att, BT_ATT_DEBUG, print_debug, "bt_att:", NULL); + + db = gatt_db_new(); + g_assert(db); + + data->client = bt_gatt_client_new(db, att, 64, 0); + g_assert(data->client); + + bt_gatt_client_set_debug(data->client, print_debug, "bt_gatt_client:", + NULL); + + bt_gatt_client_ready_register(data->client, client_ready_cb, data, + NULL); + + bt_att_unref(att); + gatt_db_unref(db); +} + +static void test_complete_cb(const void *user_data) +{ + tester_test_passed(); +} + +static void bap_disable(struct bt_bap_stream *stream, + uint8_t code, uint8_t reason, + void *user_data) +{ + if (code) + tester_test_failed(); +} + +static void bap_start(struct bt_bap_stream *stream, + uint8_t code, uint8_t reason, + void *user_data) +{ + if (code) + tester_test_failed(); +} + +static void bap_enable(struct bt_bap_stream *stream, + uint8_t code, uint8_t reason, + void *user_data) +{ + struct test_data *data = user_data; + unsigned int id = 0; + + if (code) { + tester_test_failed(); + return; + } + + switch (data->cfg->state) { + case BT_BAP_STREAM_STATE_ENABLING: + return; + case BT_BAP_STREAM_STATE_DISABLING: + id = bt_bap_stream_disable(stream, true, bap_disable, + data); + break; + case BT_BAP_STREAM_STATE_STREAMING: + if (data->cfg->snk) + return; + id = bt_bap_stream_start(stream, bap_start, data); + break; + } + + g_assert(id); +} + +static void bap_qos(struct bt_bap_stream *stream, + uint8_t code, uint8_t reason, + void *user_data) +{ + struct test_data *data = user_data; + + if (code) { + tester_test_failed(); + return; + } + + if (data->cfg->state > BT_BAP_STREAM_STATE_QOS) { + unsigned int qos_id; + + qos_id = bt_bap_stream_enable(stream, true, NULL, + bap_enable, data); + g_assert(qos_id); + } +} + +static void bap_config(struct bt_bap_stream *stream, + uint8_t code, uint8_t reason, + void *user_data) +{ + struct test_data *data = user_data; + + if (code) { + tester_test_failed(); + return; + } + + if (data->cfg->state > BT_BAP_STREAM_STATE_CONFIG) { + unsigned int qos_id; + + qos_id = bt_bap_stream_qos(stream, &data->cfg->qos, + bap_qos, data); + g_assert(qos_id); + } +} + +static bool pac_found(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac, + void *user_data) +{ + struct test_data *data = user_data; + unsigned int config_id; + struct bt_bap_stream *stream; + + stream = bt_bap_stream_new(data->bap, lpac, rpac, + &data->cfg->qos, + &data->cfg->cc); + g_assert(stream); + + queue_push_tail(data->streams, stream); + + config_id = bt_bap_stream_config(stream, &data->cfg->qos, + &data->cfg->cc, bap_config, data); + g_assert(config_id); + + return true; +} + +static void bap_ready(struct bt_bap *bap, void *user_data) +{ + bt_bap_foreach_pac(bap, BT_BAP_SINK, pac_found, user_data); + bt_bap_foreach_pac(bap, BT_BAP_SOURCE, pac_found, user_data); +} + +static void test_client_config(struct test_data *data) +{ + if (!data->cfg) + return; + + if (data->cfg->src) { + if (data->cfg->vs) + data->snk = bt_bap_add_vendor_pac(data->db, + "test-bap-snk", + BT_BAP_SINK, 0x0ff, + 0x0001, 0x0001, + NULL, data->caps, NULL); + else + data->snk = bt_bap_add_pac(data->db, "test-bap-snk", + BT_BAP_SINK, LC3_ID, + NULL, data->caps, NULL); + g_assert(data->snk); + } + + if (data->cfg->snk) { + if (data->cfg->vs) + data->src = bt_bap_add_vendor_pac(data->db, + "test-bap-src", + BT_BAP_SOURCE, 0x0ff, + 0x0001, 0x0001, + NULL, data->caps, NULL); + else + data->src = bt_bap_add_pac(data->db, "test-bap-src", + BT_BAP_SOURCE, LC3_ID, + NULL, data->caps, NULL); + g_assert(data->src); + } +} + +static void test_client(const void *user_data) +{ + struct test_data *data = (void *)user_data; + struct io *io; + + io = tester_setup_io(data->iov, data->iovcnt); + g_assert(io); + + tester_io_set_complete_func(test_complete_cb); + + data->db = gatt_db_new(); + g_assert(data->db); + + test_client_config(data); + + data->bap = bt_bap_new(data->db, bt_gatt_client_get_db(data->client)); + g_assert(data->bap); + + bt_bap_set_debug(data->bap, print_debug, "bt_bap:", NULL); + + bt_bap_ready_register(data->bap, bap_ready, data, NULL); + + if (data->cfg && data->cfg->state_func) + bt_bap_state_register(data->bap, data->cfg->state_func, NULL, + data, NULL); + + bt_bap_attach(data->bap, data->client); +} + +static int pac_config(struct bt_bap_stream *stream, struct iovec *cfg, + struct bt_bap_qos *qos, bt_bap_pac_config_t cb, + void *user_data) +{ + cb(stream, 0); + + return 0; +} + +static struct bt_bap_pac_ops bcast_pac_ops = { + .config = pac_config, +}; + +static void bsrc_pac_added(struct bt_bap_pac *pac, void *user_data) +{ + struct test_data *data = user_data; + struct bt_bap_stream *stream; + + bt_bap_pac_set_ops(pac, &bcast_pac_ops, NULL); + + for (uint8_t i = 0; i < data->cfg->streams; i++) { + stream = bt_bap_stream_new(data->bap, pac, NULL, + &data->cfg->qos, + &data->cfg->cc); + g_assert(stream); + + queue_push_tail(data->streams, stream); + + bt_bap_stream_config(stream, &data->cfg->qos, + &data->cfg->cc, NULL, data); + } +} + +static void bsrc_state_cfg(struct bt_bap_stream *stream, uint8_t old_state, + uint8_t new_state, void *user_data) +{ + struct test_data *data = user_data; + + switch (new_state) { + case BT_BAP_STREAM_STATE_CONFIG: + data->base = bt_bap_stream_get_base(stream); + + g_assert(data->base); + g_assert(data->base->iov_len == data->cfg->base.iov_len); + g_assert(memcmp(data->base->iov_base, data->cfg->base.iov_base, + data->base->iov_len) == 0); + + tester_test_passed(); + break; + } +} + +static void bsnk_pac_added(struct bt_bap_pac *pac, void *user_data) +{ + struct test_data *data = user_data; + struct bt_bap_pac *lpac; + struct iovec *cc; + struct bt_bap_stream *stream; + uint8_t bis_idx = 1; + + bt_bap_pac_set_ops(pac, &bcast_pac_ops, NULL); + + for (uint8_t i = 0; i < data->cfg->streams; i++) { + cc = bt_bap_merge_caps(&data->cfg->cc, NULL); + g_assert(cc); + + bt_bap_verify_bis(data->bap, bis_idx++, cc, &lpac); + + g_assert(lpac); + g_assert(pac == lpac); + + stream = bt_bap_stream_new(data->bap, + pac, NULL, &data->cfg->qos, cc); + + g_assert(stream); + + queue_push_tail(data->streams, stream); + + bt_bap_stream_config(stream, &data->cfg->qos, + cc, NULL, NULL); + + util_iov_free(cc, 1); + } +} + +static void bsnk_state(struct bt_bap_stream *stream, uint8_t old_state, + uint8_t new_state, void *user_data) +{ + struct test_data *data = user_data; + struct iovec *cc; + + switch (new_state) { + case BT_BAP_STREAM_STATE_CONFIG: + /* Check that stream has been configured as expected */ + cc = bt_bap_stream_get_config(stream); + + g_assert(cc); + g_assert(cc->iov_len == data->cfg->cc.iov_len); + g_assert(memcmp(cc->iov_base, data->cfg->cc.iov_base, + cc->iov_len) == 0); + + tester_test_passed(); + break; + } +} + +static void test_bcast_config(struct test_data *data) +{ + if (!data->cfg) + return; + + if (data->cfg->src) { + bt_bap_pac_register(data->bap, bsrc_pac_added, + NULL, data, NULL); + + if (data->cfg->vs) + data->bsrc = bt_bap_add_vendor_pac(data->db, + "test-bap-bsrc", + BT_BAP_BCAST_SOURCE, + 0x0ff, 0x0000, 0x0000, + NULL, data->caps, + NULL); + else + data->bsrc = bt_bap_add_pac(data->db, "test-bap-bsrc", + BT_BAP_BCAST_SOURCE, + LC3_ID, + NULL, data->caps, + NULL); + + g_assert(data->bsrc); + } + + if (data->cfg->snk) { + bt_bap_pac_register(data->bap, bsnk_pac_added, + NULL, data, NULL); + + if (data->cfg->vs) + data->bsnk = bt_bap_add_vendor_pac(data->db, + "test-bap-bsnk", + BT_BAP_BCAST_SINK, + 0xff, 0x0000, 0x0000, + NULL, data->caps, + NULL); + else + data->bsnk = bt_bap_add_pac(data->db, "test-bap-bsnk", + BT_BAP_BCAST_SINK, + LC3_ID, + NULL, data->caps, + NULL); + + g_assert(data->bsnk); + } +} + +static void test_bcast(const void *user_data) +{ + struct test_data *data = (void *)user_data; + + data->db = gatt_db_new(); + g_assert(data->db); + + data->bap = bt_bap_new(data->db, data->db); + g_assert(data->bap); + + bt_bap_set_debug(data->bap, print_debug, "bt_bap:", NULL); + + bt_bap_attach_broadcast(data->bap); + + if (data->cfg && data->cfg->state_func) + bt_bap_state_register(data->bap, data->cfg->state_func, NULL, + data, NULL); + + test_bcast_config(data); +} + +static void test_teardown(const void *user_data) +{ + struct test_data *data = (void *)user_data; + + bt_bap_unref(data->bap); + bt_gatt_client_unref(data->client); + util_iov_free(data->iov, data->iovcnt); + + util_iov_free(data->base, 1); + + bt_bap_remove_pac(data->snk); + bt_bap_remove_pac(data->src); + bt_bap_remove_pac(data->bsrc); + bt_bap_remove_pac(data->bsnk); + gatt_db_unref(data->db); + + queue_destroy(data->streams, NULL); + + tester_teardown_complete(); +} + +/* ATT: Read Request (0x0a) len 2 + * Handle: 0x0003 Type: Sink PAC (0x2bc9) + * ATT: Read Response (0x0b) len 24 + * Value: 010600000000100301ff0002020302030305041e00f00000 + * Handle: 0x0003 Type: Sink PAC (0x2bc9) + * Number of PAC(s): 1 + * PAC #0: + * Codec: LC3 (0x06) + * Codec Specific Capabilities #0: len 0x03 type 0x01 + * Sampling Frequencies: 0x00ff + * 8 Khz (0x0001) + * 11.25 Khz (0x0002) + * 16 Khz (0x0004) + * 22.05 Khz (0x0008) + * 24 Khz (0x0010) + * 32 Khz (0x0020) + * 44.1 Khz (0x0040) + * 48 Khz (0x0080) + * Codec Specific Capabilities #1: len 0x02 type 0x02 + * Frame Duration: 0x0003 + * 7.5 ms (0x01) + * 10 ms (0x02) + * Codec Specific Capabilities #2: len 0x02 type 0x03 + * Audio Channel Count: 0x03 + * 1 channel (0x01) + * 2 channels (0x02) + * Codec Specific Capabilities #3: len 0x05 type 0x04 + * Frame Length: 30 (0x001e) - 240 (0x00f0) + * ATT: Read Request (0x0a) len 2 + * Handle: 0x0006 Type: Sink Audio Location (0x2bca) + * ATT: Read Response (0x0b) len 4 + * Value: 03000000 + * Handle: 0x0006 Type: Sink Audio Locations (0x2bca) + * Location: 0x00000003 + * Front Left (0x00000001) + * Front Right (0x00000002) + */ +#define DISC_SNK_PAC(_caps...) \ + IOV_DATA(0x0a, 0x03, 0x00), \ + IOV_DATA(0x0b, 0x01, _caps), \ + IOV_DATA(0x0a, 0x06, 0x00), \ + IOV_DATA(0x0b, 0x03, 0x00, 0x00, 0x00) + +#define DISC_SNK_LC3 \ + DISC_SNK_PAC(0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x01, \ + 0xff, 0x00, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x05, 0x04, \ + 0x1e, 0x00, 0xf0, 0x00, 0x00) + +/* ATT: Read Request (0x0a) len 2 + * Handle: 0x0009 Type: Source PAC (0x2bcb) + * ATT: Read Response (0x0b) len 24 + * Value: 010600000000100301ff0002020302030305041e00f00000 + * Handle: 0x0009 Type: Source PAC (0x2bcb) + * Number of PAC(s): 1 + * PAC #0: + * Codec: LC3 (0x06) + * Codec Specific Capabilities #0: len 0x03 type 0x01 + * Sampling Frequencies: 0x00ff + * 8 Khz (0x0001) + * 11.25 Khz (0x0002) + * 16 Khz (0x0004) + * 22.05 Khz (0x0008) + * 24 Khz (0x0010) + * 32 Khz (0x0020) + * 44.1 Khz (0x0040) + * 48 Khz (0x0080) + * Codec Specific Capabilities #1: len 0x02 type 0x02 + * Frame Duration: 0x0003 + * 7.5 ms (0x01) + * 10 ms (0x02) + * Codec Specific Capabilities #2: len 0x02 type 0x03 + * Audio Channel Count: 0x03 + * 1 channel (0x01) + * 2 channels (0x02) + * Codec Specific Capabilities #3: len 0x05 type 0x04 + * Frame Length: 30 (0x001e) - 240 (0x00f0) + * ATT: Read Request (0x0a) len 2 + * Handle: 0x000c Type: Source Audio Location (0x2bcc) + * ATT: Read Response (0x0b) len 4 + * Value: 03000000 + * Handle: 0x000c Type: Source Audio Locations (0x2bcc) + * Location: 0x00000003 + * Front Left (0x00000001) + * Front Right (0x00000002) + */ +#define DISC_SRC_PAC(_caps...) \ + DISC_SNK_PAC(_caps), \ + IOV_DATA(0x0a, 0x09, 0x00), \ + IOV_DATA(0x0b, 0x01, _caps), \ + IOV_DATA(0x0a, 0x0c, 0x00), \ + IOV_DATA(0x0b, 0x03, 0x00, 0x00, 0x00) + +#define DISC_SRC_LC3 \ + DISC_SRC_PAC(0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x01, \ + 0xff, 0x00, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x05, 0x04, \ + 0x1e, 0x00, 0xf0, 0x00, 0x00) + +/* ATT: Read Request (0x0a) len 2 + * Handle: 0x000f Type: Available Audio Contexts (0x2bcd) + * ATT: Read Response (0x0b) len 4 + * Value: ff0f0e00 + * Handle: 0x000f Type: Available Audio Contexts (0x2bcd) + */ +#define DISC_CTX(_caps...) \ + DISC_SRC_PAC(_caps), \ + IOV_DATA(0x0a, 0x0f, 0x00), \ + IOV_DATA(0x0b, 0xff, 0x0f, 0x0e, 0x00) + +#define DISC_CTX_LC3 \ + DISC_CTX(0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x01, \ + 0xff, 0x00, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x05, 0x04, \ + 0x1e, 0x00, 0xf0, 0x00, 0x00) + +/* ATT: Read Request (0x0a) len 2 + * Handle: 0x0012 Type: Supported Audio Contexts (0x2bce) + * ATT: Read Response (0x0b) len 4 + * Value: ff0f0e00 + * Handle: 0x0012 Type: Supported Audio Contexts (0x2bce) + */ +#define DISC_SUP_CTX(_caps...) \ + DISC_CTX(_caps), \ + IOV_DATA(0x0a, 0x12, 0x00), \ + IOV_DATA(0x0b, 0xff, 0x0f, 0x0e, 0x00) + +#define DISC_SUP_CTX_LC3 \ + DISC_SUP_CTX(0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x01, \ + 0xff, 0x00, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x05, 0x04, \ + 0x1e, 0x00, 0xf0, 0x00, 0x00) + +/* ATT: Read Request (0x0a) len 2 + * Handle: 0x0016 Type: Sink ASE (0x2bc4) + * ATT: Read Response (0x0b) len 4 + * Value: 0100 + * Handle: 0x0016 Type: Sink ASE (0x2bc4) + * ATT: Write Request (0x12) len 4 + * Handle: 0x0017 Type: Client Characteristic Configuration (0x2902) + * Data: 0100 + * Notification (0x01) + * ATT: Write Response (0x13) len 0 + * ATT: Read Request (0x0a) len 2 + * Handle: 0x0019 Type: Sink ASE (0x2bc4) + * ATT: Read Response (0x0b) len 4 + * Value: 0200 + * Handle: 0x0019 Type: Sink ASE (0x2bc4) + * ATT: Write Request (0x12) len 4 + * Handle: 0x001a Type: Client Characteristic Configuration (0x2902) + * Data: 0100 + * Notification (0x01) + * ATT: Write Response (0x13) len 0 + */ +#define DISC_SNK_ASE(_caps...) \ + DISC_SUP_CTX(_caps), \ + IOV_DATA(0x0a, 0x16, 0x00), \ + IOV_DATA(0x0b, 0x01, 0x00), \ + IOV_DATA(0x12, 0x17, 0x00, 0x01, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x0a, 0x19, 0x00), \ + IOV_DATA(0x0b, 0x02, 0x00), \ + IOV_DATA(0x12, 0x1a, 0x00, 0x01, 0x00), \ + IOV_DATA(0x13) + +#define DISC_SNK_ASE_LC3 \ + DISC_SNK_ASE(0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x01, \ + 0xff, 0x00, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x05, 0x04, \ + 0x1e, 0x00, 0xf0, 0x00, 0x00) + +/* ATT: Read Request (0x0a) len 2 + * Handle: 0x001c Type: Source ASE (0x2bc5) + * ATT: Read Response (0x0b) len 4 + * Value: 0300 + * Handle: 0x001c Type: Source ASE (0x2bc5) + * ATT: Write Request (0x12) len 4 + * Handle: 0x001d Type: Client Characteristic Configuration (0x2902) + * Data: 0100 + * Notification (0x01) + * ATT: Write Response (0x13) len 0 + * ATT: Read Request (0x0a) len 2 + * Handle: 0x001f Type: Source ASE (0x2bc5) + * ATT: Read Response (0x0b) len 4 + * Value: 0400 + * Handle: 0x001f Type: Source ASE (0x2bc5) + * ATT: Write Request (0x12) len 4 + * Handle: 0x0020 Type: Client Characteristic Configuration (0x2902) + * Data: 0100 + * Notification (0x01) + * ATT: Write Response (0x13) len 0 + * ATT: Write Request (0x12) len 4 + * Handle: 0x0023 Type: Client Characteristic Configuration (0x2902) + * Data: 0100 + * Notification (0x01) + * ATT: Write Response (0x13) len 0 + */ +#define DISC_SRC_ASE(_cfg...) \ + DISC_SNK_ASE(_cfg), \ + IOV_DATA(0x0a, 0x1c, 0x00), \ + IOV_DATA(0x0b, 0x03, 0x00), \ + IOV_DATA(0x12, 0x1d, 0x00, 0x01, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x0a, 0x1f, 0x00), \ + IOV_DATA(0x0b, 0x04, 0x00), \ + IOV_DATA(0x12, 0x20, 0x00, 0x01, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x12, 0x23, 0x00, 0x01, 0x00), \ + IOV_DATA(0x13) + +#define DISC_SRC_ASE_LC3 \ + DISC_SRC_ASE(0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x01, \ + 0xff, 0x00, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x05, 0x04, \ + 0x1e, 0x00, 0xf0, 0x00, 0x00) + +static void test_disc(void) +{ + /* The IUT discovers the characteristics specified in the PAC + * Characteristic and Location Characteristic columns in Table 4.4. + * The IUT reads the values of the characteristics specified in the PAC + * Characteristic and Location Characteristic columns. + */ + define_test("BAP/UCL/DISC/BV-01-C", test_setup, test_client, NULL, + DISC_SNK_LC3); + define_test("BAP/UCL/DISC/BV-02-C", test_setup, test_client, NULL, + DISC_SRC_LC3); + + /* BAP/UCL/DISC/BV-06-C [Discover Available Audio Contexts] + * + * The IUT successfully reads the value of the Available Audio Contexts + * characteristic on the LowerTester. + */ + define_test("BAP/UCL/DISC/BV-06-C", test_setup, test_client, NULL, + DISC_CTX_LC3); + + /* BAP/UCL/DISC/BV-05-C [Discover Supported Audio Contexts] + * + * The IUT successfully reads the value of the Supported Audio Contexts + * characteristic on the Lower Tester. + */ + define_test("BAP/UCL/DISC/BV-05-C", test_setup, test_client, NULL, + DISC_SUP_CTX_LC3); + + /* BAP/UCL/DISC/BV-03-C [Discover Sink ASE_ID] + * BAP/UCL/DISC/BV-04-C [Discover Source ASE_ID] + * + * The IUT successfully reads the ASE_ID values of each discovered ASE + * characteristic on the LowerTester. + */ + define_test("BAP/UCL/DISC/BV-03-C", test_setup, test_client, NULL, + DISC_SNK_ASE_LC3); + define_test("BAP/UCL/DISC/BV-04-C", test_setup, test_client, NULL, + DISC_SRC_ASE_LC3); +} + +/* ATT: Write Command (0x52) len 23 + * Handle: 0x0022 + * Data: 0101010202_cfg + * ATT: Handle Value Notification (0x1b) len 7 + * Handle: 0x0022 + * Data: 0101010000 + * ATT: Handle Value Notification (0x1b) len 37 + * Handle: 0x0016 + * Data: 01010102010a00204e00409c00204e00409c00_cfg + */ +#define SCC_SNK(_cfg...) \ + IOV_DATA(0x52, 0x22, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, _cfg), \ + IOV_DATA(0x1b, 0x22, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00), \ + IOV_NULL, \ + IOV_DATA(0x1b, 0x16, 0x00, 0x01, 0x01, 0x01, 0x02, 0x01, 0x0a, 0x00, \ + 0x20, 0x4e, 0x00, 0x40, 0x9c, 0x00, 0x20, 0x4e, 0x00, \ + 0x40, 0x9c, 0x00, _cfg) + +#define SCC_SNK_LC3(_cc...) \ + DISC_SRC_ASE_LC3, \ + SCC_SNK(0x06, 0x00, 0x00, 0x00, 0x00, _cc) + +#define QOS_BALANCED_2M \ + { \ + .target_latency = BT_BAP_CONFIG_LATENCY_BALANCED, \ + .io_qos.phy = BT_BAP_CONFIG_PHY_2M, \ + } +#define QOS_UCAST \ +{\ + .ucast = QOS_BALANCED_2M, \ +} +static struct test_config cfg_snk_8_1 = { + .cc = LC3_CONFIG_8_1, + .qos = QOS_UCAST, + .snk = true, +}; + +#define SCC_SNK_8_1 \ + SCC_SNK_LC3(0x0a, 0x02, 0x01, 0x01, 0x02, 0x02, 0x00, 0x03, 0x04, \ + 0x1a, 0x00) + +static struct test_config cfg_snk_8_2 = { + .cc = LC3_CONFIG_8_2, + .qos = QOS_UCAST, + .snk = true, +}; + +#define SCC_SNK_8_2 \ + SCC_SNK_LC3(0x0a, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01, 0x03, 0x04, \ + 0x1e, 0x00) + +static struct test_config cfg_snk_16_1 = { + .cc = LC3_CONFIG_16_1, + .qos = QOS_UCAST, + .snk = true, +}; + +#define SCC_SNK_16_1 \ + SCC_SNK_LC3(0x0a, 0x02, 0x01, 0x03, 0x02, 0x02, 0x00, 0x03, 0x04, \ + 0x1e, 0x00) + +static struct test_config cfg_snk_16_2 = { + .cc = LC3_CONFIG_16_2, + .qos = QOS_UCAST, + .snk = true, +}; + +#define SCC_SNK_16_2 \ + SCC_SNK_LC3(0x0a, 0x02, 0x01, 0x03, 0x02, 0x02, 0x01, 0x03, 0x04, \ + 0x28, 0x00) + +static struct test_config cfg_snk_24_1 = { + .cc = LC3_CONFIG_24_1, + .qos = QOS_UCAST, + .snk = true, +}; + +#define SCC_SNK_24_1 \ + SCC_SNK_LC3(0x0a, 0x02, 0x01, 0x05, 0x02, 0x02, 0x00, 0x03, 0x04, \ + 0x2d, 0x00) + +static struct test_config cfg_snk_24_2 = { + .cc = LC3_CONFIG_24_2, + .qos = QOS_UCAST, + .snk = true, +}; + +#define SCC_SNK_24_2 \ + SCC_SNK_LC3(0x0a, 0x02, 0x01, 0x05, 0x02, 0x02, 0x01, 0x03, 0x04, \ + 0x3c, 0x00) + +static struct test_config cfg_snk_32_1 = { + .cc = LC3_CONFIG_32_1, + .qos = QOS_UCAST, + .snk = true, +}; + +#define SCC_SNK_32_1 \ + SCC_SNK_LC3(0x0a, 0x02, 0x01, 0x06, 0x02, 0x02, 0x00, 0x03, 0x04, \ + 0x3c, 0x00) + +static struct test_config cfg_snk_32_2 = { + .cc = LC3_CONFIG_32_2, + .qos = QOS_UCAST, + .snk = true, +}; + +#define SCC_SNK_32_2 \ + SCC_SNK_LC3(0x0a, 0x02, 0x01, 0x06, 0x02, 0x02, 0x01, 0x03, 0x04, \ + 0x50, 0x00) + +static struct test_config cfg_snk_44_1 = { + .cc = LC3_CONFIG_44_1, + .qos = QOS_UCAST, + .snk = true, +}; + +#define SCC_SNK_44_1 \ + SCC_SNK_LC3(0x0a, 0x02, 0x01, 0x07, 0x02, 0x02, 0x00, 0x03, 0x04, \ + 0x62, 0x00) + +static struct test_config cfg_snk_44_2 = { + .cc = LC3_CONFIG_44_2, + .qos = QOS_UCAST, + .snk = true, +}; + +#define SCC_SNK_44_2 \ + SCC_SNK_LC3(0x0a, 0x02, 0x01, 0x07, 0x02, 0x02, 0x01, 0x03, 0x04, \ + 0x82, 0x00) + +static struct test_config cfg_snk_48_1 = { + .cc = LC3_CONFIG_48_1, + .qos = QOS_UCAST, + .snk = true, +}; + +#define SCC_SNK_48_1 \ + SCC_SNK_LC3(0x0a, 0x02, 0x01, 0x08, 0x02, 0x02, 0x00, 0x03, 0x04, \ + 0x4b, 0x00) + +static struct test_config cfg_snk_48_2 = { + .cc = LC3_CONFIG_48_2, + .qos = QOS_UCAST, + .snk = true, +}; + +#define SCC_SNK_48_2 \ + SCC_SNK_LC3(0x0a, 0x02, 0x01, 0x08, 0x02, 0x02, 0x01, 0x03, 0x04, \ + 0x64, 0x00) + +static struct test_config cfg_snk_48_3 = { + .cc = LC3_CONFIG_48_3, + .qos = QOS_UCAST, + .snk = true, +}; + +#define SCC_SNK_48_3 \ + SCC_SNK_LC3(0x0a, 0x02, 0x01, 0x08, 0x02, 0x02, 0x00, 0x03, 0x04, \ + 0x5a, 0x00) + +static struct test_config cfg_snk_48_4 = { + .cc = LC3_CONFIG_48_4, + .qos = QOS_UCAST, + .snk = true, +}; + +#define SCC_SNK_48_4 \ + SCC_SNK_LC3(0x0a, 0x02, 0x01, 0x08, 0x02, 0x02, 0x01, 0x03, 0x04, \ + 0x78, 0x00) + +static struct test_config cfg_snk_48_5 = { + .cc = LC3_CONFIG_48_5, + .qos = QOS_UCAST, + .snk = true, +}; + +#define SCC_SNK_48_5 \ + SCC_SNK_LC3(0x0a, 0x02, 0x01, 0x08, 0x02, 0x02, 0x00, 0x03, 0x04, \ + 0x75, 0x00) + +static struct test_config cfg_snk_48_6 = { + .cc = LC3_CONFIG_48_6, + .qos = QOS_UCAST, + .snk = true, +}; + +#define SCC_SNK_48_6 \ + SCC_SNK_LC3(0x0a, 0x02, 0x01, 0x08, 0x02, 0x02, 0x01, 0x03, 0x04, \ + 0x9b, 0x00) + +/* ATT: Write Command (0x52) len 23 + * Handle: 0x0022 + * Data: 0101030202_cfg + * ATT: Handle Value Notification (0x1b) len 7 + * Handle: 0x0022 + * Data: 0101030000 + * ATT: Handle Value Notification (0x1b) len 37 + * Handle: 0x001c + * Data: 03010102010a00204e00409c00204e00409c00_cfg + */ +#define SCC_SRC(_cfg...) \ + IOV_DATA(0x52, 0x22, 0x00, 0x01, 0x01, 0x03, 0x02, 0x02, _cfg), \ + IOV_DATA(0x1b, 0x22, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00), \ + IOV_NULL, \ + IOV_DATA(0x1b, 0x1c, 0x00, 0x03, 0x01, 0x01, 0x02, 0x01, 0x0a, 0x00, \ + 0x20, 0x4e, 0x00, 0x40, 0x9c, 0x00, 0x20, 0x4e, 0x00, \ + 0x40, 0x9c, 0x00, _cfg) + +#define SCC_SRC_LC3(_cc...) \ + DISC_SRC_ASE_LC3, \ + SCC_SRC(0x06, 0x00, 0x00, 0x00, 0x00, _cc) + +static struct test_config cfg_src_8_1 = { + .cc = LC3_CONFIG_8_1, + .qos = QOS_UCAST, + .src = true, +}; + +#define SCC_SRC_8_1 \ + SCC_SRC_LC3(0x0a, 0x02, 0x01, 0x01, 0x02, 0x02, 0x00, 0x03, 0x04, \ + 0x1a, 0x00) + +static struct test_config cfg_src_8_2 = { + .cc = LC3_CONFIG_8_2, + .qos = QOS_UCAST, + .src = true, +}; + +#define SCC_SRC_8_2 \ + SCC_SRC_LC3(0x0a, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01, 0x03, 0x04, \ + 0x1e, 0x00) + +static struct test_config cfg_src_16_1 = { + .cc = LC3_CONFIG_16_1, + .qos = QOS_UCAST, + .src = true, +}; + +#define SCC_SRC_16_1 \ + SCC_SRC_LC3(0x0a, 0x02, 0x01, 0x03, 0x02, 0x02, 0x00, 0x03, 0x04, \ + 0x1e, 0x00) + +static struct test_config cfg_src_16_2 = { + .cc = LC3_CONFIG_16_2, + .qos = QOS_UCAST, + .src = true, +}; + +#define SCC_SRC_16_2 \ + SCC_SRC_LC3(0x0a, 0x02, 0x01, 0x03, 0x02, 0x02, 0x01, 0x03, 0x04, \ + 0x28, 0x00) + +static struct test_config cfg_src_24_1 = { + .cc = LC3_CONFIG_24_1, + .qos = QOS_UCAST, + .src = true, +}; + +#define SCC_SRC_24_1 \ + SCC_SRC_LC3(0x0a, 0x02, 0x01, 0x05, 0x02, 0x02, 0x00, 0x03, 0x04, \ + 0x2d, 0x00) + +static struct test_config cfg_src_24_2 = { + .cc = LC3_CONFIG_24_2, + .qos = QOS_UCAST, + .src = true, +}; + +#define SCC_SRC_24_2 \ + SCC_SRC_LC3(0x0a, 0x02, 0x01, 0x05, 0x02, 0x02, 0x01, 0x03, 0x04, \ + 0x3c, 0x00) + +static struct test_config cfg_src_32_1 = { + .cc = LC3_CONFIG_32_1, + .qos = QOS_UCAST, + .src = true, +}; + +#define SCC_SRC_32_1 \ + SCC_SRC_LC3(0x0a, 0x02, 0x01, 0x06, 0x02, 0x02, 0x00, 0x03, 0x04, \ + 0x3c, 0x00) + +static struct test_config cfg_src_32_2 = { + .cc = LC3_CONFIG_32_2, + .qos = QOS_UCAST, + .src = true, +}; + +#define SCC_SRC_32_2 \ + SCC_SRC_LC3(0x0a, 0x02, 0x01, 0x06, 0x02, 0x02, 0x01, 0x03, 0x04, \ + 0x50, 0x00) + +static struct test_config cfg_src_44_1 = { + .cc = LC3_CONFIG_44_1, + .qos = QOS_UCAST, + .src = true, +}; + +#define SCC_SRC_44_1 \ + SCC_SRC_LC3(0x0a, 0x02, 0x01, 0x07, 0x02, 0x02, 0x00, 0x03, 0x04, \ + 0x62, 0x00) + +static struct test_config cfg_src_44_2 = { + .cc = LC3_CONFIG_44_2, + .qos = QOS_UCAST, + .src = true, +}; + +#define SCC_SRC_44_2 \ + SCC_SRC_LC3(0x0a, 0x02, 0x01, 0x07, 0x02, 0x02, 0x01, 0x03, 0x04, \ + 0x82, 0x00) + +static struct test_config cfg_src_48_1 = { + .cc = LC3_CONFIG_48_1, + .qos = QOS_UCAST, + .src = true, +}; + +#define SCC_SRC_48_1 \ + SCC_SRC_LC3(0x0a, 0x02, 0x01, 0x08, 0x02, 0x02, 0x00, 0x03, 0x04, \ + 0x4b, 0x00) + +static struct test_config cfg_src_48_2 = { + .cc = LC3_CONFIG_48_2, + .qos = QOS_UCAST, + .src = true, +}; + +#define SCC_SRC_48_2 \ + SCC_SRC_LC3(0x0a, 0x02, 0x01, 0x08, 0x02, 0x02, 0x01, 0x03, 0x04, \ + 0x64, 0x00) + +static struct test_config cfg_src_48_3 = { + .cc = LC3_CONFIG_48_3, + .qos = QOS_UCAST, + .src = true, +}; + +#define SCC_SRC_48_3 \ + SCC_SRC_LC3(0x0a, 0x02, 0x01, 0x08, 0x02, 0x02, 0x00, 0x03, 0x04, \ + 0x5a, 0x00) + +static struct test_config cfg_src_48_4 = { + .cc = LC3_CONFIG_48_4, + .qos = QOS_UCAST, + .src = true, +}; + +#define SCC_SRC_48_4 \ + SCC_SRC_LC3(0x0a, 0x02, 0x01, 0x08, 0x02, 0x02, 0x01, 0x03, 0x04, \ + 0x78, 0x00) + +static struct test_config cfg_src_48_5 = { + .cc = LC3_CONFIG_48_5, + .qos = QOS_UCAST, + .src = true, +}; + +#define SCC_SRC_48_5 \ + SCC_SRC_LC3(0x0a, 0x02, 0x01, 0x08, 0x02, 0x02, 0x00, 0x03, 0x04, \ + 0x75, 0x00) + +static struct test_config cfg_src_48_6 = { + .cc = LC3_CONFIG_48_6, + .qos = QOS_UCAST, + .src = true, +}; + +#define SCC_SRC_48_6 \ + SCC_SRC_LC3(0x0a, 0x02, 0x01, 0x08, 0x02, 0x02, 0x01, 0x03, 0x04, \ + 0x9b, 0x00) + +/* Test Purpose: + * Verify that a Unicast Client IUT can initiate a Config Codec + * operation for an LC3 codec. + * + * Pass verdict: + * The IUT successfully writes to the ASE Control point with the opcode + * set to 0x01 (Config Codec) and correctly formatted parameter values + * from Table 4.9. The Codec_ID field is a 5-octet field with octet 0 + * set to the LC3 Coding_Format value defined in Bluetooth Assigned + * Numbers, octets 1–4 set to 0x0000. Each parameter (if present) + * included in the data sent in Codec_Specific_Configuration is + * formatted in an LTV structure with the length, type, and value + * specified in Table 4.10. + */ +static void test_scc_cc_lc3(void) +{ + define_test("BAP/UCL/SCC/BV-001-C [UCL SRC Config Codec, LC3 8_1]", + test_setup, test_client, &cfg_snk_8_1, SCC_SNK_8_1); + define_test("BAP/UCL/SCC/BV-002-C [UCL SRC Config Codec, LC3 8_2]", + test_setup, test_client, &cfg_snk_8_2, SCC_SNK_8_2); + define_test("BAP/UCL/SCC/BV-003-C [UCL SRC Config Codec, LC3 16_1]", + test_setup, test_client, &cfg_snk_16_1, SCC_SNK_16_1); + define_test("BAP/UCL/SCC/BV-004-C [UCL SRC Config Codec, LC3 16_2]", + test_setup, test_client, &cfg_snk_16_2, SCC_SNK_16_2); + define_test("BAP/UCL/SCC/BV-005-C [UCL SRC Config Codec, LC3 24_1]", + test_setup, test_client, &cfg_snk_24_1, SCC_SNK_24_1); + define_test("BAP/UCL/SCC/BV-006-C [UCL SRC Config Codec, LC3 24_2]", + test_setup, test_client, &cfg_snk_24_2, SCC_SNK_24_2); + define_test("BAP/UCL/SCC/BV-007-C [UCL SRC Config Codec, LC3 32_1]", + test_setup, test_client, &cfg_snk_32_1, SCC_SNK_32_1); + define_test("BAP/UCL/SCC/BV-008-C [UCL SRC Config Codec, LC3 32_2]", + test_setup, test_client, &cfg_snk_32_2, SCC_SNK_32_2); + define_test("BAP/UCL/SCC/BV-009-C [UCL SRC Config Codec, LC3 44.1_1]", + test_setup, test_client, &cfg_snk_44_1, SCC_SNK_44_1); + define_test("BAP/UCL/SCC/BV-010-C [UCL SRC Config Codec, LC3 44.1_2]", + test_setup, test_client, &cfg_snk_44_2, SCC_SNK_44_2); + define_test("BAP/UCL/SCC/BV-011-C [UCL SRC Config Codec, LC3 48_1]", + test_setup, test_client, &cfg_snk_48_1, SCC_SNK_48_1); + define_test("BAP/UCL/SCC/BV-012-C [UCL SRC Config Codec, LC3 48_2]", + test_setup, test_client, &cfg_snk_48_2, SCC_SNK_48_2); + define_test("BAP/UCL/SCC/BV-013-C [UCL SRC Config Codec, LC3 48_3]", + test_setup, test_client, &cfg_snk_48_3, SCC_SNK_48_3); + define_test("BAP/UCL/SCC/BV-014-C [UCL SRC Config Codec, LC3 48_4]", + test_setup, test_client, &cfg_snk_48_4, SCC_SNK_48_4); + define_test("BAP/UCL/SCC/BV-015-C [UCL SRC Config Codec, LC3 48_5]", + test_setup, test_client, &cfg_snk_48_5, SCC_SNK_48_5); + define_test("BAP/UCL/SCC/BV-016-C [UCL SRC Config Codec, LC3 48_6]", + test_setup, test_client, &cfg_snk_48_6, SCC_SNK_48_6); + define_test("BAP/UCL/SCC/BV-017-C [UCL SNK Config Codec, LC3 8_1]", + test_setup, test_client, &cfg_src_8_1, SCC_SRC_8_1); + define_test("BAP/UCL/SCC/BV-018-C [UCL SNK Config Codec, LC3 8_2]", + test_setup, test_client, &cfg_src_8_2, SCC_SRC_8_2); + define_test("BAP/UCL/SCC/BV-019-C [UCL SNK Config Codec, LC3 16_1]", + test_setup, test_client, &cfg_src_16_1, SCC_SRC_16_1); + define_test("BAP/UCL/SCC/BV-020-C [UCL SNK Config Codec, LC3 16_2]", + test_setup, test_client, &cfg_src_16_2, SCC_SRC_16_2); + define_test("BAP/UCL/SCC/BV-021-C [UCL SNK Config Codec, LC3 24_1]", + test_setup, test_client, &cfg_src_24_1, SCC_SRC_24_1); + define_test("BAP/UCL/SCC/BV-022-C [UCL SNK Config Codec, LC3 24_2]", + test_setup, test_client, &cfg_src_24_2, SCC_SRC_24_2); + define_test("BAP/UCL/SCC/BV-023-C [UCL SNK Config Codec, LC3 32_1]", + test_setup, test_client, &cfg_src_32_1, SCC_SRC_32_1); + define_test("BAP/UCL/SCC/BV-024-C [UCL SNK Config Codec, LC3 32_2]", + test_setup, test_client, &cfg_src_32_2, SCC_SRC_32_2); + define_test("BAP/UCL/SCC/BV-025-C [UCL SNK Config Codec, LC3 44.1_1]", + test_setup, test_client, &cfg_src_44_1, SCC_SRC_44_1); + define_test("BAP/UCL/SCC/BV-026-C [UCL SNK Config Codec, LC3 44.1_2]", + test_setup, test_client, &cfg_src_44_2, SCC_SRC_44_2); + define_test("BAP/UCL/SCC/BV-027-C [UCL SNK Config Codec, LC3 48_1]", + test_setup, test_client, &cfg_src_48_1, SCC_SRC_48_1); + define_test("BAP/UCL/SCC/BV-028-C [UCL SNK Config Codec, LC3 48_2]", + test_setup, test_client, &cfg_src_48_2, SCC_SRC_48_2); + define_test("BAP/UCL/SCC/BV-029-C [UCL SNK Config Codec, LC3 48_3]", + test_setup, test_client, &cfg_src_48_3, SCC_SRC_48_3); + define_test("BAP/UCL/SCC/BV-030-C [UCL SNK Config Codec, LC3 48_4]", + test_setup, test_client, &cfg_src_48_4, SCC_SRC_48_4); + define_test("BAP/UCL/SCC/BV-031-C [UCL SNK Config Codec, LC3 48_5]", + test_setup, test_client, &cfg_src_48_5, SCC_SRC_48_5); + define_test("BAP/UCL/SCC/BV-032-C [UCL SNK Config Codec, LC3 48_6]", + test_setup, test_client, &cfg_src_48_6, SCC_SRC_48_6); +} + +static struct test_config cfg_snk_vs = { + .cc = IOV_NULL, + .qos = QOS_UCAST, + .snk = true, + .vs = true, +}; + +#define DISC_SRC_ASE_VS \ + DISC_SRC_ASE(0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00) + +#define SCC_SNK_VS \ + DISC_SRC_ASE_VS, \ + SCC_SNK(0xff, 0x01, 0x00, 0x01, 0x00, 0x00) + +static struct test_config cfg_src_vs = { + .cc = IOV_NULL, + .qos = QOS_UCAST, + .src = true, + .vs = true, +}; + +#define SCC_SRC_VS \ + DISC_SRC_ASE_VS, \ + SCC_SRC(0xff, 0x01, 0x00, 0x01, 0x00, 0x00) + +/* Test Purpose: + * Verify that a Unicast Client IUT can initiate a Config Codec operation for a + * vendor-specific codec. + * + * Pass verdict: + * The IUT successfully writes to the ASE Control Point characteristic with the + * opcode set to 0x01 (Config Codec) and the specified parameters. The Codec_ID + * parameter is formatted with octet 0 set to 0xFF, octets 1–2 set to + * TSPX_VS_Company_ID, and octets 3–4 set to TSPX_VS_Codec_ID. + */ +static void test_scc_cc_vs(void) +{ + define_test("BAP/UCL/SCC/BV-033-C [UCL SRC Config Codec, VS]", + test_setup, test_client, &cfg_snk_vs, SCC_SNK_VS); + define_test("BAP/UCL/SCC/BV-034-C [UCL SNK Config Codec, VS]", + test_setup, test_client, &cfg_src_vs, SCC_SRC_VS); +} + +static struct test_config cfg_snk_8_1_1 = { + .cc = LC3_CONFIG_8_1, + .qos = LC3_QOS_8_1_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_8_2_1 = { + .cc = LC3_CONFIG_8_2, + .qos = LC3_QOS_8_2_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_16_1_1 = { + .cc = LC3_CONFIG_16_1, + .qos = LC3_QOS_16_1_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_16_2_1 = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_24_1_1 = { + .cc = LC3_CONFIG_24_1, + .qos = LC3_QOS_24_1_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_24_2_1 = { + .cc = LC3_CONFIG_24_2, + .qos = LC3_QOS_24_2_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_32_1_1 = { + .cc = LC3_CONFIG_32_1, + .qos = LC3_QOS_32_1_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_32_2_1 = { + .cc = LC3_CONFIG_32_2, + .qos = LC3_QOS_32_2_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_44_1_1 = { + .cc = LC3_CONFIG_44_1, + .qos = LC3_QOS_44_1_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_44_2_1 = { + .cc = LC3_CONFIG_44_2, + .qos = LC3_QOS_44_2_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_48_1_1 = { + .cc = LC3_CONFIG_48_1, + .qos = LC3_QOS_48_1_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_48_2_1 = { + .cc = LC3_CONFIG_48_2, + .qos = LC3_QOS_48_2_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_48_3_1 = { + .cc = LC3_CONFIG_48_3, + .qos = LC3_QOS_48_3_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_48_4_1 = { + .cc = LC3_CONFIG_48_4, + .qos = LC3_QOS_48_4_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_48_5_1 = { + .cc = LC3_CONFIG_48_5, + .qos = LC3_QOS_48_5_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_48_6_1 = { + .cc = LC3_CONFIG_48_6, + .qos = LC3_QOS_48_6_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +/* ATT: Write Command (0x52) len 23 + * Handle: 0x0022 + * Data: 02010000_qos + * ATT: Handle Value Notification (0x1b) len 7 + * Handle: 0x0022 + * Data: 0201010000 + * ATT: Handle Value Notification (0x1b) len 37 + * Handle: 0x0016 + * Data: 01010102010a00204e00409c00204e00409c00_qos + */ +#define QOS_SNK(_qos...) \ + IOV_DATA(0x52, 0x22, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00, _qos), \ + IOV_DATA(0x1b, 0x22, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00), \ + IOV_NULL, \ + IOV_DATA(0x1b, 0x16, 0x00, 0x01, 0x02, 0x00, 0x00, _qos) + +#define SCC_SNK_8_1_1 \ + SCC_SNK_8_1, \ + QOS_SNK(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x1a, 0x00, 0x02, 0x08, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_8_2_1 \ + SCC_SNK_8_2, \ + QOS_SNK(0x10, 0x27, 0x00, 0x00, 0x02, 0x1e, 0x00, 0x02, 0x0a, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_16_1_1 \ + SCC_SNK_16_1, \ + QOS_SNK(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x1e, 0x00, 0x02, 0x08, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_16_2_1 \ + SCC_SNK_16_2, \ + QOS_SNK(0x10, 0x27, 0x00, 0x00, 0x02, 0x28, 0x00, 0x02, 0x0a, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_24_1_1 \ + SCC_SNK_24_1, \ + QOS_SNK(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x2d, 0x00, 0x02, 0x08, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_24_2_1 \ + SCC_SNK_24_2, \ + QOS_SNK(0x10, 0x27, 0x00, 0x00, 0x02, 0x3c, 0x00, 0x02, 0x0a, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_32_1_1 \ + SCC_SNK_32_1, \ + QOS_SNK(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x3c, 0x00, 0x02, 0x08, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_32_2_1 \ + SCC_SNK_32_2, \ + QOS_SNK(0x10, 0x27, 0x00, 0x00, 0x02, 0x50, 0x00, 0x02, 0x0a, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_44_1_1 \ + SCC_SNK_44_1, \ + QOS_SNK(0xe3, 0x1f, 0x00, 0x01, 0x02, 0x62, 0x00, 0x05, 0x18, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_44_2_1 \ + SCC_SNK_44_2, \ + QOS_SNK(0x84, 0x2a, 0x00, 0x01, 0x02, 0x82, 0x00, 0x05, 0x1f, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_48_1_1 \ + SCC_SNK_48_1, \ + QOS_SNK(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x4b, 0x00, 0x05, 0x0f, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_48_2_1 \ + SCC_SNK_48_2, \ + QOS_SNK(0x10, 0x27, 0x00, 0x00, 0x02, 0x64, 0x00, 0x05, 0x14, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_48_3_1 \ + SCC_SNK_48_3, \ + QOS_SNK(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x5a, 0x00, 0x05, 0x0f, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_48_4_1 \ + SCC_SNK_48_4, \ + QOS_SNK(0x10, 0x27, 0x00, 0x00, 0x02, 0x78, 0x00, 0x05, 0x14, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_48_5_1 \ + SCC_SNK_48_5, \ + QOS_SNK(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x75, 0x00, 0x05, 0x0f, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_48_6_1 \ + SCC_SNK_48_6, \ + QOS_SNK(0x10, 0x27, 0x00, 0x00, 0x02, 0x9b, 0x00, 0x05, 0x14, 0x00, \ + 0x40, 0x9c, 0x00) + +static struct test_config cfg_src_8_1_1 = { + .cc = LC3_CONFIG_8_1, + .qos = LC3_QOS_8_1_1, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_8_2_1 = { + .cc = LC3_CONFIG_8_2, + .qos = LC3_QOS_8_2_1, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_16_1_1 = { + .cc = LC3_CONFIG_16_1, + .qos = LC3_QOS_16_1_1, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_16_2_1 = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_24_1_1 = { + .cc = LC3_CONFIG_24_1, + .qos = LC3_QOS_24_1_1, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_24_2_1 = { + .cc = LC3_CONFIG_24_2, + .qos = LC3_QOS_24_2_1, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_32_1_1 = { + .cc = LC3_CONFIG_32_1, + .qos = LC3_QOS_32_1_1, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_32_2_1 = { + .cc = LC3_CONFIG_32_2, + .qos = LC3_QOS_32_2_1, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_44_1_1 = { + .cc = LC3_CONFIG_44_1, + .qos = LC3_QOS_44_1_1, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_44_2_1 = { + .cc = LC3_CONFIG_44_2, + .qos = LC3_QOS_44_2_1, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_48_1_1 = { + .cc = LC3_CONFIG_48_1, + .qos = LC3_QOS_48_1_1, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_48_2_1 = { + .cc = LC3_CONFIG_48_2, + .qos = LC3_QOS_48_2_1, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_48_3_1 = { + .cc = LC3_CONFIG_48_3, + .qos = LC3_QOS_48_3_1, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_48_4_1 = { + .cc = LC3_CONFIG_48_4, + .qos = LC3_QOS_48_4_1, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_48_5_1 = { + .cc = LC3_CONFIG_48_5, + .qos = LC3_QOS_48_5_1, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_48_6_1 = { + .cc = LC3_CONFIG_48_6, + .qos = LC3_QOS_48_6_1, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +/* ATT: Write Command (0x52) len 23 + * Handle: 0x0022 + * Data: 02030000_qos + * ATT: Handle Value Notification (0x1b) len 7 + * Handle: 0x0022 + * Data: 0201030000 + * ATT: Handle Value Notification (0x1b) len 37 + * Handle: 0x001c + * Data: 03010102010a00204e00409c00204e00409c00_qos + */ +#define QOS_SRC(_qos...) \ + IOV_DATA(0x52, 0x22, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00, _qos), \ + IOV_DATA(0x1b, 0x22, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00), \ + IOV_NULL, \ + IOV_DATA(0x1b, 0x1c, 0x00, 0x03, 0x02, 0x00, 0x00, _qos) + +#define SCC_SRC_8_1_1 \ + SCC_SRC_8_1, \ + QOS_SRC(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x1a, 0x00, 0x02, 0x08, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_8_2_1 \ + SCC_SRC_8_2, \ + QOS_SRC(0x10, 0x27, 0x00, 0x00, 0x02, 0x1e, 0x00, 0x02, 0x0a, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_16_1_1 \ + SCC_SRC_16_1, \ + QOS_SRC(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x1e, 0x00, 0x02, 0x08, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_16_2_1 \ + SCC_SRC_16_2, \ + QOS_SRC(0x10, 0x27, 0x00, 0x00, 0x02, 0x28, 0x00, 0x02, 0x0a, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_24_1_1 \ + SCC_SRC_24_1, \ + QOS_SRC(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x2d, 0x00, 0x02, 0x08, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_24_2_1 \ + SCC_SRC_24_2, \ + QOS_SRC(0x10, 0x27, 0x00, 0x00, 0x02, 0x3c, 0x00, 0x02, 0x0a, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_32_1_1 \ + SCC_SRC_32_1, \ + QOS_SRC(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x3c, 0x00, 0x02, 0x08, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_32_2_1 \ + SCC_SRC_32_2, \ + QOS_SRC(0x10, 0x27, 0x00, 0x00, 0x02, 0x50, 0x00, 0x02, 0x0a, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_44_1_1 \ + SCC_SRC_44_1, \ + QOS_SRC(0xe3, 0x1f, 0x00, 0x01, 0x02, 0x62, 0x00, 0x05, 0x18, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_44_2_1 \ + SCC_SRC_44_2, \ + QOS_SRC(0x84, 0x2a, 0x00, 0x01, 0x02, 0x82, 0x00, 0x05, 0x1f, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_48_1_1 \ + SCC_SRC_48_1, \ + QOS_SRC(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x4b, 0x00, 0x05, 0x0f, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_48_2_1 \ + SCC_SRC_48_2, \ + QOS_SRC(0x10, 0x27, 0x00, 0x00, 0x02, 0x64, 0x00, 0x05, 0x14, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_48_3_1 \ + SCC_SRC_48_3, \ + QOS_SRC(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x5a, 0x00, 0x05, 0x0f, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_48_4_1 \ + SCC_SRC_48_4, \ + QOS_SRC(0x10, 0x27, 0x00, 0x00, 0x02, 0x78, 0x00, 0x05, 0x14, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_48_5_1 \ + SCC_SRC_48_5, \ + QOS_SRC(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x75, 0x00, 0x05, 0x0f, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_48_6_1 \ + SCC_SRC_48_6, \ + QOS_SRC(0x10, 0x27, 0x00, 0x00, 0x02, 0x9b, 0x00, 0x05, 0x14, 0x00, \ + 0x40, 0x9c, 0x00) + +static struct test_config cfg_snk_8_1_2 = { + .cc = LC3_CONFIG_8_1, + .qos = LC3_QOS_8_1_2, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_8_2_2 = { + .cc = LC3_CONFIG_8_2, + .qos = LC3_QOS_8_2_2, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_16_1_2 = { + .cc = LC3_CONFIG_16_1, + .qos = LC3_QOS_16_1_2, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_16_2_2 = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_2, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_24_1_2 = { + .cc = LC3_CONFIG_24_1, + .qos = LC3_QOS_24_1_2, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_24_2_2 = { + .cc = LC3_CONFIG_24_2, + .qos = LC3_QOS_24_2_2, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_32_1_2 = { + .cc = LC3_CONFIG_32_1, + .qos = LC3_QOS_32_1_2, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_32_2_2 = { + .cc = LC3_CONFIG_32_2, + .qos = LC3_QOS_32_2_2, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_44_1_2 = { + .cc = LC3_CONFIG_44_1, + .qos = LC3_QOS_44_1_2, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_44_2_2 = { + .cc = LC3_CONFIG_44_2, + .qos = LC3_QOS_44_2_2, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_48_1_2 = { + .cc = LC3_CONFIG_48_1, + .qos = LC3_QOS_48_1_2, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_48_2_2 = { + .cc = LC3_CONFIG_48_2, + .qos = LC3_QOS_48_2_2, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_48_3_2 = { + .cc = LC3_CONFIG_48_3, + .qos = LC3_QOS_48_3_2, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_48_4_2 = { + .cc = LC3_CONFIG_48_4, + .qos = LC3_QOS_48_4_2, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_48_5_2 = { + .cc = LC3_CONFIG_48_5, + .qos = LC3_QOS_48_5_2, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_snk_48_6_2 = { + .cc = LC3_CONFIG_48_6, + .qos = LC3_QOS_48_6_2, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +#define SCC_SNK_8_1_2 \ + SCC_SNK_8_1, \ + QOS_SNK(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x1a, 0x00, 0x0d, 0x4b, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_8_2_2 \ + SCC_SNK_8_2, \ + QOS_SNK(0x10, 0x27, 0x00, 0x00, 0x02, 0x1e, 0x00, 0x0d, 0x5f, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_16_1_2 \ + SCC_SNK_16_1, \ + QOS_SNK(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x1e, 0x00, 0x0d, 0x4b, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_16_2_2 \ + SCC_SNK_16_2, \ + QOS_SNK(0x10, 0x27, 0x00, 0x00, 0x02, 0x28, 0x00, 0x0d, 0x5f, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_24_1_2 \ + SCC_SNK_24_1, \ + QOS_SNK(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x2d, 0x00, 0x0d, 0x4b, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_24_2_2 \ + SCC_SNK_24_2, \ + QOS_SNK(0x10, 0x27, 0x00, 0x00, 0x02, 0x3c, 0x00, 0x0d, 0x5f, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_32_1_2 \ + SCC_SNK_32_1, \ + QOS_SNK(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x3c, 0x00, 0x0d, 0x4b, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_32_2_2 \ + SCC_SNK_32_2, \ + QOS_SNK(0x10, 0x27, 0x00, 0x00, 0x02, 0x50, 0x00, 0x0d, 0x5f, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_44_1_2 \ + SCC_SNK_44_1, \ + QOS_SNK(0xe3, 0x1f, 0x00, 0x01, 0x02, 0x62, 0x00, 0x0d, 0x50, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_44_2_2 \ + SCC_SNK_44_2, \ + QOS_SNK(0x84, 0x2a, 0x00, 0x01, 0x02, 0x82, 0x00, 0x0d, 0x55, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_48_1_2 \ + SCC_SNK_48_1, \ + QOS_SNK(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x4b, 0x00, 0x0d, 0x4b, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_48_2_2 \ + SCC_SNK_48_2, \ + QOS_SNK(0x10, 0x27, 0x00, 0x00, 0x02, 0x64, 0x00, 0x0d, 0x5f, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_48_3_2 \ + SCC_SNK_48_3, \ + QOS_SNK(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x5a, 0x00, 0x0d, 0x4b, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_48_4_2 \ + SCC_SNK_48_4, \ + QOS_SNK(0x10, 0x27, 0x00, 0x00, 0x02, 0x78, 0x00, 0x0d, 0x64, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_48_5_2 \ + SCC_SNK_48_5, \ + QOS_SNK(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x75, 0x00, 0x0d, 0x4b, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SNK_48_6_2 \ + SCC_SNK_48_6, \ + QOS_SNK(0x10, 0x27, 0x00, 0x00, 0x02, 0x9b, 0x00, 0x0d, 0x64, 0x00, \ + 0x40, 0x9c, 0x00) + +static struct test_config cfg_src_8_1_2 = { + .cc = LC3_CONFIG_8_1, + .qos = LC3_QOS_8_1_2, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_8_2_2 = { + .cc = LC3_CONFIG_8_2, + .qos = LC3_QOS_8_2_2, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_16_1_2 = { + .cc = LC3_CONFIG_16_1, + .qos = LC3_QOS_16_1_2, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_16_2_2 = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_2, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_24_1_2 = { + .cc = LC3_CONFIG_24_1, + .qos = LC3_QOS_24_1_2, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_24_2_2 = { + .cc = LC3_CONFIG_24_2, + .qos = LC3_QOS_24_2_2, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_32_1_2 = { + .cc = LC3_CONFIG_32_1, + .qos = LC3_QOS_32_1_2, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_32_2_2 = { + .cc = LC3_CONFIG_32_2, + .qos = LC3_QOS_32_2_2, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_44_1_2 = { + .cc = LC3_CONFIG_44_1, + .qos = LC3_QOS_44_1_2, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_44_2_2 = { + .cc = LC3_CONFIG_44_2, + .qos = LC3_QOS_44_2_2, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_48_1_2 = { + .cc = LC3_CONFIG_48_1, + .qos = LC3_QOS_48_1_2, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_48_2_2 = { + .cc = LC3_CONFIG_48_2, + .qos = LC3_QOS_48_2_2, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_48_3_2 = { + .cc = LC3_CONFIG_48_3, + .qos = LC3_QOS_48_3_2, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_48_4_2 = { + .cc = LC3_CONFIG_48_4, + .qos = LC3_QOS_48_4_2, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_48_5_2 = { + .cc = LC3_CONFIG_48_5, + .qos = LC3_QOS_48_5_2, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +static struct test_config cfg_src_48_6_2 = { + .cc = LC3_CONFIG_48_6, + .qos = LC3_QOS_48_6_2, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, +}; + +#define SCC_SRC_8_1_2 \ + SCC_SRC_8_1, \ + QOS_SRC(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x1a, 0x00, 0x0d, 0x4b, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_8_2_2 \ + SCC_SRC_8_2, \ + QOS_SRC(0x10, 0x27, 0x00, 0x00, 0x02, 0x1e, 0x00, 0x0d, 0x5f, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_16_1_2 \ + SCC_SRC_16_1, \ + QOS_SRC(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x1e, 0x00, 0x0d, 0x4b, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_16_2_2 \ + SCC_SRC_16_2, \ + QOS_SRC(0x10, 0x27, 0x00, 0x00, 0x02, 0x28, 0x00, 0x0d, 0x5f, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_24_1_2 \ + SCC_SRC_24_1, \ + QOS_SRC(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x2d, 0x00, 0x0d, 0x4b, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_24_2_2 \ + SCC_SRC_24_2, \ + QOS_SRC(0x10, 0x27, 0x00, 0x00, 0x02, 0x3c, 0x00, 0x0d, 0x5f, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_32_1_2 \ + SCC_SRC_32_1, \ + QOS_SRC(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x3c, 0x00, 0x0d, 0x4b, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_32_2_2 \ + SCC_SRC_32_2, \ + QOS_SRC(0x10, 0x27, 0x00, 0x00, 0x02, 0x50, 0x00, 0x0d, 0x5f, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_44_1_2 \ + SCC_SRC_44_1, \ + QOS_SRC(0xe3, 0x1f, 0x00, 0x01, 0x02, 0x62, 0x00, 0x0d, 0x50, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_44_2_2 \ + SCC_SRC_44_2, \ + QOS_SRC(0x84, 0x2a, 0x00, 0x01, 0x02, 0x82, 0x00, 0x0d, 0x55, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_48_1_2 \ + SCC_SRC_48_1, \ + QOS_SRC(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x4b, 0x00, 0x0d, 0x4b, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_48_2_2 \ + SCC_SRC_48_2, \ + QOS_SRC(0x10, 0x27, 0x00, 0x00, 0x02, 0x64, 0x00, 0x0d, 0x5f, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_48_3_2 \ + SCC_SRC_48_3, \ + QOS_SRC(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x5a, 0x00, 0x0d, 0x4b, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_48_4_2 \ + SCC_SRC_48_4, \ + QOS_SRC(0x10, 0x27, 0x00, 0x00, 0x02, 0x78, 0x00, 0x0d, 0x64, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_48_5_2 \ + SCC_SRC_48_5, \ + QOS_SRC(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x75, 0x00, 0x0d, 0x4b, 0x00, \ + 0x40, 0x9c, 0x00) + +#define SCC_SRC_48_6_2 \ + SCC_SRC_48_6, \ + QOS_SRC(0x10, 0x27, 0x00, 0x00, 0x02, 0x9b, 0x00, 0x0d, 0x64, 0x00, \ + 0x40, 0x9c, 0x00) + +/* Test Purpose: + * Verify that a Unicast Client IUT can initiate a Config QoS operation for the + * LC3 codec. + * + * Pass verdict: + * The IUT successfully writes to the ASE Control Point characteristic with the + * opcode set to 0x02 (Config QoS) and the specified parameters. + */ +static void test_scc_qos_lc3(void) +{ + define_test("BAP/UCL/SCC/BV-035-C [UCL SRC Config QoS, LC3 8_1_1]", + test_setup, test_client, &cfg_snk_8_1_1, + SCC_SNK_8_1_1); + define_test("BAP/UCL/SCC/BV-036-C [UCL SRC Config QoS, LC3 8_2_1]", + test_setup, test_client, &cfg_snk_8_2_1, + SCC_SNK_8_2_1); + define_test("BAP/UCL/SCC/BV-037-C [UCL SRC Config QoS, LC3 16_1_1]", + test_setup, test_client, &cfg_snk_16_1_1, + SCC_SNK_16_1_1); + define_test("BAP/UCL/SCC/BV-038-C [UCL SRC Config QoS, LC3 16_2_1]", + test_setup, test_client, &cfg_snk_16_2_1, + SCC_SNK_16_2_1); + define_test("BAP/UCL/SCC/BV-039-C [UCL SRC Config QoS, LC3 24_1_1]", + test_setup, test_client, &cfg_snk_24_1_1, + SCC_SNK_24_1_1); + define_test("BAP/UCL/SCC/BV-040-C [UCL SRC Config QoS, LC3 24_2_1]", + test_setup, test_client, &cfg_snk_24_2_1, + SCC_SNK_24_2_1); + define_test("BAP/UCL/SCC/BV-041-C [UCL SRC Config QoS, LC3 32_1_1]", + test_setup, test_client, &cfg_snk_32_1_1, + SCC_SNK_32_1_1); + define_test("BAP/UCL/SCC/BV-042-C [UCL SRC Config QoS, LC3 32_2_1]", + test_setup, test_client, &cfg_snk_32_2_1, + SCC_SNK_32_2_1); + define_test("BAP/UCL/SCC/BV-043-C [UCL SRC Config QoS, LC3 44.1_1_1]", + test_setup, test_client, &cfg_snk_44_1_1, + SCC_SNK_44_1_1); + define_test("BAP/UCL/SCC/BV-044-C [UCL SRC Config QoS, LC3 44.1_2_1]", + test_setup, test_client, &cfg_snk_44_2_1, + SCC_SNK_44_2_1); + define_test("BAP/UCL/SCC/BV-045-C [UCL SRC Config QoS, LC3 48_1_1]", + test_setup, test_client, &cfg_snk_48_1_1, + SCC_SNK_48_1_1); + define_test("BAP/UCL/SCC/BV-046-C [UCL SRC Config QoS, LC3 48_2_1]", + test_setup, test_client, &cfg_snk_48_2_1, + SCC_SNK_48_2_1); + define_test("BAP/UCL/SCC/BV-047-C [UCL SRC Config QoS, LC3 48_3_1]", + test_setup, test_client, &cfg_snk_48_3_1, + SCC_SNK_48_3_1); + define_test("BAP/UCL/SCC/BV-048-C [UCL SRC Config QoS, LC3 48_4_1]", + test_setup, test_client, &cfg_snk_48_4_1, + SCC_SNK_48_4_1); + define_test("BAP/UCL/SCC/BV-049-C [UCL SRC Config QoS, LC3 48_5_1]", + test_setup, test_client, &cfg_snk_48_5_1, + SCC_SNK_48_5_1); + define_test("BAP/UCL/SCC/BV-050-C [UCL SRC Config QoS, LC3 48_6_1]", + test_setup, test_client, &cfg_snk_48_6_1, + SCC_SNK_48_6_1); + define_test("BAP/UCL/SCC/BV-051-C [UCL SNK Config QoS, LC3 8_1_1]", + test_setup, test_client, &cfg_src_8_1_1, + SCC_SRC_8_1_1); + define_test("BAP/UCL/SCC/BV-052-C [UCL SNK Config QoS, LC3 8_2_1]", + test_setup, test_client, &cfg_src_8_2_1, + SCC_SRC_8_2_1); + define_test("BAP/UCL/SCC/BV-053-C [UCL SNK Config QoS, LC3 16_1_1]", + test_setup, test_client, &cfg_src_16_1_1, + SCC_SRC_16_1_1); + define_test("BAP/UCL/SCC/BV-054-C [UCL SNK Config QoS, LC3 16_2_1]", + test_setup, test_client, &cfg_src_16_2_1, + SCC_SRC_16_2_1); + define_test("BAP/UCL/SCC/BV-055-C [UCL SNK Config QoS, LC3 24_1_1]", + test_setup, test_client, &cfg_src_24_1_1, + SCC_SRC_24_1_1); + define_test("BAP/UCL/SCC/BV-056-C [UCL SNK Config QoS, LC3 24_2_1]", + test_setup, test_client, &cfg_src_24_2_1, + SCC_SRC_24_2_1); + define_test("BAP/UCL/SCC/BV-057-C [UCL SNK Config QoS, LC3 32_1_1]", + test_setup, test_client, &cfg_src_32_1_1, + SCC_SRC_32_1_1); + define_test("BAP/UCL/SCC/BV-058-C [UCL SNK Config QoS, LC3 32_2_1]", + test_setup, test_client, &cfg_src_32_2_1, + SCC_SRC_32_2_1); + define_test("BAP/UCL/SCC/BV-059-C [UCL SNK Config QoS, LC3 44.1_1_1]", + test_setup, test_client, &cfg_src_44_1_1, + SCC_SRC_44_1_1); + define_test("BAP/UCL/SCC/BV-060-C [UCL SNK Config QoS, LC3 44.1_2_1]", + test_setup, test_client, &cfg_src_44_2_1, + SCC_SRC_44_2_1); + define_test("BAP/UCL/SCC/BV-061-C [UCL SNK Config QoS, LC3 48_1_1]", + test_setup, test_client, &cfg_src_48_1_1, + SCC_SRC_48_1_1); + define_test("BAP/UCL/SCC/BV-062-C [UCL SNK Config QoS, LC3 48_2_1]", + test_setup, test_client, &cfg_src_48_2_1, + SCC_SRC_48_2_1); + define_test("BAP/UCL/SCC/BV-063-C [UCL SNK Config QoS, LC3 48_3_1]", + test_setup, test_client, &cfg_src_48_3_1, + SCC_SRC_48_3_1); + define_test("BAP/UCL/SCC/BV-064-C [UCL SNK Config QoS, LC3 48_4_1]", + test_setup, test_client, &cfg_src_48_4_1, + SCC_SRC_48_4_1); + define_test("BAP/UCL/SCC/BV-065-C [UCL SNK Config QoS, LC3 48_5_1]", + test_setup, test_client, &cfg_src_48_5_1, + SCC_SRC_48_5_1); + define_test("BAP/UCL/SCC/BV-066-C [UCL SNK Config QoS, LC3 48_6_1]", + test_setup, test_client, &cfg_src_48_6_1, + SCC_SRC_48_6_1); + define_test("BAP/UCL/SCC/BV-067-C [UCL SRC Config QoS, LC3 8_1_2]", + test_setup, test_client, &cfg_snk_8_1_2, + SCC_SNK_8_1_2); + define_test("BAP/UCL/SCC/BV-068-C [UCL SRC Config QoS, LC3 8_2_2]", + test_setup, test_client, &cfg_snk_8_2_2, + SCC_SNK_8_2_2); + define_test("BAP/UCL/SCC/BV-069-C [UCL SRC Config QoS, LC3 16_1_2]", + test_setup, test_client, &cfg_snk_16_1_2, + SCC_SNK_16_1_2); + define_test("BAP/UCL/SCC/BV-070-C [UCL SRC Config QoS, LC3 16_2_2]", + test_setup, test_client, &cfg_snk_16_2_2, + SCC_SNK_16_2_2); + define_test("BAP/UCL/SCC/BV-071-C [UCL SRC Config QoS, LC3 24_1_2]", + test_setup, test_client, &cfg_snk_24_1_2, + SCC_SNK_24_1_2); + define_test("BAP/UCL/SCC/BV-072-C [UCL SRC Config QoS, LC3 24_2_2]", + test_setup, test_client, &cfg_snk_24_2_2, + SCC_SNK_24_2_2); + define_test("BAP/UCL/SCC/BV-073-C [UCL SRC Config QoS, LC3 32_1_2]", + test_setup, test_client, &cfg_snk_32_1_2, + SCC_SNK_32_1_2); + define_test("BAP/UCL/SCC/BV-074-C [UCL SRC Config QoS, LC3 32_2_2]", + test_setup, test_client, &cfg_snk_32_2_2, + SCC_SNK_32_2_2); + define_test("BAP/UCL/SCC/BV-075-C [UCL SRC Config QoS, LC3 44.1_1_2]", + test_setup, test_client, &cfg_snk_44_1_2, + SCC_SNK_44_1_2); + define_test("BAP/UCL/SCC/BV-076-C [UCL SRC Config QoS, LC3 44.1_2_2]", + test_setup, test_client, &cfg_snk_44_2_2, + SCC_SNK_44_2_2); + define_test("BAP/UCL/SCC/BV-077-C [UCL SRC Config QoS, LC3 48_1_2]", + test_setup, test_client, &cfg_snk_48_1_2, + SCC_SNK_48_1_2); + define_test("BAP/UCL/SCC/BV-078-C [UCL SRC Config QoS, LC3 48_2_2]", + test_setup, test_client, &cfg_snk_48_2_2, + SCC_SNK_48_2_2); + define_test("BAP/UCL/SCC/BV-079-C [UCL SRC Config QoS, LC3 48_3_2]", + test_setup, test_client, &cfg_snk_48_3_2, + SCC_SNK_48_3_2); + define_test("BAP/UCL/SCC/BV-080-C [UCL SRC Config QoS, LC3 48_4_2]", + test_setup, test_client, &cfg_snk_48_4_2, + SCC_SNK_48_4_2); + define_test("BAP/UCL/SCC/BV-081-C [UCL SRC Config QoS, LC3 48_5_2]", + test_setup, test_client, &cfg_snk_48_5_2, + SCC_SNK_48_5_2); + define_test("BAP/UCL/SCC/BV-082-C [UCL SRC Config QoS, LC3 48_6_2]", + test_setup, test_client, &cfg_snk_48_6_2, + SCC_SNK_48_6_2); + define_test("BAP/UCL/SCC/BV-083-C [UCL SNK Config QoS, LC3 8_1_2]", + test_setup, test_client, &cfg_src_8_1_2, + SCC_SRC_8_1_2); + define_test("BAP/UCL/SCC/BV-084-C [UCL SNK Config QoS, LC3 8_2_2]", + test_setup, test_client, &cfg_src_8_2_2, + SCC_SRC_8_2_2); + define_test("BAP/UCL/SCC/BV-085-C [UCL SNK Config QoS, LC3 16_1_2]", + test_setup, test_client, &cfg_src_16_1_2, + SCC_SRC_16_1_2); + define_test("BAP/UCL/SCC/BV-086-C [UCL SNK Config QoS, LC3 16_2_2]", + test_setup, test_client, &cfg_src_16_2_2, + SCC_SRC_16_2_2); + define_test("BAP/UCL/SCC/BV-087-C [UCL SNK Config QoS, LC3 24_1_2]", + test_setup, test_client, &cfg_src_24_1_2, + SCC_SRC_24_1_2); + define_test("BAP/UCL/SCC/BV-088-C [UCL SNK Config QoS, LC3 24_2_2]", + test_setup, test_client, &cfg_src_24_2_2, + SCC_SRC_24_2_2); + define_test("BAP/UCL/SCC/BV-089-C [UCL SNK Config QoS, LC3 32_1_2]", + test_setup, test_client, &cfg_src_32_1_2, + SCC_SRC_32_1_2); + define_test("BAP/UCL/SCC/BV-090-C [UCL SNK Config QoS, LC3 32_2_2]", + test_setup, test_client, &cfg_src_32_2_2, + SCC_SRC_32_2_2); + define_test("BAP/UCL/SCC/BV-091-C [UCL SNK Config QoS, LC3 44.1_1_2]", + test_setup, test_client, &cfg_src_44_1_2, + SCC_SRC_44_1_2); + define_test("BAP/UCL/SCC/BV-092-C [UCL SNK Config QoS, LC3 44.1_2_2]", + test_setup, test_client, &cfg_src_44_2_2, + SCC_SRC_44_2_2); + define_test("BAP/UCL/SCC/BV-093-C [UCL SNK Config QoS, LC3 48_1_2]", + test_setup, test_client, &cfg_src_48_1_2, + SCC_SRC_48_1_2); + define_test("BAP/UCL/SCC/BV-094-C [UCL SNK Config QoS, LC3 48_2_2]", + test_setup, test_client, &cfg_src_48_2_2, + SCC_SRC_48_2_2); + define_test("BAP/UCL/SCC/BV-095-C [UCL SNK Config QoS, LC3 48_3_2]", + test_setup, test_client, &cfg_src_48_3_2, + SCC_SRC_48_3_2); + define_test("BAP/UCL/SCC/BV-096-C [UCL SNK Config QoS, LC3 48_4_2]", + test_setup, test_client, &cfg_src_48_4_2, + SCC_SRC_48_4_2); + define_test("BAP/UCL/SCC/BV-097-C [UCL SNK Config QoS, LC3 48_5_2]", + test_setup, test_client, &cfg_src_48_5_2, + SCC_SRC_48_5_2); + define_test("BAP/UCL/SCC/BV-098-C [UCL SNK Config QoS, LC3 48_6_2]", + test_setup, test_client, &cfg_src_48_6_2, + SCC_SRC_48_6_2); +} + +static struct test_config cfg_snk_qos_vs = { + .cc = IOV_NULL, + .qos = QOS_UCAST, + .snk = true, + .vs = true, + .state = BT_BAP_STREAM_STATE_QOS +}; + +#define SCC_SNK_QOS_VS \ + SCC_SNK_VS, \ + QOS_SNK(0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00) + +static struct test_config cfg_src_qos_vs = { + .cc = IOV_NULL, + .qos = QOS_UCAST, + .src = true, + .vs = true, + .state = BT_BAP_STREAM_STATE_QOS +}; + +#define SCC_SRC_QOS_VS \ + SCC_SRC_VS, \ + QOS_SRC(0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00) + +/* Test Purpose: + * Verify that a Unicast Client IUT can initiate a Config QoS operation for a + * vendor-specific codec. + * + * Pass verdict: + * The IUT successfully writes to the ASE Control Point characteristic with the + * opcode set to 0x02 (Config QoS) and the specified parameters. + */ +static void test_scc_qos_vs(void) +{ + define_test("BAP/UCL/SCC/BV-099-C [UCL SNK Config QoS, VS]", + test_setup, test_client, &cfg_src_qos_vs, + SCC_SRC_QOS_VS); + define_test("BAP/UCL/SCC/BV-100-C [UCL SRC QoS Codec, VS]", + test_setup, test_client, &cfg_snk_qos_vs, + SCC_SNK_QOS_VS); +} + +static struct test_config cfg_snk_enable = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_ENABLING +}; + +/* ATT: Write Command (0x52) len 23 + * Handle: 0x0022 + * Data: 03010104030201 + * ATT: Handle Value Notification (0x1b) len 7 + * Handle: 0x0022 + * Data: 0301010000 + * ATT: Handle Value Notification (0x1b) len 37 + * Handle: 0x0016 + * Data: 0101010300403020100 + */ +#define SCC_SNK_ENABLE \ + SCC_SNK_16_2_1, \ + IOV_DATA(0x52, 0x22, 0x00, 0x03, 0x01, 0x01, 0x04, 0x03, 0x02, 0x01, \ + 00), \ + IOV_DATA(0x1b, 0x22, 0x00, 0x03, 0x01, 0x01, 0x00, 0x00), \ + IOV_NULL, \ + IOV_DATA(0x1b, 0x16, 0x00, 0x01, 0x03, 0x00, 0x00, 0x04, 0x03, 0x02, \ + 0x01, 0x00) + +static struct test_config cfg_src_enable = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1, + .src = true, + .state = BT_BAP_STREAM_STATE_ENABLING +}; + +/* ATT: Write Command (0x52) len 23 + * Handle: 0x0022 + * Data: 0301030403020100 + * ATT: Handle Value Notification (0x1b) len 7 + * Handle: 0x0022 + * Data: 0301030000 + * ATT: Handle Value Notification (0x1b) len 37 + * Handle: 0x001c + * Data: 030300000403020100 + */ +#define SRC_ENABLE \ + IOV_DATA(0x52, 0x22, 0x00, 0x03, 0x01, 0x03, 0x04, 0x03, 0x02, 0x01, \ + 00), \ + IOV_DATA(0x1b, 0x22, 0x00, 0x03, 0x01, 0x01, 0x00, 0x00), \ + IOV_NULL, \ + IOV_DATA(0x1b, 0x1c, 0x00, 0x03, 0x03, 0x00, 0x00, 0x04, 0x03, 0x02, \ + 0x01, 0x00) + +#define SCC_SRC_ENABLE \ + SCC_SRC_16_2_1, \ + SRC_ENABLE + +/* Test Purpose: + * Verify that a Unicast Client IUT can initiate an Enable operation for an ASE + * with a Unicast Server that is either in the Audio Sink role or the Audio + * Source role. + * + * Pass verdict: + * The IUT successfully writes to the ASE Control Point characteristic with the + * opcode set to 0x03 (Enable) and the specified parameters. + */ +static void test_scc_enable(void) +{ + define_test("BAP/UCL/SCC/BV-101-C [UCL SRC Enable]", + test_setup, test_client, &cfg_snk_enable, + SCC_SNK_ENABLE); + define_test("BAP/UCL/SCC/BV-102-C [UCL SNK Enable]", + test_setup, test_client, &cfg_src_enable, + SCC_SRC_ENABLE); +} + +static struct test_config cfg_snk_disable = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_DISABLING +}; + +/* ATT: Write Command (0x52) len 23 + * Handle: 0x0022 + * Data: 050101 + * ATT: Handle Value Notification (0x1b) len 7 + * Handle: 0x0022 + * Data: 0501010000 + * ATT: Handle Value Notification (0x1b) len 37 + * Handle: 0x0016 + * Data: 01010102010a00204e00409c00204e00409c00_qos + */ +#define ASE_SNK_DISABLE \ + IOV_DATA(0x52, 0x22, 0x00, 0x05, 0x01, 0x01), \ + IOV_DATA(0x1b, 0x22, 0x00, 0x05, 0x01, 0x01, 0x00, 0x00), \ + IOV_NULL, \ + IOV_DATA(0x1b, 0x16, 0x00, 0x01, 0x02, 0x00, 0x00, 0x4c, 0x1d, 0x00, \ + 0x00, 0x02, 0x1a, 0x00, 0x02, 0x08, 0x00, 0x40, 0x9c, \ + 0x00) + +#define SCC_SNK_DISABLE \ + SCC_SNK_ENABLE, \ + ASE_SNK_DISABLE + +static struct test_config cfg_src_disable = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1, + .src = true, + .state = BT_BAP_STREAM_STATE_DISABLING +}; + +/* ATT: Write Command (0x52) len 23 + * Handle: 0x0022 + * Data: 050103 + * ATT: Handle Value Notification (0x1b) len 7 + * Handle: 0x0022 + * Data: 0301030000 + * ATT: Handle Value Notification (0x1b) len 37 + * Handle: 0x001c + * Data: 030300000403020100 + */ +#define ASE_SRC_DISABLE \ + IOV_DATA(0x52, 0x22, 0x00, 0x05, 0x01, 0x03), \ + IOV_DATA(0x1b, 0x22, 0x00, 0x05, 0x01, 0x03, 0x00, 0x00), \ + IOV_NULL, \ + IOV_DATA(0x1b, 0x1c, 0x00, 0x03, 0x05, 0x00, 0x00, 0x4c, 0x1d, 0x00, \ + 0x00, 0x02, 0x1a, 0x00, 0x04, 0x08, 0x00, 0x40, 0x9c, \ + 0x00) +#define SCC_SRC_DISABLE \ + SCC_SRC_ENABLE, \ + ASE_SRC_DISABLE + +static void state_start_disable(struct bt_bap_stream *stream, + uint8_t old_state, uint8_t new_state, + void *user_data) +{ + struct test_data *data = user_data; + uint8_t id; + + switch (new_state) { + case BT_BAP_STREAM_STATE_STREAMING: + id = bt_bap_stream_disable(stream, true, bap_disable, + data); + g_assert(id); + break; + } +} + +static struct test_config cfg_src_disable_streaming = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1, + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, + .state_func = state_start_disable +}; + +/* ATT: Write Command (0x52) len 23 + * Handle: 0x0022 + * Data: 040101 + * ATT: Handle Value Notification (0x1b) len 7 + * Handle: 0x0022 + * Data: 0401010000 + * ATT: Handle Value Notification (0x1b) len 37 + * Handle: 0x0016 + * Data: 0101010400403020100 + */ +#define SRC_START \ + IOV_DATA(0x52, 0x22, 0x00, 0x04, 0x01, 0x03), \ + IOV_DATA(0x1b, 0x22, 0x00, 0x04, 0x01, 0x03, 0x00, 0x00), \ + IOV_NULL, \ + IOV_DATA(0x1b, 0x1c, 0x00, 0x03, 0x04, 0x00, 0x00, 0x04, 0x03, 0x02, \ + 0x01, 0x00) + +#define SCC_SRC_DISABLE_STREAMING \ + SCC_SRC_ENABLE, \ + SRC_START, \ + ASE_SRC_DISABLE + +/* Test Purpose: + * Verify that a Unicast Client IUT can initiate a Disable operation for an ASE + * in the Enabling or Streaming state. + * + * Pass verdict: + * The IUT successfully writes to the ASE Control Point characteristic with the + * opcode set to 0x05 (Disable) and the specified parameters. + */ +static void test_scc_disable(void) +{ + define_test("BAP/UCL/SCC/BV-103-C [UCL SNK Disable in Enabling State]", + test_setup, test_client, &cfg_src_disable, + SCC_SRC_DISABLE); + define_test("BAP/UCL/SCC/BV-104-C [UCL SRC Disable in Enabling or " + "Streaming state]", + test_setup, test_client, &cfg_snk_disable, + SCC_SNK_DISABLE); + define_test("BAP/UCL/SCC/BV-105-C [UCL SNK Disable in Streaming State]", + test_setup, test_client, &cfg_src_disable_streaming, + SCC_SRC_DISABLE_STREAMING); +} + +static void bap_release(struct bt_bap_stream *stream, + uint8_t code, uint8_t reason, + void *user_data) +{ + if (code) + tester_test_failed(); +} + +static void state_cc_release(struct bt_bap_stream *stream, + uint8_t old_state, uint8_t new_state, + void *user_data) +{ + struct test_data *data = user_data; + uint8_t id; + + switch (new_state) { + case BT_BAP_STREAM_STATE_CONFIG: + id = bt_bap_stream_release(stream, bap_release, data); + g_assert(id); + break; + } +} + +static struct test_config cfg_src_cc_release = { + .cc = LC3_CONFIG_16_2, + .qos = QOS_UCAST, + .src = true, + .state_func = state_cc_release, +}; + +/* ATT: Write Command (0x52) len 23 + * Handle: 0x0022 + * Data: 080103 + * ATT: Handle Value Notification (0x1b) len 7 + * Handle: 0x0022 + * Data: 0801030000 + * ATT: Handle Value Notification (0x1b) len 37 + * Handle: 0x001c + * Data: 0300 + */ +#define ASE_SRC_RELEASE \ + IOV_DATA(0x52, 0x22, 0x00, 0x08, 0x01, 0x03), \ + IOV_DATA(0x1b, 0x22, 0x00, 0x08, 0x01, 0x03, 0x00, 0x00), \ + IOV_NULL, \ + IOV_DATA(0x1b, 0x1c, 0x00, 0x03, 0x00) + +#define SCC_SRC_CC_RELEASE \ + SCC_SRC_16_2, \ + ASE_SRC_RELEASE + +static struct test_config cfg_snk_cc_release = { + .cc = LC3_CONFIG_16_2, + .qos = QOS_UCAST, + .snk = true, + .state_func = state_cc_release, +}; + +/* ATT: Write Command (0x52) len 23 + * Handle: 0x0022 + * Data: 080101 + * ATT: Handle Value Notification (0x1b) len 7 + * Handle: 0x0022 + * Data: 0801010000 + * ATT: Handle Value Notification (0x1b) len 37 + * Handle: 0x0016 + * Data: 0300 + */ +#define ASE_SNK_RELEASE \ + IOV_DATA(0x52, 0x22, 0x00, 0x08, 0x01, 0x01), \ + IOV_DATA(0x1b, 0x22, 0x00, 0x08, 0x01, 0x01, 0x00, 0x00), \ + IOV_NULL, \ + IOV_DATA(0x1b, 0x16, 0x00, 0x03, 0x00) + +#define SCC_SNK_CC_RELEASE \ + SCC_SNK_16_2, \ + ASE_SNK_RELEASE + +static void state_qos_release(struct bt_bap_stream *stream, + uint8_t old_state, uint8_t new_state, + void *user_data) +{ + struct test_data *data = user_data; + uint8_t id; + + switch (new_state) { + case BT_BAP_STREAM_STATE_QOS: + id = bt_bap_stream_release(stream, bap_release, data); + g_assert(id); + break; + } +} + +static struct test_config cfg_src_qos_release = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1, + .src = true, + .state = BT_BAP_STREAM_STATE_QOS, + .state_func = state_qos_release, +}; + +#define SCC_SRC_QOS_RELEASE \ + SCC_SRC_16_2_1, \ + ASE_SRC_RELEASE + +static struct test_config cfg_snk_qos_release = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_QOS, + .state_func = state_qos_release, +}; + +#define SCC_SNK_QOS_RELEASE \ + SCC_SNK_16_2_1, \ + ASE_SNK_RELEASE + +static void state_enable_release(struct bt_bap_stream *stream, + uint8_t old_state, uint8_t new_state, + void *user_data) +{ + struct test_data *data = user_data; + uint8_t id; + + switch (new_state) { + case BT_BAP_STREAM_STATE_ENABLING: + id = bt_bap_stream_release(stream, bap_release, data); + g_assert(id); + break; + } +} + +static struct test_config cfg_src_enable_release = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1, + .src = true, + .state = BT_BAP_STREAM_STATE_ENABLING, + .state_func = state_enable_release, +}; + +#define SCC_SRC_ENABLE_RELEASE \ + SCC_SRC_ENABLE, \ + ASE_SRC_RELEASE + +static struct test_config cfg_snk_enable_release = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_ENABLING, + .state_func = state_enable_release, +}; + +#define SCC_SNK_ENABLE_RELEASE \ + SCC_SNK_ENABLE, \ + ASE_SNK_RELEASE + +static void state_start_release(struct bt_bap_stream *stream, + uint8_t old_state, uint8_t new_state, + void *user_data) +{ + struct test_data *data = user_data; + uint8_t id; + + switch (new_state) { + case BT_BAP_STREAM_STATE_STREAMING: + id = bt_bap_stream_release(stream, bap_release, data); + g_assert(id); + break; + } +} + +static struct test_config cfg_src_start_release = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1, + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, + .state_func = state_start_release, +}; + +#define SCC_SRC_START_RELEASE \ + SCC_SRC_ENABLE, \ + SRC_START, \ + ASE_SRC_RELEASE + +static void state_disable_release(struct bt_bap_stream *stream, + uint8_t old_state, uint8_t new_state, + void *user_data) +{ + struct test_data *data = user_data; + uint8_t id; + + switch (new_state) { + case BT_BAP_STREAM_STATE_DISABLING: + id = bt_bap_stream_release(stream, bap_release, data); + g_assert(id); + break; + } +} + +static struct test_config cfg_src_disable_release = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1, + .src = true, + .state = BT_BAP_STREAM_STATE_DISABLING, + .state_func = state_disable_release, +}; + +#define SCC_SRC_DISABLE_RELEASE \ + SCC_SRC_DISABLE, \ + ASE_SRC_RELEASE + +/* Test Purpose: + * Verify that a Unicast Client IUT can release an ASE by initiating a Release + * operation. + * + * Pass verdict: + * The IUT successfully writes to the ASE Control Point characteristic with the + * opcode set to 0x08 (Release) and the specified parameters. + */ +static void test_scc_release(void) +{ + define_test("BAP/UCL/SCC/BV-106-C [UCL SNK Release in Codec Configured" + " state]", + test_setup, test_client, &cfg_src_cc_release, + SCC_SRC_CC_RELEASE); + define_test("BAP/UCL/SCC/BV-107-C [UCL SRC Release in Codec Configured" + " state]", + test_setup, test_client, &cfg_snk_cc_release, + SCC_SNK_CC_RELEASE); + define_test("BAP/UCL/SCC/BV-108-C [UCL SNK Release in QoS Configured" + " state]", + test_setup, test_client, &cfg_src_qos_release, + SCC_SRC_QOS_RELEASE); + define_test("BAP/UCL/SCC/BV-109-C [UCL SRC Release in QoS Configured" + " state]", + test_setup, test_client, &cfg_snk_qos_release, + SCC_SNK_QOS_RELEASE); + define_test("BAP/UCL/SCC/BV-110-C [UCL SNK Release in Enabling state]", + test_setup, test_client, &cfg_src_enable_release, + SCC_SRC_ENABLE_RELEASE); + define_test("BAP/UCL/SCC/BV-111-C [UCL SRC Release in Enabling or" + " Streaming state]", + test_setup, test_client, &cfg_snk_enable_release, + SCC_SNK_ENABLE_RELEASE); + define_test("BAP/UCL/SCC/BV-112-C [UCL SNK Release in Streaming state]", + test_setup, test_client, &cfg_src_start_release, + SCC_SRC_START_RELEASE); + define_test("BAP/UCL/SCC/BV-113-C [UCL SNK Release in Disabling state]", + test_setup, test_client, &cfg_src_disable_release, + SCC_SRC_DISABLE_RELEASE); +} + +static void bap_metadata(struct bt_bap_stream *stream, + uint8_t code, uint8_t reason, + void *user_data) +{ + if (code) + tester_test_failed(); +} + +static void state_enable_metadata(struct bt_bap_stream *stream, + uint8_t old_state, uint8_t new_state, + void *user_data) +{ + struct test_data *data = user_data; + struct iovec iov = {}; + uint8_t id; + + switch (new_state) { + case BT_BAP_STREAM_STATE_ENABLING: + id = bt_bap_stream_metadata(stream, &iov, bap_metadata, + data); + g_assert(id); + break; + } +} + +static struct test_config cfg_snk_metadata = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1, + .snk = true, + .state = BT_BAP_STREAM_STATE_ENABLING, + .state_func = state_enable_metadata +}; + +/* ATT: Write Command (0x52) len 23 + * Handle: 0x0022 + * Data: 07010100 + * ATT: Handle Value Notification (0x1b) len 7 + * Handle: 0x0022 + * Data: 0701010000 + * ATT: Handle Value Notification (0x1b) len 37 + * Handle: 0x0016 + * Data: 01010102010a00204e00409c00204e00409c00_qos + */ +#define ASE_SNK_METADATA \ + IOV_DATA(0x52, 0x22, 0x00, 0x07, 0x01, 0x01, 0x00), \ + IOV_DATA(0x1b, 0x22, 0x00, 0x07, 0x01, 0x01, 0x00, 0x00), \ + IOV_NULL, \ + IOV_DATA(0x1b, 0x16, 0x00, 0x01, 0x05, 0x00, 0x00, 0x4c, 0x1d, 0x00, \ + 0x00, 0x02, 0x1a, 0x00, 0x02, 0x08, 0x00, 0x40, 0x9c, \ + 0x00) + +#define SCC_SNK_METADATA \ + SCC_SNK_ENABLE, \ + ASE_SNK_METADATA + +static struct test_config cfg_src_metadata = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1, + .src = true, + .state = BT_BAP_STREAM_STATE_ENABLING, + .state_func = state_enable_metadata +}; + +/* ATT: Write Command (0x52) len 23 + * Handle: 0x0022 + * Data: 07010300 + * ATT: Handle Value Notification (0x1b) len 7 + * Handle: 0x0022 + * Data: 0701030000 + * ATT: Handle Value Notification (0x1b) len 37 + * Handle: 0x001c + * Data: 030300000403020100 + */ +#define ASE_SRC_METADATA \ + IOV_DATA(0x52, 0x22, 0x00, 0x07, 0x01, 0x03, 0x00), \ + IOV_DATA(0x1b, 0x22, 0x00, 0x07, 0x01, 0x03, 0x00, 0x00), \ + IOV_NULL, \ + IOV_DATA(0x1b, 0x1c, 0x00, 0x03, 0x05, 0x00, 0x00, 0x4c, 0x1d, 0x00, \ + 0x00, 0x02, 0x1a, 0x00, 0x04, 0x08, 0x00, 0x40, 0x9c, \ + 0x00) +#define SCC_SRC_METADATA \ + SCC_SRC_ENABLE, \ + ASE_SRC_METADATA + +static void state_start_metadata(struct bt_bap_stream *stream, + uint8_t old_state, uint8_t new_state, + void *user_data) +{ + struct test_data *data = user_data; + struct iovec iov = {}; + uint8_t id; + + switch (new_state) { + case BT_BAP_STREAM_STATE_STREAMING: + id = bt_bap_stream_metadata(stream, &iov, bap_metadata, + data); + g_assert(id); + break; + } +} + +static struct test_config cfg_src_metadata_streaming = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1, + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, + .state_func = state_start_metadata +}; + +#define SCC_SRC_METADATA_STREAMING \ + SCC_SRC_ENABLE, \ + SRC_START, \ + ASE_SRC_METADATA + +/* Unicast Client Initiates Update Metadata Operation + * + * Test Purpose: + * Verify that a Unicast Client IUT can update the Metadata of an ASE by + * initiating an Update Metadata operation. + * + * Pass verdict: + * The IUT successfully writes to the ASE Control Point characteristic with the + * opcode set to 0x07 (Update Metadata) and the specified parameters. + */ +static void test_scc_metadata(void) +{ + define_test("BAP/UCL/SCC/BV-115-C [UCL SNK Update Metadata in Enabling " + "State]", + test_setup, test_client, &cfg_src_metadata, + SCC_SRC_METADATA); + define_test("BAP/UCL/SCC/BV-116-C [UCL SRC Update Metadata in Enabling " + "or Streaming state]", + test_setup, test_client, &cfg_snk_metadata, + SCC_SNK_METADATA); + define_test("BAP/UCL/SCC/BV-117-C [UCL SNK Update Metadata in Streaming" + " State]", + test_setup, test_client, &cfg_src_metadata_streaming, + SCC_SRC_METADATA_STREAMING); +} + +#define SNK_ENABLE \ + IOV_DATA(0x52, 0x22, 0x00, 0x03, 0x01, 0x01, 0x04, 0x03, 0x02, 0x01, \ + 00), \ + IOV_DATA(0x1b, 0x22, 0x00, 0x03, 0x01, 0x01, 0x00, 0x00), \ + IOV_NULL, \ + IOV_DATA(0x1b, 0x16, 0x00, 0x01, 0x03, 0x00, 0x00, 0x04, 0x03, 0x02, \ + 0x01, 0x00) + +#define SNK_START \ + IOV_NULL, \ + IOV_DATA(0x1b, 0x16, 0x00, 0x01, 0x04, 0x00, 0x00, 0x04, 0x03, 0x02, \ + 0x01, 0x00) + +static struct test_config str_snk_ac2_8_1_1 = { + .cc = LC3_CONFIG_8_1_AC(1), + .qos = LC3_QOS_8_1_1_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK(_freq, _ac, _dur, _len) \ + SCC_SNK_LC3(0x10, 0x02, 0x01, _freq, 0x02, 0x02, _dur, 0x03, 0x04, \ + _len, _len >> 8, 0x05, 0x03, _ac, 0x00, 0x00, 0x00) + +#define STR_SNK_8(_ac, _dur, _len) \ + STR_SNK(LC3_CONFIG_FREQ_8KHZ, _ac, _dur, _len) + +#define STR_SNK_8_1(_ac) \ + STR_SNK_8(_ac, LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_8_1) + +#define STR_SNK_QOS(_interval, _frame, _sdu, _rtn, _latency) \ + QOS_SNK(_interval & 0xff, _interval >> 8 & 0xff, \ + _interval >> 16 & 0xff, _frame, 0x02, _sdu & 0xff, \ + _sdu >> 8 & 0xff, _rtn, \ + _latency, _latency >> 8, 0x40, 0x9c, 0x00) + +#define STR_SNK_QOS_1(_sdu, _rtn, _latency) \ + STR_SNK_QOS(7500u, LC3_QOS_UNFRAMED, _sdu, _rtn, _latency) + +#define STR_SNK_8_1_1(_chans) \ + STR_SNK_8_1((BIT(_chans) - 1)), \ + STR_SNK_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_8_1, LC3_QOS_8_1_1_RTN, \ + LC3_QOS_8_1_1_LATENCY) + +#define STR_SNK_AC2_8_1_1 \ + STR_SNK_8_1_1(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_8_1_1 = { + .cc = LC3_CONFIG_8_1_AC(2), + .qos = LC3_QOS_8_1_1_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_8_1_1 \ + STR_SNK_8_1_1(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_8_2_1 = { + .cc = LC3_CONFIG_8_2_AC(1), + .qos = LC3_QOS_8_2_1_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_8_2(_ac) \ + STR_SNK_8(_ac, LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_8_2) + +#define STR_SNK_QOS_2(_sdu, _rtn, _latency) \ + STR_SNK_QOS(10000u, LC3_QOS_UNFRAMED, _sdu, _rtn, _latency) + +#define STR_SNK_8_2_1(_chans) \ + STR_SNK_8_2((BIT(_chans) - 1)), \ + STR_SNK_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_8_2, LC3_QOS_8_2_1_RTN, \ + LC3_QOS_8_2_1_LATENCY) + +#define STR_SNK_AC2_8_2_1 \ + STR_SNK_8_2_1(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_8_2_1 = { + .cc = LC3_CONFIG_8_2_AC(2), + .qos = LC3_QOS_8_2_1_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_8_2_1 \ + STR_SNK_8_2_1(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_8_1_2 = { + .cc = LC3_CONFIG_8_1_AC(1), + .qos = LC3_QOS_8_1_2_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_8_1_2(_chans) \ + STR_SNK_8_1((BIT(_chans) - 1)), \ + STR_SNK_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_8_1, LC3_QOS_8_1_2_RTN, \ + LC3_QOS_8_1_2_LATENCY) + +#define STR_SNK_AC2_8_1_2 \ + STR_SNK_8_1_2(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_8_1_2 = { + .cc = LC3_CONFIG_8_1_AC(2), + .qos = LC3_QOS_8_1_2_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_8_1_2 \ + STR_SNK_8_1_2(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_8_2_2 = { + .cc = LC3_CONFIG_8_2_AC(1), + .qos = LC3_QOS_8_2_2_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_8_2_2(_chans) \ + STR_SNK_8_2((BIT(_chans) - 1)), \ + STR_SNK_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_8_2, LC3_QOS_8_2_2_RTN, \ + LC3_QOS_8_2_2_LATENCY) + +#define STR_SNK_AC2_8_2_2 \ + STR_SNK_8_2_2(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_8_2_2 = { + .cc = LC3_CONFIG_8_2_AC(2), + .qos = LC3_QOS_8_2_2_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_8_2_2 \ + STR_SNK_8_2_2(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_16_1_1 = { + .cc = LC3_CONFIG_16_1_AC(1), + .qos = LC3_QOS_16_1_1_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_16(_ac, _dur, _len) \ + STR_SNK(LC3_CONFIG_FREQ_16KHZ, _ac, _dur, _len) + +#define STR_SNK_16_1(_ac) \ + STR_SNK_16(_ac, LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_16_1) + +#define STR_SNK_16_1_1(_chans) \ + STR_SNK_16_1((BIT(_chans) - 1)), \ + STR_SNK_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_16_1, LC3_QOS_16_1_1_RTN, \ + LC3_QOS_16_1_1_LATENCY) + +#define STR_SNK_AC2_16_1_1 \ + STR_SNK_16_1_1(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_16_1_1 = { + .cc = LC3_CONFIG_16_1_AC(2), + .qos = LC3_QOS_16_1_1_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_16_1_1 \ + STR_SNK_16_1_1(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_16_2_1 = { + .cc = LC3_CONFIG_16_2_AC(1), + .qos = LC3_QOS_16_2_1_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_16_2(_ac) \ + STR_SNK_16(_ac, LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_16_2) + +#define STR_SNK_16_2_1(_chans) \ + STR_SNK_16_2((BIT(_chans) - 1)), \ + STR_SNK_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_16_2, LC3_QOS_16_2_1_RTN, \ + LC3_QOS_16_2_1_LATENCY) + +#define STR_SNK_AC2_16_2_1 \ + STR_SNK_16_2_1(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_16_2_1 = { + .cc = LC3_CONFIG_16_2_AC(2), + .qos = LC3_QOS_16_2_1_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_16_2_1 \ + STR_SNK_16_2_1(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_16_1_2 = { + .cc = LC3_CONFIG_16_1_AC(1), + .qos = LC3_QOS_16_1_2_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_16(_ac, _dur, _len) \ + STR_SNK(LC3_CONFIG_FREQ_16KHZ, _ac, _dur, _len) + +#define STR_SNK_16_1_2(_chans) \ + STR_SNK_16_1((BIT(_chans) - 1)), \ + STR_SNK_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_16_1, LC3_QOS_16_1_2_RTN, \ + LC3_QOS_16_1_2_LATENCY) + +#define STR_SNK_AC2_16_1_2 \ + STR_SNK_16_1_2(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_16_1_2 = { + .cc = LC3_CONFIG_16_1_AC(2), + .qos = LC3_QOS_16_1_2_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_16_1_2 \ + STR_SNK_16_1_2(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_16_2_2 = { + .cc = LC3_CONFIG_16_2_AC(1), + .qos = LC3_QOS_16_2_2_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_16_2(_ac) \ + STR_SNK_16(_ac, LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_16_2) + +#define STR_SNK_16_2_2(_chans) \ + STR_SNK_16_2((BIT(_chans) - 1)), \ + STR_SNK_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_16_2, LC3_QOS_16_2_2_RTN, \ + LC3_QOS_16_2_2_LATENCY) + +#define STR_SNK_AC2_16_2_2 \ + STR_SNK_16_2_2(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_16_2_2 = { + .cc = LC3_CONFIG_16_2_AC(2), + .qos = LC3_QOS_16_2_2_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_16_2_2 \ + STR_SNK_16_2_2(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_24_1_1 = { + .cc = LC3_CONFIG_24_1_AC(1), + .qos = LC3_QOS_24_1_1_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_24(_ac, _dur, _len) \ + STR_SNK(LC3_CONFIG_FREQ_24KHZ, _ac, _dur, _len) + +#define STR_SNK_24_1(_ac) \ + STR_SNK_24(_ac, LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_24_1) + +#define STR_SNK_24_1_1(_chans) \ + STR_SNK_24_1((BIT(_chans) - 1)), \ + STR_SNK_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_24_1, LC3_QOS_24_1_1_RTN, \ + LC3_QOS_24_1_1_LATENCY) + +#define STR_SNK_AC2_24_1_1 \ + STR_SNK_24_1_1(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_24_1_1 = { + .cc = LC3_CONFIG_24_1_AC(2), + .qos = LC3_QOS_24_1_1_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_24_1_1 \ + STR_SNK_24_1_1(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_24_2_1 = { + .cc = LC3_CONFIG_24_2_AC(1), + .qos = LC3_QOS_24_2_1_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_24_2(_ac) \ + STR_SNK_24(_ac, LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_24_2) + +#define STR_SNK_24_2_1(_chans) \ + STR_SNK_24_2((BIT(_chans) - 1)), \ + STR_SNK_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_24_2, LC3_QOS_24_2_1_RTN, \ + LC3_QOS_24_2_1_LATENCY) + +#define STR_SNK_AC2_24_2_1 \ + STR_SNK_24_2_1(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_24_2_1 = { + .cc = LC3_CONFIG_24_2_AC(2), + .qos = LC3_QOS_24_2_1_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_24_2_1 \ + STR_SNK_24_2_1(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_24_1_2 = { + .cc = LC3_CONFIG_24_1_AC(1), + .qos = LC3_QOS_24_1_2_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_24_1_2(_chans) \ + STR_SNK_24_1((BIT(_chans) - 1)), \ + STR_SNK_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_24_1, LC3_QOS_24_1_2_RTN, \ + LC3_QOS_24_1_2_LATENCY) + +#define STR_SNK_AC2_24_1_2 \ + STR_SNK_24_1_2(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_24_1_2 = { + .cc = LC3_CONFIG_24_1_AC(2), + .qos = LC3_QOS_24_1_2_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_24_1_2 \ + STR_SNK_24_1_2(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_24_2_2 = { + .cc = LC3_CONFIG_24_2_AC(1), + .qos = LC3_QOS_24_2_2_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_24_2_2(_chans) \ + STR_SNK_24_2((BIT(_chans) - 1)), \ + STR_SNK_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_24_2, LC3_QOS_24_2_2_RTN, \ + LC3_QOS_24_2_2_LATENCY) + +#define STR_SNK_AC2_24_2_2 \ + STR_SNK_24_2_2(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_24_2_2 = { + .cc = LC3_CONFIG_24_2_AC(2), + .qos = LC3_QOS_24_2_2_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_24_2_2 \ + STR_SNK_24_2_2(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_32_1_1 = { + .cc = LC3_CONFIG_32_1_AC(1), + .qos = LC3_QOS_32_1_1_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_32(_ac, _dur, _len) \ + STR_SNK(LC3_CONFIG_FREQ_32KHZ, _ac, _dur, _len) + +#define STR_SNK_32_1(_ac) \ + STR_SNK_32(_ac, LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_32_1) + +#define STR_SNK_32_1_1(_chans) \ + STR_SNK_32_1((BIT(_chans) - 1)), \ + STR_SNK_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_32_1, LC3_QOS_32_1_1_RTN, \ + LC3_QOS_32_1_1_LATENCY) + +#define STR_SNK_AC2_32_1_1 \ + STR_SNK_32_1_1(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_32_1_1 = { + .cc = LC3_CONFIG_32_1_AC(2), + .qos = LC3_QOS_32_1_1_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_32_1_1 \ + STR_SNK_32_1_1(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_32_2_1 = { + .cc = LC3_CONFIG_32_2_AC(1), + .qos = LC3_QOS_32_2_1_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_32_2(_ac) \ + STR_SNK_32(_ac, LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_32_2) + +#define STR_SNK_32_2_1(_chans) \ + STR_SNK_32_2((BIT(_chans) - 1)), \ + STR_SNK_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_32_2, LC3_QOS_32_2_1_RTN, \ + LC3_QOS_32_2_1_LATENCY) + +#define STR_SNK_AC2_32_2_1 \ + STR_SNK_32_2_1(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_32_2_1 = { + .cc = LC3_CONFIG_32_2_AC(2), + .qos = LC3_QOS_32_2_1_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_32_2_1 \ + STR_SNK_32_2_1(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_32_1_2 = { + .cc = LC3_CONFIG_32_1_AC(1), + .qos = LC3_QOS_32_1_2_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_32_1_2(_chans) \ + STR_SNK_32_1((BIT(_chans) - 1)), \ + STR_SNK_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_32_1, LC3_QOS_32_1_2_RTN, \ + LC3_QOS_32_1_2_LATENCY) + +#define STR_SNK_AC2_32_1_2 \ + STR_SNK_32_1_2(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_32_1_2 = { + .cc = LC3_CONFIG_32_1_AC(2), + .qos = LC3_QOS_32_1_2_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_32_1_2 \ + STR_SNK_32_1_2(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_32_2_2 = { + .cc = LC3_CONFIG_32_2_AC(1), + .qos = LC3_QOS_32_2_2_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_32_2_2(_chans) \ + STR_SNK_32_2((BIT(_chans) - 1)), \ + STR_SNK_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_32_2, LC3_QOS_32_2_2_RTN, \ + LC3_QOS_32_2_2_LATENCY) + +#define STR_SNK_AC2_32_2_2 \ + STR_SNK_32_2_2(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_32_2_2 = { + .cc = LC3_CONFIG_32_2_AC(2), + .qos = LC3_QOS_32_2_2_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_32_2_2 \ + STR_SNK_32_2_2(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_44_1_1 = { + .cc = LC3_CONFIG_44_1_AC(1), + .qos = LC3_QOS_44_1_1_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_44(_ac, _dur, _len) \ + STR_SNK(LC3_CONFIG_FREQ_44KHZ, _ac, _dur, _len) + +#define STR_SNK_44_1(_ac) \ + STR_SNK_44(_ac, LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_44_1) + +#define STR_SNK_QOS_44_1(_sdu, _rtn, _latency) \ + STR_SNK_QOS(LC3_QOS_44_1_INTERVAL, LC3_QOS_FRAMED, _sdu, _rtn, \ + _latency) + +#define STR_SNK_44_1_1(_chans) \ + STR_SNK_44_1((BIT(_chans) - 1)), \ + STR_SNK_QOS_44_1(_chans * LC3_CONFIG_FRAME_LEN_44_1, \ + LC3_QOS_44_1_1_RTN, LC3_QOS_44_1_1_LATENCY) + +#define STR_SNK_AC2_44_1_1 \ + STR_SNK_44_1_1(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_44_1_1 = { + .cc = LC3_CONFIG_44_1_AC(2), + .qos = LC3_QOS_44_1_1_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_44_1_1 \ + STR_SNK_44_1_1(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_44_2_1 = { + .cc = LC3_CONFIG_44_2_AC(1), + .qos = LC3_QOS_44_2_1_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_44_2(_ac) \ + STR_SNK_44(_ac, LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_44_2) + +#define STR_SNK_QOS_44_2(_sdu, _rtn, _latency) \ + STR_SNK_QOS(LC3_QOS_44_2_INTERVAL, LC3_QOS_FRAMED, _sdu, _rtn, \ + _latency) + +#define STR_SNK_44_2_1(_chans) \ + STR_SNK_44_2((BIT(_chans) - 1)), \ + STR_SNK_QOS_44_2(_chans * LC3_CONFIG_FRAME_LEN_44_2, \ + LC3_QOS_44_2_1_RTN, LC3_QOS_44_2_1_LATENCY) + +#define STR_SNK_AC2_44_2_1 \ + STR_SNK_44_2_1(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_44_2_1 = { + .cc = LC3_CONFIG_44_2_AC(2), + .qos = LC3_QOS_44_2_1_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_44_2_1 \ + STR_SNK_44_2_1(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_44_1_2 = { + .cc = LC3_CONFIG_44_1_AC(1), + .qos = LC3_QOS_44_1_2_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_44_1_2(_chans) \ + STR_SNK_44_1((BIT(_chans) - 1)), \ + STR_SNK_QOS_44_1(_chans * LC3_CONFIG_FRAME_LEN_44_1, \ + LC3_QOS_44_1_2_RTN, LC3_QOS_44_1_2_LATENCY) + +#define STR_SNK_AC2_44_1_2 \ + STR_SNK_44_1_2(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_44_1_2 = { + .cc = LC3_CONFIG_44_1_AC(2), + .qos = LC3_QOS_44_1_2_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_44_1_2 \ + STR_SNK_44_1_2(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_44_2_2 = { + .cc = LC3_CONFIG_44_2_AC(1), + .qos = LC3_QOS_44_2_2_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_44_2_2(_chans) \ + STR_SNK_44_2((BIT(_chans) - 1)), \ + STR_SNK_QOS_44_2(_chans * LC3_CONFIG_FRAME_LEN_44_2, \ + LC3_QOS_44_2_2_RTN, LC3_QOS_44_2_2_LATENCY) + +#define STR_SNK_AC2_44_2_2 \ + STR_SNK_44_2_2(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_44_2_2 = { + .cc = LC3_CONFIG_44_2_AC(2), + .qos = LC3_QOS_44_2_2_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_44_2_2 \ + STR_SNK_44_2_2(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_48_1_1 = { + .cc = LC3_CONFIG_48_1_AC(1), + .qos = LC3_QOS_48_1_1_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_48(_ac, _dur, _len) \ + STR_SNK(LC3_CONFIG_FREQ_48KHZ, _ac, _dur, _len) + +#define STR_SNK_48_1(_ac) \ + STR_SNK_48(_ac, LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_48_1) + +#define STR_SNK_48_1_1(_chans) \ + STR_SNK_48_1((BIT(_chans) - 1)), \ + STR_SNK_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_48_1, LC3_QOS_48_1_1_RTN, \ + LC3_QOS_48_1_1_LATENCY) + +#define STR_SNK_AC2_48_1_1 \ + STR_SNK_48_1_1(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_48_1_1 = { + .cc = LC3_CONFIG_48_1_AC(2), + .qos = LC3_QOS_48_1_1_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_48_1_1 \ + STR_SNK_48_1_1(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_48_2_1 = { + .cc = LC3_CONFIG_48_2_AC(1), + .qos = LC3_QOS_48_2_1_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_48_2(_ac) \ + STR_SNK_48(_ac, LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_48_2) + +#define STR_SNK_48_2_1(_chans) \ + STR_SNK_48_2((BIT(_chans) - 1)), \ + STR_SNK_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_48_2, LC3_QOS_48_2_1_RTN, \ + LC3_QOS_48_2_1_LATENCY) + +#define STR_SNK_AC2_48_2_1 \ + STR_SNK_48_2_1(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_48_2_1 = { + .cc = LC3_CONFIG_48_2_AC(2), + .qos = LC3_QOS_48_2_1_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_48_2_1 \ + STR_SNK_48_2_1(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_48_3_1 = { + .cc = LC3_CONFIG_48_3_AC(1), + .qos = LC3_QOS_48_3_1_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_48_3(_ac) \ + STR_SNK_48(_ac, LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_48_3) + +#define STR_SNK_48_3_1(_chans) \ + STR_SNK_48_3((BIT(_chans) - 1)), \ + STR_SNK_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_48_3, LC3_QOS_48_3_1_RTN, \ + LC3_QOS_48_3_1_LATENCY) + +#define STR_SNK_AC2_48_3_1 \ + STR_SNK_48_3_1(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_48_3_1 = { + .cc = LC3_CONFIG_48_3_AC(2), + .qos = LC3_QOS_48_3_1_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_48_3_1 \ + STR_SNK_48_3_1(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_48_4_1 = { + .cc = LC3_CONFIG_48_4_AC(1), + .qos = LC3_QOS_48_4_1_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_48_4(_ac) \ + STR_SNK_48(_ac, LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_48_4) + +#define STR_SNK_48_4_1(_chans) \ + STR_SNK_48_4((BIT(_chans) - 1)), \ + STR_SNK_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_48_4, LC3_QOS_48_4_1_RTN, \ + LC3_QOS_48_4_1_LATENCY) + +#define STR_SNK_AC2_48_4_1 \ + STR_SNK_48_4_1(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_48_4_1 = { + .cc = LC3_CONFIG_48_4_AC(2), + .qos = LC3_QOS_48_4_1_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_48_4_1 \ + STR_SNK_48_4_1(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_48_5_1 = { + .cc = LC3_CONFIG_48_5_AC(1), + .qos = LC3_QOS_48_5_1_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_48_5(_ac) \ + STR_SNK_48(_ac, LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_48_5) + +#define STR_SNK_48_5_1(_chans) \ + STR_SNK_48_5((BIT(_chans) - 1)), \ + STR_SNK_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_48_5, LC3_QOS_48_5_1_RTN, \ + LC3_QOS_48_5_1_LATENCY) + +#define STR_SNK_AC2_48_5_1 \ + STR_SNK_48_5_1(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_48_5_1 = { + .cc = LC3_CONFIG_48_5_AC(2), + .qos = LC3_QOS_48_5_1_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_48_5_1 \ + STR_SNK_48_5_1(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_48_6_1 = { + .cc = LC3_CONFIG_48_6_AC(1), + .qos = LC3_QOS_48_6_1_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_48_6(_ac) \ + STR_SNK_48(_ac, LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_48_6) + +#define STR_SNK_48_6_1(_chans) \ + STR_SNK_48_6((BIT(_chans) - 1)), \ + STR_SNK_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_48_6, LC3_QOS_48_6_1_RTN, \ + LC3_QOS_48_6_1_LATENCY) + +#define STR_SNK_AC2_48_6_1 \ + STR_SNK_48_6_1(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_48_6_1 = { + .cc = LC3_CONFIG_48_6_AC(2), + .qos = LC3_QOS_48_6_1_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_48_6_1 \ + STR_SNK_48_6_1(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_48_1_2 = { + .cc = LC3_CONFIG_48_1_AC(1), + .qos = LC3_QOS_48_1_2_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_48_1_2(_chans) \ + STR_SNK_48_1((BIT(_chans) - 1)), \ + STR_SNK_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_48_1, LC3_QOS_48_1_2_RTN, \ + LC3_QOS_48_1_2_LATENCY) + +#define STR_SNK_AC2_48_1_2 \ + STR_SNK_48_1_2(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_48_1_2 = { + .cc = LC3_CONFIG_48_1_AC(2), + .qos = LC3_QOS_48_1_2_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_48_1_2 \ + STR_SNK_48_1_2(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_48_2_2 = { + .cc = LC3_CONFIG_48_2_AC(1), + .qos = LC3_QOS_48_2_2_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_48_2_2(_chans) \ + STR_SNK_48_2((BIT(_chans) - 1)), \ + STR_SNK_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_48_2, LC3_QOS_48_2_2_RTN, \ + LC3_QOS_48_2_2_LATENCY) + +#define STR_SNK_AC2_48_2_2 \ + STR_SNK_48_2_2(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_48_2_2 = { + .cc = LC3_CONFIG_48_2_AC(2), + .qos = LC3_QOS_48_2_2_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_48_2_2 \ + STR_SNK_48_2_2(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_48_3_2 = { + .cc = LC3_CONFIG_48_3_AC(1), + .qos = LC3_QOS_48_3_2_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_48_3_2(_chans) \ + STR_SNK_48_3((BIT(_chans) - 1)), \ + STR_SNK_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_48_3, LC3_QOS_48_3_2_RTN, \ + LC3_QOS_48_3_2_LATENCY) + +#define STR_SNK_AC2_48_3_2 \ + STR_SNK_48_3_2(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_48_3_2 = { + .cc = LC3_CONFIG_48_3_AC(2), + .qos = LC3_QOS_48_3_2_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_48_3_2 \ + STR_SNK_48_3_2(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_48_4_2 = { + .cc = LC3_CONFIG_48_4_AC(1), + .qos = LC3_QOS_48_4_2_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_48_4_2(_chans) \ + STR_SNK_48_4((BIT(_chans) - 1)), \ + STR_SNK_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_48_4, LC3_QOS_48_4_2_RTN, \ + LC3_QOS_48_4_2_LATENCY) + +#define STR_SNK_AC2_48_4_2 \ + STR_SNK_48_4_2(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_48_4_2 = { + .cc = LC3_CONFIG_48_4_AC(2), + .qos = LC3_QOS_48_4_2_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_48_4_2 \ + STR_SNK_48_4_2(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_48_5_2 = { + .cc = LC3_CONFIG_48_5_AC(1), + .qos = LC3_QOS_48_5_2_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_48_5_2(_chans) \ + STR_SNK_48_5((BIT(_chans) - 1)), \ + STR_SNK_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_48_5, LC3_QOS_48_5_2_RTN, \ + LC3_QOS_48_5_2_LATENCY) + +#define STR_SNK_AC2_48_5_2 \ + STR_SNK_48_5_2(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_48_5_2 = { + .cc = LC3_CONFIG_48_5_AC(2), + .qos = LC3_QOS_48_5_2_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_48_5_2 \ + STR_SNK_48_5_2(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac2_48_6_2 = { + .cc = LC3_CONFIG_48_6_AC(1), + .qos = LC3_QOS_48_6_2_AC(1), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_48_6_2(_chans) \ + STR_SNK_48_6((BIT(_chans) - 1)), \ + STR_SNK_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_48_6, LC3_QOS_48_6_2_RTN, \ + LC3_QOS_48_6_2_LATENCY) + +#define STR_SNK_AC2_48_6_2 \ + STR_SNK_48_6_2(1), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_snk_ac10_48_6_2 = { + .cc = LC3_CONFIG_48_6_AC(2), + .qos = LC3_QOS_48_6_2_AC(2), + .snk = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SNK_AC10_48_6_2 \ + STR_SNK_48_6_2(2), \ + SNK_ENABLE, \ + SNK_START + +static struct test_config str_src_ac1_8_1_1 = { + .cc = LC3_CONFIG_8_1_AC(1), + .qos = LC3_QOS_8_1_1_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC(_freq, _ac, _dur, _len) \ + SCC_SRC_LC3(0x10, 0x02, 0x01, _freq, 0x02, 0x02, _dur, 0x03, 0x04, \ + _len, _len >> 8, 0x05, 0x03, _ac, 0x00, 0x00, 0x00) + +#define STR_SRC_8(_ac, _dur, _len) \ + STR_SRC(LC3_CONFIG_FREQ_8KHZ, _ac, _dur, _len) + +#define STR_SRC_8_1(_ac) \ + STR_SRC_8(_ac, LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_8_1) + +#define STR_SRC_QOS(_interval, _frame, _sdu, _rtn, _latency) \ + QOS_SRC(_interval & 0xff, _interval >> 8 & 0xff, \ + _interval >> 16 & 0xff, _frame, 0x02, _sdu & 0xff, \ + _sdu >> 8 & 0xff, _rtn, \ + _latency, _latency >> 8, 0x40, 0x9c, 0x00) + +#define STR_SRC_QOS_1(_sdu, _rtn, _latency) \ + STR_SRC_QOS(7500u, LC3_QOS_UNFRAMED, _sdu, _rtn, _latency) + +#define STR_SRC_8_1_1(_chans) \ + STR_SRC_8_1((BIT(_chans) - 1)), \ + STR_SRC_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_8_1, LC3_QOS_8_1_1_RTN, \ + LC3_QOS_8_1_1_LATENCY) + +#define STR_SRC_AC1_8_1_1 \ + STR_SRC_8_1_1(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_8_1_1 = { + .cc = LC3_CONFIG_8_1_AC(2), + .qos = LC3_QOS_8_1_1_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_8_1_1 \ + STR_SRC_8_1_1(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_8_2_1 = { + .cc = LC3_CONFIG_8_2_AC(1), + .qos = LC3_QOS_8_2_1_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_8_2(_ac) \ + STR_SRC_8(_ac, LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_8_2) + +#define STR_SRC_QOS_2(_sdu, _rtn, _latency) \ + STR_SRC_QOS(10000u, LC3_QOS_UNFRAMED, _sdu, _rtn, _latency) + +#define STR_SRC_8_2_1(_chans) \ + STR_SRC_8_2((BIT(_chans) - 1)), \ + STR_SRC_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_8_2, LC3_QOS_8_2_1_RTN, \ + LC3_QOS_8_2_1_LATENCY) + +#define STR_SRC_AC1_8_2_1 \ + STR_SRC_8_2_1(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_8_2_1 = { + .cc = LC3_CONFIG_8_2_AC(2), + .qos = LC3_QOS_8_2_1_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_8_2_1 \ + STR_SRC_8_2_1(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_16_1_1 = { + .cc = LC3_CONFIG_16_1_AC(1), + .qos = LC3_QOS_16_1_1_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_16(_ac, _dur, _len) \ + STR_SRC(LC3_CONFIG_FREQ_16KHZ, _ac, _dur, _len) + +#define STR_SRC_16_1(_ac) \ + STR_SRC_16(_ac, LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_16_1) + +#define STR_SRC_16_1_1(_chans) \ + STR_SRC_16_1((BIT(_chans) - 1)), \ + STR_SRC_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_16_1, LC3_QOS_16_1_1_RTN, \ + LC3_QOS_16_1_1_LATENCY) + +#define STR_SRC_AC1_16_1_1 \ + STR_SRC_16_1_1(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_16_1_1 = { + .cc = LC3_CONFIG_16_1_AC(2), + .qos = LC3_QOS_16_1_1_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_16_1_1 \ + STR_SRC_16_1_1(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_16_2_1 = { + .cc = LC3_CONFIG_16_2_AC(1), + .qos = LC3_QOS_16_2_1_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_16_2(_ac) \ + STR_SRC_16(_ac, LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_16_2) + +#define STR_SRC_16_2_1(_chans) \ + STR_SRC_16_2((BIT(_chans) - 1)), \ + STR_SRC_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_16_2, LC3_QOS_16_2_1_RTN, \ + LC3_QOS_16_2_1_LATENCY) + +#define STR_SRC_AC1_16_2_1 \ + STR_SRC_16_2_1(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_16_2_1 = { + .cc = LC3_CONFIG_16_2_AC(2), + .qos = LC3_QOS_16_2_1_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_16_2_1 \ + STR_SRC_16_2_1(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_24_1_1 = { + .cc = LC3_CONFIG_24_1_AC(1), + .qos = LC3_QOS_24_1_1_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_24(_ac, _dur, _len) \ + STR_SRC(LC3_CONFIG_FREQ_24KHZ, _ac, _dur, _len) + +#define STR_SRC_24_1(_ac) \ + STR_SRC_24(_ac, LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_24_1) + +#define STR_SRC_24_1_1(_chans) \ + STR_SRC_24_1((BIT(_chans) - 1)), \ + STR_SRC_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_24_1, LC3_QOS_24_1_1_RTN, \ + LC3_QOS_24_1_1_LATENCY) + +#define STR_SRC_AC1_24_1_1 \ + STR_SRC_24_1_1(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_24_1_1 = { + .cc = LC3_CONFIG_24_1_AC(2), + .qos = LC3_QOS_24_1_1_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_24_1_1 \ + STR_SRC_24_1_1(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_24_2_1 = { + .cc = LC3_CONFIG_24_2_AC(1), + .qos = LC3_QOS_24_2_1_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_24_2(_ac) \ + STR_SRC_24(_ac, LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_24_2) + +#define STR_SRC_24_2_1(_chans) \ + STR_SRC_24_2((BIT(_chans) - 1)), \ + STR_SRC_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_24_2, LC3_QOS_24_2_1_RTN, \ + LC3_QOS_24_2_1_LATENCY) + +#define STR_SRC_AC1_24_2_1 \ + STR_SRC_24_2_1(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_24_2_1 = { + .cc = LC3_CONFIG_24_2_AC(2), + .qos = LC3_QOS_24_2_1_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_24_2_1 \ + STR_SRC_24_2_1(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_32_1_1 = { + .cc = LC3_CONFIG_32_1_AC(1), + .qos = LC3_QOS_32_1_1_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_32(_ac, _dur, _len) \ + STR_SRC(LC3_CONFIG_FREQ_32KHZ, _ac, _dur, _len) + +#define STR_SRC_32_1(_ac) \ + STR_SRC_32(_ac, LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_32_1) + +#define STR_SRC_32_1_1(_chans) \ + STR_SRC_32_1((BIT(_chans) - 1)), \ + STR_SRC_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_32_1, LC3_QOS_32_1_1_RTN, \ + LC3_QOS_32_1_1_LATENCY) + +#define STR_SRC_AC1_32_1_1 \ + STR_SRC_32_1_1(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_32_1_1 = { + .cc = LC3_CONFIG_32_1_AC(2), + .qos = LC3_QOS_32_1_1_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_32_1_1 \ + STR_SRC_32_1_1(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_32_2_1 = { + .cc = LC3_CONFIG_32_2_AC(1), + .qos = LC3_QOS_32_2_1_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_32_2(_ac) \ + STR_SRC_32(_ac, LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_32_2) + +#define STR_SRC_32_2_1(_chans) \ + STR_SRC_32_2((BIT(_chans) - 1)), \ + STR_SRC_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_32_2, LC3_QOS_32_2_1_RTN, \ + LC3_QOS_32_2_1_LATENCY) + +#define STR_SRC_AC1_32_2_1 \ + STR_SRC_32_2_1(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_32_2_1 = { + .cc = LC3_CONFIG_32_2_AC(2), + .qos = LC3_QOS_32_2_1_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_32_2_1 \ + STR_SRC_32_2_1(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_44_1_1 = { + .cc = LC3_CONFIG_44_1_AC(1), + .qos = LC3_QOS_44_1_1_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_44(_ac, _dur, _len) \ + STR_SRC(LC3_CONFIG_FREQ_44KHZ, _ac, _dur, _len) + +#define STR_SRC_44_1(_ac) \ + STR_SRC_44(_ac, LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_44_1) + +#define STR_SRC_QOS_44_1(_sdu, _rtn, _latency) \ + STR_SRC_QOS(LC3_QOS_44_1_INTERVAL, LC3_QOS_FRAMED, _sdu, _rtn, \ + _latency) + +#define STR_SRC_44_1_1(_chans) \ + STR_SRC_44_1((BIT(_chans) - 1)), \ + STR_SRC_QOS_44_1(_chans * LC3_CONFIG_FRAME_LEN_44_1, \ + LC3_QOS_44_1_1_RTN, LC3_QOS_44_1_1_LATENCY) + +#define STR_SRC_AC1_44_1_1 \ + STR_SRC_44_1_1(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_44_1_1 = { + .cc = LC3_CONFIG_44_1_AC(2), + .qos = LC3_QOS_44_1_1_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_44_1_1 \ + STR_SRC_44_1_1(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_44_2_1 = { + .cc = LC3_CONFIG_44_2_AC(1), + .qos = LC3_QOS_44_2_1_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_44_2(_ac) \ + STR_SRC_44(_ac, LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_44_2) + +#define STR_SRC_QOS_44_2(_sdu, _rtn, _latency) \ + STR_SRC_QOS(LC3_QOS_44_2_INTERVAL, LC3_QOS_FRAMED, _sdu, _rtn, \ + _latency) + +#define STR_SRC_44_2_1(_chans) \ + STR_SRC_44_2((BIT(_chans) - 1)), \ + STR_SRC_QOS_44_2(_chans * LC3_CONFIG_FRAME_LEN_44_2, \ + LC3_QOS_44_2_1_RTN, LC3_QOS_44_2_1_LATENCY) + +#define STR_SRC_AC1_44_2_1 \ + STR_SRC_44_2_1(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_44_2_1 = { + .cc = LC3_CONFIG_44_2_AC(2), + .qos = LC3_QOS_44_2_1_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_44_2_1 \ + STR_SRC_44_2_1(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_48_1_1 = { + .cc = LC3_CONFIG_48_1_AC(1), + .qos = LC3_QOS_48_1_1_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_48(_ac, _dur, _len) \ + STR_SRC(LC3_CONFIG_FREQ_48KHZ, _ac, _dur, _len) + +#define STR_SRC_48_1(_ac) \ + STR_SRC_48(_ac, LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_48_1) + +#define STR_SRC_48_1_1(_chans) \ + STR_SRC_48_1((BIT(_chans) - 1)), \ + STR_SRC_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_48_1, LC3_QOS_48_1_1_RTN, \ + LC3_QOS_48_1_1_LATENCY) + +#define STR_SRC_AC1_48_1_1 \ + STR_SRC_48_1_1(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_48_1_1 = { + .cc = LC3_CONFIG_48_1_AC(2), + .qos = LC3_QOS_48_1_1_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_48_1_1 \ + STR_SRC_48_1_1(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_48_2_1 = { + .cc = LC3_CONFIG_48_2_AC(1), + .qos = LC3_QOS_48_2_1_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_48_2(_ac) \ + STR_SRC_48(_ac, LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_48_2) + +#define STR_SRC_48_2_1(_chans) \ + STR_SRC_48_2((BIT(_chans) - 1)), \ + STR_SRC_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_48_2, LC3_QOS_48_2_1_RTN, \ + LC3_QOS_48_2_1_LATENCY) + +#define STR_SRC_AC1_48_2_1 \ + STR_SRC_48_2_1(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_48_2_1 = { + .cc = LC3_CONFIG_48_2_AC(2), + .qos = LC3_QOS_48_2_1_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_48_2_1 \ + STR_SRC_48_2_1(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_48_3_1 = { + .cc = LC3_CONFIG_48_3_AC(1), + .qos = LC3_QOS_48_3_1_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_48_3(_ac) \ + STR_SRC_48(_ac, LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_48_3) + +#define STR_SRC_48_3_1(_chans) \ + STR_SRC_48_3((BIT(_chans) - 1)), \ + STR_SRC_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_48_3, LC3_QOS_48_3_1_RTN, \ + LC3_QOS_48_3_1_LATENCY) + +#define STR_SRC_AC1_48_3_1 \ + STR_SRC_48_3_1(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_48_3_1 = { + .cc = LC3_CONFIG_48_3_AC(2), + .qos = LC3_QOS_48_3_1_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_48_3_1 \ + STR_SRC_48_3_1(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_48_4_1 = { + .cc = LC3_CONFIG_48_4_AC(1), + .qos = LC3_QOS_48_4_1_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_48_4(_ac) \ + STR_SRC_48(_ac, LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_48_4) + +#define STR_SRC_48_4_1(_chans) \ + STR_SRC_48_4((BIT(_chans) - 1)), \ + STR_SRC_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_48_4, LC3_QOS_48_4_1_RTN, \ + LC3_QOS_48_4_1_LATENCY) + +#define STR_SRC_AC1_48_4_1 \ + STR_SRC_48_4_1(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_48_4_1 = { + .cc = LC3_CONFIG_48_4_AC(2), + .qos = LC3_QOS_48_4_1_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_48_4_1 \ + STR_SRC_48_4_1(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_48_5_1 = { + .cc = LC3_CONFIG_48_5_AC(1), + .qos = LC3_QOS_48_5_1_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_48_5(_ac) \ + STR_SRC_48(_ac, LC3_CONFIG_DURATION_7_5, LC3_CONFIG_FRAME_LEN_48_5) + +#define STR_SRC_48_5_1(_chans) \ + STR_SRC_48_5((BIT(_chans) - 1)), \ + STR_SRC_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_48_5, LC3_QOS_48_5_1_RTN, \ + LC3_QOS_48_5_1_LATENCY) + +#define STR_SRC_AC1_48_5_1 \ + STR_SRC_48_5_1(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_48_5_1 = { + .cc = LC3_CONFIG_48_5_AC(2), + .qos = LC3_QOS_48_5_1_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_48_5_1 \ + STR_SRC_48_5_1(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_48_6_1 = { + .cc = LC3_CONFIG_48_6_AC(1), + .qos = LC3_QOS_48_6_1_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_48_6(_ac) \ + STR_SRC_48(_ac, LC3_CONFIG_DURATION_10, LC3_CONFIG_FRAME_LEN_48_6) + +#define STR_SRC_48_6_1(_chans) \ + STR_SRC_48_6((BIT(_chans) - 1)), \ + STR_SRC_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_48_6, LC3_QOS_48_6_1_RTN, \ + LC3_QOS_48_6_1_LATENCY) + +#define STR_SRC_AC1_48_6_1 \ + STR_SRC_48_6_1(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_48_6_1 = { + .cc = LC3_CONFIG_48_6_AC(2), + .qos = LC3_QOS_48_6_1_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_48_6_1 \ + STR_SRC_48_6_1(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_8_1_2 = { + .cc = LC3_CONFIG_8_1_AC(1), + .qos = LC3_QOS_8_1_2_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_8_1_2(_chans) \ + STR_SRC_8_1((BIT(_chans) - 1)), \ + STR_SRC_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_8_1, LC3_QOS_8_1_2_RTN, \ + LC3_QOS_8_1_2_LATENCY) + +#define STR_SRC_AC1_8_1_2 \ + STR_SRC_8_1_2(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_8_1_2 = { + .cc = LC3_CONFIG_8_1_AC(2), + .qos = LC3_QOS_8_1_2_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_8_1_2 \ + STR_SRC_8_1_2(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_8_2_2 = { + .cc = LC3_CONFIG_8_2_AC(1), + .qos = LC3_QOS_8_2_2_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_8_2_2(_chans) \ + STR_SRC_8_2((BIT(_chans) - 1)), \ + STR_SRC_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_8_2, LC3_QOS_8_2_2_RTN, \ + LC3_QOS_8_2_2_LATENCY) + +#define STR_SRC_AC1_8_2_2 \ + STR_SRC_8_2_2(1), \ + SRC_ENABLE, \ + SNK_START + +static struct test_config str_src_ac4_8_2_2 = { + .cc = LC3_CONFIG_8_2_AC(2), + .qos = LC3_QOS_8_2_2_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_8_2_2 \ + STR_SRC_8_2_2(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_16_1_2 = { + .cc = LC3_CONFIG_16_1_AC(1), + .qos = LC3_QOS_16_1_2_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_16_1_2(_chans) \ + STR_SRC_16_1((BIT(_chans) - 1)), \ + STR_SRC_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_16_1, LC3_QOS_16_1_2_RTN, \ + LC3_QOS_16_1_2_LATENCY) + +#define STR_SRC_AC1_16_1_2 \ + STR_SRC_16_1_2(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_16_1_2 = { + .cc = LC3_CONFIG_16_1_AC(2), + .qos = LC3_QOS_16_1_2_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_16_1_2 \ + STR_SRC_16_1_2(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_16_2_2 = { + .cc = LC3_CONFIG_16_2_AC(1), + .qos = LC3_QOS_16_2_2_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_16_2_2(_chans) \ + STR_SRC_16_2((BIT(_chans) - 1)), \ + STR_SRC_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_16_2, LC3_QOS_16_2_2_RTN, \ + LC3_QOS_16_2_2_LATENCY) + +#define STR_SRC_AC1_16_2_2 \ + STR_SRC_16_2_2(1), \ + SRC_ENABLE, \ + SNK_START + +static struct test_config str_src_ac4_16_2_2 = { + .cc = LC3_CONFIG_16_2_AC(2), + .qos = LC3_QOS_16_2_2_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_16_2_2 \ + STR_SRC_16_2_2(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_24_1_2 = { + .cc = LC3_CONFIG_24_1_AC(1), + .qos = LC3_QOS_24_1_2_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_24_1_2(_chans) \ + STR_SRC_24_1((BIT(_chans) - 1)), \ + STR_SRC_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_24_1, LC3_QOS_24_1_2_RTN, \ + LC3_QOS_24_1_2_LATENCY) + +#define STR_SRC_AC1_24_1_2 \ + STR_SRC_24_1_2(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_24_1_2 = { + .cc = LC3_CONFIG_24_1_AC(2), + .qos = LC3_QOS_24_1_2_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_24_1_2 \ + STR_SRC_24_1_2(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_24_2_2 = { + .cc = LC3_CONFIG_24_2_AC(1), + .qos = LC3_QOS_24_2_2_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_24_2_2(_chans) \ + STR_SRC_24_2((BIT(_chans) - 1)), \ + STR_SRC_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_24_2, LC3_QOS_24_2_2_RTN, \ + LC3_QOS_24_2_2_LATENCY) + +#define STR_SRC_AC1_24_2_2 \ + STR_SRC_24_2_2(1), \ + SRC_ENABLE, \ + SNK_START + +static struct test_config str_src_ac4_24_2_2 = { + .cc = LC3_CONFIG_24_2_AC(2), + .qos = LC3_QOS_24_2_2_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_24_2_2 \ + STR_SRC_24_2_2(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_32_1_2 = { + .cc = LC3_CONFIG_32_1_AC(1), + .qos = LC3_QOS_32_1_2_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_32_1_2(_chans) \ + STR_SRC_32_1((BIT(_chans) - 1)), \ + STR_SRC_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_32_1, LC3_QOS_32_1_2_RTN, \ + LC3_QOS_32_1_2_LATENCY) + +#define STR_SRC_AC1_32_1_2 \ + STR_SRC_32_1_2(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_32_1_2 = { + .cc = LC3_CONFIG_32_1_AC(2), + .qos = LC3_QOS_32_1_2_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_32_1_2 \ + STR_SRC_32_1_2(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_32_2_2 = { + .cc = LC3_CONFIG_32_2_AC(1), + .qos = LC3_QOS_32_2_2_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_32_2_2(_chans) \ + STR_SRC_32_2((BIT(_chans) - 1)), \ + STR_SRC_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_32_2, LC3_QOS_32_2_2_RTN, \ + LC3_QOS_32_2_2_LATENCY) + +#define STR_SRC_AC1_32_2_2 \ + STR_SRC_32_2_2(1), \ + SRC_ENABLE, \ + SNK_START + +static struct test_config str_src_ac4_32_2_2 = { + .cc = LC3_CONFIG_32_2_AC(2), + .qos = LC3_QOS_32_2_2_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_32_2_2 \ + STR_SRC_32_2_2(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_44_1_2 = { + .cc = LC3_CONFIG_44_1_AC(1), + .qos = LC3_QOS_44_1_2_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + + +#define STR_SRC_44_1_2(_chans) \ + STR_SRC_44_1((BIT(_chans) - 1)), \ + STR_SRC_QOS_44_1(_chans * LC3_CONFIG_FRAME_LEN_44_1, \ + LC3_QOS_44_1_2_RTN, LC3_QOS_44_1_2_LATENCY) + +#define STR_SRC_AC1_44_1_2 \ + STR_SRC_44_1_2(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_44_1_2 = { + .cc = LC3_CONFIG_44_1_AC(2), + .qos = LC3_QOS_44_1_2_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_44_1_2 \ + STR_SRC_44_1_2(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_44_2_2 = { + .cc = LC3_CONFIG_44_2_AC(1), + .qos = LC3_QOS_44_2_2_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_44_2_2(_chans) \ + STR_SRC_44_2((BIT(_chans) - 1)), \ + STR_SRC_QOS_44_2(_chans * LC3_CONFIG_FRAME_LEN_44_2, \ + LC3_QOS_44_2_2_RTN, LC3_QOS_44_2_2_LATENCY) + +#define STR_SRC_AC1_44_2_2 \ + STR_SRC_44_2_2(1), \ + SRC_ENABLE, \ + SNK_START + +static struct test_config str_src_ac4_44_2_2 = { + .cc = LC3_CONFIG_44_2_AC(2), + .qos = LC3_QOS_44_2_2_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_44_2_2 \ + STR_SRC_44_2_2(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_48_1_2 = { + .cc = LC3_CONFIG_48_1_AC(1), + .qos = LC3_QOS_48_1_2_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + + +#define STR_SRC_48_1_2(_chans) \ + STR_SRC_48_1((BIT(_chans) - 1)), \ + STR_SRC_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_48_1, LC3_QOS_48_1_2_RTN, \ + LC3_QOS_48_1_2_LATENCY) + +#define STR_SRC_AC1_48_1_2 \ + STR_SRC_48_1_2(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_48_1_2 = { + .cc = LC3_CONFIG_48_1_AC(2), + .qos = LC3_QOS_48_1_2_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_48_1_2 \ + STR_SRC_48_1_2(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_48_2_2 = { + .cc = LC3_CONFIG_48_2_AC(1), + .qos = LC3_QOS_48_2_2_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_48_2_2(_chans) \ + STR_SRC_48_2((BIT(_chans) - 1)), \ + STR_SRC_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_48_2, LC3_QOS_48_2_2_RTN, \ + LC3_QOS_48_2_2_LATENCY) + +#define STR_SRC_AC1_48_2_2 \ + STR_SRC_48_2_2(1), \ + SRC_ENABLE, \ + SNK_START + +static struct test_config str_src_ac4_48_2_2 = { + .cc = LC3_CONFIG_48_2_AC(2), + .qos = LC3_QOS_48_2_2_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_48_2_2 \ + STR_SRC_48_2_2(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_48_3_2 = { + .cc = LC3_CONFIG_48_3_AC(1), + .qos = LC3_QOS_48_3_2_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + + +#define STR_SRC_48_3_2(_chans) \ + STR_SRC_48_3((BIT(_chans) - 1)), \ + STR_SRC_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_48_3, LC3_QOS_48_3_2_RTN, \ + LC3_QOS_48_3_2_LATENCY) + +#define STR_SRC_AC1_48_3_2 \ + STR_SRC_48_3_2(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_48_3_2 = { + .cc = LC3_CONFIG_48_3_AC(2), + .qos = LC3_QOS_48_3_2_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_48_3_2 \ + STR_SRC_48_3_2(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_48_4_2 = { + .cc = LC3_CONFIG_48_4_AC(1), + .qos = LC3_QOS_48_4_2_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_48_4_2(_chans) \ + STR_SRC_48_4((BIT(_chans) - 1)), \ + STR_SRC_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_48_4, LC3_QOS_48_4_2_RTN, \ + LC3_QOS_48_4_2_LATENCY) + +#define STR_SRC_AC1_48_4_2 \ + STR_SRC_48_4_2(1), \ + SRC_ENABLE, \ + SNK_START + +static struct test_config str_src_ac4_48_4_2 = { + .cc = LC3_CONFIG_48_4_AC(2), + .qos = LC3_QOS_48_4_2_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_48_4_2 \ + STR_SRC_48_4_2(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_48_5_2 = { + .cc = LC3_CONFIG_48_5_AC(1), + .qos = LC3_QOS_48_5_2_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + + +#define STR_SRC_48_5_2(_chans) \ + STR_SRC_48_5((BIT(_chans) - 1)), \ + STR_SRC_QOS_1(_chans * LC3_CONFIG_FRAME_LEN_48_5, LC3_QOS_48_5_2_RTN, \ + LC3_QOS_48_5_2_LATENCY) + +#define STR_SRC_AC1_48_5_2 \ + STR_SRC_48_5_2(1), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac4_48_5_2 = { + .cc = LC3_CONFIG_48_5_AC(2), + .qos = LC3_QOS_48_5_2_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_48_5_2 \ + STR_SRC_48_5_2(2), \ + SRC_ENABLE, \ + SRC_START + +static struct test_config str_src_ac1_48_6_2 = { + .cc = LC3_CONFIG_48_6_AC(1), + .qos = LC3_QOS_48_6_2_AC(1), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_48_6_2(_chans) \ + STR_SRC_48_6((BIT(_chans) - 1)), \ + STR_SRC_QOS_2(_chans * LC3_CONFIG_FRAME_LEN_48_6, LC3_QOS_48_6_2_RTN, \ + LC3_QOS_48_6_2_LATENCY) + +#define STR_SRC_AC1_48_6_2 \ + STR_SRC_48_6_2(1), \ + SRC_ENABLE, \ + SNK_START + +static struct test_config str_src_ac4_48_6_2 = { + .cc = LC3_CONFIG_48_6_AC(2), + .qos = LC3_QOS_48_6_2_AC(2), + .src = true, + .state = BT_BAP_STREAM_STATE_STREAMING, +}; + +#define STR_SRC_AC4_48_6_2 \ + STR_SRC_48_6_2(2), \ + SRC_ENABLE, \ + SRC_START + +/* Unicast Client Streaming – 1 Unicast Server, 1 Stream, 1 CIS – LC3 + * + * Test Purpose: + * Verify that a Unicast Client IUT can stream audio data over one unicast + * Audio Stream to or from a Unicast Server. + * + * Pass verdict: + * If the IUT is in the Audio Sink role, the IUT receives SDUs with a zero or + * more length that contains LC3-encoded data formatted using the LC3 Media + * Packet format (defined in [3] Section 4.2). + */ +static void test_str_1_1_1_lc3(void) +{ + define_test("BAP/UCL/STR/BV-001-C [UCL, AC 2, LC3 8_1_1]", + test_setup, test_client, &str_snk_ac2_8_1_1, + STR_SNK_AC2_8_1_1); + define_test("BAP/UCL/STR/BV-002-C [UCL, AC 10, LC3 8_1_1]", + test_setup, test_client, &str_snk_ac10_8_1_1, + STR_SNK_AC10_8_1_1); + define_test("BAP/UCL/STR/BV-003-C [UCL, AC 2, LC3 8_2_1]", + test_setup, test_client, &str_snk_ac2_8_2_1, + STR_SNK_AC2_8_2_1); + define_test("BAP/UCL/STR/BV-004-C [UCL, AC 10, LC3 8_2_1]", + test_setup, test_client, &str_snk_ac10_8_2_1, + STR_SNK_AC10_8_2_1); + define_test("BAP/UCL/STR/BV-005-C [UCL, AC 2, LC3 16_1_1]", + test_setup, test_client, &str_snk_ac2_16_1_1, + STR_SNK_AC2_16_1_1); + define_test("BAP/UCL/STR/BV-006-C [UCL, AC 10, LC3 16_1_1]", + test_setup, test_client, &str_snk_ac10_16_1_1, + STR_SNK_AC10_16_1_1); + define_test("BAP/UCL/STR/BV-007-C [UCL, AC 2, LC3 16_2_1]", + test_setup, test_client, &str_snk_ac2_16_2_1, + STR_SNK_AC2_16_2_1); + define_test("BAP/UCL/STR/BV-008-C [UCL, AC 10, LC3 16_2_1]", + test_setup, test_client, &str_snk_ac10_16_2_1, + STR_SNK_AC10_16_2_1); + define_test("BAP/UCL/STR/BV-009-C [UCL, AC 2, LC3 24_1_1]", + test_setup, test_client, &str_snk_ac2_24_1_1, + STR_SNK_AC2_24_1_1); + define_test("BAP/UCL/STR/BV-010-C [UCL, AC 10, LC3 24_1_1]", + test_setup, test_client, &str_snk_ac10_24_1_1, + STR_SNK_AC10_24_1_1); + define_test("BAP/UCL/STR/BV-011-C [UCL, AC 2, LC3 24_2_1]", + test_setup, test_client, &str_snk_ac2_24_2_1, + STR_SNK_AC2_24_2_1); + define_test("BAP/UCL/STR/BV-012-C [UCL, AC 10, LC3 24_2_1]", + test_setup, test_client, &str_snk_ac10_24_2_1, + STR_SNK_AC10_24_2_1); + define_test("BAP/UCL/STR/BV-013-C [UCL, AC 2, LC3 32_1_1]", + test_setup, test_client, &str_snk_ac2_32_1_1, + STR_SNK_AC2_32_1_1); + define_test("BAP/UCL/STR/BV-014-C [UCL, AC 10, LC3 32_1_1]", + test_setup, test_client, &str_snk_ac10_32_1_1, + STR_SNK_AC10_32_1_1); + define_test("BAP/UCL/STR/BV-015-C [UCL, AC 2, LC3 32_2_1]", + test_setup, test_client, &str_snk_ac2_32_2_1, + STR_SNK_AC2_32_2_1); + define_test("BAP/UCL/STR/BV-016-C [UCL, AC 10, LC3 32_2_1]", + test_setup, test_client, &str_snk_ac10_32_2_1, + STR_SNK_AC10_32_2_1); + define_test("BAP/UCL/STR/BV-017-C [UCL, AC 2, LC3 441_1_1]", + test_setup, test_client, &str_snk_ac2_44_1_1, + STR_SNK_AC2_44_1_1); + define_test("BAP/UCL/STR/BV-018-C [UCL, AC 10, LC3 441_1_1]", + test_setup, test_client, &str_snk_ac10_44_1_1, + STR_SNK_AC10_44_1_1); + define_test("BAP/UCL/STR/BV-019-C [UCL, AC 2, LC3 44_2_1]", + test_setup, test_client, &str_snk_ac2_44_2_1, + STR_SNK_AC2_44_2_1); + define_test("BAP/UCL/STR/BV-020-C [UCL, AC 10, LC3 44_2_1]", + test_setup, test_client, &str_snk_ac10_44_2_1, + STR_SNK_AC10_44_2_1); + define_test("BAP/UCL/STR/BV-021-C [UCL, AC 2, LC3 48_1_1]", + test_setup, test_client, &str_snk_ac2_48_1_1, + STR_SNK_AC2_48_1_1); + define_test("BAP/UCL/STR/BV-022-C [UCL, AC 10, LC3 48_1_1]", + test_setup, test_client, &str_snk_ac10_48_1_1, + STR_SNK_AC10_48_1_1); + define_test("BAP/UCL/STR/BV-023-C [UCL, AC 2, LC3 48_2_1]", + test_setup, test_client, &str_snk_ac2_48_2_1, + STR_SNK_AC2_48_2_1); + define_test("BAP/UCL/STR/BV-024-C [UCL, AC 10, LC3 48_2_1]", + test_setup, test_client, &str_snk_ac10_48_2_1, + STR_SNK_AC10_48_2_1); + define_test("BAP/UCL/STR/BV-025-C [UCL, AC 2, LC3 48_3_1]", + test_setup, test_client, &str_snk_ac2_48_3_1, + STR_SNK_AC2_48_3_1); + define_test("BAP/UCL/STR/BV-026-C [UCL, AC 10, LC3 48_3_1]", + test_setup, test_client, &str_snk_ac10_48_3_1, + STR_SNK_AC10_48_3_1); + define_test("BAP/UCL/STR/BV-027-C [UCL, AC 2, LC3 48_4_1]", + test_setup, test_client, &str_snk_ac2_48_4_1, + STR_SNK_AC2_48_4_1); + define_test("BAP/UCL/STR/BV-028-C [UCL, AC 10, LC3 48_4_1]", + test_setup, test_client, &str_snk_ac10_48_4_1, + STR_SNK_AC10_48_4_1); + define_test("BAP/UCL/STR/BV-029-C [UCL, AC 2, LC3 48_5_1]", + test_setup, test_client, &str_snk_ac2_48_5_1, + STR_SNK_AC2_48_5_1); + define_test("BAP/UCL/STR/BV-030-C [UCL, AC 10, LC3 48_5_1]", + test_setup, test_client, &str_snk_ac10_48_5_1, + STR_SNK_AC10_48_5_1); + define_test("BAP/UCL/STR/BV-031-C [UCL, AC 2, LC3 48_6_1]", + test_setup, test_client, &str_snk_ac2_48_6_1, + STR_SNK_AC2_48_6_1); + define_test("BAP/UCL/STR/BV-032-C [UCL, AC 10, LC3 48_6_1]", + test_setup, test_client, &str_snk_ac10_48_6_1, + STR_SNK_AC10_48_6_1); + define_test("BAP/UCL/STR/BV-033-C [UCL, SRC, AC 1, LC3 8_1_1]", + test_setup, test_client, &str_src_ac1_8_1_1, + STR_SRC_AC1_8_1_1); + define_test("BAP/UCL/STR/BV-034-C [UCL, SRC, AC 4, LC3 8_1_1]", + test_setup, test_client, &str_src_ac4_8_1_1, + STR_SRC_AC4_8_1_1); + define_test("BAP/UCL/STR/BV-035-C [UCL, SRC, AC 1, LC3 8_2_1]", + test_setup, test_client, &str_src_ac1_8_2_1, + STR_SRC_AC1_8_2_1); + define_test("BAP/UCL/STR/BV-036-C [UCL, SRC, AC 4, LC3 8_2_1]", + test_setup, test_client, &str_src_ac4_8_2_1, + STR_SRC_AC4_8_2_1); + define_test("BAP/UCL/STR/BV-037-C [UCL, SRC, AC 1, LC3 16_1_1]", + test_setup, test_client, &str_src_ac1_16_1_1, + STR_SRC_AC1_16_1_1); + define_test("BAP/UCL/STR/BV-038-C [UCL, SRC, AC 4, LC3 16_1_1]", + test_setup, test_client, &str_src_ac4_16_1_1, + STR_SRC_AC4_16_1_1); + define_test("BAP/UCL/STR/BV-039-C [UCL, SRC, AC 1, LC3 16_2_1]", + test_setup, test_client, &str_src_ac1_16_2_1, + STR_SRC_AC1_16_2_1); + define_test("BAP/UCL/STR/BV-040-C [UCL, SRC, AC 4, LC3 16_2_1]", + test_setup, test_client, &str_src_ac4_16_2_1, + STR_SRC_AC4_16_2_1); + define_test("BAP/UCL/STR/BV-041-C [UCL, SRC, AC 1, LC3 24_1_1]", + test_setup, test_client, &str_src_ac1_24_1_1, + STR_SRC_AC1_24_1_1); + define_test("BAP/UCL/STR/BV-042-C [UCL, SRC, AC 4, LC3 24_1_1]", + test_setup, test_client, &str_src_ac4_24_1_1, + STR_SRC_AC4_24_1_1); + define_test("BAP/UCL/STR/BV-043-C [UCL, SRC, AC 1, LC3 24_2_1]", + test_setup, test_client, &str_src_ac1_24_2_1, + STR_SRC_AC1_24_2_1); + define_test("BAP/UCL/STR/BV-044-C [UCL, SRC, AC 4, LC3 24_2_1]", + test_setup, test_client, &str_src_ac4_24_2_1, + STR_SRC_AC4_24_2_1); + define_test("BAP/UCL/STR/BV-045-C [UCL, SRC, AC 1, LC3 32_1_1]", + test_setup, test_client, &str_src_ac1_32_1_1, + STR_SRC_AC1_32_1_1); + define_test("BAP/UCL/STR/BV-046-C [UCL, SRC, AC 4, LC3 32_1_1]", + test_setup, test_client, &str_src_ac4_32_1_1, + STR_SRC_AC4_32_1_1); + define_test("BAP/UCL/STR/BV-047-C [UCL, SRC, AC 1, LC3 32_2_1]", + test_setup, test_client, &str_src_ac1_32_2_1, + STR_SRC_AC1_32_2_1); + define_test("BAP/UCL/STR/BV-048-C [UCL, SRC, AC 4, LC3 32_2_1]", + test_setup, test_client, &str_src_ac4_32_2_1, + STR_SRC_AC4_32_2_1); + define_test("BAP/UCL/STR/BV-049-C [UCL, SRC, AC 1, LC3 44_1_1]", + test_setup, test_client, &str_src_ac1_44_1_1, + STR_SRC_AC1_44_1_1); + define_test("BAP/UCL/STR/BV-050-C [UCL, SRC, AC 4, LC3 44_1_1]", + test_setup, test_client, &str_src_ac4_44_1_1, + STR_SRC_AC4_44_1_1); + define_test("BAP/UCL/STR/BV-051-C [UCL, SRC, AC 1, LC3 44_2_1]", + test_setup, test_client, &str_src_ac1_44_2_1, + STR_SRC_AC1_44_2_1); + define_test("BAP/UCL/STR/BV-052-C [UCL, SRC, AC 4, LC3 44_2_1]", + test_setup, test_client, &str_src_ac4_44_2_1, + STR_SRC_AC4_44_2_1); + define_test("BAP/UCL/STR/BV-053-C [UCL, SRC, AC 1, LC3 48_1_1]", + test_setup, test_client, &str_src_ac1_48_1_1, + STR_SRC_AC1_48_1_1); + define_test("BAP/UCL/STR/BV-054-C [UCL, SRC, AC 4, LC3 48_1_1]", + test_setup, test_client, &str_src_ac4_48_1_1, + STR_SRC_AC4_48_1_1); + define_test("BAP/UCL/STR/BV-055-C [UCL, SRC, AC 1, LC3 48_2_1]", + test_setup, test_client, &str_src_ac1_48_2_1, + STR_SRC_AC1_48_2_1); + define_test("BAP/UCL/STR/BV-056-C [UCL, SRC, AC 4, LC3 48_2_1]", + test_setup, test_client, &str_src_ac4_48_2_1, + STR_SRC_AC4_48_2_1); + define_test("BAP/UCL/STR/BV-057-C [UCL, SRC, AC 1, LC3 48_3_1]", + test_setup, test_client, &str_src_ac1_48_3_1, + STR_SRC_AC1_48_3_1); + define_test("BAP/UCL/STR/BV-058-C [UCL, SRC, AC 4, LC3 48_3_1]", + test_setup, test_client, &str_src_ac4_48_3_1, + STR_SRC_AC4_48_3_1); + define_test("BAP/UCL/STR/BV-059-C [UCL, SRC, AC 1, LC3 48_4_1]", + test_setup, test_client, &str_src_ac1_48_4_1, + STR_SRC_AC1_48_4_1); + define_test("BAP/UCL/STR/BV-060-C [UCL, SRC, AC 4, LC3 48_4_1]", + test_setup, test_client, &str_src_ac4_48_4_1, + STR_SRC_AC4_48_4_1); + define_test("BAP/UCL/STR/BV-061-C [UCL, SRC, AC 1, LC3 48_5_1]", + test_setup, test_client, &str_src_ac1_48_5_1, + STR_SRC_AC1_48_5_1); + define_test("BAP/UCL/STR/BV-062-C [UCL, SRC, AC 4, LC3 48_5_1]", + test_setup, test_client, &str_src_ac4_48_5_1, + STR_SRC_AC4_48_5_1); + define_test("BAP/UCL/STR/BV-063-C [UCL, SRC, AC 1, LC3 48_6_1]", + test_setup, test_client, &str_src_ac1_48_6_1, + STR_SRC_AC1_48_6_1); + define_test("BAP/UCL/STR/BV-064-C [UCL, SRC, AC 4, LC3 48_6_1]", + test_setup, test_client, &str_src_ac4_48_6_1, + STR_SRC_AC4_48_6_1); + define_test("BAP/UCL/STR/BV-065-C [UCL, AC 2, LC3 8_1_2]", + test_setup, test_client, &str_snk_ac2_8_1_2, + STR_SNK_AC2_8_1_2); + define_test("BAP/UCL/STR/BV-066-C [UCL, AC 10, LC3 8_1_2]", + test_setup, test_client, &str_snk_ac10_8_1_2, + STR_SNK_AC10_8_1_2); + define_test("BAP/UCL/STR/BV-067-C [UCL, AC 2, LC3 8_2_2]", + test_setup, test_client, &str_snk_ac2_8_2_2, + STR_SNK_AC2_8_2_2); + define_test("BAP/UCL/STR/BV-068-C [UCL, AC 10, LC3 8_2_2]", + test_setup, test_client, &str_snk_ac10_8_2_2, + STR_SNK_AC10_8_2_2); + define_test("BAP/UCL/STR/BV-069-C [UCL, AC 2, LC3 16_1_2]", + test_setup, test_client, &str_snk_ac2_16_1_2, + STR_SNK_AC2_16_1_2); + define_test("BAP/UCL/STR/BV-070-C [UCL, AC 10, LC3 16_1_2]", + test_setup, test_client, &str_snk_ac10_16_1_2, + STR_SNK_AC10_16_1_2); + define_test("BAP/UCL/STR/BV-071-C [UCL, AC 2, LC3 16_2_2]", + test_setup, test_client, &str_snk_ac2_16_2_2, + STR_SNK_AC2_16_2_2); + define_test("BAP/UCL/STR/BV-072-C [UCL, AC 10, LC3 16_2_2]", + test_setup, test_client, &str_snk_ac10_16_2_2, + STR_SNK_AC10_16_2_2); + define_test("BAP/UCL/STR/BV-073-C [UCL, AC 2, LC3 24_1_2]", + test_setup, test_client, &str_snk_ac2_24_1_2, + STR_SNK_AC2_24_1_2); + define_test("BAP/UCL/STR/BV-074-C [UCL, AC 10, LC3 24_1_2]", + test_setup, test_client, &str_snk_ac10_24_1_2, + STR_SNK_AC10_24_1_2); + define_test("BAP/UCL/STR/BV-075-C [UCL, AC 2, LC3 24_2_2]", + test_setup, test_client, &str_snk_ac2_24_2_2, + STR_SNK_AC2_24_2_2); + define_test("BAP/UCL/STR/BV-076-C [UCL, AC 10, LC3 24_2_2]", + test_setup, test_client, &str_snk_ac10_24_2_2, + STR_SNK_AC10_24_2_2); + define_test("BAP/UCL/STR/BV-077-C [UCL, AC 2, LC3 32_1_2]", + test_setup, test_client, &str_snk_ac2_32_1_2, + STR_SNK_AC2_32_1_2); + define_test("BAP/UCL/STR/BV-078-C [UCL, AC 10, LC3 32_1_2]", + test_setup, test_client, &str_snk_ac10_32_1_2, + STR_SNK_AC10_32_1_2); + define_test("BAP/UCL/STR/BV-079-C [UCL, AC 2, LC3 32_2_2]", + test_setup, test_client, &str_snk_ac2_32_2_2, + STR_SNK_AC2_32_2_2); + define_test("BAP/UCL/STR/BV-080-C [UCL, AC 10, LC3 32_2_2]", + test_setup, test_client, &str_snk_ac10_32_2_2, + STR_SNK_AC10_32_2_2); + define_test("BAP/UCL/STR/BV-081-C [UCL, AC 2, LC3 44_1_2]", + test_setup, test_client, &str_snk_ac2_44_1_2, + STR_SNK_AC2_44_1_2); + define_test("BAP/UCL/STR/BV-082-C [UCL, AC 10, LC3 44_1_2]", + test_setup, test_client, &str_snk_ac10_44_1_2, + STR_SNK_AC10_44_1_2); + define_test("BAP/UCL/STR/BV-083-C [UCL, AC 2, LC3 44_2_2]", + test_setup, test_client, &str_snk_ac2_44_2_2, + STR_SNK_AC2_44_2_2); + define_test("BAP/UCL/STR/BV-084-C [UCL, AC 10, LC3 44_2_2]", + test_setup, test_client, &str_snk_ac10_44_2_2, + STR_SNK_AC10_44_2_2); + define_test("BAP/UCL/STR/BV-085-C [UCL, AC 2, LC3 48_1_2]", + test_setup, test_client, &str_snk_ac2_48_1_2, + STR_SNK_AC2_48_1_2); + define_test("BAP/UCL/STR/BV-086-C [UCL, AC 10, LC3 48_1_2]", + test_setup, test_client, &str_snk_ac10_48_1_2, + STR_SNK_AC10_48_1_2); + define_test("BAP/UCL/STR/BV-087-C [UCL, AC 2, LC3 48_2_2]", + test_setup, test_client, &str_snk_ac2_48_2_2, + STR_SNK_AC2_48_2_2); + define_test("BAP/UCL/STR/BV-088-C [UCL, AC 10, LC3 48_2_2]", + test_setup, test_client, &str_snk_ac10_48_2_2, + STR_SNK_AC10_48_2_2); + define_test("BAP/UCL/STR/BV-089-C [UCL, AC 2, LC3 48_3_2]", + test_setup, test_client, &str_snk_ac2_48_3_2, + STR_SNK_AC2_48_3_2); + define_test("BAP/UCL/STR/BV-090-C [UCL, AC 10, LC3 48_3_2]", + test_setup, test_client, &str_snk_ac10_48_3_2, + STR_SNK_AC10_48_3_2); + define_test("BAP/UCL/STR/BV-091-C [UCL, AC 2, LC3 48_4_2]", + test_setup, test_client, &str_snk_ac2_48_4_2, + STR_SNK_AC2_48_4_2); + define_test("BAP/UCL/STR/BV-092-C [UCL, AC 10, LC3 48_4_2]", + test_setup, test_client, &str_snk_ac10_48_4_2, + STR_SNK_AC10_48_4_2); + define_test("BAP/UCL/STR/BV-093-C [UCL, AC 2, LC3 48_5_2]", + test_setup, test_client, &str_snk_ac2_48_5_2, + STR_SNK_AC2_48_5_2); + define_test("BAP/UCL/STR/BV-094-C [UCL, AC 10, LC3 48_5_2]", + test_setup, test_client, &str_snk_ac10_48_5_2, + STR_SNK_AC10_48_5_2); + define_test("BAP/UCL/STR/BV-095-C [UCL, AC 2, LC3 48_6_2]", + test_setup, test_client, &str_snk_ac2_48_6_2, + STR_SNK_AC2_48_6_2); + define_test("BAP/UCL/STR/BV-096-C [UCL, AC 10, LC3 48_6_2]", + test_setup, test_client, &str_snk_ac10_48_6_2, + STR_SNK_AC10_48_6_2); + define_test("BAP/UCL/STR/BV-097-C [UCL, SRC, AC 1, LC3 8_1_2]", + test_setup, test_client, &str_src_ac1_8_1_2, + STR_SRC_AC1_8_1_2); + define_test("BAP/UCL/STR/BV-098-C [UCL, SRC, AC 4, LC3 8_1_2]", + test_setup, test_client, &str_src_ac4_8_1_2, + STR_SRC_AC4_8_1_2); + define_test("BAP/UCL/STR/BV-099-C [UCL, SRC, AC 1, LC3 8_2_2]", + test_setup, test_client, &str_src_ac1_8_2_2, + STR_SRC_AC1_8_2_2); + define_test("BAP/UCL/STR/BV-100-C [UCL, SRC, AC 4, LC3 8_2_2]", + test_setup, test_client, &str_src_ac4_8_2_2, + STR_SRC_AC4_8_2_2); + define_test("BAP/UCL/STR/BV-101-C [UCL, SRC, AC 1, LC3 16_1_2]", + test_setup, test_client, &str_src_ac1_16_1_2, + STR_SRC_AC1_16_1_2); + define_test("BAP/UCL/STR/BV-102-C [UCL, SRC, AC 4, LC3 16_1_2]", + test_setup, test_client, &str_src_ac4_16_1_2, + STR_SRC_AC4_16_1_2); + define_test("BAP/UCL/STR/BV-103-C [UCL, SRC, AC 1, LC3 16_2_2]", + test_setup, test_client, &str_src_ac1_16_2_2, + STR_SRC_AC1_16_2_2); + define_test("BAP/UCL/STR/BV-104-C [UCL, SRC, AC 4, LC3 16_2_2]", + test_setup, test_client, &str_src_ac4_16_2_2, + STR_SRC_AC4_16_2_2); + define_test("BAP/UCL/STR/BV-105-C [UCL, SRC, AC 1, LC3 24_1_2]", + test_setup, test_client, &str_src_ac1_24_1_2, + STR_SRC_AC1_24_1_2); + define_test("BAP/UCL/STR/BV-106-C [UCL, SRC, AC 4, LC3 24_1_2]", + test_setup, test_client, &str_src_ac4_24_1_2, + STR_SRC_AC4_24_1_2); + define_test("BAP/UCL/STR/BV-107-C [UCL, SRC, AC 1, LC3 24_2_2]", + test_setup, test_client, &str_src_ac1_24_2_2, + STR_SRC_AC1_24_2_2); + define_test("BAP/UCL/STR/BV-108-C [UCL, SRC, AC 4, LC3 24_2_2]", + test_setup, test_client, &str_src_ac4_24_2_2, + STR_SRC_AC4_24_2_2); + define_test("BAP/UCL/STR/BV-109-C [UCL, SRC, AC 1, LC3 32_1_2]", + test_setup, test_client, &str_src_ac1_32_1_2, + STR_SRC_AC1_32_1_2); + define_test("BAP/UCL/STR/BV-110-C [UCL, SRC, AC 4, LC3 32_1_2]", + test_setup, test_client, &str_src_ac4_32_1_2, + STR_SRC_AC4_32_1_2); + define_test("BAP/UCL/STR/BV-111-C [UCL, SRC, AC 1, LC3 32_2_2]", + test_setup, test_client, &str_src_ac1_32_2_2, + STR_SRC_AC1_32_2_2); + define_test("BAP/UCL/STR/BV-112-C [UCL, SRC, AC 4, LC3 32_2_2]", + test_setup, test_client, &str_src_ac4_32_2_2, + STR_SRC_AC4_32_2_2); + define_test("BAP/UCL/STR/BV-113-C [UCL, SRC, AC 1, LC3 44_1_2]", + test_setup, test_client, &str_src_ac1_44_1_2, + STR_SRC_AC1_44_1_2); + define_test("BAP/UCL/STR/BV-114-C [UCL, SRC, AC 4, LC3 44_1_2]", + test_setup, test_client, &str_src_ac4_44_1_2, + STR_SRC_AC4_44_1_2); + define_test("BAP/UCL/STR/BV-115-C [UCL, SRC, AC 1, LC3 44_2_2]", + test_setup, test_client, &str_src_ac1_44_2_2, + STR_SRC_AC1_44_2_2); + define_test("BAP/UCL/STR/BV-116-C [UCL, SRC, AC 4, LC3 44_2_2]", + test_setup, test_client, &str_src_ac4_44_2_2, + STR_SRC_AC4_44_2_2); + define_test("BAP/UCL/STR/BV-117-C [UCL, SRC, AC 1, LC3 48_1_2]", + test_setup, test_client, &str_src_ac1_48_1_2, + STR_SRC_AC1_48_1_2); + define_test("BAP/UCL/STR/BV-118-C [UCL, SRC, AC 4, LC3 48_1_2]", + test_setup, test_client, &str_src_ac4_48_1_2, + STR_SRC_AC4_48_1_2); + define_test("BAP/UCL/STR/BV-119-C [UCL, SRC, AC 1, LC3 48_2_2]", + test_setup, test_client, &str_src_ac1_48_2_2, + STR_SRC_AC1_48_2_2); + define_test("BAP/UCL/STR/BV-120-C [UCL, SRC, AC 4, LC3 48_2_2]", + test_setup, test_client, &str_src_ac4_48_2_2, + STR_SRC_AC4_48_2_2); + define_test("BAP/UCL/STR/BV-121-C [UCL, SRC, AC 1, LC3 48_3_2]", + test_setup, test_client, &str_src_ac1_48_3_2, + STR_SRC_AC1_48_3_2); + define_test("BAP/UCL/STR/BV-122-C [UCL, SRC, AC 4, LC3 48_3_2]", + test_setup, test_client, &str_src_ac4_48_3_2, + STR_SRC_AC4_48_3_2); + define_test("BAP/UCL/STR/BV-123-C [UCL, SRC, AC 1, LC3 48_4_2]", + test_setup, test_client, &str_src_ac1_48_4_2, + STR_SRC_AC1_48_4_2); + define_test("BAP/UCL/STR/BV-124-C [UCL, SRC, AC 4, LC3 48_4_2]", + test_setup, test_client, &str_src_ac4_48_4_2, + STR_SRC_AC4_48_4_2); + define_test("BAP/UCL/STR/BV-121-C [UCL, SRC, AC 1, LC3 48_5_2]", + test_setup, test_client, &str_src_ac1_48_5_2, + STR_SRC_AC1_48_5_2); + define_test("BAP/UCL/STR/BV-122-C [UCL, SRC, AC 4, LC3 48_5_2]", + test_setup, test_client, &str_src_ac4_48_5_2, + STR_SRC_AC4_48_5_2); + define_test("BAP/UCL/STR/BV-123-C [UCL, SRC, AC 1, LC3 48_6_2]", + test_setup, test_client, &str_src_ac1_48_6_2, + STR_SRC_AC1_48_6_2); + define_test("BAP/UCL/STR/BV-124-C [UCL, SRC, AC 4, LC3 48_6_2]", + test_setup, test_client, &str_src_ac4_48_6_2, + STR_SRC_AC4_48_6_2); +} + +static void test_scc(void) +{ + test_scc_cc_lc3(); + test_scc_cc_vs(); + test_scc_qos_lc3(); + test_scc_qos_vs(); + test_scc_enable(); + test_scc_disable(); + test_scc_release(); + test_scc_metadata(); + test_str_1_1_1_lc3(); +} + +static struct test_config cfg_bsrc_8_1_1 = { + .cc = LC3_CONFIG_8_1, + .qos = LC3_QOS_8_1_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_8_1), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_8_1_2 = { + .cc = LC3_CONFIG_8_1, + .qos = LC3_QOS_8_1_2_B, + .base = UTIL_IOV_INIT(BASE_LC3_8_1), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_8_2_1 = { + .cc = LC3_CONFIG_8_2, + .qos = LC3_QOS_8_2_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_8_2), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_8_2_2 = { + .cc = LC3_CONFIG_8_2, + .qos = LC3_QOS_8_2_2_B, + .base = UTIL_IOV_INIT(BASE_LC3_8_2), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_16_1_1 = { + .cc = LC3_CONFIG_16_1, + .qos = LC3_QOS_16_1_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_16_1), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_16_1_2 = { + .cc = LC3_CONFIG_16_1, + .qos = LC3_QOS_16_1_2_B, + .base = UTIL_IOV_INIT(BASE_LC3_16_1), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_16_2_1 = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_16_2), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_16_2_2 = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_2_B, + .base = UTIL_IOV_INIT(BASE_LC3_16_2), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_24_1_1 = { + .cc = LC3_CONFIG_24_1, + .qos = LC3_QOS_24_1_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_24_1), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_24_1_2 = { + .cc = LC3_CONFIG_24_1, + .qos = LC3_QOS_24_1_2_B, + .base = UTIL_IOV_INIT(BASE_LC3_24_1), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_24_2_1 = { + .cc = LC3_CONFIG_24_2, + .qos = LC3_QOS_24_2_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_24_2), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_24_2_2 = { + .cc = LC3_CONFIG_24_2, + .qos = LC3_QOS_24_2_2_B, + .base = UTIL_IOV_INIT(BASE_LC3_24_2), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_32_1_1 = { + .cc = LC3_CONFIG_32_1, + .qos = LC3_QOS_32_1_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_32_1), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_32_1_2 = { + .cc = LC3_CONFIG_32_1, + .qos = LC3_QOS_32_1_2_B, + .base = UTIL_IOV_INIT(BASE_LC3_32_1), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_32_2_1 = { + .cc = LC3_CONFIG_32_2, + .qos = LC3_QOS_32_2_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_32_2), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_32_2_2 = { + .cc = LC3_CONFIG_32_2, + .qos = LC3_QOS_32_2_2_B, + .base = UTIL_IOV_INIT(BASE_LC3_32_2), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_44_1_1 = { + .cc = LC3_CONFIG_44_1, + .qos = LC3_QOS_44_1_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_44_1), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_44_1_2 = { + .cc = LC3_CONFIG_44_1, + .qos = LC3_QOS_44_1_2_B, + .base = UTIL_IOV_INIT(BASE_LC3_44_1), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_44_2_1 = { + .cc = LC3_CONFIG_44_2, + .qos = LC3_QOS_44_2_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_44_2), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_44_2_2 = { + .cc = LC3_CONFIG_44_2, + .qos = LC3_QOS_44_2_2_B, + .base = UTIL_IOV_INIT(BASE_LC3_44_2), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_48_1_1 = { + .cc = LC3_CONFIG_48_1, + .qos = LC3_QOS_48_1_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_1), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_48_1_2 = { + .cc = LC3_CONFIG_48_1, + .qos = LC3_QOS_48_1_2_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_1), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_48_2_1 = { + .cc = LC3_CONFIG_48_2, + .qos = LC3_QOS_48_2_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_2), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_48_2_2 = { + .cc = LC3_CONFIG_48_2, + .qos = LC3_QOS_48_2_2_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_2), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_48_3_1 = { + .cc = LC3_CONFIG_48_3, + .qos = LC3_QOS_48_3_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_3), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_48_3_2 = { + .cc = LC3_CONFIG_48_3, + .qos = LC3_QOS_48_3_2_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_3), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_48_4_1 = { + .cc = LC3_CONFIG_48_4, + .qos = LC3_QOS_48_4_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_4), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_48_4_2 = { + .cc = LC3_CONFIG_48_4, + .qos = LC3_QOS_48_4_2_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_4), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_48_5_1 = { + .cc = LC3_CONFIG_48_5, + .qos = LC3_QOS_48_5_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_5), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_48_5_2 = { + .cc = LC3_CONFIG_48_5, + .qos = LC3_QOS_48_5_2_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_5), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_48_6_1 = { + .cc = LC3_CONFIG_48_6, + .qos = LC3_QOS_48_6_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_6), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +static struct test_config cfg_bsrc_48_6_2 = { + .cc = LC3_CONFIG_48_6, + .qos = LC3_QOS_48_6_2_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_6), + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +#define VS_CC \ + 0x02, 0x01, 0x08, \ + 0x02, 0x02, 0x00, \ + 0x05, 0x03, 0x01, 0x00, 0x00, 0x00, \ + 0x03, 0x04, 0x75, 0x00 + +#define VS_CFG \ + 0x10, \ + VS_CC + +#define QOS_BCAST \ +{ \ + .bcast.big = 0x00, \ + .bcast.bis = 0x00, \ + .bcast.framing = LC3_QOS_UNFRAMED, \ + .bcast.delay = 40000, \ + .bcast.io_qos.interval = 7500, \ + .bcast.io_qos.latency = 10, \ + .bcast.io_qos.sdu = 40, \ + .bcast.io_qos.phy = BT_BAP_CONFIG_PHY_2M, \ + .bcast.io_qos.rtn = 2, \ +} + +static struct test_config cfg_bsrc_vs = { + .cc = UTIL_IOV_INIT(VS_CC), + .qos = QOS_BCAST, + .base = UTIL_IOV_INIT(BASE_VS(VS_CFG)), + .vs = true, + .src = true, + .state_func = bsrc_state_cfg, + .streams = 1, +}; + +/* Test Purpose: + * Verify that a Broadcast Source IUT can configure a broadcast + * Audio Stream with information defined by the values in its BASE + * structure. The verification is performed one Codec Setting and + * set of parameters at a time, as enumerated in the test cases in + * Table 4.73. + * + * Pass verdict: + * In step 2, the AdvData field of AUX_SYNC_IND and optionally + * AUX_CHAIN_IND PDUs contains the configured BASE information. + * + * In step 3, the IUT transmits the PA synchronization information in + * the SyncInfo field of the Extended Header field of AUX_ADV_IND PDUs. + * The AUX_ADV_IND PDUs include the Service Data AD Type in the AdvData + * field with the Service UUID equal to the Broadcast Audio Announcement + * Service UUID. The additional service data includes Broadcast_ID. + * + * Each value included in the Codec_Specific_Configuration is formatted in + * an LTV structure with the length, type, and value specified in Table 4.74. + */ +static void test_bsrc_scc_config(void) +{ + define_test("BAP/BSRC/SCC/BV-01-C [Config Broadcast, LC3 8_1_1]", + NULL, test_bcast, &cfg_bsrc_8_1_1, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-02-C [Config Broadcast, LC3 8_2_1]", + NULL, test_bcast, &cfg_bsrc_8_2_1, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-03-C [Config Broadcast, LC3 16_1_1]", + NULL, test_bcast, &cfg_bsrc_16_1_1, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-04-C [Config Broadcast, LC3 16_2_1]", + NULL, test_bcast, &cfg_bsrc_16_2_1, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-05-C [Config Broadcast, LC3 24_1_1]", + NULL, test_bcast, &cfg_bsrc_24_1_1, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-06-C [Config Broadcast, LC3 24_2_1]", + NULL, test_bcast, &cfg_bsrc_24_2_1, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-07-C [Config Broadcast, LC3 32_1_1]", + NULL, test_bcast, &cfg_bsrc_32_1_1, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-08-C [Config Broadcast, LC3 32_2_1]", + NULL, test_bcast, &cfg_bsrc_32_2_1, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-09-C [Config Broadcast, LC3 44.1_1_1]", + NULL, test_bcast, &cfg_bsrc_44_1_1, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-10-C [Config Broadcast, LC3 44.1_2_1]", + NULL, test_bcast, &cfg_bsrc_44_2_1, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-11-C [Config Broadcast, LC3 48_1_1]", + NULL, test_bcast, &cfg_bsrc_48_1_1, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-12-C [Config Broadcast, LC3 48_2_1]", + NULL, test_bcast, &cfg_bsrc_48_2_1, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-13-C [Config Broadcast, LC3 48_3_1]", + NULL, test_bcast, &cfg_bsrc_48_3_1, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-14-C [Config Broadcast, LC3 48_4_1]", + NULL, test_bcast, &cfg_bsrc_48_4_1, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-15-C [Config Broadcast, LC3 48_5_1]", + NULL, test_bcast, &cfg_bsrc_48_5_1, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-16-C [Config Broadcast, LC3 48_6_1]", + NULL, test_bcast, &cfg_bsrc_48_6_1, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-17-C [Config Broadcast, LC3 8_1_2]", + NULL, test_bcast, &cfg_bsrc_8_1_2, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-18-C [Config Broadcast, LC3 8_2_2]", + NULL, test_bcast, &cfg_bsrc_8_2_2, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-19-C [Config Broadcast, LC3 16_1_2]", + NULL, test_bcast, &cfg_bsrc_16_1_2, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-20-C [Config Broadcast, LC3 16_2_2]", + NULL, test_bcast, &cfg_bsrc_16_2_2, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-21-C [Config Broadcast, LC3 24_1_2]", + NULL, test_bcast, &cfg_bsrc_24_1_2, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-22-C [Config Broadcast, LC3 24_2_2]", + NULL, test_bcast, &cfg_bsrc_24_2_2, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-23-C [Config Broadcast, LC3 32_1_2]", + NULL, test_bcast, &cfg_bsrc_32_1_2, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-24-C [Config Broadcast, LC3 32_2_2]", + NULL, test_bcast, &cfg_bsrc_32_2_2, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-25-C [Config Broadcast, LC3 44.1_1_2]", + NULL, test_bcast, &cfg_bsrc_44_1_2, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-26-C [Config Broadcast, LC3 44.1_2_2]", + NULL, test_bcast, &cfg_bsrc_44_2_2, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-27-C [Config Broadcast, LC3 48_1_2]", + NULL, test_bcast, &cfg_bsrc_48_1_2, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-28-C [Config Broadcast, LC3 48_2_2]", + NULL, test_bcast, &cfg_bsrc_48_2_2, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-29-C [Config Broadcast, LC3 48_3_2]", + NULL, test_bcast, &cfg_bsrc_48_3_2, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-30-C [Config Broadcast, LC3 48_4_2]", + NULL, test_bcast, &cfg_bsrc_48_4_2, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-31-C [Config Broadcast, LC3 48_5_2]", + NULL, test_bcast, &cfg_bsrc_48_5_2, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-32-C [Config Broadcast, LC3 48_6_2]", + NULL, test_bcast, &cfg_bsrc_48_6_2, IOV_NULL); + + define_test("BAP/BSRC/SCC/BV-33-C [Config Broadcast, VS]", + NULL, test_bcast, &cfg_bsrc_vs, IOV_NULL); +} + +static void bsrc_state_estab(struct bt_bap_stream *stream, uint8_t old_state, + uint8_t new_state, void *user_data) +{ + switch (new_state) { + case BT_BAP_STREAM_STATE_CONFIG: + bt_bap_stream_enable(stream, true, NULL, NULL, NULL); + break; + case BT_BAP_STREAM_STATE_ENABLING: + bt_bap_stream_start(stream, NULL, NULL); + break; + case BT_BAP_STREAM_STATE_STREAMING: + tester_test_passed(); + break; + } +} + +static struct test_config cfg_bsrc_8_1_1_estab = { + .cc = LC3_CONFIG_8_1, + .qos = LC3_QOS_8_1_1_B, + .src = true, + .state_func = bsrc_state_estab, + .streams = 1, +}; + +/* Test Purpose: + * Verify that a Broadcast Source IUT can establish a broadcast + * Audio Stream. + * + * Pass verdict: + * The IUT sends AUX_SYNC_IND PDUs with an Extended Header + * containing BIGInfo in the ACAD field. The IUT sends BIS Data + * PDUs over the broadcast Audio Stream. + */ +static void test_bsrc_scc_estab(void) +{ + define_test("BAP/BSRC/SCC/BV-35-C [Establishes Broadcast]", + NULL, test_bcast, &cfg_bsrc_8_1_1_estab, IOV_NULL); +} + +static void bsrc_state_disable(struct bt_bap_stream *stream, uint8_t old_state, + uint8_t new_state, void *user_data) +{ + switch (new_state) { + case BT_BAP_STREAM_STATE_CONFIG: + if (old_state == BT_BAP_STREAM_STATE_IDLE) + bt_bap_stream_enable(stream, true, NULL, NULL, NULL); + else if (old_state == BT_BAP_STREAM_STATE_STREAMING) + tester_test_passed(); + else + /* Other transitions to CONFIG state are invalid. */ + tester_test_failed(); + break; + case BT_BAP_STREAM_STATE_ENABLING: + bt_bap_stream_start(stream, NULL, NULL); + break; + case BT_BAP_STREAM_STATE_STREAMING: + bt_bap_stream_disable(stream, true, NULL, NULL); + break; + } +} + +static struct test_config cfg_bsrc_8_1_1_disable = { + .cc = LC3_CONFIG_8_1, + .qos = LC3_QOS_8_1_1_B, + .src = true, + .state_func = bsrc_state_disable, + .streams = 1, +}; + +/* Test Purpose: + * Verify that a Broadcast Source IUT can disable a broadcast + * Audio Stream. + * + * Pass verdict: + * The IUT sends a BIG_TERMINATE_IND PDU in step 1. + */ +static void test_bsrc_scc_disable(void) +{ + define_test("BAP/BSRC/SCC/BV-36-C [Disables Broadcast]", + NULL, test_bcast, &cfg_bsrc_8_1_1_disable, IOV_NULL); +} + +static void bsrc_state_release(struct bt_bap_stream *stream, uint8_t old_state, + uint8_t new_state, void *user_data) +{ + switch (new_state) { + case BT_BAP_STREAM_STATE_CONFIG: + if (old_state == BT_BAP_STREAM_STATE_IDLE) + bt_bap_stream_enable(stream, true, NULL, NULL, NULL); + else if (old_state == BT_BAP_STREAM_STATE_STREAMING) + bt_bap_stream_release(stream, NULL, NULL); + else + /* Other transitions to CONFIG state are invalid. */ + tester_test_failed(); + break; + case BT_BAP_STREAM_STATE_ENABLING: + bt_bap_stream_start(stream, NULL, NULL); + break; + case BT_BAP_STREAM_STATE_STREAMING: + bt_bap_stream_disable(stream, true, NULL, NULL); + break; + case BT_BAP_STREAM_STATE_IDLE: + tester_test_passed(); + break; + } +} + +static struct test_config cfg_bsrc_8_1_1_release = { + .cc = LC3_CONFIG_8_1, + .qos = LC3_QOS_8_1_1_B, + .src = true, + .state_func = bsrc_state_release, + .streams = 1, +}; + +/* Test Purpose: + * Verify that a Broadcast Source IUT can release a broadcast + * Audio Stream and transition from Configured state to Idle + * state. + * + * Pass verdict: + * The IUT stops transmitting periodic advertising. + */ +static void test_bsrc_scc_release(void) +{ + define_test("BAP/BSRC/SCC/BV-37-C [Releases Broadcast]", + NULL, test_bcast, &cfg_bsrc_8_1_1_release, IOV_NULL); +} + +static void test_bsrc_scc(void) +{ + test_bsrc_scc_config(); + test_bsrc_scc_estab(); + test_bsrc_scc_disable(); + test_bsrc_scc_release(); +} + +static struct test_config cfg_bsnk_8_1 = { + .cc = LC3_CONFIG_8_1, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state, + .streams = 1, +}; + +static struct test_config cfg_bsnk_8_2 = { + .cc = LC3_CONFIG_8_2, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state, + .streams = 1, +}; + +static struct test_config cfg_bsnk_16_1 = { + .cc = LC3_CONFIG_16_1, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state, + .streams = 1, +}; + +static struct test_config cfg_bsnk_16_2 = { + .cc = LC3_CONFIG_16_2, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state, + .streams = 1, +}; + +static struct test_config cfg_bsnk_24_1 = { + .cc = LC3_CONFIG_24_1, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state, + .streams = 1, +}; + +static struct test_config cfg_bsnk_24_2 = { + .cc = LC3_CONFIG_24_2, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state, + .streams = 1, +}; + +static struct test_config cfg_bsnk_32_1 = { + .cc = LC3_CONFIG_32_1, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state, + .streams = 1, +}; + +static struct test_config cfg_bsnk_32_2 = { + .cc = LC3_CONFIG_32_2, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state, + .streams = 1, +}; + +static struct test_config cfg_bsnk_44_1 = { + .cc = LC3_CONFIG_44_1, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state, + .streams = 1, +}; + +static struct test_config cfg_bsnk_44_2 = { + .cc = LC3_CONFIG_44_2, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state, + .streams = 1, +}; + +static struct test_config cfg_bsnk_48_1 = { + .cc = LC3_CONFIG_48_1, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state, + .streams = 1, +}; + +static struct test_config cfg_bsnk_48_2 = { + .cc = LC3_CONFIG_48_2, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state, + .streams = 1, +}; + +static struct test_config cfg_bsnk_48_3 = { + .cc = LC3_CONFIG_48_3, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state, + .streams = 1, +}; + +static struct test_config cfg_bsnk_48_4 = { + .cc = LC3_CONFIG_48_4, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state, + .streams = 1, +}; + +static struct test_config cfg_bsnk_48_5 = { + .cc = LC3_CONFIG_48_5, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state, + .streams = 1, +}; + +static struct test_config cfg_bsnk_48_6 = { + .cc = LC3_CONFIG_48_6, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state, + .streams = 1, +}; + +static struct test_config cfg_bsnk_vs = { + .cc = UTIL_IOV_INIT(VS_CC), + .qos = QOS_BCAST, + .snk = true, + .vs = true, + .state_func = bsnk_state, + .streams = 1, +}; + +static void test_bsnk_scc(void) +{ + define_test("BAP/BSNK/SCC/BV-01-C [Sync to PA, LC3 8_1_1]", + NULL, test_bcast, &cfg_bsnk_8_1, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-02-C [Sync to PA, LC3 8_2_1]", + NULL, test_bcast, &cfg_bsnk_8_2, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-03-C [Sync to PA, LC3 16_1_1]", + NULL, test_bcast, &cfg_bsnk_16_1, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-04-C [Sync to PA, LC3 16_2_1]", + NULL, test_bcast, &cfg_bsnk_16_2, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-05-C [Sync to PA, LC3 24_1_1]", + NULL, test_bcast, &cfg_bsnk_24_1, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-06-C [Sync to PA, LC3 24_2_1]", + NULL, test_bcast, &cfg_bsnk_24_2, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-07-C [Sync to PA, LC3 32_1_1]", + NULL, test_bcast, &cfg_bsnk_32_1, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-08-C [Sync to PA, LC3 32_2_1]", + NULL, test_bcast, &cfg_bsnk_32_2, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-09-C [Sync to PA, LC3 44.1_1_1]", + NULL, test_bcast, &cfg_bsnk_44_1, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-10-C [Sync to PA, LC3 44.1_2_1]", + NULL, test_bcast, &cfg_bsnk_44_2, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-11-C [Sync to PA, LC3 48_1_1]", + NULL, test_bcast, &cfg_bsnk_48_1, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-12-C [Sync to PA, LC3 48_2_1]", + NULL, test_bcast, &cfg_bsnk_48_2, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-13-C [Sync to PA, LC3 48_3_1]", + NULL, test_bcast, &cfg_bsnk_48_3, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-14-C [Sync to PA, LC3 48_4_1]", + NULL, test_bcast, &cfg_bsnk_48_4, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-15-C [Sync to PA, LC3 48_5_1]", + NULL, test_bcast, &cfg_bsnk_48_5, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-16-C [Sync to PA, LC3 48_6_1]", + NULL, test_bcast, &cfg_bsnk_48_6, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-17-C [Sync to PA, LC3 8_1_2]", + NULL, test_bcast, &cfg_bsnk_8_1, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-18-C [Sync to PA, LC3 8_2_2]", + NULL, test_bcast, &cfg_bsnk_8_2, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-19-C [Sync to PA, LC3 16_1_2]", + NULL, test_bcast, &cfg_bsnk_16_1, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-20-C [Sync to PA, LC3 16_2_2]", + NULL, test_bcast, &cfg_bsnk_16_2, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-21-C [Sync to PA, LC3 24_1_2]", + NULL, test_bcast, &cfg_bsnk_24_1, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-22-C [Sync to PA, LC3 24_2_2]", + NULL, test_bcast, &cfg_bsnk_24_2, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-23-C [Sync to PA, LC3 32_1_2]", + NULL, test_bcast, &cfg_bsnk_32_1, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-24-C [Sync to PA, LC3 32_2_2]", + NULL, test_bcast, &cfg_bsnk_32_2, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-25-C [Sync to PA, LC3 44.1_1_2]", + NULL, test_bcast, &cfg_bsnk_44_1, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-26-C [Sync to PA, LC3 44.1_2_2]", + NULL, test_bcast, &cfg_bsnk_44_2, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-27-C [Sync to PA, LC3 48_1_2]", + NULL, test_bcast, &cfg_bsnk_48_1, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-28-C [Sync to PA, LC3 48_2_2]", + NULL, test_bcast, &cfg_bsnk_48_2, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-29-C [Sync to PA, LC3 48_3_2]", + NULL, test_bcast, &cfg_bsnk_48_3, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-30-C [Sync to PA, LC3 48_4_2]", + NULL, test_bcast, &cfg_bsnk_48_4, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-31-C [Sync to PA, LC3 48_5_2]", + NULL, test_bcast, &cfg_bsnk_48_5, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-32-C [Sync to PA, LC3 48_6_2]", + NULL, test_bcast, &cfg_bsnk_48_6, IOV_NULL); + + define_test("BAP/BSNK/SCC/BV-33-C [Sync to PA, VS]", + NULL, test_bcast, &cfg_bsnk_vs, IOV_NULL); +} + +static void stream_count_streaming(void *data, void *user_data) +{ + struct bt_bap_stream *stream = data; + uint8_t *num = user_data; + + if (bt_bap_stream_get_state(stream) == BT_BAP_STREAM_STATE_STREAMING) + (*num)++; +} + +static void bsnk_state_str(struct bt_bap_stream *stream, uint8_t old_state, + uint8_t new_state, void *user_data) +{ + struct test_data *data = user_data; + struct iovec *cc; + uint8_t num = 0; + + switch (new_state) { + case BT_BAP_STREAM_STATE_CONFIG: + if (old_state == BT_BAP_STREAM_STATE_IDLE) { + /* Check that stream has been configured as expected */ + cc = bt_bap_stream_get_config(stream); + + g_assert(cc); + g_assert(cc->iov_len == data->cfg->cc.iov_len); + g_assert(memcmp(cc->iov_base, data->cfg->cc.iov_base, + cc->iov_len) == 0); + + /* Enable stream */ + bt_bap_stream_enable(stream, true, NULL, NULL, NULL); + } else { + /* Other state transitions are invalid */ + tester_test_failed(); + } + + break; + case BT_BAP_STREAM_STATE_ENABLING: + /* Start stream */ + bt_bap_stream_start(stream, NULL, NULL); + break; + case BT_BAP_STREAM_STATE_STREAMING: + queue_foreach(data->streams, stream_count_streaming, &num); + + if (num == data->cfg->streams) + /* Test is completed after all streams have transitioned + * to STREAMING state. + */ + tester_test_passed(); + + break; + } +} + +static struct test_config cfg_bsnk_str_8_1 = { + .cc = LC3_CONFIG_8_1, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsnk_str_8_2 = { + .cc = LC3_CONFIG_8_2, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsnk_str_16_1 = { + .cc = LC3_CONFIG_16_1, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsnk_str_16_2 = { + .cc = LC3_CONFIG_16_2, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsnk_str_24_1 = { + .cc = LC3_CONFIG_24_1, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsnk_str_24_2 = { + .cc = LC3_CONFIG_24_2, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsnk_str_32_1 = { + .cc = LC3_CONFIG_32_1, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsnk_str_32_2 = { + .cc = LC3_CONFIG_32_2, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsnk_str_44_1 = { + .cc = LC3_CONFIG_44_1, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsnk_str_44_2 = { + .cc = LC3_CONFIG_44_2, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsnk_str_48_1 = { + .cc = LC3_CONFIG_48_1, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsnk_str_48_2 = { + .cc = LC3_CONFIG_48_2, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsnk_str_48_3 = { + .cc = LC3_CONFIG_48_3, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsnk_str_48_4 = { + .cc = LC3_CONFIG_48_4, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsnk_str_48_5 = { + .cc = LC3_CONFIG_48_5, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsnk_str_48_6 = { + .cc = LC3_CONFIG_48_6, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsnk_str_vs = { + .cc = UTIL_IOV_INIT(VS_CC), + .qos = QOS_BCAST, + .snk = true, + .vs = true, + .state_func = bsnk_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsnk_str_8_1_mbis = { + .cc = LC3_CONFIG_8_1, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsnk_str_8_2_mbis = { + .cc = LC3_CONFIG_8_2, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsnk_str_16_1_mbis = { + .cc = LC3_CONFIG_16_1, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsnk_str_16_2_mbis = { + .cc = LC3_CONFIG_16_2, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsnk_str_24_1_mbis = { + .cc = LC3_CONFIG_24_1, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsnk_str_24_2_mbis = { + .cc = LC3_CONFIG_24_2, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsnk_str_32_1_mbis = { + .cc = LC3_CONFIG_32_1, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsnk_str_32_2_mbis = { + .cc = LC3_CONFIG_32_2, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsnk_str_44_1_mbis = { + .cc = LC3_CONFIG_44_1, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsnk_str_44_2_mbis = { + .cc = LC3_CONFIG_44_2, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsnk_str_48_1_mbis = { + .cc = LC3_CONFIG_48_1, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsnk_str_48_2_mbis = { + .cc = LC3_CONFIG_48_2, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsnk_str_48_3_mbis = { + .cc = LC3_CONFIG_48_3, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsnk_str_48_4_mbis = { + .cc = LC3_CONFIG_48_4, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsnk_str_48_5_mbis = { + .cc = LC3_CONFIG_48_5, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsnk_str_48_6_mbis = { + .cc = LC3_CONFIG_48_6, + .qos = QOS_BCAST, + .snk = true, + .state_func = bsnk_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsnk_str_vs_mbis = { + .cc = UTIL_IOV_INIT(VS_CC), + .qos = QOS_BCAST, + .snk = true, + .vs = true, + .state_func = bsnk_state_str, + .streams = 2, +}; + +static void test_bsnk_str(void) +{ + define_test("BAP/BSNK/STR/BV-01-C [BSNK, LC3 8_1]", + NULL, test_bcast, &cfg_bsnk_str_8_1, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-02-C [BSNK, LC3 8_2]", + NULL, test_bcast, &cfg_bsnk_str_8_2, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-03-C [BSNK, LC3 16_1]", + NULL, test_bcast, &cfg_bsnk_str_16_1, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-04-C [BSNK, LC3 16_2]", + NULL, test_bcast, &cfg_bsnk_str_16_2, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-05-C [BSNK, LC3 24_1]", + NULL, test_bcast, &cfg_bsnk_str_24_1, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-06-C [BSNK, LC3 24_2]", + NULL, test_bcast, &cfg_bsnk_str_24_2, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-07-C [BSNK, LC3 32_1]", + NULL, test_bcast, &cfg_bsnk_str_32_1, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-08-C [BSNK, LC3 32_2]", + NULL, test_bcast, &cfg_bsnk_str_32_2, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-09-C [BSNK, LC3 44.1_1]", + NULL, test_bcast, &cfg_bsnk_str_44_1, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-10-C [BSNK, LC3 44.1_2]", + NULL, test_bcast, &cfg_bsnk_str_44_2, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-11-C [BSNK, LC3 48_1]", + NULL, test_bcast, &cfg_bsnk_str_48_1, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-12-C [BSNK, LC3 48_2]", + NULL, test_bcast, &cfg_bsnk_str_48_2, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-13-C [BSNK, LC3 48_3]", + NULL, test_bcast, &cfg_bsnk_str_48_3, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-14-C [BSNK, LC3 48_4]", + NULL, test_bcast, &cfg_bsnk_str_48_4, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-15-C [BSNK, LC3 48_5]", + NULL, test_bcast, &cfg_bsnk_str_48_5, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-16-C [BSNK, LC3 48_6]", + NULL, test_bcast, &cfg_bsnk_str_48_6, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-17-C [BSNK, VS]", + NULL, test_bcast, &cfg_bsnk_str_vs, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-18-C [BSNK, Multiple BISes, LC3 8_1]", + NULL, test_bcast, &cfg_bsnk_str_8_1_mbis, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-19-C [BSNK, Multiple BISes, LC3 8_2]", + NULL, test_bcast, &cfg_bsnk_str_8_2_mbis, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-20-C [BSNK, Multiple BISes, LC3 16_1]", + NULL, test_bcast, &cfg_bsnk_str_16_1_mbis, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-21-C [BSNK, Multiple BISes, LC3 16_2]", + NULL, test_bcast, &cfg_bsnk_str_16_2_mbis, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-22-C [BSNK, Multiple BISes, LC3 24_1]", + NULL, test_bcast, &cfg_bsnk_str_24_1_mbis, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-23-C [BSNK, Multiple BISes, LC3 24_2]", + NULL, test_bcast, &cfg_bsnk_str_24_2_mbis, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-24-C [BSNK, Multiple BISes, LC3 32_1]", + NULL, test_bcast, &cfg_bsnk_str_32_1_mbis, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-25-C [BSNK, Multiple BISes, LC3 32_2]", + NULL, test_bcast, &cfg_bsnk_str_32_2_mbis, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-26-C [BSNK, Multiple BISes, LC3 44.1_1]", + NULL, test_bcast, &cfg_bsnk_str_44_1_mbis, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-27-C [BSNK, Multiple BISes, LC3 44.1_2]", + NULL, test_bcast, &cfg_bsnk_str_44_2_mbis, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-28-C [BSNK, Multiple BISes, LC3 48_1]", + NULL, test_bcast, &cfg_bsnk_str_48_1_mbis, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-29-C [BSNK, Multiple BISes, LC3 48_2]", + NULL, test_bcast, &cfg_bsnk_str_48_2_mbis, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-30-C [BSNK, Multiple BISes, LC3 48_3]", + NULL, test_bcast, &cfg_bsnk_str_48_3_mbis, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-31-C [BSNK, Multiple BISes, LC3 48_4]", + NULL, test_bcast, &cfg_bsnk_str_48_4_mbis, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-32-C [BSNK, Multiple BISes, LC3 48_5]", + NULL, test_bcast, &cfg_bsnk_str_48_5_mbis, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-33-C [BSNK, Multiple BISes, LC3 48_6]", + NULL, test_bcast, &cfg_bsnk_str_48_6_mbis, IOV_NULL); + + define_test("BAP/BSNK/STR/BV-34-C [BSNK, Multiple BISes, VS]", + NULL, test_bcast, &cfg_bsnk_str_vs_mbis, IOV_NULL); +} + +static void stream_count_config(void *data, void *user_data) +{ + struct bt_bap_stream *stream = data; + uint8_t *streams = user_data; + + if (bt_bap_stream_get_state(stream) == BT_BAP_STREAM_STATE_CONFIG) + (*streams)++; +} + +static void stream_count_enabling(void *data, void *user_data) +{ + struct bt_bap_stream *stream = data; + uint8_t *streams = user_data; + + if (bt_bap_stream_get_state(stream) == BT_BAP_STREAM_STATE_ENABLING) + (*streams)++; +} + +static void stream_enable(void *data, void *user_data) +{ + struct bt_bap_stream *stream = data; + + bt_bap_stream_enable(stream, true, NULL, NULL, NULL); +} + +static void stream_start(void *data, void *user_data) +{ + struct bt_bap_stream *stream = data; + + bt_bap_stream_start(stream, NULL, NULL); +} + +static void bsrc_state_str(struct bt_bap_stream *stream, uint8_t old_state, + uint8_t new_state, void *user_data) +{ + struct test_data *data = user_data; + uint8_t streams = 0; + + switch (new_state) { + case BT_BAP_STREAM_STATE_CONFIG: + queue_foreach(data->streams, stream_count_config, &streams); + + if (streams == data->cfg->streams) + /* After all streams have transitioned to CONFIG + * state, enable each one. + */ + queue_foreach(data->streams, stream_enable, NULL); + break; + case BT_BAP_STREAM_STATE_ENABLING: + queue_foreach(data->streams, stream_count_enabling, &streams); + + if (streams == 1) { + /* After the first stream has transitioned to ENABLING + * state, bt_bap_stream_get_base will generate the + * BASE from all previously configured streams. + */ + data->base = bt_bap_stream_get_base(stream); + + g_assert(data->base); + g_assert(data->base->iov_len == + data->cfg->base.iov_len); + g_assert(memcmp(data->base->iov_base, + data->cfg->base.iov_base, + data->base->iov_len) == 0); + } + + if (streams == data->cfg->streams) + /* After all streams have transitioned to ENABLING + * state, start each one. + */ + queue_foreach(data->streams, stream_start, NULL); + break; + case BT_BAP_STREAM_STATE_STREAMING: + queue_foreach(data->streams, stream_count_streaming, &streams); + + if (streams == data->cfg->streams) + /* Test is completed after all streams have transitioned + * to STREAMING state. + */ + tester_test_passed(); + break; + } +} + +static struct test_config cfg_bsrc_str_8_1 = { + .cc = LC3_CONFIG_8_1, + .qos = LC3_QOS_8_1_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_8_1), + .src = true, + .state_func = bsrc_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsrc_str_8_2 = { + .cc = LC3_CONFIG_8_2, + .qos = LC3_QOS_8_2_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_8_2), + .src = true, + .state_func = bsrc_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsrc_str_16_1 = { + .cc = LC3_CONFIG_16_1, + .qos = LC3_QOS_16_1_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_16_1), + .src = true, + .state_func = bsrc_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsrc_str_16_2 = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_16_2), + .src = true, + .state_func = bsrc_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsrc_str_24_1 = { + .cc = LC3_CONFIG_24_1, + .qos = LC3_QOS_24_1_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_24_1), + .src = true, + .state_func = bsrc_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsrc_str_24_2 = { + .cc = LC3_CONFIG_24_2, + .qos = LC3_QOS_24_2_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_24_2), + .src = true, + .state_func = bsrc_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsrc_str_32_1 = { + .cc = LC3_CONFIG_32_1, + .qos = LC3_QOS_32_1_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_32_1), + .src = true, + .state_func = bsrc_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsrc_str_32_2 = { + .cc = LC3_CONFIG_32_2, + .qos = LC3_QOS_32_2_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_32_2), + .src = true, + .state_func = bsrc_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsrc_str_44_1 = { + .cc = LC3_CONFIG_44_1, + .qos = LC3_QOS_44_1_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_44_1), + .src = true, + .state_func = bsrc_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsrc_str_44_2 = { + .cc = LC3_CONFIG_44_2, + .qos = LC3_QOS_44_2_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_44_2), + .src = true, + .state_func = bsrc_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsrc_str_48_1 = { + .cc = LC3_CONFIG_48_1, + .qos = LC3_QOS_48_1_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_1), + .src = true, + .state_func = bsrc_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsrc_str_48_2 = { + .cc = LC3_CONFIG_48_2, + .qos = LC3_QOS_48_2_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_2), + .src = true, + .state_func = bsrc_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsrc_str_48_3 = { + .cc = LC3_CONFIG_48_3, + .qos = LC3_QOS_48_3_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_3), + .src = true, + .state_func = bsrc_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsrc_str_48_4 = { + .cc = LC3_CONFIG_48_4, + .qos = LC3_QOS_48_4_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_4), + .src = true, + .state_func = bsrc_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsrc_str_48_5 = { + .cc = LC3_CONFIG_48_5, + .qos = LC3_QOS_48_5_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_5), + .src = true, + .state_func = bsrc_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsrc_str_48_6 = { + .cc = LC3_CONFIG_48_6, + .qos = LC3_QOS_48_6_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_6), + .src = true, + .state_func = bsrc_state_str, + .streams = 1, +}; + +static struct test_config cfg_bsrc_str_vs = { + .cc = UTIL_IOV_INIT(VS_CC), + .qos = QOS_BCAST, + .base = UTIL_IOV_INIT(BASE_VS(VS_CFG)), + .src = true, + .state_func = bsrc_state_str, + .streams = 1, + .vs = true, +}; + +/* Test Purpose: + * Verify that a Broadcast Source IUT can stream one BIS to a + * Broadcast Sink. The verification is performed for each Config + * Settings in turn. + * + * Pass verdict: + * If the Codec ID is LC3, the IUT sends encoded LC3 audio data + * in BIS Data PDUs on the broadcast Audio Stream. The audio data + * is formatted using the LC3 Media Packet format. + * + * If the Codec ID is a vendor-specific Codec ID, the IUT sends BIS + * Data PDUs on the broadcast Audio Stream. The parameters included + * in the Codec_Specific_Configuration data are as defined in + * TSPX_VS_Codec_Specific_Configuration. + * + * If the Codec ID is LC3, each parameter included in + * Codec_Specific_Configuration data is formatted in an LTV structure + * with the length, type, and value specified in Table 4.79. + */ + +static void test_bsrc_str_1b(void) +{ + define_test("BAP/BSRC/STR/BV-01-C [BSRC, LC3 8_1]", + NULL, test_bcast, &cfg_bsrc_str_8_1, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-02-C [BSRC, LC3 8_2]", + NULL, test_bcast, &cfg_bsrc_str_8_2, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-03-C [BSRC, LC3 16_1]", + NULL, test_bcast, &cfg_bsrc_str_16_1, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-04-C [BSRC, LC3 16_2]", + NULL, test_bcast, &cfg_bsrc_str_16_2, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-05-C [BSRC, LC3 24_1]", + NULL, test_bcast, &cfg_bsrc_str_24_1, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-06-C [BSRC, LC3 24_2]", + NULL, test_bcast, &cfg_bsrc_str_24_2, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-07-C [BSRC, LC3 32_1]", + NULL, test_bcast, &cfg_bsrc_str_32_1, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-08-C [BSRC, LC3 32_2]", + NULL, test_bcast, &cfg_bsrc_str_32_2, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-09-C [BSRC, LC3 44.1_1]", + NULL, test_bcast, &cfg_bsrc_str_44_1, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-10-C [BSRC, LC3 44.1_2]", + NULL, test_bcast, &cfg_bsrc_str_44_2, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-11-C [BSRC, LC3 48_1]", + NULL, test_bcast, &cfg_bsrc_str_48_1, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-12-C [BSRC, LC3 48_2]", + NULL, test_bcast, &cfg_bsrc_str_48_2, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-13-C [BSRC, LC3 48_3]", + NULL, test_bcast, &cfg_bsrc_str_48_3, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-14-C [BSRC, LC3 48_4]", + NULL, test_bcast, &cfg_bsrc_str_48_4, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-15-C [BSRC, LC3 48_5]", + NULL, test_bcast, &cfg_bsrc_str_48_5, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-16-C [BSRC, LC3 48_6]", + NULL, test_bcast, &cfg_bsrc_str_48_6, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-17-C [BSRC, VS]", + NULL, test_bcast, &cfg_bsrc_str_vs, IOV_NULL); +} + +static struct test_config cfg_bsrc_str_8_1_mbis = { + .cc = LC3_CONFIG_8_1, + .qos = LC3_QOS_8_1_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_8_1_MBIS), + .src = true, + .state_func = bsrc_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsrc_str_8_2_mbis = { + .cc = LC3_CONFIG_8_2, + .qos = LC3_QOS_8_2_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_8_2_MBIS), + .src = true, + .state_func = bsrc_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsrc_str_16_1_mbis = { + .cc = LC3_CONFIG_16_1, + .qos = LC3_QOS_16_1_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_16_1_MBIS), + .src = true, + .state_func = bsrc_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsrc_str_16_2_mbis = { + .cc = LC3_CONFIG_16_2, + .qos = LC3_QOS_16_2_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_16_2_MBIS), + .src = true, + .state_func = bsrc_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsrc_str_24_1_mbis = { + .cc = LC3_CONFIG_24_1, + .qos = LC3_QOS_24_1_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_24_1_MBIS), + .src = true, + .state_func = bsrc_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsrc_str_24_2_mbis = { + .cc = LC3_CONFIG_24_2, + .qos = LC3_QOS_24_2_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_24_2_MBIS), + .src = true, + .state_func = bsrc_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsrc_str_32_1_mbis = { + .cc = LC3_CONFIG_32_1, + .qos = LC3_QOS_32_1_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_32_1_MBIS), + .src = true, + .state_func = bsrc_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsrc_str_32_2_mbis = { + .cc = LC3_CONFIG_32_2, + .qos = LC3_QOS_32_2_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_32_2_MBIS), + .src = true, + .state_func = bsrc_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsrc_str_44_1_mbis = { + .cc = LC3_CONFIG_44_1, + .qos = LC3_QOS_44_1_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_44_1_MBIS), + .src = true, + .state_func = bsrc_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsrc_str_44_2_mbis = { + .cc = LC3_CONFIG_44_2, + .qos = LC3_QOS_44_2_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_44_2_MBIS), + .src = true, + .state_func = bsrc_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsrc_str_48_1_mbis = { + .cc = LC3_CONFIG_48_1, + .qos = LC3_QOS_48_1_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_1_MBIS), + .src = true, + .state_func = bsrc_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsrc_str_48_2_mbis = { + .cc = LC3_CONFIG_48_2, + .qos = LC3_QOS_48_2_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_2_MBIS), + .src = true, + .state_func = bsrc_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsrc_str_48_3_mbis = { + .cc = LC3_CONFIG_48_3, + .qos = LC3_QOS_48_3_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_3_MBIS), + .src = true, + .state_func = bsrc_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsrc_str_48_4_mbis = { + .cc = LC3_CONFIG_48_4, + .qos = LC3_QOS_48_4_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_4_MBIS), + .src = true, + .state_func = bsrc_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsrc_str_48_5_mbis = { + .cc = LC3_CONFIG_48_5, + .qos = LC3_QOS_48_5_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_5_MBIS), + .src = true, + .state_func = bsrc_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsrc_str_48_6_mbis = { + .cc = LC3_CONFIG_48_6, + .qos = LC3_QOS_48_6_1_B, + .base = UTIL_IOV_INIT(BASE_LC3_48_6_MBIS), + .src = true, + .state_func = bsrc_state_str, + .streams = 2, +}; + +static struct test_config cfg_bsrc_str_vs_mbis = { + .cc = UTIL_IOV_INIT(VS_CC), + .qos = QOS_BCAST, + .base = UTIL_IOV_INIT(BASE_VS_MBIS(VS_CFG)), + .src = true, + .state_func = bsrc_state_str, + .vs = true, + .streams = 2, +}; + +/* Test Purpose: + * Verify that a Broadcast Source IUT can stream multiple BISes to + * a Broadcast Sink. The verification is performed for each set of + * parameters in turn, as specified in Table 4.82. + * + * Pass verdict: + * If the Codec ID is LC3, the IUT sends encoded LC3 audio data in + * BIS Data PDUs on each synchronized BIS. + * + * If the Codec ID is a vendor-specific Codec ID, the IUT sends BIS + * Data PDUs on each synchronized BIS. The parameters included in the + * Codec_Specific_Configuration data are as defined in + * TSPX_VS_Codec_Specific_Configuration. + * + * If the Codec ID is LC3, each parameter included in + * Codec_Specific_Configuration data is formatted in an LTV structure + * with the length, type, and value specified in Table 4.83. + */ +static void test_bsrc_str_2b(void) +{ + define_test("BAP/BSRC/STR/BV-18-C [BSRC, Multiple BISes, LC3 8_1]", + NULL, test_bcast, &cfg_bsrc_str_8_1_mbis, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-19-C [BSRC, Multiple BISes, LC3 8_2]", + NULL, test_bcast, &cfg_bsrc_str_8_2_mbis, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-20-C [BSRC, Multiple BISes, LC3 16_1]", + NULL, test_bcast, &cfg_bsrc_str_16_1_mbis, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-21-C [BSRC, Multiple BISes, LC3 16_2]", + NULL, test_bcast, &cfg_bsrc_str_16_2_mbis, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-22-C [BSRC, Multiple BISes, LC3 24_1]", + NULL, test_bcast, &cfg_bsrc_str_24_1_mbis, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-23-C [BSRC, Multiple BISes, LC3 24_2]", + NULL, test_bcast, &cfg_bsrc_str_24_2_mbis, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-24-C [BSRC, Multiple BISes, LC3 32_1]", + NULL, test_bcast, &cfg_bsrc_str_32_1_mbis, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-25-C [BSRC, Multiple BISes, LC3 32_2]", + NULL, test_bcast, &cfg_bsrc_str_32_2_mbis, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-26-C [BSRC, Multiple BISes, LC3 44.1_1]", + NULL, test_bcast, &cfg_bsrc_str_44_1_mbis, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-27-C [BSRC, Multiple BISes, LC3 44.1_2]", + NULL, test_bcast, &cfg_bsrc_str_44_2_mbis, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-28-C [BSRC, Multiple BISes, LC3 48_1]", + NULL, test_bcast, &cfg_bsrc_str_48_1_mbis, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-29-C [BSRC, Multiple BISes, LC3 48_2]", + NULL, test_bcast, &cfg_bsrc_str_48_2_mbis, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-30-C [BSRC, Multiple BISes, LC3 48_3]", + NULL, test_bcast, &cfg_bsrc_str_48_3_mbis, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-31-C [BSRC, Multiple BISes, LC3 48_4]", + NULL, test_bcast, &cfg_bsrc_str_48_4_mbis, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-32-C [BSRC, Multiple BISes, LC3 48_5]", + NULL, test_bcast, &cfg_bsrc_str_48_5_mbis, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-33-C [BSRC, Multiple BISes, LC3 48_6]", + NULL, test_bcast, &cfg_bsrc_str_48_6_mbis, IOV_NULL); + + define_test("BAP/BSRC/STR/BV-34-C [BSRC, Multiple BISes, VS]", + NULL, test_bcast, &cfg_bsrc_str_vs_mbis, IOV_NULL); +} + +static void test_bsrc_str(void) +{ + test_bsrc_str_1b(); + test_bsrc_str_2b(); +} + +int main(int argc, char *argv[]) +{ + tester_init(&argc, &argv); + + test_disc(); + test_scc(); + test_bsrc_scc(); + test_bsnk_scc(); + test_bsnk_str(); + test_bsrc_str(); + + return tester_run(); +} diff --git a/unit/test-bass.c b/unit/test-bass.c new file mode 100644 index 0000000000000000000000000000000000000000..ace47d9edb8c954efaf890bf49c2b28528fcb3c0 --- /dev/null +++ b/unit/test-bass.c @@ -0,0 +1,823 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright 2023 NXP + * + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <unistd.h> +#include <string.h> +#include <sys/socket.h> +#include <fcntl.h> + +#include <glib.h> + +#include "lib/bluetooth.h" +#include "lib/uuid.h" +#include "src/shared/util.h" +#include "src/shared/io.h" +#include "src/shared/tester.h" +#include "src/shared/queue.h" +#include "src/shared/att.h" +#include "src/shared/gatt-db.h" +#include "src/shared/gatt-client.h" +#include "src/shared/gatt-server.h" +#include "src/shared/bass.h" + +struct test_data { + struct gatt_db *db; + struct bt_bass *bass; + struct bt_gatt_server *server; + struct queue *ccc_states; + size_t iovcnt; + struct iovec *iov; +}; + +struct ccc_state { + uint16_t handle; + uint16_t value; +}; + +/* ATT: Exchange MTU Request (0x02) len 2 + * Client RX MTU: 64 + * ATT: Exchange MTU Response (0x03) len 2 + * Server RX MTU: 64 + */ +#define EXCHANGE_MTU \ + IOV_DATA(0x02, 0x40, 0x00), \ + IOV_DATA(0x03, 0x40, 0x00) + +/* ATT: Find By Type Value Request (0x06) len 8 + * Handle range: 0x0001-0xffff + * Attribute Type(UUID): Primary Service (0x2800) + * Value to find: Broadcast Audio Scan Service (0x184f) + * ATT: Find By Type Value Response (0x07) len 4 + * Handle range: 0x0001-0x0009 + * ATT: Find By Type Value Request (0x06) len 8 + * Handle range: 0x000a-0xffff + * Attribute Type(UUID): Primary Service (0x2800) + * Value to find: Broadcast Audio Scan Service (0x184f) + * ATT: Error Response (0x01) len 4 + * Find By Type Value Request (0x06) + * Handle: 0x000a + * Error: Attribute Not Found (0x0a) + */ +#define BASS_FIND_BY_TYPE_VALUE \ + IOV_DATA(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0x4f, 0x18), \ + IOV_DATA(0x07, 0x01, 0x00, 0x09, 0x00), \ + IOV_DATA(0x06, 0x0a, 0x00, 0xff, 0xff, 0x00, 0x28, 0x4f, 0x18), \ + IOV_DATA(0x01, 0x06, 0x0a, 0x00, 0x0a) + +/* ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0001-0x0009 + * Attribute type: Characteristic (0x2803) + * ATT: Read By Type Response (0x09) len 22 + * Attribute data length: 7 + * Attribute data list: 3 entries + * Handle: 0x0002 + * Value: 120300c82b + * Properties: 0x12 + * Read (0x02) + * Notify (0x10) + * Value Handle: 0x0003 + * Value UUID: Broadcast Receive State (0x2bc8) + * Handle: 0x0005 + * Value: 120600c82b + * Properties: 0x12 + * Read (0x02) + * Notify (0x10) + * Value Handle: 0x0006 + * Value UUID: Broadcast Receive State (0x2bc8) + * Handle: 0x0008 + * Value: 0c0900c72b + * Properties: 0x0c + * Write (0x08) + * Write Without Response (0x04) + * Value Handle: 0x0009 + * Value UUID: Broadcast Audio Scan Control Point (0x2bc7) + * ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0009-0x0009 + * Attribute type: Characteristic (0x2803) + * ATT: Error Response (0x01) len 4 + * Read By Type Request (0x08) + * Handle: 0x0009 + * Error: Attribute Not Found (0x0a) + */ +#define DISC_BASS_CHAR \ + IOV_DATA(0x08, 0x01, 0x00, 0x09, 0x00, 0x03, 0x28), \ + IOV_DATA(0x09, 0x07, \ + 0x02, 0x00, 0x12, 0x03, 0x00, 0xc8, 0x2b, \ + 0x05, 0x00, 0x12, 0x06, 0x00, 0xc8, 0x2b, \ + 0x08, 0x00, 0x0c, 0x09, 0x00, 0xc7, 0x2b), \ + IOV_DATA(0x08, 0x09, 0x00, 0x09, 0x00, 0x03, 0x28), \ + IOV_DATA(0x01, 0x08, 0x09, 0x00, 0x0a) + +/* ATT: Read By Group Type Request (0x10) len 6 + * Handle range: 0x0001-0xffff + * Attribute group type: Primary Service (0x2800) + * ATT: Read By Group Type Response (0x11) len 7 + * Attribute data length: 6 + * Attribute group list: 1 entry + * Handle range: 0x0001-0x0009 + * UUID: Broadcast Audio Scan Service (0x184f) + * ATT: Read By Group Type Request (0x10) len 6 + * Handle range: 0x000a-0xffff + * Attribute group type: Primary Service (0x2800) + * ATT: Error Response (0x01) len 4 + * Read By Group Type Request (0x10) + * Handle: 0x000a + * Error: Attribute Not Found (0x0a) + */ +#define DISC_BASS_SER \ + EXCHANGE_MTU,\ + IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28), \ + IOV_DATA(0x11, 0x06, 0x01, 0x00, 0x09, 0x00, 0x4f, 0x18), \ + IOV_DATA(0x10, 0x0a, 0x00, 0xff, 0xff, 0x00, 0x28), \ + IOV_DATA(0x01, 0x10, 0x0a, 0x00, 0x0a), \ + BASS_FIND_BY_TYPE_VALUE, \ + DISC_BASS_CHAR + +/* ATT: Find Information Request (0x04) len 4 + * Handle range: 0x0004-0x0004 + * ATT: Find Information Response (0x05) len 5 + * Format: Handle(s) and 16 bit bluetooth UUID(s) (0x01) + * Handle: 0x0004 + * Attribute: Client Characteristic Configuration (0x2902) + * ATT: Find Information Request (0x04) len 4 + * Handle range: 0x0007-0x0007 + * ATT: Find Information Response (0x05) len 5 + * Format: Handle(s) and 16 bit bluetooth UUID(s) (0x01) + * Handle: 0x0007 + * Attribute: Client Characteristic Configuration (0x2902) + */ +#define BASS_FIND_INFO \ + IOV_DATA(0x04, 0x04, 0x00, 0x04, 0x00), \ + IOV_DATA(0x05, 0x01, 0x04, 0x00, 0x02, 0x29), \ + IOV_DATA(0x04, 0x07, 0x00, 0x07, 0x00), \ + IOV_DATA(0x05, 0x01, 0x07, 0x00, 0x02, 0x29) + +#define DISC_BCAST_AUDIO_SCAN_CP \ + BASS_FIND_BY_TYPE_VALUE, \ + DISC_BASS_CHAR, \ + BASS_FIND_INFO + +/* ATT: Read Request (0x0a) len 2 + * Handle: 0x0004 Type: Client Characteristic Configuration (0x2902) + * ATT: Read Response (0x0b) len 2 + * Value: 0000 + * Handle: 0x0004 Type: Client Characteristic Configuration (0x2902) + * ATT: Read Request (0x0a) len 2 + * Handle: 0x0007 Type: Client Characteristic Configuration (0x2902) + * ATT: Read Response (0x0b) len 2 + * Value: 0000 + * Handle: 0x0007 Type: Client Characteristic Configuration (0x2902) + */ +#define BASS_READ_CHAR_DESC \ + IOV_DATA(0x0a, 0x04, 0x00), \ + IOV_DATA(0x0b, 0x00, 0x00), \ + IOV_DATA(0x0a, 0x07, 0x00), \ + IOV_DATA(0x0b, 0x00, 0x00) + +#define DISC_BCAST_RECV_STATE \ + DISC_BCAST_AUDIO_SCAN_CP, \ + BASS_READ_CHAR_DESC + +/* ATT: Write Request (0x12) len 4 + * Handle: 0x0004 Type: Client Characteristic Configuration (0x2902) + * Data: 0100 + * Notification (0x01) + * ATT: Write Response (0x13) len 0 + * ATT: Write Request (0x12) len 4 + * Handle: 0x0007 Type: Client Characteristic Configuration (0x2902) + * Data: 0100 + * Notification (0x01) + * ATT: Write Response (0x13) len 0 + */ +#define BASS_WRITE_CHAR_DESC \ + IOV_DATA(0x12, 0x04, 0x00, 0x01, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x12, 0x07, 0x00, 0x01, 0x00), \ + IOV_DATA(0x13) + +/* ATT: Read Request (0x0a) len 2 + * Handle: 0x0003 Type: Broadcast Receive State (0x2bc8) + * ATT: Read Response (0x0b) len 0 + * Handle: 0x0003 Broadcast Receive State (0x2bc8) + * ATT: Read Request (0x0a) len 2 + * Handle: 0x0006 Type: Broadcast Receive State (0x2bc8) + * ATT: Read Response (0x0b) len 0 + * Handle: 0x0006 Broadcast Receive State (0x2bc8) + */ +#define BASS_READ_BCAST_RECV_STATE_CHARS \ + IOV_DATA(0x0a, 0x03, 0x00), \ + IOV_DATA(0x0b), \ + IOV_DATA(0x0a, 0x06, 0x00), \ + IOV_DATA(0x0b) + +#define BASS_CP_WRITE_CMD(_op, _args...) \ + IOV_DATA(0x52, 0x09, 0x00, _op, _args) + +#define BASS_CP_WRITE_REQ(_op, _args...) \ + IOV_DATA(0x12, 0x09, 0x00, _op, _args) + +/* ATT: Write Command (0x52) len 19 + * Handle: 0x0009 Type: Broadcast Audio Scan Control Point (0x2bc7) + * Data: 0401693C4572685526613465597073275455 + * Opcode: Set Broadcast_Code + * Source_ID: 1 + * Broadcast_Code: 0x55542773705965346126556872453c69 + * ATT: Write Command (0x52) len 2 + * Handle: 0x0009 Type: Broadcast Audio Scan Control Point (0x2bc7) + * Data: 0501 + * Opcode: Remove Source + * Source_ID: 1 + */ +#define IGNORE_INVALID_SRC_ID \ + EXCHANGE_MTU, \ + BASS_FIND_BY_TYPE_VALUE, \ + DISC_BASS_CHAR, \ + BASS_FIND_INFO, \ + BASS_WRITE_CHAR_DESC, \ + BASS_READ_BCAST_RECV_STATE_CHARS, \ + BASS_CP_WRITE_CMD(0x04, 0x01, 0x69, 0x3C, 0x45, 0x72, 0x68, \ + 0x55, 0x26, 0x61, 0x34, 0x65, 0x59, 0x70, \ + 0x73, 0x27, 0x54, 0x55), \ + IOV_NULL, \ + BASS_CP_WRITE_CMD(0x05, 0x01) + +/* ATT: Write Command (0x52) len 26 + * Handle: 0x0009 Type: Broadcast Audio Scan Control Point (0x2bc7) + * Data: 0200F2698BE807C0003412000610270200000000000000000000 + * Opcode: Add Source + * Advertiser_Address_Type: Public Device or Public Identity Address + * Advertiser_Address: c0:07:e8:8b:69:f2 + * Advertising_SID: 0x00 + * Broadcast_ID: 0x001234 + * PA_Sync: 0x06 (Reserved for Future Use) + * PA_Interval: 0x2710 + * Num_Subgroups: 2 + * Subgroup #0: + * BIS_Sync: 00000000000000000000000000000000 + * Metadata_Length: 0 + * Subgroup #1: + * BIS_Sync: 00000000000000000000000000000000 + * Metadata_Length: 0 + * ATT: Write Command (0x52) len 26 + * Handle: 0x0009 Type: Broadcast Audio Scan Control Point (0x2bc7) + * Data: 0205F2698BE807C0003412000210270200000000000000000000 + * Opcode: Add Source + * Advertiser_Address_Type: 0x05 (Reserved for Future Use) + * Advertiser_Address: c0:07:e8:8b:69:f2 + * Advertising_SID: 0x00 + * Broadcast_ID: 0x001234 + * PA_Sync: Synchronize to PA (PAST not available) + * PA_Interval: 0x2710 + * Num_Subgroups: 2 + * Subgroup #0: + * BIS_Sync: 00000000000000000000000000000000 + * Metadata_Length: 0 + * Subgroup #1: + * BIS_Sync: 00000000000000000000000000000000 + * Metadata_Length: 0 + * ATT: Write Command (0x52) len 26 + * Handle: 0x0009 Type: Broadcast Audio Scan Control Point (0x2bc7) + * Data: 0200F2698BE807C0003412000210270201000000000100000000 + * Opcode: Add Source + * Advertiser_Address_Type: Public Device or Public Identity Address + * Advertiser_Address: c0:07:e8:8b:69:f2 + * Advertising_SID: 0x00 + * Broadcast_ID: 0x001234 + * PA_Sync: Synchronize to PA (PAST not available) + * PA_Interval: 0x2710 + * Num_Subgroups: 2 + * Subgroup #0: + * BIS_Sync: 00000000000000000000000000000001 + * Metadata_Length: 0 + * Subgroup #1: + * BIS_Sync: 00000000000000000000000000000001 + * Metadata_Length: 0 + */ +#define ADD_SRC_INVALID_PARAMS \ + EXCHANGE_MTU, \ + BASS_FIND_BY_TYPE_VALUE, \ + DISC_BASS_CHAR, \ + BASS_FIND_INFO, \ + BASS_WRITE_CHAR_DESC,\ + BASS_READ_BCAST_RECV_STATE_CHARS, \ + BASS_CP_WRITE_CMD(0x02, 0x00, 0xF2, 0x69, 0x8B, 0xE8, 0x07, 0xC0, \ + 0x00, 0x34, 0x12, 0x00, 0x06, 0x10, 0x27, 0x02, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00), \ + IOV_NULL, \ + BASS_CP_WRITE_CMD(0x02, 0x05, 0xF2, 0x69, 0x8B, 0xE8, 0x07, 0xC0, \ + 0x00, 0x34, 0x12, 0x00, 0x02, 0x10, 0x27, 0x02, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00), \ + IOV_NULL, \ + BASS_CP_WRITE_CMD(0x02, 0x05, 0xF2, 0x69, 0x8B, 0xE8, 0x07, 0xC0, \ + 0x3F, 0x34, 0x12, 0x00, 0x02, 0x10, 0x27, 0x02, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00), \ + IOV_NULL, \ + BASS_CP_WRITE_CMD(0x02, 0x00, 0xF2, 0x69, 0x8B, 0xE8, 0x07, 0xC0, \ + 0x00, 0x34, 0x12, 0x00, 0x02, 0x10, 0x27, 0x02, \ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, \ + 0x00, 0x00) + +/* ATT: Write Request (0x12) len 3 + * Handle: 0x0009 Type: Broadcast Audio Scan Control Point (0x2bc7) + * Data: FF + * Opcode: 0xff (Reserved For Future Use) + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0009 + * Error: Opcode Not Supported (0x80) + */ +#define OPCODE_NOT_SUPPORTED \ + EXCHANGE_MTU, \ + BASS_FIND_BY_TYPE_VALUE, \ + DISC_BASS_CHAR, \ + BASS_FIND_INFO, \ + BASS_WRITE_CHAR_DESC,\ + BASS_READ_BCAST_RECV_STATE_CHARS, \ + BASS_CP_WRITE_REQ(0xFF), \ + IOV_DATA(0x01, 0x12, 0x09, 0x00, 0x80) + +/* ATT: Write Request (0x12) len 5 + * Handle: 0x0009 Type: Broadcast Audio Scan Control Point (0x2bc7) + * Data: 006dfe + * Opcode: Remote Scan Stopped + * Extra Data: 0xfe6d + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0009 + * Error: Write Request Rejected (0xFC) + * ATT: Write Request (0x12) len 5 + * Handle: 0x0009 Type: Broadcast Audio Scan Control Point (0x2bc7) + * Data: 006dfe + * Opcode: Remote Scan Started + * Extra Data: 0xa2c2 + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0009 + * Error: Write Request Rejected (0xFC) + * ATT: Write Request (0x12) len 25 + * Handle: 0x0009 Type: Broadcast Audio Scan Control Point (0x2bc7) + * Data: 0200F2698BE807C0003412000210270100000000000000 + * Opcode: Add Source + * Advertiser_Address_Type: Public Device or Public Identity Address + * Advertiser_Address: c0:07:e8:8b:69:f2 + * Advertising_SID: 0x00 + * Broadcast_ID: 0x001234 + * PA_Sync: Synchronize to PA (PAST not available) + * PA_Interval: 0x2710 + * Num_Subgroups: 1 + * Subgroup #0: + * BIS_Sync: 00000000000000000000000000000001 + * Metadata_Length: 0 + * Extra Data: 0x0000 + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0009 + * Error: Write Request Rejected (0xFC) + * ATT: Write Request (0x12) len 13 + * Handle: 0x0009 Type: Broadcast Audio Scan Control Point (0x2bc7) + * Data: 03000210270100000000001500 + * Opcode: Modify Source + * Source_ID: 0x00 + * PA_Sync: Synchronize to PA (PAST not available) + * PA_Interval: 0x2710 + * Num_Subgroups: 1 + * Subgroup #0: + * BIS_Sync: 00000000000000000000000000000001 + * Metadata_Length: 0 + * Extra Data: 0x0015 + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0009 + * Error: Write Request Rejected (0xFC) + * ATT: Write Request (0x12) len 20 + * Handle: 0x0009 Type: Broadcast Audio Scan Control Point (0x2bc7) + * Data: 0400B803EAC6AFBB65A25A41F153056802010000 + * Opcode: Set Broadcast_Code + * Source_ID: 0x00 + * Broadcast_Code: 0x0102680553f1415aa265bbafc6ea03b8 + * Extra Data: 0x0000 + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0009 + * Error: Write Request Rejected (0xFC) + * ATT: Write Request (0x12) len 4 + * Handle: 0x0009 Type: Broadcast Audio Scan Control Point (0x2bc7) + * Data: 05008F13 + * Opcode: Remove Source + * Source_ID: 0x00 + * Extra Data: 0x138f + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0009 + * Error: Write Request Rejected (0xFC) + */ +#define INVALID_LEN \ + EXCHANGE_MTU, \ + BASS_FIND_BY_TYPE_VALUE, \ + DISC_BASS_CHAR, \ + BASS_FIND_INFO, \ + BASS_WRITE_CHAR_DESC,\ + BASS_READ_BCAST_RECV_STATE_CHARS, \ + BASS_CP_WRITE_REQ(0x00, 0x6D, 0xFE), \ + IOV_DATA(0x01, 0x12, 0x09, 0x00, 0xFC), \ + BASS_CP_WRITE_REQ(0x01, 0xC2, 0xA2), \ + IOV_DATA(0x01, 0x12, 0x09, 0x00, 0xFC), \ + BASS_CP_WRITE_REQ(0x02, 0x00, 0xF2, 0x69, 0x8B, 0xE8, 0x07, 0xC0, \ + 0x00, 0x34, 0x12, 0x00, 0x02, 0x10, 0x27, 0x01, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), \ + IOV_DATA(0x01, 0x12, 0x09, 0x00, 0xFC), \ + BASS_CP_WRITE_REQ(0x03, 0x00, 0x02, 0x10, 0x27, 0x01, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x15, 0x00), \ + IOV_DATA(0x01, 0x12, 0x09, 0x00, 0xFC), \ + BASS_CP_WRITE_REQ(0x04, 0x00, 0xB8, 0x03, 0xEA, 0xC6, 0xAF, 0xBB, \ + 0x65, 0xA2, 0x5A, 0x41, 0xF1, 0x53, 0x05, 0x68, \ + 0x02, 0x01, 0x00, 0x00), \ + IOV_DATA(0x01, 0x12, 0x09, 0x00, 0xFC), \ + BASS_CP_WRITE_REQ(0x05, 0x00, 0x8F, 0x13), \ + IOV_DATA(0x01, 0x12, 0x09, 0x00, 0xFC) + +/* ATT: Write Request (0x12) len 20 + * Handle: 0x0009 Type: Broadcast Audio Scan Control Point (0x2bc7) + * Data: 0400B803EAC6AFBB65A25A41F153056802010000 + * Opcode: Set Broadcast_Code + * Source_ID: 0x05 + * Broadcast_Code: 0x0102680553f1415aa265bbafc6ea03b + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0009 + * Error: Invalid Source ID (0x81) + * ATT: Write Request (0x12) len 4 + * Handle: 0x0009 Type: Broadcast Audio Scan Control Point (0x2bc7) + * Data: 005 + * Opcode: Remove Source + * Source_ID: 0x05 + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0009 + * Error: Invalid Source ID (0x81) + */ +#define INVALID_SRC_ID \ + EXCHANGE_MTU, \ + BASS_FIND_BY_TYPE_VALUE, \ + DISC_BASS_CHAR, \ + BASS_FIND_INFO, \ + BASS_WRITE_CHAR_DESC, \ + BASS_READ_BCAST_RECV_STATE_CHARS, \ + BASS_CP_WRITE_REQ(0x04, 0x05, 0xB8, 0x03, 0xEA, 0xC6, 0xAF, 0xBB, \ + 0x65, 0xA2, 0x5A, 0x41, 0xF1, 0x53, 0x05, 0x68, \ + 0x02, 0x01), \ + IOV_DATA(0x01, 0x12, 0x09, 0x00, 0x81), \ + BASS_CP_WRITE_REQ(0x05, 0x05), \ + IOV_DATA(0x01, 0x12, 0x09, 0x00, 0x81) + +#define iov_data(args...) ((const struct iovec[]) { args }) + +#define define_test(name, function, _cfg, args...) \ + do { \ + const struct iovec iov[] = { args }; \ + static struct test_data data; \ + data.iovcnt = ARRAY_SIZE(iov_data(args)); \ + data.iov = util_iov_dup(iov, ARRAY_SIZE(iov_data(args))); \ + tester_add(name, &data, NULL, function, \ + test_teardown); \ + } while (0) + +static void test_complete_cb(const void *user_data) +{ + tester_test_passed(); +} + +static void print_debug(const char *str, void *user_data) +{ + const char *prefix = user_data; + + if (tester_use_debug()) + tester_debug("%s%s", prefix, str); +} + +static void test_teardown(const void *user_data) +{ + struct test_data *data = (void *)user_data; + + bt_bass_unref(data->bass); + bt_gatt_server_unref(data->server); + util_iov_free(data->iov, data->iovcnt); + + gatt_db_unref(data->db); + + queue_destroy(data->ccc_states, free); + + tester_teardown_complete(); +} + +static bool ccc_state_match(const void *a, const void *b) +{ + const struct ccc_state *ccc = a; + uint16_t handle = PTR_TO_UINT(b); + + return ccc->handle == handle; +} + +static struct ccc_state *find_ccc_state(struct test_data *data, + uint16_t handle) +{ + return queue_find(data->ccc_states, ccc_state_match, + UINT_TO_PTR(handle)); +} + +static struct ccc_state *get_ccc_state(struct test_data *data, uint16_t handle) +{ + struct ccc_state *ccc; + + ccc = find_ccc_state(data, handle); + if (ccc) + return ccc; + + ccc = new0(struct ccc_state, 1); + ccc->handle = handle; + queue_push_tail(data->ccc_states, ccc); + + return ccc; +} + +static void gatt_ccc_read_cb(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct test_data *data = user_data; + struct ccc_state *ccc; + uint16_t handle; + uint8_t ecode = 0; + const uint8_t *value = NULL; + size_t len = 0; + + handle = gatt_db_attribute_get_handle(attrib); + + ccc = get_ccc_state(data, handle); + if (!ccc) { + ecode = BT_ATT_ERROR_UNLIKELY; + goto done; + } + + len = sizeof(ccc->value); + value = (void *) &ccc->value; + +done: + gatt_db_attribute_read_result(attrib, id, ecode, value, len); +} + +static void gatt_ccc_write_cb(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + const uint8_t *value, size_t len, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct test_data *data = (void *)user_data; + struct ccc_state *ccc_state; + uint16_t val; + uint8_t ecode = 0; + + if (!value || len > 2) { + ecode = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN; + goto done; + } + + if (offset > 2) { + ecode = BT_ATT_ERROR_INVALID_OFFSET; + goto done; + } + + if (len == 1) + val = *value; + else + val = get_le16(value); + + ccc_state = get_ccc_state(data, gatt_db_attribute_get_handle(attrib)); + if (!ccc_state) + return; + + /* If value is identical, then just succeed */ + if (val == ccc_state->value) + goto done; + + ccc_state->value = val; + +done: + gatt_db_attribute_write_result(attrib, id, ecode); +} + +static void gatt_notify_cb(struct gatt_db_attribute *attrib, + struct gatt_db_attribute *ccc, + const uint8_t *value, size_t len, + struct bt_att *att, void *user_data) +{ + struct test_data *data = user_data; + struct ccc_state *ccc_state; + + ccc_state = find_ccc_state(data, gatt_db_attribute_get_handle(ccc)); + if (!ccc_state || !(ccc_state->value & 0x0001)) + return; + + bt_gatt_server_send_notification(data->server, + gatt_db_attribute_get_handle(attrib), + value, len, false); +} + +static void test_server(const void *user_data) +{ + struct test_data *data = (void *)user_data; + struct bt_att *att; + struct io *io; + + io = tester_setup_io(data->iov, data->iovcnt); + g_assert(io); + + tester_io_set_complete_func(test_complete_cb); + + att = bt_att_new(io_get_fd(io), false); + g_assert(att); + + bt_att_set_debug(att, BT_ATT_DEBUG, print_debug, "bt_att:", NULL); + + data->db = gatt_db_new(); + g_assert(data->db); + + gatt_db_ccc_register(data->db, gatt_ccc_read_cb, gatt_ccc_write_cb, + gatt_notify_cb, data); + + data->bass = bt_bass_new(data->db, NULL, BDADDR_ANY); + g_assert(data->bass); + + bt_bass_set_att(data->bass, att); + bt_bass_attach(data->bass, NULL); + + bt_bass_set_debug(data->bass, print_debug, "bt_bass:", NULL); + + data->server = bt_gatt_server_new(data->db, att, 64, 0); + g_assert(data->server); + + bt_gatt_server_set_debug(data->server, print_debug, "bt_gatt_server:", + NULL); + + data->ccc_states = queue_new(); + + tester_io_send(); + + bt_att_unref(att); +} + +static void test_sggit(void) +{ + /* BASS/SR/SGGIT/SER/BV-01-C [Service GGIT - Broadcast Scan] + * + * For each ATT_Read_By_Group_Type_Request, the IUT sends a correctly + * formatted ATT_Read_By_Group_Type_Response reporting BASS to the + * Lower Tester, or an ATT_Error_Response if there is no handle/UUID + * pair matching the request. + * + * For each ATT_Find_By_Type_Value_Request, the IUT sends one + * ATT_Find_By_Type_Value_Response reporting BASS to the Lower Tester, + * or an ATT_Error_Response when there are no more services matching + * the request. + * + * The IUT sends one ATT_Read_By_Type_Response to the Lower Tester for + * each received ATT_Read_By_Type_Request, if it has characteristic + * declarations within the handle range, or an ATT_Error_Response if + * there are no further characteristic declarations within the + * handle range of the request. The IUT reports all BASS + * characteristics. + */ + define_test("BASS/SR/SGGIT/SER/BV-01-C", test_server, NULL, + DISC_BASS_SER); + + /* BASS/SR/SGGIT/CHA/BV-01-C [Service GGIT - + * Broadcast Audio Scan Control Point] + * + * The IUT sends one ATT_Read_By_Type_Response to the Lower Tester for + * each received ATT_Read_By_Type_Request, if it has characteristic + * declarations within the handle range, or an ATT_Error_Response if + * there are no further characteristic declarations within the + * handle range of the request. The IUT reports one instance of the + * Broadcast Audio Scan Control Point characteristic. + */ + define_test("BASS/SR/SGGIT/CHA/BV-01-C", test_server, NULL, + DISC_BCAST_AUDIO_SCAN_CP); + + /* BASS/SR/SGGIT/CHA/BV-02-C [Service GGIT - + * Broadcast Receive State] + * + * The IUT sends one ATT_Read_By_Type_Response to the Lower Tester for + * each received ATT_Read_By_Type_Request, if it has characteristic + * declarations within the handle range, or an ATT_Error_Response if + * there are no further characteristic declarations within the + * handle range of the request. The IUT reports two instances of the + * Broadcast Receive State characteristic. + * + * The IUT sends one ATT_Find_Information_Response to the Lower Tester + * for each received ATT_Find_Information_Request, if it has + * characteristic descriptors within the handle range, or an + * ATT_Error_Response if there are no characteristic descriptors within + * the handle range of the request. For each Broadcast Receive State + * characteristic, the IUT reports one Client Characteristic + * Configuration descriptor. + * + * The IUT sends an ATT_Read_Response to the Lower Tester for each + * ATT_Read_Request. + */ + define_test("BASS/SR/SGGIT/CHA/BV-02-C", test_server, NULL, + DISC_BCAST_RECV_STATE); +} + +static void test_spe(void) +{ + /* BASS/SR/SPE/BI-01-C [Ignore Invalid Source ID] + * + * Test Purpose: + * Verify that the BASS Server IUT does not respond to a control point + * procedure call that uses an invalid Source_ID parameter. + * + * Pass verdict: + * The IUT does not send a notification of the Broadcast Receive State + * characteristic. + */ + define_test("BASS/SR/SPE/BI-01-C", test_server, NULL, + IGNORE_INVALID_SRC_ID); + + /* BASS/SR/SPE/BI-03-C [Add Source - Ignore Invalid Values] + * + * Test Purpose: + * Verify that the BASS Server IUT ignores Add Source control point + * procedure calls that include an RFU or Invalid parameter. + * + * Pass verdict: + * The IUT does not send a notification of the Broadcast Receive State + * characteristic. + */ + define_test("BASS/SR/SPE/BI-03-C", test_server, NULL, + ADD_SRC_INVALID_PARAMS); + + /* BASS/SR/SPE/BI-04-C [Opcode Not Supported] + * + * Test Purpose: + * Verify that the BASS Server IUT returns an Opcode Not Supported error + * response when the opcode written is not supported by the IUT or is + * within a range that is reserved for future use being written to the + * Broadcast Audio Scan Control Point. + * + * Pass verdict: + * The IUT sends an error response of OPCODE NOT SUPPORTED. + */ + define_test("BASS/SR/SPE/BI-04-C", test_server, NULL, + OPCODE_NOT_SUPPORTED); + + /* BASS/SR/SPE/BI-06-C [Invalid Length] + * + * Test Purpose: + * Verify that the BASS Server IUT rejects writing of an opcode with + * an invalid length. + * + * Pass verdict: + * The IUT rejects the opcode. + */ + define_test("BASS/SR/SPE/BI-06-C", test_server, NULL, + INVALID_LEN); + + /* BASS/SR/SPE/BI-07-C [Invalid Source ID] + * + * Test Purpose: + * Verify that the BASS Server IUT returns an error when a control + * point procedure passing an invalid Source_ID parameter is called. + * + * Pass verdict: + * The IUT sends an ATT Error Response with the Error Code set to + * Invalid Source_ID. + */ + define_test("BASS/SR/SPE/BI-07-C", test_server, NULL, + INVALID_SRC_ID); +} + +int main(int argc, char *argv[]) +{ + tester_init(&argc, &argv); + + test_sggit(); + test_spe(); + + return tester_run(); +} diff --git a/unit/test-crypto.c b/unit/test-crypto.c index 3a88b4a52b47793d87e2a2c055c4a4596361c92f..8fd7bec8ea83cc7f764a2df2c7d84d97a286f021 100644 --- a/unit/test-crypto.c +++ b/unit/test-crypto.c @@ -311,6 +311,78 @@ static void test_verify_sign(gconstpointer data) tester_test_passed(); } +static void test_sef(const void *data) +{ + const uint8_t sirk[16] = { + 0xcd, 0xcc, 0x72, 0xdd, 0x86, 0x8c, 0xcd, 0xce, + 0x22, 0xfd, 0xa1, 0x21, 0x09, 0x7d, 0x7d, 0x45 }; + const uint8_t k[16] = { + 0xd9, 0xce, 0xe5, 0x3c, 0x22, 0xc6, 0x1e, 0x06, + 0x6f, 0x69, 0x48, 0xd4, 0x9b, 0x1b, 0x6e, 0x67 }; + const uint8_t exp[16] = { + 0x46, 0xd3, 0x5f, 0xf2, 0xd5, 0x62, 0x25, 0x7e, + 0xa0, 0x24, 0x35, 0xe1, 0x35, 0x38, 0x0a, 0x17 }; + uint8_t res[16]; + + tester_debug("SIRK:"); + util_hexdump(' ', sirk, 16, print_debug, NULL); + + tester_debug("K:"); + util_hexdump(' ', k, 16, print_debug, NULL); + + if (!bt_crypto_sef(crypto, k, sirk, res)) { + tester_test_failed(); + return; + } + + tester_debug("Expected:"); + util_hexdump(' ', exp, 16, print_debug, NULL); + + tester_debug("Result:"); + util_hexdump(' ', res, 16, print_debug, NULL); + + if (memcmp(res, exp, 16)) { + tester_test_failed(); + return; + } + + tester_test_passed(); +} + +static void test_sih(const void *data) +{ + const uint8_t k[16] = { + 0xcd, 0xcc, 0x72, 0xdd, 0x86, 0x8c, 0xcd, 0xce, + 0x22, 0xfd, 0xa1, 0x21, 0x09, 0x7d, 0x7d, 0x45 }; + const uint8_t r[3] = { 0x63, 0xf5, 0x69 }; + const uint8_t exp[3] = { 0xda, 0x48, 0x19 }; + uint8_t hash[3]; + + tester_debug("K:"); + util_hexdump(' ', k, 16, print_debug, NULL); + + tester_debug("R:"); + util_hexdump(' ', r, 3, print_debug, NULL); + + if (!bt_crypto_sih(crypto, k, r, hash)) { + tester_test_failed(); + return; + } + + tester_debug("Expected:"); + util_hexdump(' ', exp, 3, print_debug, NULL); + + tester_debug("Result:"); + util_hexdump(' ', hash, 3, print_debug, NULL); + + if (memcmp(hash, exp, 3)) { + tester_test_failed(); + return; + } + + tester_test_passed(); +} + int main(int argc, char *argv[]) { int exit_status; @@ -337,6 +409,8 @@ int main(int argc, char *argv[]) NULL, test_verify_sign, NULL); tester_add("/crypto/verify_sign_too_short", &verify_sign_too_short_data, NULL, test_verify_sign, NULL); + tester_add("/crypto/sef", NULL, NULL, test_sef, NULL); + tester_add("/crypto/sih", NULL, NULL, test_sih, NULL); exit_status = tester_run(); diff --git a/unit/test-eir.c b/unit/test-eir.c index e05a37d01306965787b0c036c88025d661f9228c..49ce65f24bc939e3a74488ea2c4798f1603c73a4 100644 --- a/unit/test-eir.c +++ b/unit/test-eir.c @@ -21,6 +21,7 @@ #include "lib/sdp.h" #include "src/shared/tester.h" #include "src/shared/util.h" +#include "src/shared/ad.h" #include "src/eir.h" struct test_data { @@ -539,6 +540,54 @@ static void print_debug(const char *str, void *user_data) tester_debug("%s%s", prefix, str); } +static void test_ad(const struct test_data *test, struct eir_data *eir) +{ + struct bt_ad *ad; + GSList *list; + + ad = bt_ad_new_with_data(test->eir_size, test->eir_data); + g_assert(ad); + + g_assert_cmpint(bt_ad_get_flags(ad), ==, test->flags); + g_assert_cmpstr(bt_ad_get_name(ad), ==, test->name); + g_assert_cmpint(bt_ad_get_tx_power(ad), ==, test->tx_power); + + if (test->uuid) { + int i; + + for (i = 0; test->uuid[i]; i++) { + bt_uuid_t uuid; + + bt_string_to_uuid(&uuid, test->uuid[i]); + g_assert(bt_ad_has_service_uuid(ad, &uuid)); + } + } + + for (list = eir->msd_list; list; list = list->next) { + struct eir_msd *msd = list->data; + struct bt_ad_manufacturer_data adm; + + adm.manufacturer_id = msd->company; + adm.data = msd->data; + adm.len = msd->data_len; + + g_assert(bt_ad_has_manufacturer_data(ad, &adm)); + } + + for (list = eir->sd_list; list; list = list->next) { + struct eir_sd *sd = list->data; + struct bt_ad_service_data ads; + + bt_string_to_uuid(&ads.uuid, sd->uuid); + ads.data = sd->data; + ads.len = sd->data_len; + + g_assert(bt_ad_has_service_data(ad, &ads)); + } + + bt_ad_unref(ad); +} + static void test_parsing(gconstpointer data) { const struct test_data *test = data; @@ -599,6 +648,8 @@ static void test_parsing(gconstpointer data) "Service Data:"); } + test_ad(data, &eir); + eir_data_free(&eir); tester_test_passed(); diff --git a/unit/test-gatt.c b/unit/test-gatt.c index f92d860c4e3b09c8a9b05c9ece8f84af887999dc..1613fbcb5f219e0d784459b3e367b748d0505bf9 100644 --- a/unit/test-gatt.c +++ b/unit/test-gatt.c @@ -1237,6 +1237,7 @@ add_char_with_value(struct gatt_db_attribute *service_att, uint16_t handle, if (handle) attrib = gatt_db_service_insert_characteristic(service_att, + handle - 1, handle, uuid, att_permissions, char_properties, @@ -1908,6 +1909,60 @@ static struct gatt_db *make_test_spec_large_db_1(void) return make_db(specs); } +/* + * Tiny database which fits into a single minimum sized-pdu with services + * added in the following order to check ability to create hash db: + * - one secondary service at handle 0x0003, + * - one primary service at the max handle, + * - one primary service at handle 0x0001. + */ + +static struct gatt_db *make_test_tail_db(void) +{ + const struct att_handle_spec specs[] = { + SECONDARY_SERVICE(0x0003, DEVICE_INFORMATION_UUID, 16), + CHARACTERISTIC_STR(GATT_CHARAC_MANUFACTURER_NAME_STRING, + BT_ATT_PERM_READ | + BT_ATT_PERM_WRITE, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_NOTIFY | + BT_GATT_CHRC_PROP_INDICATE | + BT_GATT_CHRC_PROP_EXT_PROP, + "BlueZ"), + DESCRIPTOR(GATT_CLIENT_CHARAC_CFG_UUID, BT_ATT_PERM_READ | + BT_ATT_PERM_WRITE, 0x00, 0x00), + DESCRIPTOR_STR(GATT_CHARAC_USER_DESC_UUID, BT_ATT_PERM_READ, + "Manufacturer Name"), + DESCRIPTOR(GATT_CHARAC_EXT_PROPER_UUID, BT_ATT_PERM_READ, 0x01, + 0x00), + CHARACTERISTIC_STR(GATT_CHARAC_SOFTWARE_REVISION_STRING, + BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_INDICATE, + "5.59"), + DESCRIPTOR(GATT_CLIENT_CHARAC_CFG_UUID, BT_ATT_PERM_READ + | BT_ATT_PERM_WRITE, 0x00, 0x00), + + PRIMARY_SERVICE(0xFFFF - 9 + 1, GAP_UUID, 9), + INCLUDE(0x0003), + CHARACTERISTIC_STR(GATT_CHARAC_DEVICE_NAME, BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ, + "BlueZ Unit Tester"), + CHARACTERISTIC(0000B009-0000-0000-0123-456789abcdef, + BT_ATT_PERM_READ | BT_ATT_PERM_WRITE, + BT_GATT_CHRC_PROP_READ | + BT_GATT_CHRC_PROP_EXT_PROP, 0x09), + DESCRIPTOR(GATT_CHARAC_EXT_PROPER_UUID, BT_ATT_PERM_READ, 0x01, + 0x00), + CHARACTERISTIC(GATT_CHARAC_APPEARANCE, BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ, 0x00, 0x00), + PRIMARY_SERVICE(0x0001, DEVICE_INFORMATION_UUID, 1), + { } + }; + + return make_db(specs); +} + static void test_client(gconstpointer data) { create_context(512, data); @@ -2345,10 +2400,22 @@ static const struct test_step test_indication_server_1 = { .length = 0x03, }; +static void test_hash_db(gconstpointer data) +{ + struct context *context = create_context(512, data); + + /* test that gatt_db_get_hash is able to manage services at tail end of + * a db. + */ + gatt_db_get_hash(context->server_db); + + context_quit(context); +} + int main(int argc, char *argv[]) { struct gatt_db *service_db_1, *service_db_2, *service_db_3; - struct gatt_db *ts_small_db, *ts_large_db_1; + struct gatt_db *ts_small_db, *ts_large_db_1, *ts_tail_db; tester_init(&argc, &argv); @@ -2357,6 +2424,7 @@ int main(int argc, char *argv[]) service_db_3 = make_service_data_3_db(); ts_small_db = make_test_spec_small_db(); ts_large_db_1 = make_test_spec_large_db_1(); + ts_tail_db = make_test_tail_db(); /* * Server Configuration @@ -4487,5 +4555,9 @@ int main(int argc, char *argv[]) raw_pdu(0xff, 0x00), raw_pdu()); + define_test_server("/robustness/hash-db", + test_hash_db, ts_tail_db, NULL, + {}); + return tester_run(); } diff --git a/unit/test-hog.c b/unit/test-hog.c index 067497de41c2d56424e00b92cfab590896249cc4..a7cb5f0d35838b20ed385f726c46c03ed08482da 100644 --- a/unit/test-hog.c +++ b/unit/test-hog.c @@ -182,7 +182,7 @@ static struct context *create_context(gconstpointer data) fd = open("/dev/null", O_WRONLY | O_CLOEXEC); g_assert(fd > 0); - context->hog = bt_hog_new(fd, name, vendor, product, version, NULL); + context->hog = bt_hog_new(fd, name, vendor, product, version, 0, NULL); g_assert(context->hog); channel = g_io_channel_unix_new(sv[1]); diff --git a/unit/test-mesh-crypto.c b/unit/test-mesh-crypto.c index f9b7d81da714133d65fa618891d909de1d86c694..39632d9734f2b97a0b73cb008d07d5e0ada0ddbe 100644 --- a/unit/test-mesh-crypto.c +++ b/unit/test-mesh-crypto.c @@ -633,6 +633,36 @@ static const struct mesh_crypto_test s8_4_3 = { .beacon = "01003ecaff672f673370123456788ea261582f364f6f", }; +static const struct mesh_crypto_test s8_4_6_1 = { + .name = "8.4.6.1 Private Beacon IVU", + + .net_key = "f7a2a44f8e8a8029064f173ddc1e2b00", + .iv_index = 0x1010abcd, + + .enc_key = "6be76842460b2d3a5850d4698409f1bb", + .rand = "435f18f85cf78a3121f58478a5", + + .beacon_type = 0x02, + .beacon_flags = 0x02, + .beacon_cmac = "f3174f022a514741", + .beacon = "02435f18f85cf78a3121f58478a561e488e7cbf3174f022a514741", +}; + +static const struct mesh_crypto_test s8_4_6_2 = { + .name = "8.4.6.2 Private Beacon IVU Complete", + + .net_key = "3bbb6f1fbd53e157417f308ce7aec58f", + .iv_index = 0x00000000, + + .enc_key = "ca478cdac626b7a8522d7272dd124f26", + .rand = "1b998f82927535ea6f3076f422", + + .beacon_type = 0x02, + .beacon_flags = 0x00, + .beacon_cmac = "2f0ffb94cf97f881", + .beacon = "021b998f82927535ea6f3076f422ce827408ab2f0ffb94cf97f881", +}; + static const struct mesh_crypto_test s8_6_2 = { .name = "8.6.2 Service Data using Node Identity", @@ -683,6 +713,17 @@ static void verify_data(const char *label, unsigned int indent, l_free(str); } +static void verify_bool(const char *label, unsigned int indent, + bool sample, bool data) +{ + l_info("%-20s =%*c%s", label, 1 + (indent * 2), ' ', + sample ? "true" : "false"); + l_info("%-20s %*c%s => %s", "", 1 + (indent * 2), ' ', + data ? "true" : "false", + EVALNUM(sample, data)); + EXITNUM(sample, data); +} + static void verify_bool_not_both(const char *label, unsigned int indent, bool sample, bool data) { @@ -796,10 +837,11 @@ static void check_encrypt_segment(const struct mesh_crypto_test *keys, uint32_t hdr; uint64_t net_mic64, net_mic32; size_t net_msg_len; + bool status; uint8_t key_aid = keys->key_aid | (keys->akf ? KEY_ID_AKF : 0x00); if (keys->ctl) { - mesh_crypto_packet_build(keys->ctl, keys->net_ttl, + status = mesh_crypto_packet_build(keys->ctl, keys->net_ttl, keys->net_seq[0], keys->net_src, keys->net_dst, keys->opcode, @@ -809,7 +851,7 @@ static void check_encrypt_segment(const struct mesh_crypto_test *keys, enc_msg, len, packet, &packet_len); } else { - mesh_crypto_packet_build(keys->ctl, keys->net_ttl, + status = mesh_crypto_packet_build(keys->ctl, keys->net_ttl, keys->net_seq[0], keys->net_src, keys->net_dst, keys->opcode, @@ -822,6 +864,10 @@ static void check_encrypt_segment(const struct mesh_crypto_test *keys, l_info(COLOR_YELLOW "Segment-%d" COLOR_OFF, seg); + verify_bool("Crypto packet build", 0, true, status); + if (!status) + return; + hdr = l_get_be32(packet + 9); verify_uint8("SEG", 9, keys->segmented << (SEG_HDR_SHIFT % 8), packet[9] & (1 << (SEG_HDR_SHIFT % 8))); @@ -870,15 +916,20 @@ static void check_encrypt_segment(const struct mesh_crypto_test *keys, net_msg_len = len + 2; show_data("TransportPayload", 7, packet + 7, net_msg_len); - mesh_crypto_packet_encrypt(packet, packet_len, + status = mesh_crypto_packet_encrypt(packet, packet_len, enc_key, keys->iv_index, false, keys->ctl, keys->net_ttl, keys->net_seq[0], keys->net_src); + verify_bool("Crypto packet encrypt", 0, true, status); + if (!status) + return; + mesh_crypto_privacy_counter(keys->iv_index, packet + 7, priv_rand); + l_info(""); show_uint32("IVindex", 0, keys->iv_index); verify_data("NetworkNonce", 0, keys->net_nonce[0], net_nonce, 13); @@ -907,10 +958,15 @@ static void check_encrypt_segment(const struct mesh_crypto_test *keys, } show_data("PreObsPayload", 1, packet + 1, 6 + net_msg_len); - mesh_crypto_network_obfuscate(packet, priv_key, + status = mesh_crypto_network_obfuscate(packet, priv_key, keys->iv_index, keys->ctl, keys->net_ttl, keys->net_seq[0], keys->net_src); + + verify_bool("Crypto network obfuscate", 0, true, status); + if (!status) + return; + show_data("PostObsPayload", 1, packet + 1, 6 + net_msg_len); packet[0] = (keys->iv_index & 0x01) << 7 | nid; @@ -926,7 +982,7 @@ static void check_encrypt(const struct mesh_crypto_test *keys) uint8_t *dev_key; uint8_t *app_key; uint8_t *net_key; - uint8_t nid; + uint8_t nid = 0; uint8_t enc_key[16]; uint8_t priv_key[16]; uint8_t net_nonce[13]; @@ -949,6 +1005,7 @@ static void check_encrypt(const struct mesh_crypto_test *keys) uint8_t packet_len; uint16_t i, seg_max, seg_len = 0; uint32_t seqZero, hdr; + bool status; l_info(COLOR_BLUE "[Encrypt %s]" COLOR_OFF, keys->name); verify_bool_not_both("CTL && Segmented", 0, keys->ctl, keys->segmented); @@ -960,8 +1017,7 @@ static void check_encrypt(const struct mesh_crypto_test *keys) show_data("NetworkKey", 0, net_key, 16); - if (keys->akf) { - mesh_crypto_k4(app_key, &key_aid); + if (keys->akf && mesh_crypto_k4(app_key, &key_aid)) { key_aid |= KEY_ID_AKF; } else { key_aid = 0; @@ -1034,7 +1090,7 @@ static void check_encrypt(const struct mesh_crypto_test *keys) seg_max = SEG_MAX(keys->segmented, app_msg_len + 8); enc_msg = l_malloc(app_msg_len + 8); - mesh_crypto_payload_encrypt(aad, app_msg, + status = mesh_crypto_payload_encrypt(aad, app_msg, enc_msg, app_msg_len, keys->net_src, keys->net_dst, key_aid, keys->app_seq, keys->iv_index, @@ -1044,7 +1100,7 @@ static void check_encrypt(const struct mesh_crypto_test *keys) seg_max = SEG_MAX(keys->segmented, app_msg_len + 4); enc_msg = l_malloc(app_msg_len + 4); - mesh_crypto_payload_encrypt(aad, app_msg, + status = mesh_crypto_payload_encrypt(aad, app_msg, enc_msg, app_msg_len, keys->net_src, keys->net_dst, key_aid, keys->app_seq, keys->iv_index, @@ -1052,6 +1108,10 @@ static void check_encrypt(const struct mesh_crypto_test *keys) keys->akf ? app_key : dev_key); } + verify_bool("Crypto payload encrypt", 0, true, status); + if (!status) + return; + if (keys->dev_key && !keys->akf) show_data("DeviceKey", 0, dev_key, 16); @@ -1097,7 +1157,8 @@ static void check_encrypt(const struct mesh_crypto_test *keys) } if (keys->ctl) { - mesh_crypto_packet_build(keys->ctl, keys->net_ttl, + status = mesh_crypto_packet_build(keys->ctl, + keys->net_ttl, keys->net_seq[i], keys->net_src, keys->net_dst, keys->opcode, @@ -1107,7 +1168,8 @@ static void check_encrypt(const struct mesh_crypto_test *keys) enc_msg + 1, seg_len, packet, &packet_len); } else { - mesh_crypto_packet_build(keys->ctl, keys->net_ttl, + status = mesh_crypto_packet_build(keys->ctl, + keys->net_ttl, keys->net_seq[i], keys->net_src, keys->net_dst, keys->opcode, @@ -1120,6 +1182,10 @@ static void check_encrypt(const struct mesh_crypto_test *keys) if (seg_max) l_info(COLOR_YELLOW "Segment-%d" COLOR_OFF, i); + verify_bool("Crypto packet build", 0, true, status); + if (!status) + return; + hdr = l_get_be32(packet + 9); verify_uint8("SEG", 9, keys->segmented << (SEG_HDR_SHIFT % 8), packet[9] & (1 << (SEG_HDR_SHIFT % 8))); @@ -1193,12 +1259,16 @@ static void check_encrypt(const struct mesh_crypto_test *keys) net_msg_len = seg_len + 2; show_data("TransportPayload", 7, packet + 7, net_msg_len); - mesh_crypto_packet_encrypt(packet, packet_len, enc_key, + status = mesh_crypto_packet_encrypt(packet, packet_len, enc_key, keys->iv_index, false, keys->ctl, keys->net_ttl, keys->net_seq[i], keys->net_src); + verify_bool("Crypto packet encrypt", 0, true, status); + if (!status) + return; + mesh_crypto_privacy_counter(keys->iv_index, packet + 7, priv_rand); @@ -1232,11 +1302,15 @@ static void check_encrypt(const struct mesh_crypto_test *keys) } show_data("PreObsPayload", 1, packet + 1, 6 + net_msg_len); - mesh_crypto_network_obfuscate(packet, priv_key, + status = mesh_crypto_network_obfuscate(packet, priv_key, keys->iv_index, keys->ctl, keys->net_ttl, keys->net_seq[i], keys->net_src); + verify_bool("Crypto network obfuscate", 0, true, status); + if (!status) + return; + show_data("PostObsPayload", 1, packet + 1, 6 + net_msg_len); packet[0] = (keys->iv_index & 0x01) << 7 | nid; @@ -1265,19 +1339,20 @@ static void check_decrypt_segment(const struct mesh_crypto_test *keys, uint8_t net_clr[29]; uint64_t net_mic64, calc_net_mic64; uint32_t hdr, net_mic32, calc_net_mic32; - bool ctl, segmented, relay, szmic, key_akf; + bool ctl, segmented, relay, szmic, key_akf, status; uint8_t ttl, opcode, key_aid, segO, segN; uint32_t seq; uint16_t src, dst, seqZero; memcpy(net_clr, pkt, pkt_len); show_data("NetworkMessage", 0, pkt, pkt_len); - mesh_crypto_packet_decode(pkt, pkt_len, + status = mesh_crypto_packet_decode(pkt, pkt_len, false, net_clr, keys->iv_index, enc_key, priv_key); show_data("Decoded", 0, net_clr, pkt_len); - mesh_crypto_packet_parse(net_clr, pkt_len, + if (status) + status = mesh_crypto_packet_parse(net_clr, pkt_len, &ctl, &ttl, &seq, &src, &dst, NULL, &opcode, @@ -1286,6 +1361,10 @@ static void check_decrypt_segment(const struct mesh_crypto_test *keys, &segO, &segN, &msg, &msg_len); + verify_bool("Crypto Decode-Parse", 0, true, status); + if (!status) + return; + if (ctl) { net_mic64 = l_get_be64(pkt + pkt_len - 8); show_data("EncryptedPayload", 7, pkt + 7, pkt_len - 7 - 8); @@ -1416,7 +1495,7 @@ static void check_decrypt(const struct mesh_crypto_test *keys) uint16_t app_msg_len = 0; uint32_t calc_net_mic32, net_mic32 = 0; uint64_t calc_net_mic64, net_mic64 = 0; - bool net_ctl, net_segmented, net_rly, net_akf; + bool net_ctl, net_segmented, net_rly, net_akf, status; uint8_t net_aid, net_ttl, nid, net_segO, net_segN = 0; uint32_t net_seq, hdr, seqZero = 0; uint16_t net_src, net_dst; @@ -1501,8 +1580,14 @@ static void check_decrypt(const struct mesh_crypto_test *keys) net_msg = packet + 7; net_msg_len = packet_len - 7; - mesh_crypto_network_clarify(packet, priv_key, keys->iv_index, - &net_ctl, &net_ttl, &net_seq, &net_src); + status = mesh_crypto_network_clarify(packet, priv_key, + keys->iv_index, &net_ctl, &net_ttl, &net_seq, + &net_src); + + verify_bool("Crypto Clarify", 0, true, status); + if (!status) + return; + show_str("Packet", 0, keys->packet[i]); @@ -1731,42 +1816,67 @@ static void check_beacon(const struct mesh_crypto_test *keys) { uint8_t *net_key; uint8_t *beacon_cmac; - uint8_t beacon[22]; + uint8_t *random = NULL; + uint8_t beacon[29]; uint8_t enc_key[16]; uint8_t net_id[8]; uint8_t cmac[8]; - uint64_t cmac_tmp; + uint64_t cmac_tmp = 0; + + if (keys->beacon_type < 1 || keys->beacon_type > 2) + verify_uint8("Unknown Beacon", 0, true, + (keys->beacon_type >= 1 || keys->beacon_type <= 2)); net_key = l_util_from_hexstring(keys->net_key, NULL); beacon_cmac = l_util_from_hexstring(keys->beacon_cmac, NULL); - mesh_crypto_nkbk(net_key, enc_key); + if (keys->beacon_type == 1) { + mesh_crypto_nkbk(net_key, enc_key); + } else { + mesh_crypto_nkpk(net_key, enc_key); + random = l_util_from_hexstring(keys->rand, NULL); + } + mesh_crypto_k3(net_key, net_id); l_info(COLOR_BLUE "[%s]" COLOR_OFF, keys->name); verify_data("NetworkKey", 0, keys->net_key, net_key, 16); + show_uint8("Beacon Flags", 0, keys->beacon_flags); show_uint32("IVindex", 0, keys->iv_index); verify_data("BeaconKey", 0, keys->enc_key, enc_key, 16); - verify_data("NetworkID", 0, keys->net_id, net_id, 8); beacon[0] = keys->beacon_type; - beacon[1] = keys->beacon_flags; - memcpy(beacon + 2, net_id, 8); - l_put_be32(keys->iv_index, beacon + 10); - mesh_crypto_beacon_cmac(enc_key, net_id, keys->iv_index, - !!(keys->beacon_flags & 0x01), - !!(keys->beacon_flags & 0x02), - &cmac_tmp); - - l_put_be64(cmac_tmp, cmac); - l_put_be64(cmac_tmp, beacon + 14); - verify_data("BeaconCMAC", 0, keys->beacon_cmac, cmac, 8); - verify_data("Beacon", 0, keys->beacon, beacon, sizeof(beacon)); + if (keys->beacon_type == 1) { + verify_data("NetworkID", 0, keys->net_id, net_id, 8); + beacon[1] = keys->beacon_flags; + memcpy(beacon + 2, net_id, 8); + l_put_be32(keys->iv_index, beacon + 10); + mesh_crypto_beacon_cmac(enc_key, net_id, keys->iv_index, + !!(keys->beacon_flags & 0x01), + !!(keys->beacon_flags & 0x02), + &cmac_tmp); + + l_put_be64(cmac_tmp, cmac); + l_put_be64(cmac_tmp, beacon + 14); + verify_data("BeaconCMAC", 0, keys->beacon_cmac, cmac, 8); + verify_data("SNBeacon", 0, keys->beacon, beacon, 22); + } else { + show_data("Random", 0, random, sizeof(random)); + memcpy(beacon + 1, random, 13); + beacon[14] = keys->beacon_flags; + l_put_be32(keys->iv_index, beacon + 15); + mesh_crypto_aes_ccm_encrypt(random, enc_key, NULL, 0, + beacon + 14, 5, + beacon + 14, NULL, 8); + verify_data("BeaconMIC", 0, keys->beacon_cmac, beacon + 19, 8); + verify_data("PrivBeacon", 0, keys->beacon, beacon, 27); + } l_info(""); + l_free(random); l_free(beacon_cmac); l_free(net_key); } @@ -2071,6 +2181,8 @@ int main(int argc, char *argv[]) /* Section 8.4 Beacon Sample Data */ check_beacon(&s8_4_3); + check_beacon(&s8_4_6_1); + check_beacon(&s8_4_6_2); /* Section 8.6 Mesh Proxy Service sample data */ check_id_beacon(&s8_6_2); diff --git a/unit/test-micp.c b/unit/test-micp.c new file mode 100644 index 0000000000000000000000000000000000000000..a7fc7fb321bd150b323555ed32564e988832d39f --- /dev/null +++ b/unit/test-micp.c @@ -0,0 +1,838 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2023 NXP Semiconductors. All rights reserved. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <unistd.h> +#include <string.h> +#include <sys/socket.h> +#include <fcntl.h> + + +#include <glib.h> + +#include "lib/bluetooth.h" +#include "lib/uuid.h" +#include "src/shared/util.h" +#include "src/shared/tester.h" +#include "src/shared/queue.h" +#include "src/shared/att.h" +#include "src/shared/gatt-db.h" +#include "src/shared/gatt-server.h" +#include "src/shared/gatt-helpers.h" +#include "src/shared/micp.h" + +struct test_data_mics { + struct gatt_db *db; + struct bt_micp *micp; + struct bt_gatt_server *server; + struct bt_gatt_client *client; + struct queue *ccc_states; + size_t iovcnt; + struct iovec *iov; +}; + +struct test_data_micp { + struct gatt_db *db; + struct bt_micp *micp; + struct bt_gatt_client *client; + size_t iovcnt; + struct iovec *iov; +}; + +struct ccc_state { + uint16_t handle; + uint16_t value; +}; + +struct notify { + uint16_t handle, ccc_handle; + uint8_t *value; + uint16_t len; + bt_gatt_server_conf_func_t conf; + void *user_data; +}; + +#define MICP_GATT_CLIENT_MTU 64 + +#define iov_data(args...) ((const struct iovec[]) { args }) + +#define define_test_mics(name, function, _cfg, args...) \ + do { \ + const struct iovec iov[] = { args }; \ + static struct test_data_mics data; \ + data.iovcnt = ARRAY_SIZE(iov_data(args)); \ + data.iov = util_iov_dup(iov, ARRAY_SIZE(iov_data(args))); \ + tester_add(name, &data, NULL, function, \ + test_teardown_mics); \ + } while (0) + +#define define_test_micp(name, function, _cfg, args...) \ + do { \ + const struct iovec iov[] = { args }; \ + static struct test_data_micp data; \ + data.iovcnt = ARRAY_SIZE(iov_data(args)); \ + data.iov = util_iov_dup(iov, ARRAY_SIZE(iov_data(args))); \ + tester_add(name, &data, test_setup, function, \ + test_teardown_micp); \ + } while (0) + +static void print_debug(const char *str, void *user_data) +{ + const char *prefix = user_data; + + if (tester_use_debug()) + tester_debug("%s%s", prefix, str); +} + +static void test_teardown_mics(const void *user_data) +{ + struct test_data_mics *data = (void *)user_data; + + bt_micp_unref(data->micp); + bt_gatt_server_unref(data->server); + util_iov_free(data->iov, data->iovcnt); + gatt_db_unref(data->db); + + queue_destroy(data->ccc_states, free); + + tester_teardown_complete(); +} + +static void test_teardown_micp(const void *user_data) +{ + struct test_data_micp *data = (void *)user_data; + + bt_micp_unref(data->micp); + bt_gatt_client_unref(data->client); + util_iov_free(data->iov, data->iovcnt); + gatt_db_unref(data->db); + + tester_teardown_complete(); +} + +static void test_complete_cb(const void *user_data) +{ + tester_test_passed(); +} + +static void client_ready_cb(bool success, uint8_t att_ecode, void *user_data) +{ + + if (!success) + tester_setup_failed(); + else + tester_setup_complete(); +} + +static void micp_write_cb(bool success, uint8_t att_ecode, void *user_data) +{ + if (success) + printf("MICP Write successful\n"); + else + printf("\nWrite failed: 0x%02x\n", att_ecode); +} + +static void micp_write_value(struct bt_micp *micp, void *user_data) +{ + struct bt_mics *mics = micp_get_mics(micp); + uint16_t value_handle; + int ret; + uint16_t value = cpu_to_le16(0x0001); + + gatt_db_attribute_get_char_data(mics->ms, NULL, &value_handle, + NULL, NULL, NULL); + + printf("%s handle: %x\n", __func__, value_handle); + ret = bt_gatt_client_write_value(micp->client, value_handle, + (void *)&value, sizeof(value), micp_write_cb, NULL, NULL); + + if (!ret) + printf("bt_gatt_client_write_value() : Write FAILED"); +} + +static void micp_ready(struct bt_micp *micp, void *user_data) +{ + micp_write_value(micp, user_data); +} + +static void test_client(const void *user_data) +{ + struct test_data_micp *data = (void *)user_data; + struct io *io; + + io = tester_setup_io(data->iov, data->iovcnt); + g_assert(io); + + tester_io_set_complete_func(test_complete_cb); + + data->db = gatt_db_new(); + g_assert(data->db); + + data->micp = bt_micp_new(data->db, bt_gatt_client_get_db(data->client)); + g_assert(data->micp); + + bt_micp_set_debug(data->micp, print_debug, "bt_micp: ", NULL); + + bt_micp_ready_register(data->micp, micp_ready, data, NULL); + + bt_micp_attach(data->micp, data->client); +} + +static bool ccc_state_match(const void *a, const void *b) +{ + const struct ccc_state *ccc = a; + uint16_t handle = PTR_TO_UINT(b); + + return ccc->handle == handle; +} + +static struct ccc_state *find_ccc_state(struct test_data_mics *data, + uint16_t handle) +{ + return queue_find(data->ccc_states, ccc_state_match, + UINT_TO_PTR(handle)); +} + +static struct ccc_state *get_ccc_state(struct test_data_mics *data, + uint16_t handle) +{ + struct ccc_state *ccc; + + ccc = find_ccc_state(data, handle); + if (ccc) + return ccc; + + ccc = new0(struct ccc_state, 1); + ccc->handle = handle; + queue_push_tail(data->ccc_states, ccc); + + return ccc; +} + +static void gatt_notify_cb(struct gatt_db_attribute *attrib, + struct gatt_db_attribute *ccc, + const uint8_t *value, size_t len, + struct bt_att *att, void *user_data) +{ + struct test_data_mics *data = user_data; + struct notify notify; + + memset(¬ify, 0, sizeof(notify)); + + notify.handle = gatt_db_attribute_get_handle(attrib); + notify.ccc_handle = gatt_db_attribute_get_handle(ccc); + notify.value = (void *) value; + notify.len = len; + + printf("%s: notify.value:%d notify->len:%d\n", __func__, + (int)*(notify.value), notify.len); + if (!bt_gatt_server_send_notification(data->server, + notify.handle, notify.value, + notify.len, false)) + printf("%s: Failed to send notification\n", __func__); +} + +static void gatt_ccc_read_cb(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offset, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct test_data_mics *data = user_data; + struct ccc_state *ccc; + uint16_t handle; + uint8_t ecode = 0; + const uint8_t *value = NULL; + size_t len = 0; + + handle = gatt_db_attribute_get_handle(attrib); + + ccc = get_ccc_state(data, handle); + if (!ccc) { + ecode = BT_ATT_ERROR_UNLIKELY; + goto done; + } + + len = sizeof(ccc->value); + value = (void *) &ccc->value; + +done: + gatt_db_attribute_read_result(attrib, id, ecode, value, len); +} + +static void test_server(const void *user_data) +{ + struct test_data_mics *data = (void *)user_data; + struct bt_att *att; + struct io *io; + + io = tester_setup_io(data->iov, data->iovcnt); + g_assert(io); + + tester_io_set_complete_func(test_complete_cb); + + att = bt_att_new(io_get_fd(io), false); + g_assert(att); + + bt_att_set_debug(att, BT_ATT_DEBUG, print_debug, "bt_att:", NULL); + + data->db = gatt_db_new(); + g_assert(data->db); + + gatt_db_ccc_register(data->db, gatt_ccc_read_cb, NULL, + gatt_notify_cb, data); + + data->micp = bt_micp_new(data->db, NULL); + g_assert(data->micp); + + data->server = bt_gatt_server_new(data->db, att, 64, 0); + g_assert(data->server); + + bt_gatt_server_set_debug(data->server, print_debug, "bt_gatt_server:", + NULL); + + data->ccc_states = queue_new(); + + tester_io_send(); + + bt_att_unref(att); +} + +/* + * ATT: Exchange MTU Request (0x02) len 2 + * Client RX MTU: 64 + * + * ATT: Exchange MTU Response (0x03) len 2 + * Server RX MTU: 64 + */ +#define ATT_EXCHANGE_MTU IOV_DATA(0x02, 0x40, 0x00), \ + IOV_DATA(0x03, 0x40, 0x00) + +/* + * ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0001-0xffff + * Attribute type: Server Supported Features (0x2b3a) + * + * ATT: Error Response (0x01) len 4 + * Read By Type Request (0x08) + * Handle: 0x0001 + * Error: Attribute Not Found (0x0a) + */ +#define MICP_READ_SR_FEATURE IOV_DATA(0x08, 0x01, 0x00, 0Xff, 0xff, \ + 0x3a, 0x2b), \ + IOV_DATA(0x01, 0x08, 0x01, 0x00, 0x0a) + +/* + * ATT: Read By Group Type Request (0x10) len 6 + * Handle range: 0x0001-0xffff + * Attribute group type: Primary Service (0x2800) + * + * ATT: Read By Group Type Response (0x11) len 7 + * Attribute data length: 6 + * Attribute group list: 1 entry + * Handle range: 0x0001-0x0004 + * UUID: Microphone Control (0x184d) + * + * ATT: Read By Group Type Request (0x10) len 6 + * Handle range: 0x0005-0xffff + * Attribute group type: Primary Service (0x2800) + * + * ATT: Error Response (0x01) len 4 + * Read By Group Type Request (0x10) + * Handle: 0x0006 + * Error: Attribute Not Found (0x0a) + */ +#define MICP_READ_GROUP_TYPE \ + IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28), \ + IOV_DATA(0x11, 0x06, \ + 0x01, 0x00, 0x04, 0x00, 0x4d, 0x18), \ + IOV_DATA(0x10, 0x05, 0x00, 0xff, 0xff, 0x00, 0x28), \ + IOV_DATA(0x01, 0x10, 0x06, 0x00, 0x0a) + +/* + * ATT: Read By Group Type Request (0x10) len 6 + * Handle range: 0x0001-0xffff + * Attribute group type: Secondary Service (0x2801) + * + * ATT: Error Response (0x01) len 4 + * Read By Group Type Request (0x10) + * Handle: 0x0001 + * Error: Attribute Not Found (0x0a) + */ +#define MICP_READ_REQ_SECOND_SERVICE \ + IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28), \ + IOV_DATA(0x01, 0x10, 0x01, 0x00, 0x0a) + +/* + * ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0001-0x0004 + * Attribute type: Include (0x2802) + * + * ATT: Error Response (0x01) len 4 + * Read By Type Request (0x08) + * Handle: 0x0001 + * Error: Attribute Not Found (0x0a) + */ +#define MICP_READ_REQ_INCLUDE_SERVICE \ + IOV_DATA(0x08, 0x01, 0x00, 0x04, 0x00, 0x02, 0x28), \ + IOV_DATA(0x01, 0x08, 0x01, 0x00, 0x0a) + +/* ATT: Find Information Request (0x04) len 4 + * Handle range: 0x0004-0x0004 + */ +#define MICP_FIND_INFO_REQ \ + IOV_DATA(0x04, 0x04, 0x00, 0x04, 0x00), \ + IOV_DATA(0x05, 0x01, 0x04, 0x00, 0x02, 0x29) + +/* + * ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0001-0x0004 + * Attribute type: Characteristic (0x2803) + * + * ATT: Read By Type Response (0x09) len 8 + * Attribute data length: 7 + * Attribute data list: 1 entry + * Handle: 0x0002 + * Value: 1a0300c32b + * + * ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0003-0x0004 + * Attribute type: Characteristic (0x2803) + * + * ATT: Error Response (0x01) len 4 + * Read By Type Request (0x08) + * Handle: 0x0004 + * Error: Attribute Not Found (0x0a) + */ +#define MICP_READ_REQ_CHAR \ + IOV_DATA(0x08, 0x01, 0x00, 0x04, 0x00, 0x03, 0x28),\ + IOV_DATA(0x09, 0x07, \ + 0x02, 0x00, 0x1a, 0x03, 0x00, 0xc3, 0x2b), \ + IOV_DATA(0x08, 0x03, 0x00, 0x04, 0x00, 0x03, 0x28), \ + IOV_DATA(0x01, 0x08, 0x04, 0x00, 0x0a) +/* + * ATT: Read Request (0x0a) len 2 + * Handle: 0x0003 + * + * ATT: Read Response (0x0b) len 1 + */ +#define MICS_MUTE_READ \ + IOV_DATA(0x0a, 0x03, 0x00), \ + IOV_DATA(0x0b, 0x01) + +/* + * ATT: Write Request (0x12) len 4 + * Handle: 0x0004 + * Data: 0100 + * ATT: Write Response (0x13) len 0 + */ +#define MICS_EN_MUTE_DISCPTR \ + IOV_DATA(0x12, 0x04, 0x00, 0x01, 0x00), \ + IOV_DATA(0x13) + +#define MICS_MUTE_WRITE \ + IOV_DATA(0x12, 0x03, 0x00, 0x01),\ + IOV_DATA(0x13) + +#define MICP_CL_CGGIT_SER_BV_01_C \ + MICS_MUTE_READ, \ + MICS_EN_MUTE_DISCPTR, \ + IOV_DATA(0x12, 0x03, 0x00, 0x01, 0x00), \ + IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x013) + +#define MICP_CL_CGGIT_CHA_BV_01_C \ + MICS_MUTE_READ, \ + MICS_EN_MUTE_DISCPTR, \ + IOV_DATA(0x12, 0x03, 0x00, 0x01, 0x00), \ + IOV_DATA(0x013) + +#define MICP_CL_SPE_BI_01_C \ + MICS_MUTE_READ, \ + MICS_EN_MUTE_DISCPTR, \ + IOV_DATA(0x12, 0x03, 0x00, 0x01, 0x00), \ + IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x80) + +/* GATT Discover All procedure */ +static const struct iovec setup_data[] = { + ATT_EXCHANGE_MTU, + MICP_READ_SR_FEATURE, + MICP_READ_GROUP_TYPE, + MICP_READ_REQ_SECOND_SERVICE, + MICP_READ_REQ_INCLUDE_SERVICE, + MICP_READ_REQ_CHAR, + MICP_FIND_INFO_REQ +}; + +static void test_setup(const void *user_data) +{ + struct test_data_micp *data = (void *)user_data; + struct bt_att *att; + struct gatt_db *db; + struct io *io; + + io = tester_setup_io(setup_data, ARRAY_SIZE(setup_data)); + g_assert(io); + + att = bt_att_new(io_get_fd(io), false); + g_assert(att); + + bt_att_set_debug(att, BT_ATT_DEBUG, print_debug, "bt_att:", NULL); + + db = gatt_db_new(); + g_assert(db); + + data->client = bt_gatt_client_new(db, att, MICP_GATT_CLIENT_MTU, 0); + g_assert(data->client); + + bt_gatt_client_set_debug(data->client, print_debug, "bt_gatt_client:", + NULL); + + bt_gatt_client_ready_register(data->client, client_ready_cb, data, + NULL); + + bt_att_unref(att); + gatt_db_unref(db); +} + +/* + * ATT: Write Request (0x12) len 3 + * Handle: 0x0003 + * Data: 00 + * + * ATT: Write Response (0x13) len 0 + */ +#define MICS_MUTE_WRITE_VAL_00 \ + IOV_DATA(0x12, 0x03, 0x00, 0x00), \ + IOV_DATA(0x13) + +/* + * ATT: Write Request (0x12) len 3 + * Handle: 0x0003 + * Data: 01 + * + * ATT: Write Response (0x13) len 0 + */ +#define MICS_MUTE_WRITE_VAL_01 \ + IOV_DATA(0x12, 0x03, 0x00, 0x01), \ + IOV_DATA(0x13) +/* + * ATT: Read Request (0x0a) len 2 + * Handle: 0x0003 + * + * ATT: Read Response (0x0b) len 1 + */ +#define MICS_MUTE_READ \ + IOV_DATA(0x0a, 0x03, 0x00), \ + IOV_DATA(0x0b, 0x01) + +/* + * ATT: Read By Group Type Request (0x10) len 6 + * Handle range: 0x0001-0xffff + * Attribute group type: Primary Service (0x2800) + * + * ATT: Read By Group Type Response (0x11) len 7 + * Attribute data length: 6 + * Attribute group list: 1 entry + * Handle range: 0x0001-0x0004 + * UUID: Microphone Control (0x184d) + * + * ATT: Read By Group Type Request (0x10) len 6 + * Handle range: 0x0005-0xffff + * Attribute group type: Primary Service (0x2800) + * + * ATT: Error Response (0x01) len 4 + * Read By Group Type Request (0x10) + * Handle: 0x0005 + * Error: Attribute Not Found (0x0a) + */ +#define DISCOVER_PRIM_SERV_NOTIF \ + IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28), \ + IOV_DATA(0x11, 0x06, 0x01, 0x00, 0x04, 0x00, 0x4d, 0x18), \ + IOV_DATA(0x10, 0x05, 0x00, 0xff, 0xff, 0x00, 0x28), \ + IOV_DATA(0x01, 0x10, 0x05, 0x00, 0x0a) + +/* + * ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0001-0x0005 + * Attribute type: Characteristic (0x2803) + * + * ATT: Read By Type Response (0x09) len 8 + * Attribute data length: 7 + * Attribute data list: 1 entry + * Handle: 0x0002 + * Value: 1a0300c32b + * + * ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0005-0x0005 + * Attribute type: Characteristic (0x2803) + * + * ATT: Error Response (0x01) len 4 + * Read By Type Request (0x08) + * Handle: 0x0005 + * Error: Attribute Not Found (0x0a) + */ +#define DISC_MICS_CHAR_1 \ + IOV_DATA(0x08, 0x01, 0x00, 0x05, 0x00, 0x03, 0x28), \ + IOV_DATA(0x09, 0x07, \ + 0x02, 0x00, 0x1a, 0x03, 0x00, 0xc3, 0x2b), \ + IOV_DATA(0x08, 0x05, 0x00, 0x05, 0x00, 0x03, 0x28), \ + IOV_DATA(0x01, 0x08, 0x05, 0x00, 0x0a) + +/* + * ATT: Find By Type Value Request (0x06) len 8 + * Handle range: 0x0001-0xffff + * Attribute type: Primary Service (0x2800) + * UUID: Microphone Control (0x184d) + * + * ATT: Find By Type Value Response (0x07) len 4 + * Handle range: 0x0001-0x0004 + * + * ATT: Find By Type Value Request (0x06) len 8 + * Handle range: 0x0005-0xffff + * Attribute type: Primary Service (0x2800) + * UUID: Microphone Control (0x184d) + * + * ATT: Error Response (0x01) len 4 + * Find By Type Value Request (0x06) + * Handle: 0x0005 + * Error: Attribute Not Found (0x0a) + */ +#define MICS_FIND_BY_TYPE_VALUE \ + IOV_DATA(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0x4d, 0x18), \ + IOV_DATA(0x07, 0x01, 0x00, 0x04, 0x00), \ + IOV_DATA(0x06, 0x05, 0x00, 0xff, 0xff, 0x00, 0x28, 0x4d, 0x18), \ + IOV_DATA(0x01, 0x06, 0x05, 0x00, 0x0a) + +/* + * ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0001-0x0005 + * Attribute type: Characteristic (0x2803) + * + * ATT: Read By Type Response (0x09) len 8 + * Attribute data length: 7 + * Attribute data list: 1 entry + * Handle: 0x0002 + * Value: 1a0300c32b + * + * ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0003-0x0005 + * Attribute type: Characteristic (0x2803) + * + * ATT: Error Response (0x01) len 4 + * Read By Type Request (0x08) + * Handle: 0x0003 + * Error: Attribute Not Found (0x0a) + */ +#define DISC_MICS_CHAR_AFTER_TYPE \ + IOV_DATA(0x08, 0x01, 0x00, 0x05, 0x00, 0x03, 0x28), \ + IOV_DATA(0x09, 0x07, \ + 0x02, 0x00, 0x1a, 0x03, 0x00, 0xc3, 0x2b), \ + IOV_DATA(0x08, 0x03, 0x00, 0x05, 0x00, 0x03, 0x28), \ + IOV_DATA(0x01, 0x08, 0x03, 0x00, 0x0a) + +/* + * ATT: Write Request (0x12) len 4 + * Handle: 0x0004 + * Data: 0000 + * + * ATT: Write Response (0x13) len 0 + * + * ATT: Write Request (0x12) len 4 + * Handle: 0x0004 + * Data: 0100 + * + * ATT: Write Response (0x13) len 0 + */ +#define MICS_WRITE_CCD \ + IOV_DATA(0x12, 0x04, 0x00, 0x00, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x12, 0x04, 0x00, 0x01, 0x00), \ + IOV_DATA(0x13) + +/* + * ATT: Find Information Request (0x04) len 4 + * Handle range: 0x0004-0x0005 + * + * ATT: Find Information Response (0x05) len 5 + * Format: UUID-16 (0x01) + * Handle: 0x0004 + * UUID: Client Characteristic Configuration (0x2902) + * + * ATT: Find Information Request (0x04) len 4 + * Handle range: 0x0005-0x0005 + * + * ATT: Error Response (0x01) len 4 + * Find Information Request (0x04) + * Handle: 0x0005 + * Error: Attribute Not Found (0x0a) + */ +#define MICS_FIND_INFO \ + IOV_DATA(0x04, 0x04, 0x00, 0x05, 0x00), \ + IOV_DATA(0x05, 0x01, 0x04, 0x00, 0x02, 0x29), \ + IOV_DATA(0x04, 0x05, 0x00, 0x05, 0x00), \ + IOV_DATA(0x01, 0x04, 0x05, 0x00, 0x0a) + +/* + * 1.reads the characteristic value for the + * Mute characteristic + * 2.update the Mute characteristic to 0 or 1 + * 3.sends a notification containing the updated value + * of the Mute characteristic + * 4.update the Mute characteristic to 0 or 1 which ever + * different than step 2 + * 5.sends a notification containing the updated value of + * the Mute characteristic + */ +#define MICS_SR_SPN_BV_01_C \ + ATT_EXCHANGE_MTU, \ + DISCOVER_PRIM_SERV_NOTIF, \ + DISC_MICS_CHAR_1, \ + MICS_FIND_BY_TYPE_VALUE, \ + DISC_MICS_CHAR_AFTER_TYPE, \ + MICS_FIND_INFO, \ + MICS_WRITE_CCD, \ + IOV_DATA(0x0a, 0x03, 0x00), \ + IOV_DATA(0x0b, 0x01), \ + MICS_MUTE_WRITE_VAL_00, \ + IOV_DATA(0x1b, 0x03, 0x00, 0x00), \ + MICS_MUTE_WRITE_VAL_01, \ + IOV_DATA(0x1b, 0x03, 0x00, 0x01), \ + IOV_DATA(0x0a, 0x03, 0x00), \ + IOV_DATA(0x0b, 0x01) + +#define MICS_SR_SGGIT_SER_BV_01_C \ + ATT_EXCHANGE_MTU, \ + DISCOVER_PRIM_SERV_NOTIF, \ + MICS_FIND_BY_TYPE_VALUE + +#define MICS_SR_SGGIT_CHA_BV_01_C \ + ATT_EXCHANGE_MTU, \ + DISCOVER_PRIM_SERV_NOTIF, \ + MICS_FIND_BY_TYPE_VALUE, \ + DISC_MICS_CHAR_AFTER_TYPE + +/* + * ATT: Write Request (0x12) len 3 + * Handle: 0x0003 + * Data: 02 + * + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0003 + * Error: Value Not Allowed (0x13) + * + * ATT: Write Request (0x12) len 3 + * Handle: 0x0003 + * Data: 05 + * + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0003 + * Error: Value Not Allowed (0x13) + */ +#define MICS_WRITE_MUTE_CHAR_INVALID \ + IOV_DATA(0x12, 0x03, 0x00, 0x02), \ + IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x13), \ + IOV_DATA(0x12, 0x03, 0x00, 0x05), \ + IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x13) + +#define MICS_SR_SPE_BI_1_C \ + ATT_EXCHANGE_MTU, \ + DISCOVER_PRIM_SERV_NOTIF, \ + MICS_FIND_BY_TYPE_VALUE, \ + MICS_WRITE_MUTE_CHAR_INVALID + +/* + * ATT: Read Request (0x0a) len 2 + * Handle: 0x0003 + * + * ATT: Read Response (0x0b) len 1 + */ +#define MICS_MUTE_READ_INVALID \ + IOV_DATA(0x0a, 0x03, 0x00), \ + IOV_DATA(0x0b, 0x02) + +/* + * ATT: Write Request (0x12) len 3 + * Handle: 0x0003 + * Data: 01 + * + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0003 + * Error: Reserved (0x80) + */ +#define MICS_MUTE_WRITE_1 \ + IOV_DATA(0x12, 0x03, 0x00, 0x01), \ + IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x80) + +/* + * ATT: Write Request (0x12) len 3 + * Handle: 0x0003 + * Data: 00 + * + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0003 + * Error: Reserved (0x80) + */ +#define MICS_MUTE_WRITE_0 \ + IOV_DATA(0x12, 0x03, 0x00, 0x00), \ + IOV_DATA(0x01, 0x12, 0x03, 0x00, 0x80) + +#define MICS_SR_SPE_BI_02_C \ + ATT_EXCHANGE_MTU, \ + DISCOVER_PRIM_SERV_NOTIF, \ + MICS_FIND_BY_TYPE_VALUE, \ + MICS_MUTE_READ_INVALID, \ + MICS_MUTE_WRITE_0, \ + MICS_MUTE_WRITE_1 + +int main(int argc, char *argv[]) +{ + + tester_init(&argc, &argv); + + /* MICS Testcases */ + define_test_mics("MICS/SR/SGGIT/SER/BV-01-C", test_server, NULL, + MICS_SR_SGGIT_SER_BV_01_C); + define_test_mics("MICS/SR/SGGIT/CHA/BV-01-C", test_server, NULL, + MICS_SR_SGGIT_CHA_BV_01_C); + define_test_mics("MICS/SR/SPE/BI-01-C", test_server, NULL, + MICS_SR_SPE_BI_1_C); + + /* MICS/SR/SPE/BI-02-C: + * In function *mics_new(struct gatt_db *db)[src/shared/micp.c] + * by default the mics->mute_stat is set to MICS_MUTED[0x01]. + * As per test specs, Testcase MICS/SR/SPE/BI-02-C, Initial + * condition of mute state should be MICS_DISABLED[0x02]. + * To verify this Unit test case we have to modify the initial + * state of mics->mute_stat to MICS_DISABLED in code + * [in func mics_new()], build it and run bluetoothd. Then run + * this unit test case and this test case will Pass. + */ + /* define_test_mics("MICS/SR/SPE/BI-02-C", test_server, NULL, + * MICS_SR_SPE_BI_02_C); + */ + define_test_mics("MICS/SR/SPN/BV-01-C", test_server, NULL, + MICS_SR_SPN_BV_01_C); + + /* MICP Testcases */ + define_test_micp("MICP/CL/CGGIT/SER/BV-01-C", test_client, NULL, + MICP_CL_CGGIT_SER_BV_01_C); + define_test_micp("MICP/CL/CGGIT/CHA/BV-01-C", test_client, NULL, + MICP_CL_CGGIT_CHA_BV_01_C); + define_test_micp("MICP/CL/SPE/BI-01-C", test_client, NULL, + MICP_CL_SPE_BI_01_C); + + return tester_run(); +} diff --git a/unit/test-midi.c b/unit/test-midi.c index 644fcdc6dd2073de142417430a9b8c5c9ea1e308..702133e599b233a7d44edf842067f3d0f45d4338 100644 --- a/unit/test-midi.c +++ b/unit/test-midi.c @@ -525,50 +525,54 @@ static const snd_seq_event_t event5_expect[] = { static const struct midi_write_test midi5 = BLE_WRITE_TEST_INIT(event5, event5_expect); -static void test_midi_writer(gconstpointer data) +struct midi_data { + size_t events_tested; + const struct midi_write_test *midi_test; + struct midi_read_parser *midi_in; +} midi_data; + +static void compare_events_cb(const struct midi_write_parser *parser, + void *user_data) { - const struct midi_write_test *midi_test = data; - struct midi_write_parser midi_out; - struct midi_read_parser midi_in; - size_t i; /* event counter */ - size_t j; /* test counter */ - struct midi_data { - size_t events_tested; - const struct midi_write_test *midi_test; - struct midi_read_parser *midi_in; - } midi_data; + struct midi_data *midi_data = user_data; + const struct midi_write_test *midi_test = midi_data->midi_test; + struct midi_read_parser *midi_in = midi_data->midi_in; + size_t i = 0; - void compare_events_cb(const struct midi_write_parser *parser, void *user_data) { - struct midi_data *midi_data = user_data; - const struct midi_write_test *midi_test = midi_data->midi_test; - struct midi_read_parser *midi_in = midi_data->midi_in; - size_t i = 0; + midi_read_reset(midi_in); - midi_read_reset(midi_in); + while (i < midi_write_data_size(parser)) { + snd_seq_event_t ev; + size_t count; - while (i < midi_write_data_size(parser)) { - snd_seq_event_t ev; - size_t count; + snd_seq_ev_clear(&ev); - snd_seq_ev_clear(&ev); + count = midi_read_raw(midi_in, midi_write_data(parser) + i, + midi_write_data_size(parser) - i, &ev); - count = midi_read_raw(midi_in, midi_write_data(parser) + i, - midi_write_data_size(parser) - i, &ev); + g_assert_cmpuint(count, >, 0); - g_assert_cmpuint(count, >, 0); + if (ev.type != SND_SEQ_EVENT_NONE){ + g_assert_cmpint(midi_data->events_tested, <, + midi_test->event_expect_size); + compare_events(&midi_test->event_expect + [midi_data->events_tested], + &ev); + midi_data->events_tested++; + } - if (ev.type != SND_SEQ_EVENT_NONE){ - g_assert_cmpint(midi_data->events_tested, - <, - midi_test->event_expect_size); - compare_events(&midi_test->event_expect[midi_data->events_tested], - &ev); - midi_data->events_tested++; - } + i += count; + } +}; - i += count; - } - }; +static void test_midi_writer(gconstpointer data) +{ + const struct midi_write_test *midi_test = data; + struct midi_write_parser midi_out; + struct midi_read_parser midi_in; + size_t i; /* event counter */ + size_t j; /* test counter */ + struct midi_data midi_data; midi_read_init(&midi_in); diff --git a/unit/test-uhid.c b/unit/test-uhid.c index 8a8eef855bc59cd9912ca5cca3820be9ab3c7206..c5848bef97f969850a490c4f7a46ac46266e85e2 100644 --- a/unit/test-uhid.c +++ b/unit/test-uhid.c @@ -33,8 +33,19 @@ struct test_pdu { size_t size; }; +struct test_device { + const char *name; + uint32_t vendor; + uint32_t product; + uint32_t version; + uint32_t country; + uint8_t type; + struct iovec map; +}; + struct test_data { char *test_name; + struct test_device *test_device; struct test_pdu *pdu_list; }; @@ -54,17 +65,21 @@ struct context { .size = sizeof(*args), \ } -#define define_test(name, function, args...) \ +#define define_test_device(name, function, device, args...) \ do { \ const struct test_pdu pdus[] = { \ args, { } \ }; \ static struct test_data data; \ data.test_name = g_strdup(name); \ + data.test_device = device; \ data.pdu_list = util_memdup(pdus, sizeof(pdus)); \ tester_add(name, &data, NULL, function, NULL); \ } while (0) +#define define_test(name, function, args...) \ + define_test_device(name, function, NULL, args) + static void test_debug(const char *str, void *user_data) { const char *prefix = user_data; @@ -85,6 +100,7 @@ static void destroy_context(struct context *context) if (context->source > 0) g_source_remove(context->source); + bt_uhid_unregister_all(context->uhid); bt_uhid_unref(context->uhid); test_free(context->data); @@ -117,8 +133,8 @@ static gboolean send_pdu(gpointer user_data) len = write(context->fd, pdu->data, pdu->size); - - util_hexdump('<', pdu->data, len, test_debug, "uHID: "); + if (tester_use_debug()) + util_hexdump('<', pdu->data, len, test_debug, "uHID: "); g_assert_cmpint(len, ==, pdu->size); @@ -159,7 +175,8 @@ static gboolean test_handler(GIOChannel *channel, GIOCondition cond, g_assert(len > 0); - util_hexdump('>', buf, len, test_debug, "uHID: "); + if (tester_use_debug()) + util_hexdump('>', buf, len, test_debug, "uHID: "); g_assert_cmpint(len, ==, pdu->size); @@ -173,8 +190,25 @@ static gboolean test_handler(GIOChannel *channel, GIOCondition cond, static struct context *create_context(gconstpointer data) { struct context *context = g_new0(struct context, 1); + const struct test_data *test_data = data; GIOChannel *channel; int err, sv[2]; + uid_t uid = getuid(); + + context->data = data; + + /* Device testings requires extra permissions in order to be able to + * create devices. + */ + if (test_data->test_device && !uid) { + context->uhid = bt_uhid_new_default(); + if (!context->uhid) { + tester_test_abort(); + context_quit(context); + return NULL; + } + return context; + } err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv); g_assert(err == 0); @@ -196,7 +230,6 @@ static struct context *create_context(gconstpointer data) g_io_channel_unref(channel); context->fd = sv[1]; - context->data = data; return context; } @@ -228,19 +261,47 @@ static const struct uhid_event ev_feature = { static void test_client(gconstpointer data) { struct context *context = create_context(data); + struct test_device *device; + int err; - if (g_str_equal(context->data->test_name, "/uhid/command/create")) - bt_uhid_send(context->uhid, &ev_create); + if (!context) + return; - if (g_str_equal(context->data->test_name, "/uhid/command/destroy")) - bt_uhid_send(context->uhid, &ev_destroy); + device = context->data->test_device; + if (device) + err = bt_uhid_create(context->uhid, device->name, + BDADDR_ANY, BDADDR_ANY, + device->vendor, device->product, + device->version, device->country, + device->type, device->map.iov_base, + device->map.iov_len); + else + err = bt_uhid_create(context->uhid, "", NULL, NULL, 0, 0, 0, 0, + BT_UHID_NONE, NULL, 0); + + if (err < 0) { + tester_debug("create failed: %s\n", strerror(-err)); + tester_test_failed(); + } + + if (g_str_equal(context->data->test_name, "/uhid/command/destroy")) { + err = bt_uhid_destroy(context->uhid, true); + if (err < 0) + tester_test_failed(); + } if (g_str_equal(context->data->test_name, - "/uhid/command/feature_answer")) - bt_uhid_send(context->uhid, &ev_feature_answer); + "/uhid/command/feature_answer")) { + err = bt_uhid_send(context->uhid, &ev_feature_answer); + if (err < 0) + tester_test_failed(); + } - if (g_str_equal(context->data->test_name, "/uhid/command/input")) - bt_uhid_send(context->uhid, &ev_input); + if (g_str_equal(context->data->test_name, "/uhid/command/input")) { + err = bt_uhid_input(context->uhid, 0, NULL, 0); + if (err < 0) + tester_test_failed(); + } context_quit(context); } @@ -269,6 +330,29 @@ static void test_server(gconstpointer data) g_idle_add(send_pdu, context); } + +static struct test_device mx_anywhere_3 = { + .name = "MX Anywhere 3", + .vendor = 0x46D, + .product = 0xB025, + .version = 0x14, + .country = 0x00, + .type = BT_UHID_MOUSE, + .map = UTIL_IOV_INIT(0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x85, 0x02, + 0x09, 0x01, 0xA1, 0x00, 0x95, 0x10, 0x75, 0x01, + 0x15, 0x00, 0x25, 0x01, 0x05, 0x09, 0x19, 0x01, + 0x29, 0x10, 0x81, 0x02, 0x05, 0x01, 0x16, 0x01, + 0xF8, 0x26, 0xFF, 0x07, 0x75, 0x0C, 0x95, 0x02, + 0x09, 0x30, 0x09, 0x31, 0x81, 0x06, 0x15, 0x81, + 0x25, 0x7F, 0x75, 0x08, 0x95, 0x01, 0x09, 0x38, + 0x81, 0x06, 0x95, 0x01, 0x05, 0x0C, 0x0A, 0x38, + 0x02, 0x81, 0x06, 0xC0, 0xC0, 0x06, 0x43, 0xFF, + 0x0A, 0x02, 0x02, 0xA1, 0x01, 0x85, 0x11, 0x75, + 0x08, 0x95, 0x13, 0x15, 0x00, 0x26, 0xFF, 0x00, + 0x09, 0x02, 0x81, 0x00, 0x09, 0x02, 0x91, 0x00, + 0xC0), +}; + int main(int argc, char *argv[]) { tester_init(&argc, &argv); @@ -282,5 +366,8 @@ int main(int argc, char *argv[]) define_test("/uhid/event/output", test_server, event(&ev_output)); define_test("/uhid/event/feature", test_server, event(&ev_feature)); + define_test_device("/uhid/device/mx_anywhere_3", test_client, + &mx_anywhere_3, event(&ev_create)); + return tester_run(); } diff --git a/unit/test-vcp.c b/unit/test-vcp.c new file mode 100644 index 0000000000000000000000000000000000000000..6a61ea2c44d6609fcd6758caefa37df9bb5685b0 --- /dev/null +++ b/unit/test-vcp.c @@ -0,0 +1,2761 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2023 NXP Semiconductors. All rights reserved. + * + * This file contains only VOCS related Unit Test cases. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _GNU_SOURCE +#include <unistd.h> +#include <string.h> +#include <sys/socket.h> +#include <fcntl.h> + +#include <glib.h> + +#include "lib/bluetooth.h" +#include "lib/uuid.h" +#include "src/shared/util.h" +#include "src/shared/tester.h" +#include "src/shared/queue.h" +#include "src/shared/att.h" +#include "src/shared/gatt-db.h" +#include "src/shared/gatt-client.h" +#include "src/shared/gatt-server.h" +#include "src/shared/vcp.h" + +struct test_data { + struct gatt_db *db; + struct bt_vcp *vcp; + struct bt_gatt_server *server; + struct queue *ccc_states; + size_t iovcnt; + struct iovec *iov; +}; + +struct notify { + uint16_t handle, ccc_handle; + uint8_t *value; + uint16_t len; + bt_gatt_server_conf_func_t conf; + void *user_data; +}; + +struct ccc_state { + uint16_t handle; + uint16_t value; +}; + +#define iov_data(args...) ((const struct iovec[]) { args }) + +#define define_test(name, function, _cfg, args...) \ + do { \ + const struct iovec iov[] = { args }; \ + static struct test_data data; \ + data.iovcnt = ARRAY_SIZE(iov_data(args)); \ + data.iov = util_iov_dup(iov, ARRAY_SIZE(iov_data(args))); \ + tester_add(name, &data, NULL, function, \ + test_teardown); \ + } while (0) + +static void test_complete_cb(const void *user_data) +{ + tester_test_passed(); +} + +static void print_debug(const char *str, void *user_data) +{ + const char *prefix = user_data; + + if (tester_use_debug()) + tester_debug("%s%s", prefix, str); +} + +static void test_teardown(const void *user_data) +{ + struct test_data *data = (void *)user_data; + + bt_vcp_unref(data->vcp); + bt_gatt_server_unref(data->server); + util_iov_free(data->iov, data->iovcnt); + + gatt_db_unref(data->db); + + queue_destroy(data->ccc_states, free); + + tester_teardown_complete(); +} + +static bool ccc_state_match(const void *a, const void *b) +{ + const struct ccc_state *ccc = a; + uint16_t handle = PTR_TO_UINT(b); + + return ccc->handle == handle; +} + +static struct ccc_state *find_ccc_state(struct test_data *data, + uint16_t handle) +{ + return queue_find(data->ccc_states, ccc_state_match, + UINT_TO_PTR(handle)); +} + +static struct ccc_state *get_ccc_state(struct test_data *data, + uint16_t handle) +{ + struct ccc_state *ccc; + + ccc = find_ccc_state(data, handle); + if (ccc) + return ccc; + + ccc = new0(struct ccc_state, 1); + ccc->handle = handle; + queue_push_tail(data->ccc_states, ccc); + + return ccc; +} + +static void gatt_notify_cb(struct gatt_db_attribute *attrib, + struct gatt_db_attribute *ccc, + const uint8_t *value, size_t len, + struct bt_att *att, void *user_data) +{ + struct test_data *data = user_data; + uint16_t handle = gatt_db_attribute_get_handle(attrib); + + if (!bt_gatt_server_send_notification(data->server, + handle, value, len, false)) + printf("%s: Failed to send notification\n", __func__); +} + +static void gatt_ccc_read_cb(struct gatt_db_attribute *attrib, + unsigned int id, uint16_t offest, + uint8_t opcode, struct bt_att *att, + void *user_data) +{ + struct test_data *data = user_data; + struct ccc_state *ccc; + uint16_t handle; + uint8_t ecode = 0; + uint16_t value = 0; + + handle = gatt_db_attribute_get_handle(attrib); + + ccc = get_ccc_state(data, handle); + if (!ccc) { + ecode = BT_ATT_ERROR_UNLIKELY; + goto done; + } + + value = cpu_to_le16(ccc->value); + +done: + gatt_db_attribute_read_result(attrib, id, ecode, (void *)&value, + sizeof(value)); +} + +static void test_server(const void *user_data) +{ + struct test_data *data = (void *)user_data; + struct bt_att *att; + struct io *io; + + io = tester_setup_io(data->iov, data->iovcnt); + g_assert(io); + + tester_io_set_complete_func(test_complete_cb); + + att = bt_att_new(io_get_fd(io), false); + g_assert(att); + + bt_att_set_debug(att, BT_ATT_DEBUG, print_debug, "bt_att:", NULL); + + data->db = gatt_db_new(); + g_assert(data->db); + + gatt_db_ccc_register(data->db, gatt_ccc_read_cb, NULL, + gatt_notify_cb, data); + + data->vcp = bt_vcp_new(data->db, NULL); + g_assert(data->vcp); + + data->server = bt_gatt_server_new(data->db, att, 64, 0); + g_assert(data->server); + + bt_gatt_server_set_debug(data->server, print_debug, "bt_gatt_server", + NULL); + + data->ccc_states = queue_new(); + + tester_io_send(); + + bt_att_unref(att); +} + + /* ATT: Exchange MTU Request (0x02) len 2 + * Client RX MTU: 64 + * ATT: Exchange MTU Response (0x03) len 2 + * Server RX MTU: 64 + */ +#define VCS_EXCHANGE_MTU \ + IOV_DATA(0x02, 0x40, 0x00), \ + IOV_DATA(0x03, 0x40, 0x00) + + /* ATT: Read By Group Type Request (0x10) len 6 + * Handle range: 0x0001-0xffff + * Attribute group type: Primary Service (0x2800) + * + * ATT: Read By Group Type Response (0x11) len 7 + * Attribute data length: 6 + * Attribute group list: 1 entry + * Handle range: 0x001d-0x0027 + * UUID: Volume Control (0x1844) + * + * ATT: Read By Group Type Request (0x10) len 6 + * Handle range: 0x0027-0xffff + * Attribute group type: Primary Service (0x2800) + * + * ATT: Error Response (0x01) len 4 + * Read By Group Type Request (0x10) + * Handle: 0x0027 + * Error: Attribute Not Found (0x0a) + */ +#define VOCS_AICS_PRIMARY_SERVICE_VCS \ + IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28), \ + IOV_DATA(0x11, 0x06, 0x1d, 0x00, 0x27, 0x00, 0x44, 0x18), \ + IOV_DATA(0x10, 0x27, 0x00, 0xff, 0xff, 0x00, 0x28), \ + IOV_DATA(0x01, 0x10, 0x27, 0x00, 0x0a) + + /* ATT: Read By Group Type Request (0x10) len 6 + * Handle range: 0x0001-0xffff + * Attribute group type: Secondary Service (0x2801) + * + * ATT: Read By Group Type Response (0x11) len 7 + * Attribute data length: 6 + * Attribute group list: 2 entry + * Handle range: 0x0001-0x000c + * UUID: Volume Offset Control (0x1845) + * Handle range: 0x000d-0x001c + * UUID: Audio Input Control (0x1843) + * + * ATT: Read By Group Type Request (0x10) len 6 + * Handle range: 0x001d-0xffff + * Attribute group type: Secondary Service (0x2801) + * + * ATT: Error Response (0x01) len 4 + * Read By Group Type Request (0x10) + * Handle: 0x001d + * Error: Attribute Not Found (0x0a) + */ +#define VOCS_AICS_SECONDARY_SERVICE \ + IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28), \ + IOV_DATA(0x11, 0x06, \ + 0x01, 0x00, 0x0c, 0x00, 0x45, 0x18, \ + 0x0d, 0x00, 0x1c, 0x00, 0x43, 0x18), \ + IOV_DATA(0x10, 0x1d, 0x00, 0xff, 0xff, 0x01, 0x28), \ + IOV_DATA(0x01, 0x10, 0x1d, 0x00, 0x0a) + + /* ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0001-0xffff + * Attribute type: Include (0x2802) + * + * ATT: Read By Type Response (0x09) len 9 + * Attribute data length: 8 + * Attribute data list: 2 entries + * Handle: 0x001e + * Value: 01000c004518 + * Handle: 0x001f + * Value: 0d001c004318 + * + * ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0020-0xffff + * Attribute type: Include (0x2802) + * + * ATT: Error Response (0x01) len 4 + * Read By Type Request (0x08) + * Handle: 0x0020 + * Error: Attribute Not Found (0x0a) + */ +#define VOCS_AICS_INCLUDED_SERVICE \ + IOV_DATA(0x08, 0x01, 0x00, 0xff, 0xff, 0x02, 0x28), \ + IOV_DATA(0x09, 0x08, \ + 0x1e, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x45, 0x18, \ + 0x1f, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x43, 0x18), \ + IOV_DATA(0x08, 0x20, 0x00, 0xff, 0xff, 0x02, 0x28), \ + IOV_DATA(0x01, 0x08, 0x20, 0x00, 0x0a) + + /* ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0001-0x000c + * Attribute type: Characteristic (0x2803) + * + * ATT: Read By Type Response (0x09) len 29 + * Attribute data length: 7 + * Attribute data list: 4 entries + * Handle: 0x0002 + * Value: 120300802b + * Handle: 0x0005 + * Value: 120600812b + * Handle: 0x0008 + * Value: 080900822b + * Handle: 0x000a + * Value: 120b00832b + * + * ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x000b-0x000c + * Attribute type: Characteristic (0x2803) + * + * ATT: Error Response (0x01) len 4 + * Read By Type Request (0x08) + * Handle: 0x000b + * Error: Attribute Not Found (0x0a) + */ +#define VOCS_DISC_CHAR \ + IOV_DATA(0x08, 0x01, 0x00, 0x0c, 0x00, 0x03, 0x28), \ + IOV_DATA(0x09, 0x07, \ + 0x02, 0x00, 0x12, 0x03, 0x00, 0x80, 0x2b, \ + 0x05, 0x00, 0x12, 0x06, 0x00, 0x81, 0x2b, \ + 0x08, 0x00, 0x08, 0x09, 0x00, 0x82, 0x2b, \ + 0x0a, 0x00, 0x12, 0x0b, 0x00, 0x83, 0x2b), \ + IOV_DATA(0x08, 0x0b, 0x00, 0x0c, 0x00, 0x03, 0x28), \ + IOV_DATA(0x01, 0x08, 0x0b, 0x00, 0x0a) + + /* + * ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x000d-0x001c + * Attribute type: Characteristic (0x2803) + * + * ATT: Read By Type Response (0x09) len 43 + * Attribute data length: 7 + * Attribute data list: 6 entries + * Handle: 0x000e + * Value: 120f00772b + * Handle: 0x0011 + * Value: 021200782b + * Handle: 0x0013 + * Value: 021400792b + * Handle: 0x0015 + * Value: 1216007a2b + * Handle: 0x0018 + * Value: 0819007b2b + * Handle: 0x001a + * Value: 161b007c2b + * + * ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x001b-0x001c + * Attribute type: Characteristic (0x2803) + * + * ATT: Error Response (0x01) len 4 + * Read By Type Request (0x08) + * Handle: 0x001b + * Error: Attribute Not Found (0x0a) + */ + #define AICS_DISC_CHAR \ + IOV_DATA(0x08, 0x0d, 0x00, 0x1c, 0x00, 0x03, 0x28), \ + IOV_DATA(0x09, 0x07, \ + 0x0e, 0x00, 0x12, 0x0f, 0x00, 0x77, 0x2b, \ + 0x11, 0x00, 0x02, 0x12, 0x00, 0x78, 0x2b, \ + 0x13, 0x00, 0x02, 0x14, 0x00, 0x79, 0x2b, \ + 0x15, 0x00, 0x12, 0x16, 0x00, 0x7a, 0x2b, \ + 0x18, 0x00, 0x08, 0x19, 0x00, 0x7b, 0x2b, \ + 0x1a, 0x00, 0x16, 0x1b, 0x00, 0x7c, 0x2b), \ + IOV_DATA(0x08, 0x1b, 0x00, 0x1c, 0x00, 0x03, 0x28), \ + IOV_DATA(0x01, 0x08, 0x1b, 0x00, 0x0a) + + /* ATT: Find Information Request (0x04) len 4 + * Handle range: 0x0004-0x0004 + * + * ATT: Find Information Response (0x05) len 5 + * Format: UUID-16 (0x01) + * Handle: 0x0004 + * UUID: Client Characteristic Configuration (0x2902) + * + * ATT: Find Information Request (0x04) len 4 + * Handle range: 0x0007-0x0007 + * + * ATT: Find Information Response (0x05) len 5 + * Format: UUID-16 (0x01) + * Handle: 0x0007 + * UUID: Client Characteristic Configuration (0x2902) + * + * ATT: Find Information Request (0x04) len 4 + * Handle range: 0x000c-0x000c + * + * ATT: Find Information Response (0x05) len 5 + * Format: UUID-16 (0x01) + * Handle: 0x000c + * UUID: Client Characteristic Configuration (0x2902) + */ +#define VOCS_DISC_CHAR_DESC \ + IOV_DATA(0x04, 0x04, 0x00, 0x04, 0x00), \ + IOV_DATA(0x05, 0x01, 0x04, 0x00, 0x02, 0x29), \ + IOV_DATA(0x04, 0x07, 0x00, 0x07, 0x00), \ + IOV_DATA(0x05, 0x01, 0x07, 0x00, 0x02, 0x29), \ + IOV_DATA(0x04, 0x0c, 0x00, 0x0c, 0x00), \ + IOV_DATA(0x05, 0x01, 0x0c, 0x00, 0x02, 0x29) + + /* + * ATT: Find Information Request (0x04) len 4 + * Handle range: 0x0010-0x0010 + * + * ATT: Find Information Response (0x05) len 5 + * Format: UUID-16 (0x01) + * Handle: 0x0010 + * UUID: Client Characteristic Configuration (0x2902) + * + * ATT: Find Information Request (0x04) len 4 + * Handle range: 0x0017-0x0017 + * + * ATT: Find Information Response (0x05) len 5 + * Format: UUID-16 (0x01) + * Handle: 0x0017 + * UUID: Client Characteristic Configuration (0x2902) + * + * ATT: Find Information Request (0x04) len 4 + * Handle range: 0x001c-0x001c + * + * ATT: Find Information Response (0x05) len 5 + * Format: UUID-16 (0x01) + * Handle: 0x001c + * UUID: Client Characteristic Configuration (0x2902) + */ + #define AICS_DISC_CHAR_DESC \ + IOV_DATA(0x04, 0x10, 0x00, 0x10, 0x00), \ + IOV_DATA(0x05, 0x01, 0x10, 0x00, 0x02, 0x29), \ + IOV_DATA(0x04, 0x17, 0x00, 0x17, 0x00), \ + IOV_DATA(0x05, 0x01, 0x17, 0x00, 0x02, 0x29), \ + IOV_DATA(0x04, 0x1c, 0x00, 0x1c, 0x00), \ + IOV_DATA(0x05, 0x01, 0x1c, 0x00, 0x02, 0x29) + + /* ATT: Read Request (0x0a) len 2 + * Handle: 0x0004 + * + * ATT: Read Response (0x0b) len 2 + * + * ATT: Read Request (0x0a) len 2 + * Handle: 0x0007 + * + * ATT: Read Response (0x0b) len 2 + * + * ATT: Read Request (0x0a) len 2 + * Handle: 0x000c + * + * ATT: Read Request (0x0a) len 2 + * Handle: 0x000c + */ +#define VOCS_READ_CHAR_DESC \ + IOV_DATA(0x0a, 0x04, 0x00), \ + IOV_DATA(0x0b, 0x00, 0x00), \ + IOV_DATA(0x0a, 0x07, 0x00), \ + IOV_DATA(0x0b, 0x00, 0x00), \ + IOV_DATA(0x0a, 0x0c, 0x00), \ + IOV_DATA(0x0b, 0x00, 0x00) + + /* + * ATT: Read Request (0x0a) len 2 + * Handle: 0x0010 + * ATT: Read Response (0x0b) len 2 + * + * ATT: Read Request (0x0a) len 2 + * Handle: 0x0017 + * ATT: Read Response (0x0b) len 2 + * + * ATT: Read Request (0x0a) len 2 + * Handle: 0x001c + * ATT: Read Response (0x0b) len 2 + */ +#define AICS_READ_CHAR_DESC \ + IOV_DATA(0x0a, 0x10, 0x00), \ + IOV_DATA(0x0b, 0x00, 0x00), \ + IOV_DATA(0x0a, 0x17, 0x00), \ + IOV_DATA(0x0b, 0x00, 0x00), \ + IOV_DATA(0x0a, 0x1c, 0x00), \ + IOV_DATA(0x0b, 0x00, 0x00) + + /* + * ATT: Read Request (0x0a) len 2 + * Handle: 0x0012 + * + * ATT: Read Response (0x0b) len 3 + */ +#define AICS_READ_CHAR_GAIN_SETTNG_PROP \ + IOV_DATA(0x0a, 0x12, 0x00), \ + IOV_DATA(0x0b, 0x01, 0x80, 0x7f) + + /* + * ATT: Read Request (0x0a) len 2 + * Handle: 0x000f + * + * ATT: Read Response (0x0b) len 4 + */ +#define AICS_READ_CHAR_AUD_IP_STATE \ + IOV_DATA(0x0a, 0x0f, 0x00), \ + IOV_DATA(0x0b, 0x58, 0x00, 0x02, 00) + + /* + * ATT: Read Request (0x0a) len 2 + * Handle: 0x000f + * + * ATT: Read Response (0x0b) len 4 + */ +#define AICS_READ_CHAR_AUD_IP_STATE_MUT_DIS \ + IOV_DATA(0x0a, 0x0f, 0x00), \ + IOV_DATA(0x0b, 0x58, 0x02, 0x02, 00) + + /* + * ATT: Read Request (0x0a) len 2 + * Handle: 0x000f + * + * ATT: Read Response (0x0b) len 4 + */ +#define AICS_READ_CHAR_AUD_IP_STATE_MUTED \ + IOV_DATA(0x0a, 0x0f, 0x00), \ + IOV_DATA(0x0b, 0x58, 0x01, 0x02, 00) + + /* + * ATT: Read Request (0x0a) len 2 + * Handle: 0x000f + * + * ATT: Read Response (0x0b) len 4 + */ +#define AICS_READ_CHAR_AUD_IP_STATE_UNMUTED \ + IOV_DATA(0x0a, 0x0f, 0x00), \ + IOV_DATA(0x0b, 0x58, 0x00, 0x02, 00) + + /* + * ATT: Read Request (0x0a) len 2 + * Handle: 0x000f + * + * ATT: Read Response (0x0b) len 4 + */ +#define AICS_READ_CHAR_AUD_IP_STATE_AUTOMATIC \ + IOV_DATA(0x0a, 0x0f, 0x00), \ + IOV_DATA(0x0b, 0x58, 0x00, 0x03, 00) + + /* + * ATT: Read Request (0x0a) len 2 + * Handle: 0x000f + * + * ATT: Read Response (0x0b) len 4 + */ +#define AICS_READ_CHAR_AUD_IP_STATE_MANUAL \ + IOV_DATA(0x0a, 0x0f, 0x00), \ + IOV_DATA(0x0b, 0x58, 0x00, 0x02, 00) + + /* + * ATT: Read Request (0x0a) len 2 + * Handle: 0x0012 + * + * ATT: Read Response (0x0b) len 3 + */ +#define AICS_READ_CHAR_GAIN_SETTING_PROP \ + IOV_DATA(0x0a, 0x12, 0x00), \ + IOV_DATA(0x0b, 0x01, 0x80, 0x7f) + + /* + * ATT: Read Request (0x0a) len 2 + * Handle: 0x0014 + * + * ATT: Read Response (0x0b) len 1 + */ +#define AICS_READ_CHAR_AUD_IP_TYPE \ + IOV_DATA(0x0a, 0x14, 0x00), \ + IOV_DATA(0x0b, 0x01) + + /* + * ATT: Read Request (0x0a) len 2 + * Handle: 0x0014 + * + * ATT: Read Response (0x0b) len 1 + */ +#define AICS_READ_CHAR_AUD_IP_STATUS \ + IOV_DATA(0x0a, 0x16, 0x00), \ + IOV_DATA(0x0b, 0x01) + + /* + * ATT: Write Request (0x12) len 5 + * Handle: 0x0019 + * Data: 016401 + * + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0019 + * Error: Reserved (0x80) + * + * ATT: Write Request (0x12) len 4 + * Handle: 0x0019 + * Data: 0265/0366/0467/0568 + * + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0019 + * Error: Reserved (0x80) + */ +#define AICS_CP_WR_INVLD_CHG_COUNTER \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x64, 0x01), \ + IOV_DATA(0x01, 0x12, 0x19, 0x00, 0x80), \ + IOV_DATA(0x12, 0x19, 0x00, 0x02, 0x65), \ + IOV_DATA(0x01, 0x12, 0x19, 0x00, 0x80), \ + IOV_DATA(0x12, 0x19, 0x00, 0x03, 0x66), \ + IOV_DATA(0x01, 0x12, 0x19, 0x00, 0x80), \ + IOV_DATA(0x12, 0x19, 0x00, 0x04, 0x67), \ + IOV_DATA(0x01, 0x12, 0x19, 0x00, 0x80), \ + IOV_DATA(0x12, 0x19, 0x00, 0x05, 0x68), \ + IOV_DATA(0x01, 0x12, 0x19, 0x00, 0x80) + + /* + * ATT: Write Request (0x12) len 4 + * Handle: 0x0019 + * Data: 0600/ff00 + * + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0019 + * Error: Reserved (0x81) + */ +#define AICS_CP_WR_INVLD_OP_CODE \ + IOV_DATA(0x12, 0x19, 0x00, 0x06, 0x00), \ + IOV_DATA(0x01, 0x12, 0x19, 0x00, 0x81), \ + IOV_DATA(0x12, 0x19, 0x00, 0xff, 0x00), \ + IOV_DATA(0x01, 0x12, 0x19, 0x00, 0x81) + + /* + * ATT: Write Request (0x12) len 4 + * Handle: 0x0019 + * Data: 0200 + * + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0019 + * Error: Reserved (0x82) + */ +#define AICS_CP_WR_UNMUTE \ + IOV_DATA(0x12, 0x19, 0x00, 0x02, 0x00), \ + IOV_DATA(0x01, 0x12, 0x19, 0x00, 0x82) + + /* + * ATT: Write Request (0x12) len 4 + * Handle: 0x0019 + * Data: 0300 + * + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0019 + * Error: Reserved (0x82) + */ +#define AICS_CP_WR_MUTE \ + IOV_DATA(0x12, 0x19, 0x00, 0x03, 0x00), \ + IOV_DATA(0x01, 0x12, 0x19, 0x00, 0x82) + + /* + * ATT: Write Request (0x12) len 4 + * Handle: 0x0019 + * Data: 0200 + * + * ATT: Write Response (0x13) len 0 + */ +#define AICS_CP_WR_UNMUTE_SUCCESS \ + IOV_DATA(0x12, 0x19, 0x00, 0x02, 0x00), \ + IOV_DATA(0x13) + + /* + * ATT: Write Request (0x12) len 4 + * Handle: 0x0019 + * Data: 0300 + * + * ATT: Write Response (0x13) len 0 + */ +#define AICS_CP_WR_MUTE_SUCCESS \ + IOV_DATA(0x12, 0x19, 0x00, 0x03, 0x00), \ + IOV_DATA(0x13) + + /* + * ATT: Write Request (0x12) len 4 + * Handle: 0x0019 + * Data: 0400 + * + * ATT: Write Response (0x13) len 0 + */ +#define AICS_CP_WR_MANUAL_GAIN \ + IOV_DATA(0x12, 0x19, 0x00, 0x04, 0x00), \ + IOV_DATA(0x13) + + /* + * ATT: Write Request (0x12) len 4 + * Handle: 0x0019 + * Data: 0500 + * + * ATT: Write Response (0x13) len 0 + */ +#define AICS_CP_WR_AUTOMATIC_GAIN \ + IOV_DATA(0x12, 0x19, 0x00, 0x05, 0x00), \ + IOV_DATA(0x13) + + /* + * ATT: Write Request (0x12) len 5 + * Handle: 0x0019 + * Data: 01007f + * + * ATT: Write Response (0x13) len 0 + */ +#define AICS_CP_WR_GAIN_SETTING_MAX \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x00, 0x7f), \ + IOV_DATA(0x13) + + /* + * ATT: Write Request (0x12) len 5 + * Handle: 0x0019 + * Data: 010080 + * + * ATT: Write Response (0x13) len 0 + */ +#define AICS_CP_WR_GAIN_SETTING_MIN \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x01, 0x80), \ + IOV_DATA(0x13) + + /* + * ATT: Write Request (0x12) len 4 + * Handle: 0x0010 + * Data: 0100 + * + * ATT: Write Response (0x13) len 0 + */ +#define AICS_ENABLE_AUD_IP_STATE_CC \ + IOV_DATA(0x12, 0x10, 0x00, 0x01, 0x00), \ + IOV_DATA(0X13) + + /* + * ATT: Handle Value Notification (0x1b) len 6 + * Handle: 0x000f + * Data: 58000201 + */ +#define AICS_AUD_IP_STATE_UNMUTED_NOTIF \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x58, 0x00, 0x02, 0x01) + + /* + * ATT: Handle Value Notification (0x1b) len 6 + * Handle: 0x000f + * Data: 58010201 + */ +#define AICS_AUD_IP_STATE_MUTED_NOTIF \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x58, 0x01, 0x02, 0x01) + + /* + * ATT: Handle Value Notification (0x1b) len 6 + * Handle: 0x000f + * Data: 58000201 + * + */ +#define AICS_AUD_IP_STATE_MANUAL_GAIN_NOTIF \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x58, 0x00, 0x02, 0x01) + + /* + * ATT: Handle Value Notification (0x1b) len 6 + * Handle: 0x000f + * Data: 58000301 + */ +#define AICS_AUD_IP_STATE_AUTOMATIC_GAIN_NOTIF \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x58, 0x00, 0x03, 0x01) + + /* + * ATT: Handle Value Notification (0x1b) len 6 + * Handle: 0x000f + * Data: 7f000201 + */ +#define AICS_AUD_IP_STATE_GAIN_SETTING_MAX_NOTIF \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x7f, 0x00, 0x02, 0x01) + + /* + * ATT: Handle Value Notification (0x1b) len 6 + * Handle: 0x000f + * Data: 80000202 + */ +#define AICS_AUD_IP_STATE_GAIN_SETTING_MIN_NOTIF \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x80, 0x00, 0x02, 0x02) + + /* + * AICS/SR/CP/BV-01-C + * Test Procedure: + * 1. The Lower Tester executes the GATT Read Characteristic Value + * sub-procedure for the Audio Input State characteristic. + * 2. The Lower Tester executes the GATT Read Characteristic Value + * sub-procedure for the Gain Setting Properties characteristic. + * Repeat steps 3–5 for (255 – Change_Counter value) + 1 times. + * [AICS_CP_WR_GAIN_SETTING_255_LOOP does the above point] + * 3. The Lower Tester executes the GATT Write Characteristic Value + * sub-procedure for the Audio Input Control Point characteristic with + * the Set Gain Setting Opcode, Gain Setting parameter set to a random + * value between the Gain_Setting_Minimum field and Gain_Setting_Maximum + * field values and different than the last iteration, and the + * Change_Counter parameter. + * 4. The Lower Tester receives a Write Response indicating that the IUT + * has accepted the Opcode. + * 5. The Lower Tester receives a GATT Characteristic Value Notification + * for the Audio Input State characteristic. + * + */ +#define AICS_CP_WR_GAIN_SETTING_255_LOOP \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x00, 0xc4), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xc4, 0x00, 0x02, 0x01), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x01, 0xaf), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xaf, 0x00, 0x02, 0x02), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x02, 0xcd), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xcd, 0x00, 0x02, 0x03), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x03, 0xd4), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xd4, 0x00, 0x02, 0x04), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x04, 0x08), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x08, 0x00, 0x02, 0x05), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x05, 0x88), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x88, 0x00, 0x02, 0x06), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x06, 0xde), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xde, 0x00, 0x02, 0x07), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x07, 0x21), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x21, 0x00, 0x02, 0x08), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x08, 0x41), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x41, 0x00, 0x02, 0x09), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x09, 0x08), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x08, 0x00, 0x02, 0x0a), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x0a, 0x05), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x05, 0x00, 0x02, 0x0b), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x0b, 0x18), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x18, 0x00, 0x02, 0x0c), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x0c, 0x28), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x28, 0x00, 0x02, 0x0d), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x0d, 0xca), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xca, 0x00, 0x02, 0x0e), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x0e, 0xa0), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xa0, 0x00, 0x02, 0x0f), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x0f, 0xd0), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xd0, 0x00, 0x02, 0x10), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x10, 0xec), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xec, 0x00, 0x02, 0x11), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x11, 0x3c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x3c, 0x00, 0x02, 0x12), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x12, 0x09), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x09, 0x00, 0x02, 0x13), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x13, 0x05), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x05, 0x00, 0x02, 0x14), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x14, 0x29), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x29, 0x00, 0x02, 0x15), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x15, 0x28), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x28, 0x00, 0x02, 0x16), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x16, 0x25), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x25, 0x00, 0x02, 0x17), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x17, 0x31), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x31, 0x00, 0x02, 0x18), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x18, 0x49), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x49, 0x00, 0x02, 0x19), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x19, 0x12), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x12, 0x00, 0x02, 0x1a), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x1a, 0x09), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x09, 0x00, 0x02, 0x1b), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x1b, 0x29), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x29, 0x00, 0x02, 0x1c), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x1c, 0x55), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x55, 0x00, 0x02, 0x1d), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x1d, 0x35), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x35, 0x00, 0x02, 0x1e), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x1e, 0x59), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x59, 0x00, 0x02, 0x1f), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x1f, 0x69), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x69, 0x00, 0x02, 0x20), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x20, 0x22), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x22, 0x00, 0x02, 0x21), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x21, 0x79), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x79, 0x00, 0x02, 0x22), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x22, 0x11), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x11, 0x00, 0x02, 0x23), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x23, 0x21), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x21, 0x00, 0x02, 0x24), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x24, 0x0a), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x0a, 0x00, 0x02, 0x25), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x25, 0x0b), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x0b, 0x00, 0x02, 0x26), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x26, 0x0c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x0c, 0x00, 0x02, 0x27), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x27, 0x0d), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x0d, 0x00, 0x02, 0x28), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x28, 0x0e), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x0e, 0x00, 0x02, 0x29), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x29, 0x0f), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x0f, 0x00, 0x02, 0x2a), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x2a, 0x61), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x61, 0x00, 0x02, 0x2b), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x2b, 0x63), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x63, 0x00, 0x02, 0x2c), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x2c, 0x64), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x64, 0x00, 0x02, 0x2d), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x2d, 0x68), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x68, 0x00, 0x02, 0x2e), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x2e, 0x14), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x14, 0x00, 0x02, 0x2f), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x2f, 0x33), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x33, 0x00, 0x02, 0x30), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x30, 0x31), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x31, 0x00, 0x02, 0x31), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x31, 0x3e), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x3e, 0x00, 0x02, 0x32), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x32, 0x79), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x79, 0x00, 0x02, 0x33), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x33, 0x99), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x99, 0x00, 0x02, 0x34), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x34, 0x81), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x81, 0x00, 0x02, 0x35), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x35, 0x73), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x73, 0x00, 0x02, 0x36), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x36, 0x75), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x75, 0x00, 0x02, 0x37), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x37, 0x6f), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x6f, 0x00, 0x02, 0x38), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x38, 0x4e), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x4e, 0x00, 0x02, 0x39), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x39, 0x1a), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x1a, 0x00, 0x02, 0x3a), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x3a, 0x1c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x1c, 0x00, 0x02, 0x3b), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x3b, 0x2c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x2c, 0x00, 0x02, 0x3c), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x3c, 0x5a), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x5a, 0x00, 0x02, 0x3d), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x3d, 0x3d), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x3d, 0x00, 0x02, 0x3e), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x3e, 0x5f), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x5f, 0x00, 0x02, 0x3f), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x3f, 0x6e), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x6e, 0x00, 0x02, 0x40), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x40, 0x2c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x2c, 0x00, 0x02, 0x41), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x41, 0x7c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x7c, 0x00, 0x02, 0x42), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x42, 0x01), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x01, 0x00, 0x02, 0x43), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x43, 0x2b), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x2b, 0x00, 0x02, 0x44), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x44, 0xbc), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xbc, 0x00, 0x02, 0x45), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x45, 0x3b), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x3b, 0x00, 0x02, 0x46), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x46, 0x4c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x4c, 0x00, 0x02, 0x47), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x47, 0x3d), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x3d, 0x00, 0x02, 0x48), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x48, 0x7e), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x7e, 0x00, 0x02, 0x49), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x49, 0x2f), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x2f, 0x00, 0x02, 0x4a), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x4a, 0x71), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x71, 0x00, 0x02, 0x4b), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x4b, 0x93), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x93, 0x00, 0x02, 0x4c), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x4c, 0x6c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x6c, 0x00, 0x02, 0x4d), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x4d, 0x78), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x78, 0x00, 0x02, 0x4e), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x4e, 0x44), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x44, 0x00, 0x02, 0x4f), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x4f, 0x83), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x83, 0x00, 0x02, 0x50), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x50, 0x2c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x2c, 0x00, 0x02, 0x51), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x51, 0x7e), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x7e, 0x00, 0x02, 0x52), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x52, 0x61), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x61, 0x00, 0x02, 0x53), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x53, 0xbb), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xbb, 0x00, 0x02, 0x54), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x54, 0xb1), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xb1, 0x00, 0x02, 0x55), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x55, 0x3e), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x3e, 0x00, 0x02, 0x56), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x56, 0xca), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xca, 0x00, 0x02, 0x57), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x57, 0x3f), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x3f, 0x00, 0x02, 0x58), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x58, 0x3e), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x3e, 0x00, 0x02, 0x59), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x59, 0xdf), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xdf, 0x00, 0x02, 0x5a), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x5a, 0xe1), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xe1, 0x00, 0x02, 0x5b), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x5b, 0xd3), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xd3, 0x00, 0x02, 0x5c), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x5c, 0x9c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x9c, 0x00, 0x02, 0x5d), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x5d, 0x70), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x70, 0x00, 0x02, 0x5e), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x5e, 0xa4), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xa4, 0x00, 0x02, 0x5f), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x5f, 0x8a), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x8a, 0x00, 0x02, 0x60), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x60, 0x7c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x7c, 0x00, 0x02, 0x61), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x61, 0x5f), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x5f, 0x00, 0x02, 0x62), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x62, 0x6a), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x6a, 0x00, 0x02, 0x63), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x63, 0xb3), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xb3, 0x00, 0x02, 0x64), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x64, 0xb7), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xb7, 0x00, 0x02, 0x65), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x65, 0x3b), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x3b, 0x00, 0x02, 0x66), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x66, 0x4a), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x4a, 0x00, 0x02, 0x67), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x67, 0x3b), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x3b, 0x00, 0x02, 0x68), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x68, 0x8e), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x8e, 0x00, 0x02, 0x69), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x69, 0xef), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xef, 0x00, 0x02, 0x6a), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x6a, 0xe5), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xe5, 0x00, 0x02, 0x6b), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x6b, 0xe3), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xe3, 0x00, 0x02, 0x6c), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x6c, 0x5c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x5c, 0x00, 0x02, 0x6d), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x6d, 0x79), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x79, 0x00, 0x02, 0x6e), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x6e, 0xa1), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xa1, 0x00, 0x02, 0x6f), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x6f, 0x8b), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x8b, 0x00, 0x02, 0x70), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x70, 0x5e), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x5e, 0x00, 0x02, 0x71), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x71, 0x0f), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x0f, 0x00, 0x02, 0x72), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x72, 0x6c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x6c, 0x00, 0x02, 0x73), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x73, 0xb9), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xb9, 0x00, 0x02, 0x74), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x74, 0xb0), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xb0, 0x00, 0x02, 0x75), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x75, 0x31), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x31, 0x00, 0x02, 0x76), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x76, 0x4d), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x4d, 0x00, 0x02, 0x77), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x77, 0x39), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x39, 0x00, 0x02, 0x78), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x78, 0xde), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xde, 0x00, 0x02, 0x79), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x79, 0xe9), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xe9, 0x00, 0x02, 0x7a), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x7a, 0xe8), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xe8, 0x00, 0x02, 0x7b), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x7b, 0xa3), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xa3, 0x00, 0x02, 0x7c), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x7c, 0xcc), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xcc, 0x00, 0x02, 0x7d), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x7d, 0x89), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x89, 0x00, 0x02, 0x7e), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x7e, 0xa9), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xa9, 0x00, 0x02, 0x7f), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x7f, 0x83), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x83, 0x00, 0x02, 0x80), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x80, 0x4e), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x4e, 0x00, 0x02, 0x81), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x81, 0x9f), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x9f, 0x00, 0x02, 0x82), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x82, 0x6f), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x6f, 0x00, 0x02, 0x83), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x83, 0xb5), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xb5, 0x00, 0x02, 0x84), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x84, 0xb4), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xb4, 0x00, 0x02, 0x85), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x85, 0x21), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x21, 0x00, 0x02, 0x86), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x86, 0x7d), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x7d, 0x00, 0x02, 0x87), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x87, 0x29), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x29, 0x00, 0x02, 0x88), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x88, 0x9d), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x9d, 0x00, 0x02, 0x89), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x89, 0xe1), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xe1, 0x00, 0x02, 0x8a), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x8a, 0xa8), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xa8, 0x00, 0x02, 0x8b), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x8b, 0xaa), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xaa, 0x00, 0x02, 0x8c), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x8c, 0x1c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x1c, 0x00, 0x02, 0x8d), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x8d, 0x59), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x59, 0x00, 0x02, 0x8e), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x8e, 0xc9), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xc9, 0x00, 0x02, 0x8f), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x8f, 0x33), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x33, 0x00, 0x02, 0x90), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x90, 0xe0), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xe0, 0x00, 0x02, 0x91), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x91, 0xf1), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xf1, 0x00, 0x02, 0x92), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x92, 0x6e), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x6e, 0x00, 0x02, 0x93), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x93, 0xb3), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xb3, 0x00, 0x02, 0x94), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x94, 0xb8), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xb8, 0x00, 0x02, 0x95), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x95, 0x2f), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x2f, 0x00, 0x02, 0x96), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x96, 0x7c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x7c, 0x00, 0x02, 0x97), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x97, 0x25), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x25, 0x00, 0x02, 0x98), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x98, 0x9e), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x9e, 0x00, 0x02, 0x99), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x99, 0xed), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xed, 0x00, 0x02, 0x9a), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x9a, 0xa5), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xa5, 0x00, 0x02, 0x9b), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x9b, 0xab), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xab, 0x00, 0x02, 0x9c), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x9c, 0x5c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x5c, 0x00, 0x02, 0x9d), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x9d, 0x5c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x5c, 0x00, 0x02, 0x9e), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x9e, 0xc8), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xc8, 0x00, 0x02, 0x9f), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0x9f, 0x3b), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x3b, 0x00, 0x02, 0xa0), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xa0, 0xed), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xed, 0x00, 0x02, 0xa1), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xa1, 0x9a), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x9a, 0x00, 0x02, 0xa2), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xa2, 0x6b), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x6b, 0x00, 0x02, 0xa3), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xa3, 0xb9), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xb9, 0x00, 0x02, 0xa4), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xa4, 0xbe), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xbe, 0x00, 0x02, 0xa5), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xa5, 0x2e), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x2e, 0x00, 0x02, 0xa6), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xa6, 0x7c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x7c, 0x00, 0x02, 0xa7), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xa7, 0x24), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x24, 0x00, 0x02, 0xa8), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xa8, 0x9b), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x9b, 0x00, 0x02, 0xa9), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xa9, 0xee), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xee, 0x00, 0x02, 0xaa), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xaa, 0xc2), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xc2, 0x00, 0x02, 0xab), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xab, 0xc0), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xc0, 0x00, 0x02, 0xac), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xac, 0x10), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x10, 0x00, 0x02, 0xad), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xad, 0x58), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x58, 0x00, 0x02, 0xae), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xae, 0xa9), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xa9, 0x00, 0x02, 0xaf), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xaf, 0x30), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x30, 0x00, 0x02, 0xb0), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xb0, 0x49), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x49, 0x00, 0x02, 0xb1), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xb1, 0x90), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x90, 0x00, 0x02, 0xb2), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xb2, 0x60), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x60, 0x00, 0x02, 0xb3), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xb3, 0xbf), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xbf, 0x00, 0x02, 0xb4), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xb4, 0xbd), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xbd, 0x00, 0x02, 0xb5), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xb5, 0x33), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x33, 0x00, 0x02, 0xb6), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xb6, 0x77), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x77, 0x00, 0x02, 0xb7), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xb7, 0x89), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x89, 0x00, 0x02, 0xb8), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xb8, 0x9f), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x9f, 0x00, 0x02, 0xb9), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xb9, 0xf1), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xf1, 0x00, 0x02, 0xba), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xba, 0xaa), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xaa, 0x00, 0x02, 0xbb), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xbb, 0xac), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xac, 0x00, 0x02, 0xbc), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xbc, 0x1e), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x1e, 0x00, 0x02, 0xbd), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xbd, 0x58), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x58, 0x00, 0x02, 0xbe), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xbe, 0xcd), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xcd, 0x00, 0x02, 0xbf), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xbf, 0x3a), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x3a, 0x00, 0x02, 0xc0), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xc0, 0x48), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x48, 0x00, 0x02, 0xc1), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xc1, 0x9a), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x9a, 0x00, 0x02, 0xc2), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xc2, 0x6c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x6c, 0x00, 0x02, 0xc3), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xc3, 0x7a), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x7a, 0x00, 0x02, 0xc4), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xc4, 0x7d), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x7d, 0x00, 0x02, 0xc5), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xc5, 0x7c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x7c, 0x00, 0x02, 0xc6), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xc6, 0x7d), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x7d, 0x00, 0x02, 0xc7), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xc7, 0x7e), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x7e, 0x00, 0x02, 0xc8), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xc8, 0x7f), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x7f, 0x00, 0x02, 0xc9), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xc9, 0xf0), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xf0, 0x00, 0x02, 0xca), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xca, 0xf1), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xf1, 0x00, 0x02, 0xcb), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xcb, 0xf2), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xf2, 0x00, 0x02, 0xcc), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xcc, 0xf3), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xf3, 0x00, 0x02, 0xcd), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xcd, 0xf4), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xf4, 0x00, 0x02, 0xce), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xce, 0xc1), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xc1, 0x00, 0x02, 0xcf), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xcf, 0xc2), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0xc2, 0x00, 0x02, 0xd0), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xd0, 0x4f), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x4f, 0x00, 0x02, 0xd1), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xd1, 0x60), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x60, 0x00, 0x02, 0xd2), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xd2, 0x6a), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x6a, 0x00, 0x02, 0xd3), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xd3, 0x6b), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x6b, 0x00, 0x02, 0xd4), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xd4, 0x6c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x6c, 0x00, 0x02, 0xd5), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xd5, 0x6d), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x6d, 0x00, 0x02, 0xd6), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xd6, 0x6e), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x6e, 0x00, 0x02, 0xd7), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xd7, 0x6f), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x6f, 0x00, 0x02, 0xd8), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xd8, 0x91), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x91, 0x00, 0x02, 0xd9), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xd9, 0x92), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x92, 0x00, 0x02, 0xda), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xda, 0x93), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x93, 0x00, 0x02, 0xdb), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xdb, 0x94), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x94, 0x00, 0x02, 0xdc), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xdc, 0x95), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x95, 0x00, 0x02, 0xdd), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xdd, 0x96), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x96, 0x00, 0x02, 0xde), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xde, 0x97), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x97, 0x00, 0x02, 0xdf), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xdf, 0x98), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x98, 0x00, 0x02, 0xe0), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xe0, 0x59), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x59, 0x00, 0x02, 0xe1), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xe1, 0x5a), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x5a, 0x00, 0x02, 0xe2), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xe2, 0x5b), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x5b, 0x00, 0x02, 0xe3), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xe3, 0x5c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x5c, 0x00, 0x02, 0xe4), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xe4, 0x5d), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x5d, 0x00, 0x02, 0xe5), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xe5, 0x5e), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x5e, 0x00, 0x02, 0xe6), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xe6, 0x5f), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x5f, 0x00, 0x02, 0xe7), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xe7, 0x70), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x70, 0x00, 0x02, 0xe8), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xe8, 0x71), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x71, 0x00, 0x02, 0xe9), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xe9, 0x72), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x72, 0x00, 0x02, 0xea), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xea, 0x73), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x73, 0x00, 0x02, 0xeb), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xeb, 0x74), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x74, 0x00, 0x02, 0xec), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xec, 0x4a), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x4a, 0x00, 0x02, 0xed), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xed, 0x4b), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x4b, 0x00, 0x02, 0xee), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xee, 0x4c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x4c, 0x00, 0x02, 0xef), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xef, 0x50), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x50, 0x00, 0x02, 0xf0), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xf0, 0x40), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x40, 0x00, 0x02, 0xf1), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xf1, 0x30), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x30, 0x00, 0x02, 0xf2), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xf2, 0x50), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x50, 0x00, 0x02, 0xf3), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xf3, 0x60), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x60, 0x00, 0x02, 0xf4), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xf4, 0x10), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x10, 0x00, 0x02, 0xf5), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xf5, 0x11), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x11, 0x00, 0x02, 0xf6), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xf6, 0x12), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x12, 0x00, 0x02, 0xf7), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xf7, 0x13), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x13, 0x00, 0x02, 0xf8), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xf8, 0x14), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x14, 0x00, 0x02, 0xf9), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xf9, 0x15), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x15, 0x00, 0x02, 0xfa), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xfa, 0x16), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x16, 0x00, 0x02, 0xfb), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xfb, 0x18), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x18, 0x00, 0x02, 0xfc), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xfc, 0x19), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x19, 0x00, 0x02, 0xfd), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xfd, 0x1a), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x1a, 0x00, 0x02, 0xfe), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xfe, 0x1b), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x1b, 0x00, 0x02, 0xff), \ + IOV_DATA(0x12, 0x19, 0x00, 0x01, 0xff, 0x1c), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x0f, 0x00, 0x1c, 0x00, 0x02, 0x00) + + /* ATT: Read Request (0x0a) len 2 + * Handle: 0x0003 + * + * ATT: Read Response (0x0b) len 3 + */ +#define VOCS_READ_CHAR_VOL_OFFSET \ + IOV_DATA(0x0a, 0x03, 0x00), \ + IOV_DATA(0x0b, 0x00, 0x00, 0x00) + + /* ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0002-0x0003 + * Attribute type: Offset State (0x2b80) + * + * ATT: Read By Type Response (0x09) len 6 + * Attribute data length: 5 + * Attribute data list: 1 entry + * Handle: 0x0003 + * Value: 000000 + */ +#define VOCS_READ_CHAR_VOL_OFFSET_UUID \ + IOV_DATA(0x08, 0x02, 0x00, 0x03, 0x00, 0x80, 0x2b), \ + IOV_DATA(0x09, 0x05, 0x03, 0x00, 0x00, 0x00, 0x00) + + /* ATT: Read Request (0x0a) len 2 + * Handle: 0x0006 + * + * ATT: Read Response (0x0b) len 4 + */ +#define VOCS_READ_CHAR_AUD_LOC \ + IOV_DATA(0x0a, 0x06, 0x00), \ + IOV_DATA(0x0b, 0x02, 0x00, 0x00, 0x00) + + /* ATT: Read By Type Request (0x08) len 6 + * Handle range: 0x0005-0x0006 + * Attribute type: Audio Location (0x2b81) + * + * ATT: Read By Type Response (0x09) len 7 + * Attribute data length: 6 + * Attribute data list: 1 entry + * Handle: 0x0006 + * Value: 02000000 + */ +#define VOCS_READ_CHAR_AUD_LOC_UUID \ + IOV_DATA(0x08, 0x05, 0x00, 0x06, 0x00, 0x81, 0x2b), \ + IOV_DATA(0x09, 0x06, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00) + + /* ATT: Write Request (0x12) len 6 + * Handle: 0x0009 + * Data: 01280a00 + * + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0009 + * Error: Reserved (0x80) + */ +#define VOCS_CP_INVALID_CHNG_COUNTER \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x28, 0x0a, 0x00),\ + IOV_DATA(0x01, 0x12, 0x09, 0x00, 0x80) + + /* ATT: Write Request (0x12) len 6 + * Handle: 0x0009 + * Data: 00007800 + * + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0009 + * Error: Reserved (0x81) + */ +#define VOCS_CP_INVALID_OPCODE \ + IOV_DATA(0x12, 0x09, 0x00, 0x00, 0x00, 0x78, 0x00),\ + IOV_DATA(0x01, 0x12, 0x09, 0x00, 0x81) + + /* ATT: Write Request (0x12) len 6 + * Handle: 0x0009 + * Data: 01000e01 + * + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0009 + * Error: Reserved (0x82) + * + * ATT: Write Request (0x12) len 6 + * Handle: 0x0009 + * Data: 0100f2fe + * + * ATT: Error Response (0x01) len 4 + * Write Request (0x12) + * Handle: 0x0009 + * Error: Reserved (0x82) + */ +#define VOCS_CP_OUT_OF_RANGE_VALUE \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x00, 0x0e, 0x01), \ + IOV_DATA(0x01, 0x12, 0x09, 0x00, 0x82), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x00, 0xf2, 0xfe),\ + IOV_DATA(0x01, 0x12, 0x09, 0x00, 0x82) + + /* ATT: Write Request (0x12) len 4 + * Handle: 0x0004 + * Data: 0100 + * + * ATT: Write Response (0x13) len 0 + */ +#define VOCS_ENNABLE_VOL_OFFSET_CCD \ + IOV_DATA(0x12, 0x04, 0x00, 0x01, 0x00), \ + IOV_DATA(0x13) + +#define VOCS_SR_SGGIT_CHA_TST_CMDS \ + VCS_EXCHANGE_MTU, \ + VOCS_AICS_PRIMARY_SERVICE_VCS, \ + VOCS_AICS_SECONDARY_SERVICE, \ + VOCS_AICS_INCLUDED_SERVICE, \ + VOCS_DISC_CHAR, \ + VOCS_DISC_CHAR_DESC, \ + VOCS_READ_CHAR_DESC + +#define AICS_SR_SGGIT_CHA_TST_CMDS \ + VCS_EXCHANGE_MTU, \ + VOCS_AICS_PRIMARY_SERVICE_VCS, \ + VOCS_AICS_SECONDARY_SERVICE, \ + VOCS_AICS_INCLUDED_SERVICE, \ + AICS_DISC_CHAR, \ + AICS_DISC_CHAR_DESC, \ + AICS_READ_CHAR_DESC + +#define AICS_SR_SGGIT_CHA_BV_01_C \ + AICS_SR_SGGIT_CHA_TST_CMDS, \ + AICS_READ_CHAR_AUD_IP_STATE + +#define AICS_SR_SGGIT_CHA_BV_02_C \ + AICS_SR_SGGIT_CHA_TST_CMDS, \ + AICS_READ_CHAR_GAIN_SETTING_PROP + +#define AICS_SR_SGGIT_CHA_BV_03_C \ + AICS_SR_SGGIT_CHA_TST_CMDS, \ + AICS_READ_CHAR_AUD_IP_TYPE + +#define AICS_SR_SGGIT_CHA_BV_04_C \ + AICS_SR_SGGIT_CHA_TST_CMDS, \ + AICS_READ_CHAR_AUD_IP_STATUS + +#define AICS_SR_SGGIT_CHA_BV_05_C \ + AICS_SR_SGGIT_CHA_TST_CMDS + +#define AICS_SR_SGGIT_CHA_BV_06_C \ + AICS_SR_SGGIT_CHA_TST_CMDS + +#define AICS_SR_SGGIT_CP_BI_01_C \ + AICS_SR_SGGIT_CHA_TST_CMDS, \ + AICS_READ_CHAR_AUD_IP_STATE, \ + AICS_CP_WR_INVLD_CHG_COUNTER + +#define AICS_SR_SGGIT_CP_BI_02_C \ + AICS_SR_SGGIT_CHA_TST_CMDS, \ + AICS_CP_WR_INVLD_OP_CODE + +#define AICS_SR_SGGIT_CP_BI_03_C \ + AICS_SR_SGGIT_CHA_TST_CMDS, \ + AICS_READ_CHAR_AUD_IP_STATE_MUT_DIS, \ + AICS_CP_WR_UNMUTE, \ + AICS_CP_WR_MUTE + +#define AICS_SR_CP_BV_01_C \ + AICS_SR_SGGIT_CHA_TST_CMDS, \ + AICS_ENABLE_AUD_IP_STATE_CC, \ + AICS_READ_CHAR_AUD_IP_STATE, \ + AICS_READ_CHAR_GAIN_SETTNG_PROP, \ + AICS_CP_WR_GAIN_SETTING_255_LOOP + +#define AICS_SR_CP_BV_02_C \ + AICS_SR_SGGIT_CHA_TST_CMDS, \ + AICS_ENABLE_AUD_IP_STATE_CC, \ + AICS_READ_CHAR_AUD_IP_STATE_MUTED, \ + AICS_CP_WR_UNMUTE_SUCCESS, \ + AICS_AUD_IP_STATE_UNMUTED_NOTIF + +#define AICS_SR_CP_BV_03_C \ + AICS_SR_SGGIT_CHA_TST_CMDS, \ + AICS_ENABLE_AUD_IP_STATE_CC, \ + AICS_READ_CHAR_AUD_IP_STATE_UNMUTED, \ + AICS_CP_WR_MUTE_SUCCESS, \ + AICS_AUD_IP_STATE_MUTED_NOTIF + +#define AICS_SR_CP_BV_04_C \ + AICS_SR_SGGIT_CHA_TST_CMDS, \ + AICS_ENABLE_AUD_IP_STATE_CC, \ + AICS_READ_CHAR_AUD_IP_STATE_AUTOMATIC, \ + AICS_CP_WR_MANUAL_GAIN, \ + AICS_AUD_IP_STATE_MANUAL_GAIN_NOTIF + +#define AICS_SR_CP_BV_05_C \ + AICS_SR_SGGIT_CHA_TST_CMDS, \ + AICS_ENABLE_AUD_IP_STATE_CC, \ + AICS_READ_CHAR_AUD_IP_STATE_MANUAL, \ + AICS_CP_WR_AUTOMATIC_GAIN, \ + AICS_AUD_IP_STATE_AUTOMATIC_GAIN_NOTIF + +#define AICS_SR_SPE_BI_01_C \ + AICS_SR_SGGIT_CHA_TST_CMDS, \ + AICS_ENABLE_AUD_IP_STATE_CC, \ + AICS_READ_CHAR_AUD_IP_STATE, \ + AICS_READ_CHAR_GAIN_SETTNG_PROP, \ + AICS_CP_WR_GAIN_SETTING_MAX, \ + AICS_AUD_IP_STATE_GAIN_SETTING_MAX_NOTIF, \ + AICS_CP_WR_GAIN_SETTING_MIN, \ + AICS_AUD_IP_STATE_GAIN_SETTING_MIN_NOTIF + +#define VOCS_SR_SGGIT_SER_BV_01_C \ + VOCS_SR_SGGIT_CHA_TST_CMDS + +#define VOCS_SR_SGGIT_CHA_BV_01_C \ + VOCS_SR_SGGIT_CHA_TST_CMDS, \ + VOCS_READ_CHAR_VOL_OFFSET, \ + VOCS_READ_CHAR_VOL_OFFSET_UUID + +#define VOCS_SR_SGGIT_CHA_BV_02_C \ + VOCS_SR_SGGIT_CHA_TST_CMDS, \ + VOCS_READ_CHAR_AUD_LOC, \ + VOCS_READ_CHAR_AUD_LOC_UUID + +#define VOCS_SR_SGGIT_CHA_BV_03_C \ + VOCS_SR_SGGIT_CHA_TST_CMDS + +#define VOCS_SR_SGGIT_CHA_BV_04_C \ + VOCS_SR_SGGIT_CHA_TST_CMDS + +#define VOCS_SR_SGGIT_CP_BI_01_C \ + VOCS_SR_SGGIT_CHA_TST_CMDS, \ + VOCS_CP_INVALID_CHNG_COUNTER + +#define VOCS_SR_SGGIT_CP_BI_02_C \ + VOCS_SR_SGGIT_CHA_TST_CMDS, \ + VOCS_CP_INVALID_OPCODE + +#define VOCS_SR_SGGIT_CP_BI_03_C \ + VOCS_SR_SGGIT_CHA_TST_CMDS, \ + VOCS_CP_OUT_OF_RANGE_VALUE + +#define VOCS_SR_SPE_BI_01_C \ + VOCS_SR_SGGIT_CHA_TST_CMDS, \ + VOCS_READ_CHAR_AUD_LOC + /* + * VOCS/SR/CP/BV-01-C [Set Volume Offset] + * Do Initial Condition Proedures + * 1. The Lower Tester executes the GATT Read Characteristic + * Value sub-procedure for the Volume Offset State characteristic. + * Repeat steps 2-4 for (255 - Change_Counter value) + 1 times. + * 2. The Lower Tester executes the GATT Write Characteristic Value + * sub-procedure for the Volume + * Offset Control Point characteristic with the Set Volume Offset + * Opcode, with the Volume Offset parameters set to a random value + * different from the last one, and the Change_Counter parameter. + * 3. The Lower Tester receives a Write Response indicating that the IUT + * has accepted the Opcode. + * 4. The Lower Tester receives a GATT Characteristic Value Notification + * for the Volume Offset State characteristic. + */ +#define VOCS_SR_CP_BV_01_C \ + VOCS_SR_SGGIT_CHA_TST_CMDS, \ + VOCS_ENNABLE_VOL_OFFSET_CCD, \ + VOCS_READ_CHAR_VOL_OFFSET, \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x00, 0xde, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xde, 0x00, 0x01), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x01, 0xda, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xda, 0xff, 0x02), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x02, 0x1a, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x1a, 0x00, 0x03), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x03, 0x49, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x49, 0xff, 0x04), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x04, 0x05, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x05, 0xff, 0x05), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x05, 0xf1, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xf1, 0xff, 0x06), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x06, 0xca, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xca, 0xff, 0x07), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x07, 0x5c, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x5c, 0x00, 0x08), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x08, 0xaf, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xaf, 0x00, 0x09), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x09, 0x5f, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x5f, 0x00, 0x0a), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x0a, 0x69, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x69, 0xff, 0x0b), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x0b, 0x3d, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x3d, 0xff, 0x0c), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x0c, 0xb6, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xb6, 0xff, 0x0d), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x0d, 0xa4, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xa4, 0x00, 0x0e), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x0e, 0x14, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x14, 0xff, 0x0f), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x0f, 0x2a, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x2a, 0xff, 0x10), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x10, 0x51, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x51, 0x00, 0x11), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x011, 0xc4, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xc4, 0xff, 0x12), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x12, 0xe8, 00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xe8, 0x00, 0x13), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x13, 0xca, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xca, 0xff, 0x14), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x14, 0xe6, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xe6, 0xff, 0x15), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x15, 0x62, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x62, 0x00, 0x16), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x16, 0x22, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x22, 0x00, 0x17), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x17, 0xa1, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xa1, 0xff, 0x18), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x18, 0xaa, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xaa, 0x00, 0x19), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x19, 0x65, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x65, 0x00, 0x1a), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x1a, 0x11, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x11, 0xff, 0x1b), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x1b, 0x69, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x69, 0xff, 0x1c), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x1c, 0xee, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xee, 0x00, 0x1d), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x1d, 0xaa, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xaa, 0xff, 0x1e), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x1e, 0x1f, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x1f, 0xff, 0x1f), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x1f, 0xbe, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xbe, 0x00, 0x20), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x20, 0x93, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x93, 0xff, 0x21), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x21, 0x11, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x11, 0xff, 0x22), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x22, 0x83, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x83, 0xff, 0x23), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x23, 0xf8, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xf8, 0x00, 0x24), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x24, 0x90, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x90, 0xff, 0x25), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x25, 0x0c, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x0c, 0x00, 0x26), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x26, 0xc8, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xc8, 0x00, 0x27), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x27, 0x59, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x59, 0xff, 0x28), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x28, 0x80, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x80, 0xff, 0x29), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x29, 0x0d, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x0d, 0xff, 0x2a), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x2a, 0x0c, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x0c, 0x00, 0x2b), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x2b, 0x0a, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x0a, 0x00, 0x2c), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x2c, 0x12, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x12, 0x00, 0x2d), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x2d, 0x0b, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x0b, 0xff, 0x2e), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x2e, 0x83, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x83, 0xff, 0x2f), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x2f, 0x91, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x91, 0xff, 0x30), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x30, 0x71, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x71, 0xff, 0x31), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x31, 0x72, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x72, 0xff, 0x32), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x32, 0x75, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x75, 0xff, 0x33), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x33, 0x78, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x78, 0xff, 0x34), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x34, 0x61, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x61, 0xff, 0x35), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x35, 0x63, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x63, 0xff, 0x36), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x36, 0x38, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x38, 0xff, 0x37), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x37, 0x21, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x21, 0xff, 0x38), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x38, 0xa4, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xa4, 0x00, 0x39), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x39, 0xb4, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xb4, 0x00, 0x3a), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x3a, 0xb5, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xb5, 0xff, 0x3b), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x3b, 0xac, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xac, 0x00, 0x3c), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x3c, 0xab, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xab, 0x00, 0x3d), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x3d, 0xad, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xad, 0x00, 0x3e), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x3e, 0x83, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x83, 0xff, 0x3f), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x3f, 0x84, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x84, 0xff, 0x40), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x40, 0x85, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x85, 0xff, 0x41), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x41, 0x86, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x86, 0xff, 0x42), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x42, 0x87, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x87, 0xff, 0x43), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x43, 0x87, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x87, 0xff, 0x44), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x44, 0x05, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x05, 0x000, 0x45), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x45, 0xce, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xce, 0x00, 0x46), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x46, 0x96, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x96, 0x00, 0x47), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x47, 0x07, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x07, 0x00, 0x48), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x48, 0x08, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x08, 0x00, 0x49), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x49, 0x09, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x09, 0xff, 0x4a), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x4a, 0x0a, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x0a, 0xff, 0x4b), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x4b, 0x11, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x11, 0xff, 0x4c), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x4c, 0x22, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x22, 0xff, 0x4d), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x4d, 0x33, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x33, 0xff, 0x4e), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x4e, 0x09, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x09, 0xff, 0x4f), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x4f, 0x19, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x19, 0xff, 0x50), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x50, 0x1a, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x1a, 0xff, 0x51), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x51, 0x1b, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x1b, 0xff, 0x52), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x52, 0xa1, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xa1, 0x00, 0x53), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x53, 0xa2, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xa2, 0x00, 0x54), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x54, 0xb2, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xb2, 0x00, 0x55), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x55, 0xb3, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xb3, 0x00, 0x56), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x56, 0x68, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x68, 0x00, 0x57), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x57, 0x69, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x69, 0x00, 0x58), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x58, 0x6a, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x6a, 0x00, 0x59), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x59, 0x7a, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x7a, 0x00, 0x5a), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x5a, 0x7b, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x7b, 0x00, 0x5b), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x5b, 0x8c, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x8c, 0x00, 0x5c), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x5c, 0x9c, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x9c, 0x00, 0x5d), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x5d, 0x9b, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x9b, 0x00, 0x5e), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x5e, 0x9c, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x9c, 0x00, 0x5f), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x5f, 0x9d, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x9d, 0x00, 0x60), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x60, 0x9e, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x9e, 0x00, 0x61), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x61, 0x21, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x21, 0x00, 0x62), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x62, 0x23, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x23, 0x00, 0x63), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x63, 0x24, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x24, 0x00, 0x64), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x64, 0x34, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x34, 0x00, 0x65), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x65, 0x44, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x44, 0x00, 0x66), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x66, 0x45, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x45, 0x00, 0x67), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x67, 0x9d, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x9d, 0x00, 0x68), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x68, 0x9d, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x9d, 0x00, 0x69), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x69, 0x9d, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x9d, 0x00, 0x6a), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x6a, 0x49, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x49, 0x00, 0x6b), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x6b, 0x39, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x39, 0x00, 0x6c), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x6c, 0x9d, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x9d, 0x00, 0x6d), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x6d, 0x9e, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x9e, 0x00, 0x6e), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x6e, 0x9f, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x9f, 0x00, 0x6f), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x6f, 0x91, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x91, 0x00, 0x70), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x70, 0x18, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x18, 0x00, 0x71), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x71, 0x34, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x34, 0xff, 0x72), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x72, 0x44, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x44, 0xff, 0x73), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x73, 0x05, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x05, 0xff, 0x74), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x74, 0x06, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x06, 0xff, 0x75), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x75, 0x38, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x38, 0x00, 0x76), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x76, 0x48, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x48, 0x00, 0x77), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x77, 0x58, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x58, 0x00, 0x78), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x78, 0x88, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x88, 0x00, 0x79), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x79, 0x98, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x98, 0x00, 0x7a), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x7a, 0x91, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x91, 0x00, 0x7b), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x7b, 0x95, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x95, 0x00, 0x7c), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x7c, 0x89, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x89, 0x00, 0x7d), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x7d, 0x82, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x82, 0x00, 0x7e), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x7e, 0x88, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x88, 0x00, 0x7f), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x7f, 0x66, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x66, 0x00, 0x80), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x80, 0x55, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x55, 0x00, 0x81), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x81, 0x44, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x44, 0x00, 0x82), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x82, 0x33, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x33, 0x00, 0x83), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x83, 0x22, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x22, 0x00, 0x84), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x84, 0x11, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x11, 0x00, 0x85), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x85, 0x01, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x01, 0x00, 0x86), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x86, 0x3a, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x3a, 0x00, 0x87), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x87, 0x3b, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x3b, 0x00, 0x88), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x88, 0x3c, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x3c, 0x00, 0x89), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x89, 0x4c, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x4c, 0x00, 0x8a), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x8a, 0x5c, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x5c, 0x00, 0x8b), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x8b, 0x6c, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x6c, 0x00, 0x8c), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x8c, 0xab, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xab, 0xff, 0x8d), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x8d, 0xac, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xac, 0xff, 0x8e), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x8e, 0xbc, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xbc, 0x00, 0x8f), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x8f, 0xbb, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xbb, 0x00, 0x90), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x90, 0x11, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x11, 0x00, 0x91), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x91, 0x21, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x21, 0x00, 0x92), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x92, 0x31, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x31, 0x00, 0x93), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x93, 0x21, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x21, 0x00, 0x94), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x94, 0x31, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x31, 0x00, 0x95), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x95, 0x41, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x41, 0x00, 0x96), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x96, 0x51, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x51, 0x00, 0x97), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x97, 0x61, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x61, 0x00, 0x98), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x98, 0x81, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x81, 0x00, 0x99), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x99, 0x55, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x55, 0x00, 0x9a), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x9a, 0x59, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x59, 0x00, 0x9b), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x9b, 0x56, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x56, 0x00, 0x9c), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x9c, 0x57, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x57, 0x00, 0x9d), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x9d, 0x58, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x58, 0x00, 0x9e), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x9e, 0x59, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x59, 0x00, 0x9f), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x9f, 0x60, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x60, 0x00, 0xa0), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xa0, 0x0b, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x0b, 0xff, 0xa1), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xa1, 0x0c, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x0c, 0xff, 0xa2), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xa2, 0x0c, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x0c, 0xff, 0xa3), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xa3, 0x0d, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x0d, 0xff, 0xa4), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xa4, 0x53, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x53, 0xff, 0xa5), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xa5, 0x54, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x54, 0xff, 0xa6), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xa6, 0x75, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x75, 0xff, 0xa7), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xa7, 0x76, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x76, 0xff, 0xa8), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xa8, 0x77, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x77, 0xff, 0xa9), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xa9, 0x78, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x78, 0xff, 0xaa), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xaa, 0x76, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x76, 0xff, 0xab), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xab, 0xa1, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xa1, 0x00, 0xac), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xac, 0xc1, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xc1, 0x00, 0xad), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xad, 0xd1, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xd1, 0x00, 0xae), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xae, 0xe1, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xe1, 0x00, 0xaf), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xaf, 0xf1, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xf1, 0x00, 0xb0), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xb0, 0xae, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xae, 0x00, 0xb1), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xb1, 0xbe, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xbe, 0x00, 0xb2), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xb2, 0xdd, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xdd, 0x00, 0xb3), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xb3, 0xee, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xee, 0x00, 0xb4), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xb4, 0x1d, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x1d, 0x00, 0xb5), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xb5, 0x3a, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x3a, 0x00, 0xb6), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xb6, 0x4a, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x4a, 0x00, 0xb7), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xb7, 0x5a, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x5a, 0x00, 0xb8), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xb8, 0x7e, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x7e, 0x00, 0xb9), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xb9, 0x3f, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x3f, 0x00, 0xba), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xba, 0x3f, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x3f, 0x00, 0xbb), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xbb, 0xa1, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xa1, 0x00, 0xbc), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xbc, 0xa2, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xa2, 0x00, 0xbd), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xbd, 0xa3, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xa3, 0x00, 0xbe), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xbe, 0xa4, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xa4, 0x00, 0xbf), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xbf, 0xa5, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xa5, 0x00, 0xc0), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xc0, 0xa6, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xa6, 0x00, 0xc1), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xc1, 0x1f, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x1f, 0x00, 0xc2), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xc2, 0x2f, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x2f, 0x00, 0xc3), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xc3, 0x3f, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x3f, 0x00, 0xc4), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xc4, 0x4f, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x4f, 0x00, 0xc5), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xc5, 0x5f, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x5f, 0x00, 0xc6), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xc6, 0x6f, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x6f, 0x00, 0xc7), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xc7, 0x7f, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x7f, 0x00, 0xc8), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xc8, 0x1d, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x1d, 0x00, 0xc9), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xc9, 0xaa, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xaa, 0x00, 0xca), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xca, 0xbb, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xbb, 0x00, 0xcb), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xcb, 0xcd, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xcd, 0x00, 0xcc), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xcc, 0xce, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xce, 0x00, 0xcd), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xcd, 0xde, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xde, 0x00, 0xce), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xce, 0xdf, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xdf, 0x00, 0xcf), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xcf, 0xdb, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xdb, 0x00, 0xd0), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xd0, 0x6e, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x6e, 0x00, 0xd1), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xd1, 0x5e, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x5e, 0x00, 0xd2), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xd2, 0x8e, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x8e, 0x00, 0xd3), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xd3, 0x9e, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x9e, 0x00, 0xd4), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xd4, 0xae, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xae, 0x00, 0xd5), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xd5, 0xbe, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xbe, 0x00, 0xd6), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xd6, 0xee, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xee, 0x00, 0xd7), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xd7, 0x1c, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x1c, 0x00, 0xd8), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xd8, 0x33, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x33, 0x00, 0xd9), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xd9, 0x88, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x88, 0x00, 0xda), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xda, 0x0d, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x0d, 0x00, 0xdb), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xdb, 0x88, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x88, 0x00, 0xdc), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xdc, 0x99, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x99, 0x00, 0xdd), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xdd, 0x66, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x66, 0x00, 0xde), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xde, 0x49, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x49, 0x00, 0xdf), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xdf, 0x86, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x86, 0x00, 0xe0), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xe0, 0x3a, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x3a, 0x00, 0xe1), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xe1, 0xd0, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xd0, 0x00, 0xe2), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xe2, 0xd2, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xd2, 0x00, 0xe3), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xe3, 0xd3, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xd3, 0x00, 0xe4), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xe4, 0xd4, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xd4, 0x00, 0xe5), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xe5, 0xdf, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xdf, 0x00, 0xe6), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xe6, 0xef, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xef, 0x00, 0xe7), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xe7, 0xed, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xed, 0x00, 0xe8), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xe8, 0xcc, 0x00), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xcc, 0x00, 0xe9), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xe9, 0x1f, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x1f, 0xff, 0xea), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xea, 0x2f, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x2f, 0xff, 0xeb), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xeb, 0x3f, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x3f, 0xff, 0xec), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xec, 0x4f, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x4f, 0xff, 0xed), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xed, 0x5f, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x5f, 0xff, 0xee), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xee, 0x6f, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x6f, 0xff, 0xef), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xef, 0x7f, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x7f, 0xff, 0xf0), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xf0, 0xc9, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xc9, 0xff, 0xf1), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xf1, 0xb9, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xb9, 0xff, 0xf2), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xf2, 0xd9, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xd9, 0xff, 0xf3), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xf3, 0xe1, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0xe1, 0xff, 0xf4), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xf4, 0x8f, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x8f, 0xff, 0xf5), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xf5, 0x7a, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x7a, 0xff, 0xf6), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xf6, 0x7b, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x7b, 0xff, 0xf7), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xf7, 0x7c, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x7c, 0xff, 0xf8), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xf8, 0x7d, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x7d, 0xff, 0xf9), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xf9, 0x7e, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x7e, 0xff, 0xfa), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xfa, 0x6a, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x6a, 0xff, 0xfb), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xfb, 0x6b, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x6b, 0xff, 0xfc), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xfc, 0x7e, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x7e, 0xff, 0xfd), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xfd, 0x0a, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x0a, 0xff, 0xfe), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xfe, 0x0b, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x0b, 0xff, 0xff), \ + IOV_DATA(0x12, 0x09, 0x00, 0x01, 0xff, 0x0c, 0xff), \ + IOV_DATA(0x13), \ + IOV_DATA(0x1b, 0x03, 0x00, 0x0c, 0xff, 0x00) + +static void test_vocs_unit_testcases(void) +{ + /* + * VOCS Unit Testcases + */ + define_test("VOCS/SR/SGGIT/SER/BV-01-C", test_server, NULL, + VOCS_SR_SGGIT_SER_BV_01_C); + + define_test("VOCS/SR/SGGIT/CHA/BV-01-C", test_server, NULL, + VOCS_SR_SGGIT_CHA_BV_01_C); + define_test("VOCS/SR/SGGIT/CHA/BV-02-C", test_server, NULL, + VOCS_SR_SGGIT_CHA_BV_02_C); + define_test("VOCS/SR/SGGIT/CHA/BV-03-C", test_server, NULL, + VOCS_SR_SGGIT_CHA_BV_03_C); + define_test("VOCS/SR/SGGIT/CHA/BV-04-C", test_server, NULL, + VOCS_SR_SGGIT_CHA_BV_04_C); + + define_test("VOCS/SR/SGGIT/CP/BI-01-C", test_server, NULL, + VOCS_SR_SGGIT_CP_BI_01_C); + define_test("VOCS/SR/SGGIT/CP/BI-02-C", test_server, NULL, + VOCS_SR_SGGIT_CP_BI_02_C); + define_test("VOCS/SR/SGGIT/CP/BI-03-C", test_server, NULL, + VOCS_SR_SGGIT_CP_BI_03_C); + + define_test("VOCS/SR/SPE/BI-01-C", test_server, NULL, + VOCS_SR_SPE_BI_01_C); + + define_test("VOCS/SR/CP/BV-01-C", test_server, NULL, + VOCS_SR_CP_BV_01_C); +} + +static void test_aics_unit_testcases(void) +{ + /* + * AICS Unit Testcases + */ + define_test("AICS/SR/SGGIT/CHA/BV-01-C", test_server, NULL, + AICS_SR_SGGIT_CHA_BV_01_C); + + define_test("AICS/SR/SGGIT/CHA/BV-02-C", test_server, NULL, + AICS_SR_SGGIT_CHA_BV_02_C); + + define_test("AICS/SR/SGGIT/CHA/BV-03-C", test_server, NULL, + AICS_SR_SGGIT_CHA_BV_03_C); + + define_test("AICS/SR/SGGIT/CHA/BV-04-C", test_server, NULL, + AICS_SR_SGGIT_CHA_BV_04_C); + + define_test("AICS/SR/SGGIT/CHA/BV-05-C", test_server, NULL, + AICS_SR_SGGIT_CHA_BV_05_C); + + define_test("AICS/SR/SGGIT/CHA/BV-06-C", test_server, NULL, + AICS_SR_SGGIT_CHA_BV_06_C); + + define_test("AICS/SR/SGGIT/CP/BI-01-C", test_server, NULL, + AICS_SR_SGGIT_CP_BI_01_C); + + define_test("AICS/SR/SGGIT/CP/BI-02-C", test_server, NULL, + AICS_SR_SGGIT_CP_BI_02_C); + + /* AICS/SR/SGGIT/CP/BI-03-C: + * In function *aics_new(struct gatt_db *db)[src/shared/vcp.c] + * by default state of the 'aics_aud_ip_st->mute' is set to + * AICS_NOT_MUTED[0x00];. + * As per test specs, Testcase AICS/SR/SGGIT/CP/BI-03-C, Initial + * condition of mute state should be AICS_DISABLED[0x02]. + * To verify this Unit test case we have to modify the initial + * state of 'aics_aud_ip_st->mute' to AICS_DISABLED in code + * [in func aics_new()], build it and run bluetoothd. Then run + * this unit test case and this test case will Pass. + */ + /* define_test("AICS/SR/SGGIT/CP/BI-03-C", test_server, NULL, + * AICS_SR_SGGIT_CP_BI_03_C); + */ + + /* AICS/SR/SGGIT/CP/BI-04-C - TO-DO Need to give two times input + * from user during test case run + */ + + define_test("AICS/SR/CP/BV-01-C", test_server, NULL, + AICS_SR_CP_BV_01_C); + + /* AICS/SR/CP/BV-02-C: + * In function *aics_new(struct gatt_db *db)[src/shared/vcp.c] + * by default state of the 'aics_aud_ip_st->mute' is set to + * AICS_NOT_MUTED[0x00];. + * As per test specs, Testcase AICS/SR/CP/BV-02-C, Initial + * condition of mute state should be AICS_MUTED[0x01]. + * To verify this Unit test case we have to modify the initial + * state of 'aics_aud_ip_st->mute' to AICS_MUTED in code + * [in func aics_new()], build it and run bluetoothd. Then run + * this unit test case and this test case will Pass. + */ + /* define_test("AICS/SR/CP/BV-02-C", test_server, NULL, + * AICS_SR_CP_BV_02_C); + */ + + /* AICS/SR/CP/BV-03-C: + * In function *aics_new(struct gatt_db *db)[src/shared/vcp.c] + * by default state of the 'aics_aud_ip_st->mute' is set to + * AICS_NOT_MUTED[0x00];. + * As per test specs, Testcase AICS/SR/CP/BV-03-C, Initial + * condition of mute state should be AICS_NOT_MUTED[0x00]. + * If you have changed this value to some other value, then + * To verify this Unit test case you have to modify the initial + * state of 'aics_aud_ip_st->mute' to AICS_NOT_MUTED in code + * [in func aics_new()], build it and run bluetoothd. Then run + * this unit test case and this test case will Pass. + */ + /* define_test("AICS/SR/CP/BV-03-C", test_server, NULL, + * AICS_SR_CP_BV_03_C); + */ + + /* AICS/SR/CP/BV-04-C: + * In function *aics_new(struct gatt_db *db)[src/shared/vcp.c] + * by default state of the 'aics_aud_ip_st->gain_mode' is set to + * AICS_GAIN_MODE_MANUAL[0x02];. + * As per test specs, Testcase AICS/SR/CP/BV-04-C, Initial + * value of gain mode field, should be AICS_GAIN_MODE_AUTO[0x03]. + * To verify this Unit test case you have to modify the initial + * state of 'aics_aud_ip_st->gain_mode' to AICS_GAIN_MODE_AUTO in code + * [in func aics_new()], build it and run bluetoothd. Then run + * this unit test case and this test case will Pass. + */ + /* define_test("AICS/SR/CP/BV-04-C", test_server, NULL, + * AICS_SR_CP_BV_04_C); + */ + + /* AICS/SR/CP/BV-05-C: + * In function *aics_new(struct gatt_db *db)[src/shared/vcp.c] + * by default state of the 'aics_aud_ip_st->gain_mode' is set to + * AICS_GAIN_MODE_MANUAL[0x02];. + * As per test specs, Testcase AICS/SR/CP/BV-05-C, Initial + * value of gain mode field, should be AICS_GAIN_MODE_MANUAL[0x02]. + * If you have changed this value to some other value, then + * To verify this Unit test case you have to modify the initial + * state of 'aics_aud_ip_st->gain_mode' to AICS_GAIN_MODE_MANUAL in code + * [in func aics_new()], build it and run bluetoothd. Then run + * this unit test case and this test case will Pass. + */ + /* define_test("AICS/SR/CP/BV-05-C", test_server, NULL, + * AICS_SR_CP_BV_05_C); + */ + define_test("AICS/SR/SPE/BI-01-C", test_server, NULL, + AICS_SR_SPE_BI_01_C); + + +} +int main(int argc, char *argv[]) +{ + tester_init(&argc, &argv); + + test_vocs_unit_testcases(); + test_aics_unit_testcases(); + + return tester_run(); +} +